Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #2519 > unrolled thread

proposal to allow to set the delimiter in str.format to something other than curly bracket

Started byAlia Khouri <alia_khouri@yahoo.com>
First post2011-04-03 03:07 -0700
Last post2011-04-04 14:32 -0700
Articles 9 — 5 participants

Back to article view | Back to comp.lang.python


Contents

  proposal to allow to set the delimiter in str.format to something other than curly bracket Alia Khouri <alia_khouri@yahoo.com> - 2011-04-03 03:07 -0700
    Re: proposal to allow to set the delimiter in str.format to something other than curly bracket Corey Richardson <kb1pkl@aim.com> - 2011-04-03 06:53 -0400
      Re: proposal to allow to set the delimiter in str.format to something other than curly bracket Alia Khouri <alia_khouri@yahoo.com> - 2011-04-03 05:17 -0700
    Re: proposal to allow to set the delimiter in str.format to something other than curly bracket Terry Reedy <tjreedy@udel.edu> - 2011-04-04 01:17 -0400
      Re: proposal to allow to set the delimiter in str.format to something other than curly bracket Alia Khouri <alia_khouri@yahoo.com> - 2011-04-04 08:42 -0700
        Re: proposal to allow to set the delimiter in str.format to something other than curly bracket Peter Otten <__peter__@web.de> - 2011-04-04 18:18 +0200
          Re: proposal to allow to set the delimiter in str.format to something other than curly bracket Alia Khouri <alia_khouri@yahoo.com> - 2011-04-04 13:45 -0700
            Re: proposal to allow to set the delimiter in str.format to something other than curly bracket Neil Cerutti <neilc@norwich.edu> - 2011-04-05 13:45 +0000
          Re: proposal to allow to set the delimiter in str.format to something other than curly bracket Alia Khouri <alia_khouri@yahoo.com> - 2011-04-04 14:32 -0700

#2519 — proposal to allow to set the delimiter in str.format to something other than curly bracket

FromAlia Khouri <alia_khouri@yahoo.com>
Date2011-04-03 03:07 -0700
Subjectproposal to allow to set the delimiter in str.format to something other than curly bracket
Message-ID<a227e6f7-45ae-4404-973f-b69adf156440@d19g2000yql.googlegroups.com>
Hi folks,

I've been using ironpython2.7 in a project, and I was generating some
csharp code when i discovered that I couldn't use use str.format
because the interference with the brackets-aplenty situation in
csharp.

In [1]: code = "class {0}Model { public bool IsModel(){ return
true; } }"

In [2]: code.format('My')
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call
last)

KeyError: ' public bool IsModel(){ return true; } '

Please note I had no trouble with the trusty old % interpolation
method.

Now given that using str.format in this use case (code generation) is
equally difficult for other bracketed languages, and that str.format
is supposed to eventually become 'best-practice' for python string
formatting, can I get some feedback on a proposal that for the odd
case when brackets don't cut it, there is a way to redefine the
delimiter for str.format so that one could do something like this:

    str.format_delimiter = ("[[", "]]")

and we could write something like this:

In [1]: code = "class [[0]]Model { public bool IsModel(){ return
true; } }"
In [2]: code.format('My')
Out[3]: 'class MyModel { public bool IsModel(){ return true; } }'


Please give your +N or -N and reasons below.

AK

[toc] | [next] | [standalone]


#2524

FromCorey Richardson <kb1pkl@aim.com>
Date2011-04-03 06:53 -0400
Message-ID<mailman.166.1301828304.2990.python-list@python.org>
In reply to#2519
On 04/03/2011 06:07 AM, Alia Khouri wrote:
> Hi folks,
> 
> I've been using ironpython2.7 in a project, and I was generating some
> csharp code when i discovered that I couldn't use use str.format
> because the interference with the brackets-aplenty situation in
> csharp.
> 

Roll your own http://docs.python.org/library/string.html#string.Formatter

-- 
Corey Richardson

[toc] | [prev] | [next] | [standalone]


#2526

FromAlia Khouri <alia_khouri@yahoo.com>
Date2011-04-03 05:17 -0700
Message-ID<0c67412d-32fa-498e-bc2a-23a48e1deef3@e21g2000yqe.googlegroups.com>
In reply to#2524
On Apr 3, 1:53 pm, Corey Richardson <kb1...@aim.com> wrote:
> On 04/03/2011 06:07 AM, Alia Khouri wrote:
>
> > Hi folks,
>
> > I've been using ironpython2.7 in a project, and I was generating some
> > csharp code when i discovered that I couldn't use use str.format
> > because the interference with the brackets-aplenty situation in
> > csharp.
>
> Roll your ownhttp://docs.python.org/library/string.html#string.Formatter
>

(-:

Thanks for the tip, looks I can subclass string.Template to get what I
need.

Kicking myself for posting too early...

AK

[toc] | [prev] | [next] | [standalone]


#2547

FromTerry Reedy <tjreedy@udel.edu>
Date2011-04-04 01:17 -0400
Message-ID<mailman.180.1301894287.2990.python-list@python.org>
In reply to#2519
On 4/3/2011 6:07 AM, Alia Khouri wrote:
> Hi folks,
>
> I've been using ironpython2.7 in a project, and I was generating some
> csharp code when i discovered that I couldn't use use str.format
> because the interference with the brackets-aplenty situation in
> csharp.
>
> In [1]: code = "class {0}Model { public bool IsModel(){ return
> true; } }"
>
> In [2]: code.format('My')

Just double the brackets, just as one doubles '\\' to get '\' in a string.

 >>> "class {0}Model {{ public bool IsModel(){{ returntrue; }} 
}}".format('My')
'class MyModel { public bool IsModel(){ returntrue; } }'


-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#2571

FromAlia Khouri <alia_khouri@yahoo.com>
Date2011-04-04 08:42 -0700
Message-ID<902f640f-7540-4309-bb54-a1e71d86bb87@d28g2000yqc.googlegroups.com>
In reply to#2547
Terry Reedy wrote:

> Just double the brackets, just as one doubles '\\' to get '\' in a string.
>
>  >>> "class {0}Model {{ public bool IsModel(){{ returntrue; }}}}".format('My')
>
> 'class MyModel { public bool IsModel(){ returntrue; } }'
>

Indeed, I tried that, but it means I have to double bracket all the
csharp code which just creates more work for me.

Here is my solution (aka Cheetah ultra-light) ripped from
stdlib.string: it involves hacking the string.Template class so that
you get attribute lookups. I know it uses eval, and it's probably
highly insecure, but it's for one off batch jobs, and I hope it
doesn't hurt anyone:

<code>
import re

class _multimap:
    """Helper class for combining multiple mappings.

    Used by .substitute() to combine the mapping and keyword
    arguments.
    """
    def __init__(self, primary, secondary):
        self._primary = primary
        self._secondary = secondary

    def __getitem__(self, key):
        try:
            return self._primary[key]
        except KeyError:
            return self._secondary[key]


class _TemplateMetaclass(type):
    pattern = r"""
    %(delim)s(?:
      (?P<escaped>%(delim)s) |   # Escape sequence of two delimiters
      (?P<named>%(id)s)      |   # delimiter and a Python identifier
      {(?P<braced>%(id)s)}   |   # delimiter and a braced identifier
      (?P<invalid>)              # Other ill-formed delimiter exprs
    )
    """

    def __init__(cls, name, bases, dct):
        super(_TemplateMetaclass, cls).__init__(name, bases, dct)
        if 'pattern' in dct:
            pattern = cls.pattern
        else:
            pattern = _TemplateMetaclass.pattern % {
                'delim' : re.escape(cls.delimiter),
                'id'    : cls.idpattern,
                }
        cls.pattern = re.compile(pattern, re.IGNORECASE | re.VERBOSE)


class Template:
    """A string class for supporting $-substitutions."""
    __metaclass__ = _TemplateMetaclass

    delimiter = '$'
    idpattern = r'[_a-z][_a-z0-9\.]*'

    def __init__(self, template):
        self.template = template

    # Search for $$, $identifier, ${identifier}, and any bare $'s

    def _invalid(self, mo):
        i = mo.start('invalid')
        lines = self.template[:i].splitlines(True)
        if not lines:
            colno = 1
            lineno = 1
        else:
            colno = i - len(''.join(lines[:-1]))
            lineno = len(lines)
        raise ValueError('Invalid placeholder in string: line %d, col
%d' %
                         (lineno, colno))

    def substitute(self, *args, **kws):
        if len(args) > 1:
            raise TypeError('Too many positional arguments')
        if not args:
            mapping = kws
        elif kws:
            mapping = _multimap(kws, args[0])
        else:
            mapping = args[0]
        # Helper function for .sub()
        def convert(mo):
            # Check the most common path first.
            named = mo.group('named') or mo.group('braced')
            if named is not None:
                # We use this idiom instead of str() because the
latter will
                # fail if val is a Unicode containing non-ASCII
characters.
                # XXXX here is the probably dangerous eval hack XXXXXX
                if '.' in named:
                    return eval(named, kws)
                else:
                    val = mapping[named]
                    return '%s' % (val,)

            if mo.group('escaped') is not None:
                return self.delimiter
            if mo.group('invalid') is not None:
                self._invalid(mo)
            raise ValueError('Unrecognized named group in pattern',
                             self.pattern)
        return self.pattern.sub(convert, self.template)


def test_templates():
    class P: pass
    p = P()
    p.name = 'ak'
    txt = 'hello there ${o.name}'
    t = Template(txt)
    assert t.substitute(o=p) == 'hello there ak'

if __name__ == '__main__': test_templates()

</code>

[toc] | [prev] | [next] | [standalone]


#2573

FromPeter Otten <__peter__@web.de>
Date2011-04-04 18:18 +0200
Message-ID<mailman.7.1301933897.9059.python-list@python.org>
In reply to#2571
Alia Khouri wrote:

> Terry Reedy wrote:
> 
>> Just double the brackets, just as one doubles '\\' to get '\' in a
>> string.
>>
>> >>> "class {0}Model {{ public bool IsModel(){{ returntrue;
>> }}}}".format('My')
>>
>> 'class MyModel { public bool IsModel(){ returntrue; } }'
>>
> 
> Indeed, I tried that, but it means I have to double bracket all the
> csharp code which just creates more work for me.

You could automatically convert from a custom format like that in your 
original post:

import re

_lookup = {
    "[[": "{",
    "]]": "}",
    "{": "{{",
    "}": "}}",
}

def _substitute(m):
    return _lookup[m.group()]

def custom_format(template, *args, **kw):
    return (re.compile(r"\[\[|]]|\{|\}")
            .sub(_substitute, template)
            .format(*args, **kw))

code = "class [[0]]Model { public bool IsModel(){ return a[42] || true; } }"
print custom_format(code, "My")

[toc] | [prev] | [next] | [standalone]


#2596

FromAlia Khouri <alia_khouri@yahoo.com>
Date2011-04-04 13:45 -0700
Message-ID<de6117d4-867a-450d-bf8a-4a9482204cd4@18g2000prd.googlegroups.com>
In reply to#2573
Peter Otten wrote:
> You could automatically convert from a custom format like that in your
> original post:
>
> import re
>
> _lookup = {
>     "[[": "{",
>     "]]": "}",
>     "{": "{{",
>     "}": "}}",
>
> }
>
> def _substitute(m):
>     return _lookup[m.group()]
>
> def custom_format(template, *args, **kw):
>     return (re.compile(r"\[\[|]]|\{|\}")
>             .sub(_substitute, template)
>             .format(*args, **kw))
>
> code = "class [[0]]Model { public bool IsModel(){ return a[42] || true; } }"
> print custom_format(code, "My")

Nice! I didn't think of that. I guess I could get some additional
performance by taking the re.compile step out of the function. Thanks
for the tip!

AK

AK

[toc] | [prev] | [next] | [standalone]


#2649

FromNeil Cerutti <neilc@norwich.edu>
Date2011-04-05 13:45 +0000
Message-ID<900kohFh35U8@mid.individual.net>
In reply to#2596
On 2011-04-04, Alia Khouri <alia_khouri@yahoo.com> wrote:
> Nice! I didn't think of that. I guess I could get some
> additional performance by taking the re.compile step out of the
> function. Thanks for the tip!

I recommend "The Pragmatic Programmer," (Hunt, Thomas) ISBN
978-0201616224 and "The Practice of Programming," (Kernighan,
Pike) ISBN 978-0201615869 for more practical tips like this one.
As a mostly self-taught programmer, both books helped me
immensely. If you're a seasoned pro with a CS degree, you might
not find them quite as interesting, though. The second book,
especially, does not cover issues relating to large scale
software development.

As for factoring out re.compile, I believe they are cached by the
re module, so you would save the cost of retrieving the cached
regex, but not the cost of building it.

-- 
Neil Cerutti

[toc] | [prev] | [next] | [standalone]


#2599

FromAlia Khouri <alia_khouri@yahoo.com>
Date2011-04-04 14:32 -0700
Message-ID<e86c298c-069d-447a-bb8a-ea2f9fffb552@34g2000pru.googlegroups.com>
In reply to#2573
Peter Otten wrote:

> You could automatically convert from a custom format like that in your
> original post...

<snip>

Here's a class wrapping your functionality:

import re

class Template(object):
    '''uses double brackets e.g [[ob.attr]] as delims to get
      around curly bracket ({}) collisions when generating code
    '''
    _pattern = re.compile(r"\[\[|]]|\{|\}")
    _lookup = {
        "[[": "{",
        "]]": "}",
        "{": "{{",
        "}": "}}",
    }
    def __init__(self, txt):
        self.txt = txt
        self.type = type

    def _substitute(self, m):
        return self._lookup[m.group()]

    def render(self, *args, **kwds):
        return self._pattern.sub(
            self._substitute, self.txt).format(*args, **kwds)

def test_Template():
    class P: pass
    p = P()
    p.name = 'peter'
    txt = 'hello there [[o.name]]'
    t = Template(txt)
    assert t.render(o=p) == 'hello there peter'

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web