At 03:10 AM 5/5/2006 -0300, Jorge Godoy wrote:
>Em Sexta 05 Maio 2006 02:55, Jorge Godoy escreveu:
> > Hi Phillip,
> >
> >
> > I was talking to Kevin Dangoor a while ago about implementing some
> > extension to Turbogears' "tg-admin info" where it listed not only what
> > Turbogears required to work, but also what requires Turbogears.
> >
> > Currently pkg_resources provides a "require()" method --
> > http://peak.telecommunity.com/DevCenter/PythonEggs#automatic-discovery --
> > and I'd like to know what do you think about implementing a dual operation
> > for this and providing an is_required_by() method?
> >
> > The idea is to provide the package name and list all eggs that requires
> > this package.
>
>I believe I got the correct syntax for this.  What do you think?  (I'm not
>using the same abstraction as you do in your code, this is just a sample
>implementation)
>
>
> >>> def is_required_by(package):
>...     for item in pkg_resources.AvailableDistributions():
>...         for required in pkg_resources.require(item):
>...             if str(required).startswith(package): print item

A few pointers:

1. 'AvailableDistributions' is deprecated and will disappear in 0.7; please 
use 'Environment' instead.

2. You're going to get false positive hits if 'package' is something like 
'turbo' -- use 'if required.key==safe_name(package).lower()' instead.  (Or 
better yet, do 'package = safe_name(package).lower()' at the start of the 
routine, outside the loops.)

3. As written, your code may scan sys.path directories multiple times, and 
thus be slow.  Rather than using 'require()', I suggest using the 
'resolve()' method of a working set, and passing in the environment you 
started with.

4. As written, your routine is not at all specific about which packages are 
required by which versions of things, and in fact it will show only the 
dependencies for versions that are currently active on sys.path.  As a 
result, it's also subject to throwing version conflict errors.

I strongly suggest that you define which versions of which packages you 
mean for this to operate on.  As written, it displays dependencies for the 
version on sys.path, or the most recent version if none is defined.  And it 
has side effects, since it will add things to sys.path as it runs.  This 
isn't a good idea.

What you should do is get a collection of Distribution instances that 
reflect the set of eggs that you want to verify dependencies for.  You 
should then ask each instance for its requirements, e.g.:

     def depends_on(dist, req):
         if not isinstance(req, Requirement):
             req = Requirement.parse(req)
         for r in dist.requires():
             if r.key == req.key:
                 return True
         else:
             return False

You can now do something like '[dist for dist in eggs if 
depends_on(dist,"foo")]'.

No, it's not recursive, but its behavior is well-defined, it doesn't do 
repeated disk scans each time you make a pass over the set, and it doesn't 
alter the contents of sys.path in any way.  If you want it to be recursive, 
you would do something like:

     def find_dependers(req, distributions, memo=None):
         if memo is None:
             memo = {}
         for dist in distributions:
             if dist in memo:
                 continue
             memo[dist] = 1
             if depends_on(dist, req):
                 yield dist
                 for dist in find_dependers(dist.as_requirement(), 
distributions, memo):
                     yield dist

This should yield the distributions from the input list that require 'req'.

So your only remaining problem would be to specify what distributions 
should be given as the input list.  You may wish to simply flatten an 
Environment, which would list all the installed eggs that depend on another 
egg, whether they are active on sys.path at present or not.  e.g.:

    env = Environment()
    list(find_dependers('foo', [d for k in env for d in env[k]]))

You could also just use working_set as the list of 'distributions', in 
which case only the distributions active on sys.path would be tested for 
dependencies.

None of the above code is tested, but should put you on the right 
track.  Please also consult the API documentation at:

     http://peak.telecommunity.com/DevCenter/PkgResources

to find out more about using the APIs I used above.

_______________________________________________
Distutils-SIG maillist  -  [email protected]
http://mail.python.org/mailman/listinfo/distutils-sig

Reply via email to