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