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