diff treepkg/cmdexpand.py @ 44:a2ce575ce82b

add cmdexpand function and tests
author Bernhard Herzog <bh@intevation.de>
date Mon, 19 Mar 2007 20:14:07 +0100
parents
children 83e1aa122ad0
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/treepkg/cmdexpand.py	Mon Mar 19 20:14:07 2007 +0100
@@ -0,0 +1,73 @@
+# Copyright (C) 2007 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh@intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Shell like string splitting and expansion"""
+
+import re
+import shlex
+
+
+# helper for the other regular expression matching a python identifier
+match_identifier = "[_a-zA-Z][_a-zA-Z0-9]*"
+
+# regular expression to use for word expansion matching a dollar
+# followed by exactly one of these:
+#  a) another dollar sign or the at-sign (for quoting of these characters)
+#  b) a python identifier
+#  c) a python identifier enclosed in braces
+#  d) something else which indicates invalid use of the dollar sign
+rx_word_expansion = re.compile(r"\$((?P<delim>[$@])"
+                               r"|(?P<named>%(identifier)s)"
+                               r"|\{(?P<braced>%(identifier)s)\}"
+                               r"|(?P<invalid>))"
+                               % dict(identifier=match_identifier))
+
+# regular expression matching an entire word that has to be list
+# expanded.  The regex matches if the word starts with an at-sign.  The
+# part of the word that followes the at-sign either matches an
+# identifier with the named group "named" or anything else which
+# indicates invalid use the at-sign.
+rx_list_expansion = re.compile(r"^@((?P<named>%(identifier)s)|(?P<invalid>.+))$"
+                               % dict(identifier=match_identifier))
+
+# match an unquoted at-sign.
+rx_unquoted_at = re.compile("[^$]@")
+
+def expandword(word, mapping):
+    def replacment(match):
+        key = match.group("named") or match.group("braced")
+        if key:
+            return str(mapping[key])
+
+        delim = match.group("delim")
+        if delim:
+            return delim
+
+        # otherwise invalid has matched and we raise a value error
+        assert match.group("invalid") != None
+        raise ValueError
+
+    return rx_word_expansion.sub(replacment, word)
+
+def cmdexpand(string, **kw):
+    words = shlex.split(string)
+    for index, word in reversed(list(enumerate(words))):
+        match = rx_unquoted_at.search(word)
+        if match:
+            raise ValueError("%r contains an unquoted '@'" % word)
+        match = rx_list_expansion.match(word)
+        if match:
+            key = match.group("named")
+            if key:
+                words[index:index + 1] = (str(item) for item in kw[key])
+            else:
+                assert match.group("invalid") != None
+                raise ValueError("In %r the characters after the '@'"
+                                 " do not match a python identifier" % word)
+        else:
+            words[index] = expandword(word, kw)
+    return words
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)