[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