[Python-checkins] python/nondist/sandbox/string/string alt292.py, NONE, 1.1

rhettinger at users.sourceforge.net rhettinger at users.sourceforge.net
Mon Aug 9 07:52:51 CEST 2004


Update of /cvsroot/python/python/nondist/sandbox/string/string
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27487

Added Files:
	alt292.py 
Log Message:
Suggest an alternate approach to implementing PEP292 with functions.



--- NEW FILE: alt292.py ---
# Alternate implementation of PEP 292
#   uses functions instead of classes
#   does not consume memory with a pre-converted template
#   directly extendable with a user supplied pattern
#   C speed iteration using re.sub instead of % formatting
#
# Todo:
#   rename functions for clarity (sub_from_env or somesuch)
#   add dotted attribute lookup

__all__ = ['regularsub', 'safesub', 'envsub']

import re
import sys

_pattern = re.compile(r'(\${2})|\$([_a-z][_a-z0-9]*)|\${([_a-z][_a-z0-9]*)}',
                      re.IGNORECASE)

def regularsub(template, mapping, pattern=_pattern):
    # raises KeyError if key not found
    def xlat(matchobj, mapping=mapping):
        escape, name, braced = matchobj.groups()
        if escape is not None:
            return '$'
        return mapping[name or braced]
    return pattern.sub(xlat, template)

def safesub(template, mapping, pattern=_pattern):
    # Idempotent if key is missing
    def xlat(matchobj, mapping=mapping):
        escape, name, braced = matchobj.groups()
        if escape is not None:
            return '$'
        if name is not None:
            try:
                return mapping[name]
            except KeyError:
                return '$' + name
        try:
            return mapping[braced]
        except KeyError:
            return '${' + braced + '}'
    return _pattern.sub(xlat, template)

def envsub(template):
    # Default mapping from the locals/globals of caller
    frame = sys._getframe(1)
    mapping = frame.f_globals.copy()
    mapping.update(frame.f_locals)
    mapping['$$'] = '$'
    def xlat(matchobj, mapping=mapping):
        return mapping[matchobj.group(matchobj.lastindex)]
    return _pattern.sub(xlat, template)


####### Unittests  ########################

import unittest
class TestSimplerSubstitutions(unittest.TestCase):

    def test_regular(self):
        s = '$name was born in ${country} $$'
        self.assertEqual(
            regularsub(s, {'name':'Guido', 'country':'the Netherlands'}),
            'Guido was born in the Netherlands $')
        maps = [
            {'name':'Tim'},
            {'country':'the Netherlands'},
            {},
        ]
        for mapping in maps:
            self.assertRaises(KeyError, regularsub, s, mapping)

    def test_safe(self):
        s = '$name was born in ${country} $$'
        pairs = [
            ({'name':'Guido', 'country':'the Netherlands'}, 'Guido was born in the Netherlands $'),
            ({'name':'Tim'}, 'Tim was born in ${country} $'),
            ({'country':'the Netherlands'}, '$name was born in the Netherlands $'),
            ({}, '$name was born in ${country} $'),
        ]
        for mapping, expected in pairs:
            self.assertEqual(safesub(s, mapping), expected)

    def test_env(self):
        s = '$name was born in ${country} $$'
        name = 'Guido'
        country = 'the Netherlands'
        self.assertEqual(envsub(s), 'Guido was born in the Netherlands $')
        del name
        self.assertRaises(KeyError, envsub, s)


if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(unittest.makeSuite(TestSimplerSubstitutions))
    unittest.TextTestRunner(verbosity=2).run(suite)



More information about the Python-checkins mailing list