Package osh :: Module function
[frames] | no frames]

Source Code for Module osh.function

  1  # osh 
  2  # Copyright (C) Jack Orenstein <jao@geophile.com> 
  3  # 
  4  # This program is free software; you can redistribute it and/or modify 
  5  # it under the terms of the GNU General Public License as published by 
  6  # the Free Software Foundation; either version 2 of the License, or 
  7  # (at your option) any later version. 
  8  # 
  9  # This program is distributed in the hope that it will be useful, 
 10  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 12  # GNU General Public License for more details. 
 13  # 
 14  # You should have received a copy of the GNU General Public License 
 15  # along with this program; if not, write to the Free Software 
 16  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 17   
 18  """Encapsulates functions used in osh commands such as C{f} and C{select}. 
 19   
 20  osh function syntax:: 
 21   
 22      [[lambda] ARGS:] EXPRESSION 
 23   
 24  C{ARGS}: Comma-separated list of function arguments, optionally preceded by keyword 
 25  C{lambda}. C{ARGS} may be omitted only for a function with no arguments. 
 26   
 27  C{EXPRESSION}: A Python expression written in terms of the function arguments. 
 28   
 29  Example:: 
 30   
 31      x: max(x, 10) 
 32  """ 
 33   
 34  import copy 
 35  import sys 
 36  import types 
 37   
 38  import core 
 39   
 40  _LAMBDA = 'lambda ' 
 41  _LAMBDA_COLON = 'lambda:' 
 42   
 43  # "Private" name (with leading underscore) so that epydoc doesn't document the class 
44 -class _Function(object):
45 """Represents a function for use by osh commands with function arguments, 46 e.g., select. 47 """ 48 49 _function_spec = None 50 _function = None 51 _function_id = None 52
53 - def __init__(self, function_spec, namespace = core.__dict__):
54 """Creates a Function. 55 - function_spec: String specification of a function. Uses lambda notation, 56 but the 'lambda' keyword is optional. 57 - namespace: The default is reasonable; there's been no need to 58 override it so far. 59 """ 60 if type(function_spec) in (types.FunctionType, types.BuiltinFunctionType): 61 self._function = function_spec 62 else: 63 self._function_spec = function_spec 64 lambda_expression = self.parse(function_spec.strip()) 65 # Create a namespace including symbols defined by the current osh invocation. 66 namespace = copy.copy(namespace) 67 namespace.update(core.namespace()) 68 self._function = eval(lambda_expression, namespace)
69
70 - def __repr__(self):
71 return 'function(%s)' % self._function_spec
72
73 - def __call__(self, *args): # args = None):
74 return self._function(*args)
75
76 - def parse(self, function_spec):
77 # If the function spec starts with a lambda, then just use it as is. 78 # Otherwise, it could be: 79 # - function with arg list, e.g. "x, y: x + y" 80 # - zero-arg list with colon, e.g. ": processes()" 81 # - zero-arg list without colon, e.g. "processes()" 82 # Try prepending "lambda:" and "lambda" until there's 83 # no syntax error. Crude but effective. 84 if function_spec.startswith(_LAMBDA) or function_spec.startswith(_LAMBDA_COLON): 85 # ok as is 86 pass 87 else: 88 fixed_function_spec = '%s: %s' % (_LAMBDA, function_spec) 89 try: 90 eval(fixed_function_spec) 91 function_spec = fixed_function_spec 92 except: 93 fixed_function_spec = '%s %s' % (_LAMBDA, function_spec) 94 try: 95 eval(fixed_function_spec) 96 function_spec = fixed_function_spec 97 except: 98 raise NotAFunctionException('Illegal function spec: %s' % function_spec) 99 return function_spec
100
101 -class NotAFunctionException(Exception):
102
103 - def __init__(self, message):
104 Exception.__init__(self, message)
105
106 -def _operator_to_function(op):
107 if op == '+': 108 f = lambda x, y: x + y 109 elif op == '*': 110 f = lambda x, y: x * y 111 elif op == '^': 112 f = lambda x, y: x ^ y 113 elif op == '&': 114 f = lambda x, y: x & y 115 elif op == '|': 116 f = lambda x, y: x | y 117 elif op == 'and': 118 f = lambda x, y: x and y 119 elif op == 'or': 120 f = lambda x, y: x or y 121 elif op == 'max': 122 f = lambda x, y: max(x, y) 123 elif op == 'min': 124 f = lambda x, y: min(x, y) 125 else: 126 f = None 127 return f
128
129 -def _create_function(x):
130 f = None 131 if type(x) in [types.FunctionType, types.BuiltinFunctionType]: 132 f = _Function(x) 133 elif isinstance(x, str): 134 op = _operator_to_function(x) 135 if op: 136 f = _Function(op) 137 else: 138 f = _Function(x) 139 return f
140