[Distutils] Re: FW: Extracting meta-data from distributions

Greg Ward gward@python.net
Sat, 5 Aug 2000 22:57:39 -0400

On 05 August 2000, Amos Latteier said:
> Right. However I was looking for something I could do from Python, not
> the command line. I'd like to import the distribution's setup module and
> then interrogate it from Python to find out meta-data.

I know, how about
  os.popen("%s setup.py --name --version" % sys.executable).read()

Just kidding!

Right now, I can't think of a good way to do this.  As you suspected,
you'd have to write your own setup() function and stick it into
distutils.core before importing setup, then just "import setup".
setup.py would then call your craftily constructed 'setup()' function
instead of the standard one.

Obviously, your setup() would probably look an awful lot like the one in 
distutils.core; you should really read through the source to see what it 
does.  Here's a summary:

  * figure out the distribution class to use (default
  * instantiate the distribution class, using (most of) the keyword args
    to 'setup()' as constructor args.  (IOW,
      setup(name="Distutils, version="1.0")
    is nearly equivalent to
      Distribution(name="Distutils, version="1.0")
  * parse config files
  * parse the command line
  * run all commands mentioned on the command line, using the
    per-command options that were found by parsing config files
    and the command line

You might think that this:

  from distutils.dist import Distribution
  from distutils import core
  core.setup = Distribution
  import setup

would work, but there are two problems:
  * there's at least one keyword arg to 'setup()' that is not
    passed to the Distribution constructor: 'distclass', which
    specifies the distribution class to use (this is one of
    the "backdoors" for extending the Distutils, but (AFAIK)
    it has never been used in practice)
  * no way to get at the Distribution object slyly created for you

Next option: write your own version of 'setup()' that just does the
first two steps and stores the created object somewhere you can get your
hands on it (eg. a global in distutils.core), and then replace
distutils.core.setup with your version.

Best option: change the Distutils so that it (optionally) does this for
you.  Eg. where a normal setup script does this:

    from distutils.core import setup
    setup(name = "Distutils,
          version = "1.0")

and nothing more, your tool would do something like this:

    from distutils import core

    core.do_nothing_mode()       # better name?
    import setup
    dist = core.get_distribution()
    dist.get_name(), dist.get_version(), ...

I think you could get away with execfile()'ing "setup.py" instead of
importing it; it's not really a module to be imported, after all.  It
would have the same effect: call the official Distutils 'setup()'
function, which -- since we're in "do nothing" mode -- just does the
first two steps and saves the distribution object somewhere.
'get_distribution()' would then retrieve that distribution object so you
can query its meta-data.

A bit of a hack, sure, I think it'll work.  Let me know if you cook up a 
patch to core.py, or if you'd rather I did it.  Shouldn't be too hard.

> To install a distribution obviously you must trust it. I'm imaging a
> system that does stuff like crawl the web looking for Python
> distributions, downloads them and parses them for meta-data. In this
> case I don't trust the distribution enough to install it, but I do want
> to find out what it has to say for itself.

Yeah, I can definitely see that as useful in (say) a Distutils-aware
Vaults of Parnassus.  You still have to import or execfile() untrusted
code, of course.  Ahh well...

Greg Ward - geek-at-large                               gward@python.net
All the world's a stage and most of us are desperately unrehearsed.