PEP 359: The "make" Statement

Steven Bethard steven.bethard at gmail.com
Fri Apr 14 11:31:28 EDT 2006


Steven Bethard wrote:
> Duncan Booth wrote:
>> Steven Bethard wrote:
>>
>>> Should users of the make statement be able to determine in which dict
>>> object the code is executed?  The make statement could look for a
>>> ``__make_dict__`` attribute and call it to allow things like::
>>>
>>>      make Element html:
>>>          make Element body:
>>>              make Element h1:
>>>                  '''First heading text'''
>>>              make Element h1:
>>>                  '''Second heading text'''
>>
> [snip]
>> There is another effect which should be considered here. If you allow 
>> Element to create an object to be used as the namespace, then as well 
>> as doing special tracking when values are set in the namespace it can 
>> also pre-seed it with names which magically appear in scope within the 
>> make.
>>
>> e.g.
>>
>> make Element html:
>>     make Element body:
>>         make Element p:
>>             text('But this ')
>>             make Element strong:
>>                  text('could')
>>             text(' be made to work')
> 
> This is nice.  I'll have to play around with it a bit to see how hard it 
> would be to make it work.

Okay, I think it'll work[1].  I'm going to update this section to 
something more like:


Open Issues
===========

...

Should users of the make statement be able to determine in which dict
object the code is executed?  This would allow the make statement to
be used in situations where a normal dict object would not suffice,
e.g. if order and repeated names must be allowed. Allowing this sort
of customization could allow XML to be written like::

     make Element html:
         make Element body:
             text('before first h1')
             make Element h1:
                 attrib(style='first')
                 text('first h1')
                 tail('after first h1')
             make Element h1:
                 attrib(style='second')
                 text('second h1')
                 tail('after second h1')

     assert etree.ElementTree.tostring(body) == '''\
     <html>\
     <body>\
     before first h1\
     <h1 style="first">first h1</h1>\
     after first h1\
     <h1 style="second">second h1</h1>\
     after second h1\
     </body>\
     </html>\
     '''

Assuming that the make statement calls the callable's
``__make_dict__`` to get the dict in which to execute the code, the
following should make the above make statements work::

     class Element(object):

         class __make_dict__(dict):

             def __init__(self, *args, **kwargs):
                 self._super = super(Element.__make_dict__, self)
                 self._super.__init__(*args, **kwargs)
                 self.elements = []
                 self.text = None
                 self.tail = None
                 self.attrib = {}

             def __getitem__(self, name):
                 try:
                     return self._super.__getitem__(name)
                 except KeyError:
                     if name in ['attrib', 'text', 'tail']:
                         return getattr(self, 'set_%s' % name)
                     else:
                         return globals()[name]

             def __setitem__(self, name, value):
                 self._super.__setitem__(name, value)
                 self.elements.append(value)

             def set_attrib(self, **kwargs):
                 self.attrib = kwargs

             def set_text(self, text):
                 self.text = text

             def set_tail(self, text):
                 self.tail = text

         def __new__(cls, name, args, edict):
             get_element = etree.ElementTree.Element
             result = get_element(name, attrib=edict.attrib)
             result.text = edict.text
             result.tail = edict.tail
             for element in edict.elements:
                 result.append(element)
             return result



[1] Here's the code I used to test it.

 >>> def make(callable, name, args, block_string):
...     try:
...         make_dict = callable.__make_dict__
...     except AttributeError:
...         make_dict = dict
...     block_dict = make_dict()
...     exec block_string in block_dict
...     return callable(name, args, block_dict)
...
 >>> class Element(object):
...     class __make_dict__(dict):
...         def __init__(self, *args, **kwargs):
...             self._super = super(Element.__make_dict__, self)
...             self._super.__init__(*args, **kwargs)
...             self.elements = []
...             self.text = None
...             self.tail = None
...             self.attrib = {}
...         def __getitem__(self, name):
...             try:
...                 return self._super.__getitem__(name)
...             except KeyError:
...                 if name in ['attrib', 'text', 'tail']:
...                     return getattr(self, 'set_%s' % name)
...                 else:
...                     return globals()[name]
...         def __setitem__(self, name, value):
...             self._super.__setitem__(name, value)
...             self.elements.append(value)
...         def set_attrib(self, **kwargs):
...             self.attrib = kwargs
...         def set_text(self, text):
...             self.text = text
...         def set_tail(self, text):
...             self.tail = text
...     def __new__(cls, name, args, edict):
...         get_element = etree.ElementTree.Element
...         result = get_element(name, attrib=edict.attrib)
...         result.text = edict.text
...         result.tail = edict.tail
...         for element in edict.elements:
...             result.append(element)
...         return result
...
 >>> body = make(Element, 'body', (), textwrap.dedent("""\
...     text('before first h1')
...     h1 = make(Element, 'h1', (), textwrap.dedent('''
...         attrib(style='first')
...         text('first h1')
...         tail('after first h1')
...     '''))
...     h1 = make(Element, 'h1', (), textwrap.dedent('''
...         attrib(style='second')
...         text('second h1')
...         tail('after second h1')
...     '''))
... """))
 >>> assert etree.ElementTree.tostring(body) == '''\
... <body>\
... before first h1\
... <h1 style="first">first h1</h1>\
... after first h1\
... <h1 style="second">second h1</h1>\
... after second h1\
... </body>\
... '''


STeVe



More information about the Python-list mailing list