Skip to content

Commit

Permalink
Merge 38a85e8 into 95184aa
Browse files Browse the repository at this point in the history
  • Loading branch information
shibasisp committed May 31, 2017
2 parents 95184aa + 38a85e8 commit c43fe32
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 42 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -11,3 +11,4 @@ casacore.egg-info/
.coverage
.virtualenv/
.virtualenv3/
htmlcov
1 change: 0 additions & 1 deletion casacore/tables/__init__.py
Expand Up @@ -66,4 +66,3 @@
from .tableiter import tableiter
from .tablerow import tablerow
from .tableutil import *

44 changes: 28 additions & 16 deletions casacore/util/substitute.py
Expand Up @@ -24,10 +24,11 @@
# Charlottesville, VA 22903-2475 USA
#
# $Id$
__all__ = ['getlocals', 'getvariable', 'substitute']

import numpy as np

__all__ = ['getlocals', 'getvariable', 'substitute']


def getlocals(back=2):
"""Get the local variables some levels back (-1 is top)."""
Expand All @@ -44,14 +45,14 @@ def getlocals(back=2):


def getvariable(name):
"""Get the value of a local variable somewhere in the call stack"""
"""Get the value of a local variable somewhere in the call stack."""
import inspect
fr = inspect.currentframe()
try:
while fr:
fr = fr.f_back
vars = fr.f_locals
if vars.has_key(name):
if name in vars:
return vars[name]
except:
pass
Expand All @@ -75,7 +76,7 @@ def substitute(s, objlist=(), globals={}, locals={}):
if an environment variable is used. Note that an extra backslash
is required in Python to escape the backslash.
The output contains the quotes and backslashes.
3. A variable is looked up in the given localand global namespaces.
3. A variable is looked up in the given local and global namespaces.
4. If the variable `name` has a vector value, its substitution is
enclosed in square brackets and separated by commas.
5. A string value is enclosed in double quotes. If the value
Expand All @@ -90,7 +91,8 @@ def substitute(s, objlist=(), globals={}, locals={}):
1. The first field is the object type (e.g. `table`)
2. The second field is a prefix for the sequence number (usually empty).
E.g. regions could have prefix 'r' resulting in a substitution like `$r1`.
E.g. regions could have prefix 'r' resulting in a substitution like
`$r1`.
3. The third field is a list of objects to be substituted. New objects
get appended to it. Usually the list is initially empty.
Expand All @@ -99,19 +101,29 @@ def substitute(s, objlist=(), globals={}, locals={}):
It correctly handles parentheses and quotes in the expression.
For example::
a=2
b=3
substitute('$(a+b)+$a') # results in '5+2' (not '7')
substitute('$((a+b)+$a)') # results in '7'
substitute('$((a+b)*(a+b))') # results in '25'
substitute('$(len("ab cd( de"))') # results in '9'
>>> a = 2
>>> b = 3
>>> substitute('$(a+b)+$a')
'5+2'
>>> substitute('$(a+b+a)')
'7'
>>> substitute('$((a+b)+$a)')
'$((a+b)+$a)'
>>> substitute('$((a+b)*(a+b))')
'25'
>>> substitute('$(len("ab cd( de"))')
'9'
Substitution is NOT recursive. E.g. if a=1 and b="$a",
the result of substitute("$b") is "$a" and not 1.
"""
# Get the local variables at the caller level if not given.
if len(locals) == 0:
if not locals:
locals = getlocals(3)
# Initialize some variables.
backslash = False
Expand All @@ -130,12 +142,12 @@ def substitute(s, objlist=(), globals={}, locals={}):
continue
# If a dollar is found, we might have a name or expression.
# Alphabetics and underscore are always part of name.
if dollar and nparen == 0:
if tmp == '_' or (tmp >= 'a' and tmp <= 'z') or (tmp >= 'A' and tmp <= 'Z'):
if dollar and nparen == 0:
if tmp == '_' or ('a' <= tmp <= 'z') or ('A' <= tmp <= 'Z'):
name += tmp
continue
# Numerics are only part if not first character.
if tmp >= '0' and tmp <= '9' and name != '':
if '0' <= tmp <= '9' and name != '':
name += tmp
continue
# $( indicates the start of an expression to evaluate.
Expand Down Expand Up @@ -204,7 +216,7 @@ def substitutename(name, objlist, globals, locals):
# First try as a single variable; otherwise as an expression.
try:
v = getvariable(name)
if v == None:
if v is None:
v = eval(name, globals, locals)
except NameError:
return '$' + name
Expand Down
50 changes: 25 additions & 25 deletions tests/test_util.py
Expand Up @@ -8,30 +8,6 @@ def f1(arg):
print(a, arg, s)


def f2():
a=2
b=3
c="xyz"
d1=True
s1=(1,2,3)
s2=['ab','cde','f','ghij']

assert substitute ('$a $b $c $d1') == '2 3 "xyz" T'
assert substitute ('$(a) $(b) $(c) $(d1)') == '2 3 "xyz" T'
assert substitute ('$b $0 $a "$a" $b') == '3 $0 2 "$a" 3'
assert substitute ('$(a+b)') == '5'
assert substitute ('$((a+b)*(a+b))') == '25'
assert substitute ('$((a+b)*(a+c))') == '$((a+b)*(a+c))'
assert substitute ('"$(a+b)"') == '"$(a+b)"'
assert substitute ('\\$(a+b) \\\\$a \\$a') == '\\$(a+b) \\\\2 \\$a'

assert substitute('$(a+b)+$a') == '5+2'
assert substitute('$((a+b)+a)') == '7'
assert substitute('$((a+b)*(a+b))') == '25'
assert substitute('$(len("ab cd( de"))') == '9'
assert substitute(' $s1 $s2 ') == ' [1,2,3] ["ab","cde","f","ghij"] '


class TestUtil(unittest.TestCase):
def test_util(self):
a = 1
Expand All @@ -41,4 +17,28 @@ def test_util(self):
print("a=%d, b=%d, %s => %s" % (a, b, p, s))
f1(23)
f1('xyz')
f2()

def test_substitute(self):
a = 2
b = 3
c = "xyz"
d1 = True
s1 = (1, 2, 3)
s2 = ['ab', 'cde', 'f', 'ghij']

self.assertTrue(substitute('$a $b $c $d1') == '2 3 "xyz" T')
self.assertTrue(substitute('$(a) $(b) $(c) $(d1)') == '2 3 "xyz" T')
self.assertTrue(substitute('$b $0 $a "$a" $b') == '3 $0 2 "$a" 3')
self.assertTrue(substitute('$(a+b)') == '5')
self.assertTrue(substitute('$((a+b)*(a+b))') == '25')
self.assertTrue(substitute('$((a+b)*(a+c))') == '$((a+b)*(a+c))')
self.assertTrue(substitute('"$(a+b)"') == '"$(a+b)"')
self.assertTrue(substitute('\\$(a+b) \\\\$a \\$a') ==
'\\$(a+b) \\\\2 \\$a')

self.assertTrue(substitute('$(a+b)+$a') == '5+2')
self.assertTrue(substitute('$((a+b)+a)') == '7')
self.assertTrue(substitute('$((a+b)*(a+b))') == '25')
self.assertTrue(substitute('$(len("ab cd( de"))') == '9')
self.assertTrue(substitute(
' $s1 $s2 ') == ' [1,2,3] ["ab","cde","f","ghij"] ')

0 comments on commit c43fe32

Please sign in to comment.