[Web-SIG] OT: dotted names
Alice Bevan–McGregor
alice at gothcandy.com
Wed Jul 6 20:33:34 CEST 2011
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.
More information about the Web-SIG
mailing list