Coverage for larch/builtins.py: 57%

161 statements  

« prev     ^ index     » next       coverage.py v7.6.0, created at 2024-10-16 21:04 +0000

1#!/usr/bin/env python 

2""" Builtins for larch""" 

3 

4import sys 

5import time 

6 

7from . import utils 

8from .utils.show import _larch_builtins as show_builtins 

9 

10from .larchlib import parse_group_args, Journal 

11from .symboltable import Group 

12from .version import show_version 

13 

14from . import math 

15from . import io 

16from . import fitting 

17from . import xray 

18from . import xrf 

19from . import xafs 

20from . import xrd 

21from . import xrmmap 

22from . import wxlib 

23 

24from .utils import physical_constants 

25 

26__core_modules = [math, fitting, io, xray, xrf, xafs, xrd, xrmmap, wxlib] 

27 

28try: 

29 from . import epics 

30 __core_modules.append(epics) 

31except ImportError: 

32 pass 

33 

34if wxlib.HAS_WXPYTHON: 

35 try: 

36 from .wxlib import plotter 

37 from . import wxmap, wxxas, wxxrd 

38 __core_modules.extend([plotter, wxmap, wxxas, wxxrd]) 

39 except: 

40 pass 

41 

42# inherit most available symbols from python's __builtins__ 

43from_builtin = [sym for sym in __builtins__ if not sym.startswith('__')] 

44 

45# inherit these from math (many will be overridden by numpy) 

46from_math = ('acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 

47 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'exp', 

48 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'hypot', 

49 'isinf', 'isnan', 'ldexp', 'log', 'log10', 'log1p', 'modf', 

50 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 

51 'trunc') 

52 

53# inherit these from numpy 

54from_numpy = ('abs', 'add', 'all', 'amax', 'amin', 'angle', 'any', 'append', 

55 'arange', 'arccos', 'arccosh', 'arcsin', 'arcsinh', 'arctan', 'arctan2', 

56 'arctanh', 'argmax', 'argmin', 'argsort', 'argwhere', 'around', 'array', 

57 'asarray', 'atleast_1d', 'atleast_2d', 'atleast_3d', 'average', 'bartlett', 

58 'bitwise_and', 'bitwise_not', 'bitwise_or', 'bitwise_xor', 'blackman', 

59 'broadcast', 'ceil', 'choose', 'clip', 'column_stack', 'common_type', 

60 'complex128', 'compress', 'concatenate', 'conjugate', 'convolve', 

61 'copysign', 'corrcoef', 'correlate', 'cos', 'cosh', 'cov', 'cross', 

62 'cumprod', 'cumsum', 'datetime_data', 'deg2rad', 'degrees', 'delete', 

63 'diag', 'diag_indices', 'diag_indices_from', 'diagflat', 'diagonal', 

64 'diff', 'digitize', 'divide', 'dot', 'dsplit', 'dstack', 'dtype', 'e', 

65 'ediff1d', 'empty', 'empty_like', 'equal', 'exp', 'exp2', 'expand_dims', 

66 'expm1', 'extract', 'eye', 'fabs', 'fft', 'fill_diagonal', 'finfo', 'fix', 

67 'flatiter', 'flatnonzero', 'fliplr', 'flipud', 'float64', 'floor', 

68 'floor_divide', 'fmax', 'fmin', 'fmod', 'format_parser', 'frexp', 

69 'frombuffer', 'fromfile', 'fromfunction', 'fromiter', 'frompyfunc', 

70 'fromregex', 'fromstring', 'genfromtxt', 'getbufsize', 'geterr', 

71 'gradient', 'greater', 'greater_equal', 'hamming', 'hanning', 'histogram', 

72 'histogram2d', 'histogramdd', 'hsplit', 'hstack', 'hypot', 'i0', 

73 'identity', 'iinfo', 'imag', 'indices', 'inexact', 'inf', 'info', 'inner', 

74 'insert', 'int32', 'integer', 'interp', 'intersect1d', 'invert', 

75 'iscomplex', 'iscomplexobj', 'isfinite', 'isinf', 'isnan', 'isneginf', 

76 'isposinf', 'isreal', 'isrealobj', 'isscalar', 'iterable', 'kaiser', 

77 'kron', 'ldexp', 'left_shift', 'less', 'less_equal', 'linalg', 'linspace', 

78 'little_endian', 'loadtxt', 'log', 'log10', 'log1p', 'log2', 'logaddexp', 

79 'logaddexp2', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 

80 'logspace', 'longdouble', 'longlong', 'mask_indices', 'matrix', 'maximum', 

81 'may_share_memory', 'mean', 'median', 'memmap', 'meshgrid', 'minimum', 

82 'mintypecode', 'mod', 'modf', 'msort', 'multiply', 'nan', 'nan_to_num', 

83 'nanargmax', 'nanargmin', 'nanmax', 'nanmin', 'nansum', 'ndarray', 

84 'ndenumerate', 'ndim', 'ndindex', 'negative', 'nextafter', 'nonzero', 

85 'not_equal', 'number', 'ones', 'ones_like', 'outer', 'packbits', 

86 'percentile', 'pi', 'piecewise', 'place', 'poly', 'poly1d', 'polyadd', 

87 'polyder', 'polydiv', 'polyint', 'polymul', 'polynomial', 'polysub', 

88 'polyval', 'power', 'prod', 'ptp', 'put', 'putmask', 'rad2deg', 'radians', 

89 'random', 'ravel', 'real', 'real_if_close', 'reciprocal', 'record', 

90 'remainder', 'repeat', 'reshape', 'resize', 'right_shift', 'rint', 'roll', 

91 'rollaxis', 'roots', 'rot90', 'round', 'searchsorted', 'select', 

92 'setbufsize', 'setdiff1d', 'seterr', 'setxor1d', 'shape', 'short', 'sign', 

93 'signbit', 'signedinteger', 'sin', 'sinc', 'single', 'sinh', 'size', 

94 'sort', 'sort_complex', 'spacing', 'split', 'sqrt', 'square', 'squeeze', 

95 'std', 'subtract', 'sum', 'swapaxes', 'take', 'tan', 'tanh', 'tensordot', 

96 'tile', 'trace', 'transpose', 'tri', 'tril', 'tril_indices', 

97 'tril_indices_from', 'trim_zeros', 'triu', 'triu_indices', 

98 'triu_indices_from', 'true_divide', 'trunc', 'ubyte', 'uint', 'uint32', 

99 'union1d', 'unique', 'unravel_index', 'unsignedinteger', 'unwrap', 

100 'ushort', 'vander', 'var', 'vdot', 'vectorize', 'vsplit', 'vstack', 

101 'where', 'zeros', 'zeros_like') 

102 

103numpy_renames = {'ln':'log', 'asin':'arcsin', 'acos':'arccos', 

104 'atan':'arctan', 'atan2':'arctan2', 'atanh':'arctanh', 

105 'acosh':'arccosh', 'asinh':'arcsinh', 'npy_save': 'save', 

106 'npy_load': 'load', 'npy_copy': 'copy'} 

107 

108constants = {} 

109for pconst_name in ('PLANCK_HC', 'AVOGADRO', 'AMU', 

110 'R_ELECTRON_ANG','DEG2RAD', 'RAD2DEG'): 

111 constants[pconst_name] = getattr(physical_constants, pconst_name) 

112 

113 

114 

115## More builtin commands, to set up the larch language: 

116 

117# def _group(_larch=None, **kws): 

118# """create a group""" 

119# if _larch is None: 

120# _larch = Group() 

121# else: 

122# group = _larch.symtable.create_group() 

123# for key, val in kws.items(): 

124# setattr(group, key, val) 

125# return group 

126 

127def _eval(text, filename=None, _larch=None): 

128 """evaluate a string of larch text 

129 """ 

130 if _larch is None: 

131 raise Warning("cannot eval string -- larch broken?") 

132 return _larch.eval(text, fname=filename) 

133 

134 

135def _run(filename=None, new_module=None, _larch=None): 

136 "execute the larch text in a file as larch code." 

137 if _larch is None: 

138 raise Warning(f"cannot run file '{filename:s}' -- larch broken?") 

139 return _larch.runfile(filename, new_module=new_module) 

140 

141def _reload(mod, _larch=None): 

142 """reload a module, either larch or python""" 

143 if _larch is None: 

144 raise Warning(f"cannot reload module '{mod:s}' -- larch broken?") 

145 

146 modname = None 

147 if mod in _larch.symtable._sys.modules.values(): 

148 for k, v in _larch.symtable._sys.modules.items(): 

149 if v == mod: 

150 modname = k 

151 elif mod in sys.modules.values(): 

152 for k, v in sys.modules.items(): 

153 if v == mod: 

154 modname = k 

155 elif (mod in _larch.symtable._sys.modules.keys() or 

156 mod in sys.modules.keys()): 

157 modname = mod 

158 

159 if modname is not None: 

160 return _larch.import_module(modname, do_reload=True) 

161 

162def _help(*args, _larch=None): 

163 "show help on topic or object" 

164 write = sys.stdout.write 

165 if _larch is not None: 

166 write = _larch.writer.write 

167 buff = [] 

168 for arg in args: 

169 if _larch is not None and isinstance(arg, str): 

170 arg= _larch.symtable.get_symbol(arg, create=False) 

171 buff.append(repr(arg)) 

172 if callable(arg) and arg.__doc__ is not None: 

173 buff.append(arg.__doc__) 

174 buff.append('') 

175 write('\n'.join(buff)) 

176 

177 

178def _journal(*args, **kws): 

179 return Journal(*args, **kws) 

180 

181def _dir(obj=None, _larch=None): 

182 "return directory of an object -- thin wrapper about python builtin" 

183 if obj is None and _larch is not None: 

184 obj = _larch.symtable 

185 return dir(obj) 

186 

187def _subgroups(obj): 

188 "return list of subgroups" 

189 if isinstance(obj, Group): 

190 return obj._subgroups() 

191 raise Warning("subgroups() argument must be a group") 

192 

193def _groupitems(obj): 

194 "returns group items as if items() method of a dict" 

195 if isinstance(obj, Group): 

196 return obj._members().items() 

197 raise Warning("group_items() argument must be a group") 

198 

199def _which(sym, _larch=None): 

200 "return full path of object, or None if object cannot be found" 

201 if _larch is None: 

202 raise Warning("cannot run which() -- larch broken?") 

203 stable = _larch.symtable 

204 if hasattr(sym, '__name__'): 

205 sym = sym.__name__ 

206 if isinstance(sym, str) and stable.has_symbol(sym): 

207 obj = stable.get_symbol(sym) 

208 if obj is not None: 

209 return '%s.%s' % (stable.get_parentpath(sym), sym) 

210 return None 

211 

212def _exists(sym, _larch=None): 

213 "return True if a named symbol exists and can be found, False otherwise" 

214 return _which(sym, _larch=_larch) is not None 

215 

216def _isgroup(obj, _larch=None): 

217 """return whether argument is a group or the name of a group 

218 

219 With additional arguments (all must be strings), it also tests 

220 that the group has an an attribute named for each argument. This 

221 can be used to test not only if a object is a Group, but whether 

222 it a group with expected arguments. 

223 

224 > x = 10 

225 > g = group(x=x, y=2) 

226 > isgroup(g), isgroup(x) 

227 True, False 

228 > isgroup('g'), isgroup('x') 

229 True, False 

230 > isgroup(g, 'x', 'y') 

231 True 

232 > isgroup(g, 'x', 'y', 'z') 

233 False 

234 

235 """ 

236 if (_larch is not None and 

237 isinstance(obj, str) and 

238 _larch.symtable.has_symbol(obj)): 

239 obj = _larch.symtable.get_symbol(obj) 

240 return isinstance(obj, Group) 

241 

242 

243def _pause(msg='Hit return to continue', _larch=None): 

244 if _larch is None: 

245 raise Warning("cannot pause() -- larch broken?") 

246 return input(msg) 

247 

248def _sleep(t=0): 

249 return time.sleep(t) 

250_sleep.__doc__ = time.sleep.__doc__ 

251 

252def _time(): 

253 return time.time() 

254_time.__doc__ = time.time.__doc__ 

255 

256def _strftime(format, *args): 

257 return time.strftime(format, *args) 

258_strftime.__doc__ = time.strftime.__doc__ 

259 

260 

261def save_history(filename, session_only=False, maxlines=5000, _larch=None): 

262 """save history of larch commands to a file""" 

263 _larch.input.history.save(filename, session_only=session_only, maxlines=maxlines) 

264 

265def show_history(max_lines=10000, _larch=None): 

266 """show history of larch commands""" 

267 nhist = min(max_lines, len(_larch.history.buffer)) 

268 for hline in _larch.history.buffer[-nhist:]: 

269 _larch.writer.write("%s\n" % hline) 

270 

271def init_display_group(_larch): 

272 symtab = _larch.symtable 

273 if not symtab.has_group('_sys.display'): 

274 symtab.new_group('_sys.display') 

275 colors = {} 

276 colors['text'] = {'color': None} 

277 colors['text2'] = {'color': 'cyan'} 

278 colors['comment'] = {'color': 'green'} 

279 colors['error'] = {'color': 'red', 'attrs': ['bold']} 

280 display = symtab._sys.display 

281 display.colors = colors 

282 display.use_color = True 

283 display.terminal = 'xterm' 

284 

285 

286_main_builtins = dict(group=Group, Group=Group, dir=_dir, which=_which, 

287 exists=_exists, isgroup=_isgroup, 

288 subgroups=_subgroups, group_items=_groupitems, 

289 parse_group_args=parse_group_args, pause=_pause, 

290 sleep=_sleep, systime=_time, clock=_time, 

291 strftime=_strftime, reload=_reload, run=_run, 

292 eval=_eval, help=_help, journal=_journal, 

293 show_version=show_version, 

294 save_history=save_history, 

295 show_history=show_history) 

296 

297_main_builtins.update(utils._larch_builtins) 

298_main_builtins.update(show_builtins) 

299 

300 

301# names to fill in the larch namespace at startup 

302init_builtins = dict(_builtin=_main_builtins) 

303 

304# functions to run (with signature fcn(_larch)) at interpreter startup 

305init_funcs = [init_display_group] 

306 

307# group/classes to register for save-restore 

308init_moddocs = {} 

309 

310for cmod in __core_modules: 

311 if cmod is None: 

312 continue 

313 cmodname = getattr(cmod, '_larch_name', cmod.__name__) 

314 if cmodname.startswith('larch.'): 

315 cmodname = cmodname.replace('larch.', '_') 

316 

317 doc = getattr(cmod, '__DOC__', None) 

318 if doc is not None: 

319 init_moddocs[cmodname] = doc 

320 builtins = getattr(cmod, '_larch_builtins', {}) 

321 init_fcn = getattr(cmod, '_larch_init', None) 

322 

323 for bkey, bval in builtins.items(): 

324 if bkey not in init_builtins: 

325 init_builtins[bkey] = bval 

326 else: 

327 init_builtins[bkey].update(bval) 

328 

329 if init_fcn is not None: 

330 init_funcs.append(init_fcn) 

331 

332# list of supported valid commands -- don't need parentheses for these 

333valid_commands = ['run', 'help', 'show', 'which', 'more', 'cd']