On 2011-04-15 22:33:08 +0000, P.J. Eby said:

At 04:11 PM 4/15/2011 -0400, Fred Drake wrote:
These end users don't really care if the object identified is a class or
function in module, a nested attribute on a class, or anything else, so
long as it does what it's advertised to do.  By not pushing implementation
details into the identifier, the package maintainer is free to change the
implementation in more ways, without creating backward incompatibility.

That would be one advantage of using entry points
instead.  ;-)  (i.e., the user doesn't specify the object location,
the package author does.)

Note, however, that one must perform considerably more work to
resolve a name, when you don't know whether each part of the name is
a module or an attribute.

Not if, as you mention, you use an explicit format. The format my resolver code uses (and this code is utilized in marrow.mailer for manager/transport lookup, marrow.server.http's command-line script to resolve WSGI applications, and marrow.templating to resolve templates) covers the following:

:: <object>
:: entrypoint_name
:: ../relative/path/to/something
:: ./relative/path/to/something
:: /absolute/path/to/something
:: package.relative/path/to/something
:: package.absolute.path
:: package.submodule:object
:: package.submodule:object.attribute

What is allowed on any given resolution depends on if the resolver request is looking for an on-disk path or object.

Using the above as an example, you can define the use of the SMTP transport within marrow.mailer in two ways:

from marrow.mailer.transport.smtp import SMTPTransport
config = dict(transport=SMTPTransport) # direct reference
config = dict(transport="smtp") # entry point
config = dict( # object lookup
   transport = "marrow.mailer.transport.smtp:SMTPTransport"
 )

When configuring m.s.http to load an app, you can:

# p-code
HTTPServer.serve("project.application:WSGIApp.factory")

When choosing templates, OTOH, you can do the following:

return "./templates/foo.html", dict()
return "/var/www/foo.html", dict()
return "myapp.templates.foo", dict()
return "myapp/templates/foo.html", dict()
return "myapp.stemplates:email.welcome", dict()

Either you have to get an AttributeError first, and then fall back to importing, or get an ImportError first, and fall back to getattr.

If you examine the above closely, the differing formats are easily identifiable using a few == and 'in' conditionals:

if not isinstance(ref, basestring):
   return ref

if ref[0] == '.': pass # relative
if ref[0] == '/': pass # absolute
if '/' not in ref and '.' not in ref and ':' not in ref:
   pass # entrypoint
if ':' in ref:
   import_, _, attrs = ref.partition(':')
   base = __import__(import_)
   for attr in attrs.split('.'):
       base = getattr(base, attr)
   return attr
if '/' in ref:
   import_, _, path = ref.partition('/')
   pass # use pkg_resources + path to pull file from package

If the syntax is explicit, OTOH, then you don't have to guess, thereby saving lots of work and wasteful exceptions.

:)

        — Alice.


_______________________________________________
Web-SIG mailing list
Web-SIG@python.org
Web SIG: http://www.python.org/sigs/web-sig
Unsubscribe: 
http://mail.python.org/mailman/options/web-sig/archive%40mail-archive.com

Reply via email to