Mercurial > treepkg > treepkg
annotate treepkg/cmdexpand.py @ 521:d26642ed6afa
use empty string as default config values instead of None
author | Bjoern Ricks <bricks@intevation.de> |
---|---|
date | Wed, 10 Nov 2010 16:48:03 +0000 |
parents | 83e1aa122ad0 |
children | 9d44d4da3411 |
rev | line source |
---|---|
44
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
1 # Copyright (C) 2007 by Intevation GmbH |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
2 # Authors: |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
3 # Bernhard Herzog <bh@intevation.de> |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
4 # |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
5 # This program is free software under the GPL (>=v2) |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
6 # Read the file COPYING coming with the software for details. |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
7 |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
8 """Shell like string splitting and expansion""" |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
9 |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
10 import re |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
11 import shlex |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
12 |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
13 |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
14 # helper for the other regular expression matching a python identifier |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
15 match_identifier = "[_a-zA-Z][_a-zA-Z0-9]*" |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
16 |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
17 # regular expression to use for word expansion matching a dollar |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
18 # followed by exactly one of these: |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
19 # a) another dollar sign or the at-sign (for quoting of these characters) |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
20 # b) a python identifier |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
21 # c) a python identifier enclosed in braces |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
22 # d) something else which indicates invalid use of the dollar sign |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
23 rx_word_expansion = re.compile(r"\$((?P<delim>[$@])" |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
24 r"|(?P<named>%(identifier)s)" |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
25 r"|\{(?P<braced>%(identifier)s)\}" |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
26 r"|(?P<invalid>))" |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
27 % dict(identifier=match_identifier)) |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
28 |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
29 # regular expression matching an entire word that has to be list |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
30 # expanded. The regex matches if the word starts with an at-sign. The |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
31 # part of the word that followes the at-sign either matches an |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
32 # identifier with the named group "named" or anything else which |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
33 # indicates invalid use the at-sign. |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
34 rx_list_expansion = re.compile(r"^@((?P<named>%(identifier)s)|(?P<invalid>.+))$" |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
35 % dict(identifier=match_identifier)) |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
36 |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
37 # match an unquoted at-sign. |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
38 rx_unquoted_at = re.compile("[^$]@") |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
39 |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
40 def expandword(word, mapping): |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
41 def replacment(match): |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
42 key = match.group("named") or match.group("braced") |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
43 if key: |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
44 return str(mapping[key]) |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
45 |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
46 delim = match.group("delim") |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
47 if delim: |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
48 return delim |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
49 |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
50 # otherwise invalid has matched and we raise a value error |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
51 assert match.group("invalid") != None |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
52 raise ValueError |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
53 |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
54 return rx_word_expansion.sub(replacment, word) |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
55 |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
56 def cmdexpand(string, **kw): |
56
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
57 """Split the string into 'words' and expand variable references. |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
58 |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
59 The string is first split into words with shlex.split. Each of the |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
60 words is then subjected to either word expansion or list expansion. |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
61 Word expansion is very similar to what the Template class in Python's |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
62 string module provides: |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
63 |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
64 '$$' is expanded to '$' |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
65 |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
66 '$@' is expanded to '@' |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
67 |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
68 '$identifier' is expanded to the value of the variable given by |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
69 identifier. The identifier has the same syntax as a normal Python |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
70 identifier. The identifier stops at the first non-identifier |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
71 character. The value is converted to a string with str. |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
72 |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
73 '${identifier}' is treated like '$identifier' and provides a way to |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
74 delimit the identifier in cases where the identifier is followed by |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
75 characters that would otherwise be interpreted as part of the |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
76 identifier. |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
77 |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
78 A word will remain a single word after the expansion even if the |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
79 expanded string would be treated as multiple words by shlex. |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
80 |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
81 A list expansion is applied to words that consist of a '@' followed by |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
82 an identifier. Nothing else must be in the word. The variable the |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
83 identifier refers to must be a sequence and the word will be replaced by |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
84 the sequence with each element of the sequence converted to a string |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
85 with str. |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
86 |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
87 The variables known to the function are the keyword arguments. |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
88 |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
89 Examples: |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
90 |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
91 >>> from cmdexpand import cmdexpand |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
92 >>> cmdexpand("ssh $user$@$host", user="john", host="python") |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
93 ['ssh', 'john@python'] |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
94 |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
95 >>> cmdexpand("scp @files $user$@$host:$remotedir", user="john", |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
96 ... host="python", files=["main.py", "cmdexpand.py"], |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
97 ... remotedir="/home/john/files") |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
98 ['scp', 'main.py', 'cmdexpand.py', 'john@python:/home/john/files'] |
83e1aa122ad0
upgrade cmdexpand to newer version
Bernhard Herzog <bh@intevation.de>
parents:
44
diff
changeset
|
99 """ |
44
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
100 words = shlex.split(string) |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
101 for index, word in reversed(list(enumerate(words))): |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
102 match = rx_unquoted_at.search(word) |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
103 if match: |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
104 raise ValueError("%r contains an unquoted '@'" % word) |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
105 match = rx_list_expansion.match(word) |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
106 if match: |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
107 key = match.group("named") |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
108 if key: |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
109 words[index:index + 1] = (str(item) for item in kw[key]) |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
110 else: |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
111 assert match.group("invalid") != None |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
112 raise ValueError("In %r the characters after the '@'" |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
113 " do not match a python identifier" % word) |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
114 else: |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
115 words[index] = expandword(word, kw) |
a2ce575ce82b
add cmdexpand function and tests
Bernhard Herzog <bh@intevation.de>
parents:
diff
changeset
|
116 return words |