[Web-SIG] PasteDeploy 0.1

Ian Bicking ianb at colorstudy.com
Wed Aug 24 00:27:39 CEST 2005


Phillip J. Eby wrote:
> I was thinking something more like this:
> 
>     class globalconfigservice:
>         def __init__(self, parent_component, **args):
>             self._parent = parent_component
>             self._data = args
> 
>         def get_service(self, key):
>             if key=='global_config':
>                 return self
>             return self._parent.get_service(key)
> 
>         def __getitem__(self,key):
>             try:
>                 return self._data[key]
>             except KeyError:
>                 previous = self._parent.get_service('global_config')
>                 if previous is None:
>                     raise
>                 result = self._data[key] = previous[key]
>                 return result
> 
> This isn't a wrapper, so it doesn't know about the "next" component, and 
> doesn't need to.  Parent components can be shared by multiple children.  
> Wrappers, on the other hand, transform their child, and are not 
> considered a parent component.

So services (aka components) are just a objects with .get_service(key) 
methods?  Is there any other API or semantics implied?

>> OK, well now I'm a bit confused... is globalconfigservice a wrapper?  
>> I assume globalconfigservice can't modify the parent_component it is 
>> passed, and has to create a new one?
> 
> 
> No. The globalconfigservice *becomes* the parent_component of the 
> components that follow it, until another non-wrapper component is 
> defined (which then becomes the parent of those that follow it, and so on).

Does the configuration somehow indicate that something produces a 
component, as opposed to producing the object-in-question (WSGI 
application for us)?  I'm not clear how an application, an application 
wrapper, and a component wrapper are distinguished.

>> Hmm... it would be nice to allow configuration filenames to be 
>> variables.  Though "in" and "from" don't scream "config file" and 
>> "egg" to me -- they are both equally vague terms.  I'd rather see "in 
>> egg" and "in file".
> 
> 
> I'd rather just use 'from ProjectNameHere' and 'from "config_URL_here"', 
> since these two syntaxes can cover everything you or I have thus far 
> imagined.

What exactly do you envision for config URLs?

>>>     main :=
>>>         login wrapper from Paste:
>>>             # blah
>>>         urlmap from Paste:
>>>             "/"     := static
>>>             "/blog" := main in "blog.ini"
>>>             "/cms"  :=
>>>                  auth wrapper from Paste:
>>>                      require_role = "admin"
>>>                  filebrowser from FileBrowser:
>>>                      document_root = static.document_root
>>
>>
>> ...for instance, when this was "main = pipeline:", it was clear this 
>> was just another "create", except using "pipeline" to create the 
>> object, and pipeline looks at the section contents.  The unnamed 
>> sections below it are just like positional parameters (would named 
>> sections be ordered? -- I've always wanted ordered class statements, I 
>> imagine I'd like to keep order here too)
> 
> 
> I don't really want them to be positional parameters, I want them to 
> stack.  If pipelines were rare, I'd just nest them and use e.g. a 'next' 
> keyword.  However, nested pipelines mean you have to indent everything 
> every time you add a new wrapper, which would be like having to do 
> "else: if:" instead of "elif:".

A stack and positional parameters are nearly the same thing...

def pipeline(*args):
     app = args[-1]
     wrappers = args[:-1]
     wrappers.reverse()
     for wrapper in wrappers:
         app = wrapper(app)
     return wrapper

...?  Throw in a couple other arguments and whatnot for keywords or 
whatever, it doesn't matter.

Another case where I would use positional parameters to do something 
different would be a cascading dispatcher, like:

main is cascade from Paste:
     static from Paste:
         document_root = "/..."
     blog from MyBlog:
         ...
     catch = 404

I can phrase the same thing in other ways (in paste.deploy it uses the 
sorted keys that start with "app"), but it seems like an unexpected 
bonus if the format is general enough to do this.

>> I don't have any attachment to "pipeline", but I think some word is 
>> fine in that position, and I don't see why this is a particularly 
>> "special" construct (except of course that it should be builtin).  
>> Would this be allowed?:
>>
>> main = urlmap from Paste:
>>   "/" = static from Paste:
>>     document_root = "/home/me/htdocs"
> 
> 
> This syntax is ambiguous, because you don't know if the thing after the 
> '=' should be parsed as a Python expression or as a constructor 
> expression, at least not without significant parser lookahead.  
> Significant lookahead isn't that good for a human reader, either.  
> That's why I think we need syntax to distinguish "object definition" 
> from "value assignment".

OK, I see the issue now.  I guess "is" is fine; I think using different 
punctuation like := is much too subtle.

>>> But that doesn't actually seem to help visually, and makes it harder 
>>> to write because you have to remember all the time whether you need 
>>> ":" or ":=".  Maybe this would be better:
>>>     main is:
>>>         login wrapper from Paste:
>>>             # blah
>>>         urlmap from Paste:
>>>             match_mode = "longest"
>>>             "/" is static
>>>             "/blog" is main in "blog.ini"
>>>             "/cms" is:
>>>                  auth wrapper from Paste:
>>>                      require_role = "admin"
>>>                  filebrowser from FileBrowser:
>>>                      document_root = static.document_root
>>
>>
>> While I'm not attached to "pipeline", "is" is about as vague as "in" 
>> and "from".
> 
> 
> Well, I'm fine with dropping "in", so we would have only two special 
> keywords, "is" and "from", and they're not interchangeable, so there's a 
> minimum of ambiguity.  Also, I chose "from" because of the similarity to 
> importing, and "is" implies object identity as well as definition (e.g. 
> "the definition of main is...").

If you really want similarities, invert "is" and call it "as".  "foo 
from AnEgg as main:".  But I think that's backwards, so I wouldn't 
really advocate for it.

> (One of the things I'm trying to do with this syntax, btw, is stick with 
> Python's tokens and keywords, so that the tokenize module can do most of 
> the heavy lifting, and I'd also prefer we didn't introduce new reserved 
> words that aren't keywords in Python.)
> 
> 
>> Assuming "main" was a special magic name for the primary application.  
>> I would certainly assume that reading the config file (even I'd never 
>> seen these config files before).  I, for instance, do not like 
>> Python's "if __name__=='__main__'" idiom; I think using a conventional 
>> name to indicate the primary function of a file is just fine.
> 
> 
> Well, __name__=='__main__' doesn't apply here.  I see this as the 
> difference between def statements and regular statements in a module.  
> Function bodies aren't executed unless they're used, so it seems wrong 
> to me to have a def main.  If the magic name were __main__ I could 
> accept it more, except for the fact that it would then highlight the 
> point that if the idiom is common enough to need a magic name, then it's 
> common enough to warrant a way of doing it without a name!

I think we disagree about one-app-per-file, and perhaps you also have a 
notion that doesn't come out in all of your examples that you want a 
stack represented at the top-level of the file...?  That is, like:

   auth from Paste:
     ...
   # wraps...
   session from Session:
     ...
   # wraps
   main from MyApp:
     ...


If that's what you are getting at, I *really* don't like that.  Config 
files don't use top-level ordering often at all.  The few cases where 
order matters, it's purely as priority for overlapping options (like 
rewrite rules).  And those few cases suck anyway because of the 
ambiguity of overlap, so it's kind of the exception that proves the rule.

I'm okay with ordering *under* the top-level names, like:

   main is:
     auth from Paste:
       ...
     session from Session:
       ...

... it doesn't appeal to me, but it doesn't bother me.

I don't want "main" (or worse "__main__") to be special, just to be 
conventional, like as a default to a keyword argument.

It's an ugly wart that every (good!) script in Python looks like:

   def main():
       ...

   if __name__ == '__main__':
       main()

That's nothing but stupid boilerplate, because otherwise you can't get 
at that function if you put everything in the "if" statement.  In the 
same way, I want to be able to  be able to pick pieces out of a 
configuration file without creating the main application, and I want to 
be able to look in the main application without creating it (since it's 
mostly opaque once it's been created).

__main__ is completely unnecessary, as "main" seems quite special on its 
own without scary underscores.  It's a very natural name, and one that 
should be intuitive to anyone reading the file.  That it has a name 
shows that it is a distinct entity, but a series of unnamed entries in 
the config file doesn't imply that in the same way.

>>   That's fine by me; I normalize \ to / in paste.deploy and run 
>> urllib.unquote on the result already.  I'm not sure what to do with 
>> \'s; they are dumb and annoying and I hate them, but when they slip 
>> into the system it should at least handle them reasonably.
> 
> 
> I think \ should have its normal meaning in a string literal, unless a 
> "raw" literal is used.

Hmm... it doesn't really matter to me, since I never use Windows.  But 
whenever I gaze upon Windows filenames in Python they hurt my eyes.

I agree anything in "" should be a string literal, with all the string 
literal rules.  Maybe these don't have to be string literals.

-- 
Ian Bicking  /  ianb at colorstudy.com  /  http://blog.ianbicking.org


More information about the Web-SIG mailing list