Coverage for /Users/Newville/Codes/xraylarch/larch/builtins.py: 57%

162 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-11-09 10:08 -0600

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 

54 

55from_numpy = ('Inf', 'NAN', 'abs', 'absolute', 'add', 'all', 'allclose', 

56 'alltrue', 'amax', 'amin', 'angle', 'any', 'append', 'arange', 

57 'arccos', 'arccosh', 'arcsin', 'arcsinh', 'arctan', 'arctan2', 

58 'arctanh', 'argmax', 'argmin', 'argsort', 'argwhere', 'around', 

59 'array', 'asanyarray', 'asarray', 'atleast_1d', 'atleast_2d', 

60 'atleast_3d', 'average', 'bartlett', 'bincount', 'bitwise_and', 

61 'bitwise_not', 'bitwise_or', 'bitwise_xor', 'blackman', 

62 'broadcast', 'ceil', 'chararray', 'choose', 'clip', 

63 'column_stack', 'common_type', 'complex128', 'compress', 

64 'concatenate', 'conjugate', 'convolve', 'copysign', 'corrcoef', 

65 'correlate', 'cos', 'cosh', 'cov', 'cross', 'cumprod', 

66 'cumproduct', 'cumsum', 'datetime_data', 'deg2rad', 'degrees', 

67 'delete', 'diag', 'diag_indices', 'diag_indices_from', 

68 'diagflat', 'diagonal', 'diff', 'digitize', 'divide', 'dot', 

69 'dsplit', 'dstack', 'dtype', 'e', 'ediff1d', 'empty', 

70 'empty_like', 'equal', 'exp', 'exp2', 'expand_dims', 'expm1', 

71 'extract', 'eye', 'fabs', 'fft', 'fill_diagonal', 'finfo', 'fix', 

72 'flatiter', 'flatnonzero', 'fliplr', 'flipud', 'float64', 

73 'floor', 'floor_divide', 'fmax', 'fmin', 'fmod', 'format_parser', 

74 'frexp', 'frombuffer', 'fromfile', 'fromfunction', 'fromiter', 

75 'frompyfunc', 'fromregex', 'fromstring', 'genfromtxt', 

76 'getbufsize', 'geterr', 'gradient', 'greater', 'greater_equal', 

77 'hamming', 'hanning', 'histogram', 'histogram2d', 'histogramdd', 

78 'hsplit', 'hstack', 'hypot', 'i0', 'identity', 'iinfo', 'imag', 

79 'in1d', 'index_exp', 'indices', 'inexact', 'inf', 'info', 

80 'infty', 'inner', 'insert', 'int32', 'integer', 'interp', 

81 'intersect1d', 'invert', 'iscomplex', 'iscomplexobj', 'isfinite', 

82 'isinf', 'isnan', 'isneginf', 'isposinf', 'isreal', 'isrealobj', 

83 'isscalar', 'issctype', 'iterable', 'kaiser', 'kron', 'ldexp', 

84 'left_shift', 'less', 'less_equal', 'linalg', 'linspace', 

85 'little_endian', 'loadtxt', 'log', 'log10', 'log1p', 'log2', 

86 'logaddexp', 'logaddexp2', 'logical_and', 'logical_not', 

87 'logical_or', 'logical_xor', 'logspace', 'longcomplex', 

88 'longdouble', 'longfloat', 'longlong', 'mask_indices', 'mat', 

89 'matrix', 'max', 'maximum', 'maximum_sctype', 'may_share_memory', 

90 'mean', 'median', 'memmap', 'meshgrid', 'mgrid', 'min', 

91 'minimum', 'mintypecode', 'mod', 'modf', 'msort', 'multiply', 

92 'nan', 'nan_to_num', 'nanargmax', 'nanargmin', 'nanmax', 

93 'nanmin', 'nansum', 'nbytes', 'ndarray', 'ndenumerate', 'ndim', 

94 'ndindex', 'negative', 'nextafter', 'nonzero', 'not_equal', 

95 'number', 'obj2sctype', 'ogrid', 'ones', 'ones_like', 'outer', 

96 'packbits', 'percentile', 'pi', 'piecewise', 'place', 'poly', 

97 'poly1d', 'polyadd', 'polyder', 'polydiv', 'polyint', 'polymul', 

98 'polynomial', 'polysub', 'polyval', 'power', 'prod', 'product', 

99 'ptp', 'put', 'putmask', 'rad2deg', 'radians', 'random', 'ravel', 

100 'real', 'real_if_close', 'reciprocal', 'record', 'remainder', 

101 'repeat', 'reshape', 'resize', 'right_shift', 'rint', 'roll', 

102 'rollaxis', 'roots', 'rot90', 'round', 'round_', 'row_stack', 

103 'savetxt', 'savez', 'searchsorted', 'select', 'setbufsize', 

104 'setdiff1d', 'seterr', 'setxor1d', 'shape', 'short', 'sign', 

105 'signbit', 'signedinteger', 'sin', 'sinc', 'single', 

106 'singlecomplex', 'sinh', 'size', 'sometrue', 'sort', 

107 'sort_complex', 'spacing', 'split', 'sqrt', 'square', 'squeeze', 

108 'std', 'subtract', 'sum', 'swapaxes', 'take', 'tan', 'tanh', 

109 'tensordot', 'tile', 'trace', 'transpose', 'trapz', 'tri', 

110 'tril', 'tril_indices', 'tril_indices_from', 'trim_zeros', 

111 'triu', 'triu_indices', 'triu_indices_from', 'true_divide', 

112 'trunc', 'ubyte', 'uint', 'uint32', 'union1d', 'unique', 

113 'unpackbits', 'unravel_index', 'unsignedinteger', 'unwrap', 

114 'ushort', 'vander', 'var', 'vdot', 'vectorize', 'vsplit', 

115 'vstack', 'where', 'who', 'zeros', 'zeros_like') 

116 

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

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

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

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

121 

122constants = {} 

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

124 'R_ELECTRON_ANG','DEG2RAD', 'RAD2DEG'): 

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

126 

127 

128 

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

130 

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

132# """create a group""" 

133# if _larch is None: 

134# _larch = Group() 

135# else: 

136# group = _larch.symtable.create_group() 

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

138# setattr(group, key, val) 

139# return group 

140 

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

142 """evaluate a string of larch text 

143 """ 

144 if _larch is None: 

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

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

147 

148 

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

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

151 if _larch is None: 

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

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

154 

155def _reload(mod, _larch=None): 

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

157 if _larch is None: 

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

159 

160 modname = None 

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

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

163 if v == mod: 

164 modname = k 

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

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

167 if v == mod: 

168 modname = k 

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

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

171 modname = mod 

172 

173 if modname is not None: 

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

175 

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

177 "show help on topic or object" 

178 write = sys.stdout.write 

179 if _larch is not None: 

180 write = _larch.writer.write 

181 buff = [] 

182 for arg in args: 

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

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

185 buff.append(repr(arg)) 

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

187 buff.append(arg.__doc__) 

188 buff.append('') 

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

190 

191 

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

193 return Journal(*args, **kws) 

194 

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

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

197 if obj is None and _larch is not None: 

198 obj = _larch.symtable 

199 return dir(obj) 

200 

201def _subgroups(obj): 

202 "return list of subgroups" 

203 if isinstance(obj, Group): 

204 return obj._subgroups() 

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

206 

207def _groupitems(obj): 

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

209 if isinstance(obj, Group): 

210 return obj._members().items() 

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

212 

213def _which(sym, _larch=None): 

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

215 if _larch is None: 

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

217 stable = _larch.symtable 

218 if hasattr(sym, '__name__'): 

219 sym = sym.__name__ 

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

221 obj = stable.get_symbol(sym) 

222 if obj is not None: 

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

224 return None 

225 

226def _exists(sym, _larch=None): 

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

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

229 

230def _isgroup(obj, _larch=None): 

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

232 

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

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

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

236 it a group with expected arguments. 

237 

238 > x = 10 

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

240 > isgroup(g), isgroup(x) 

241 True, False 

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

243 True, False 

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

245 True 

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

247 False 

248 

249 """ 

250 if (_larch is not None and 

251 isinstance(obj, str) and 

252 _larch.symtable.has_symbol(obj)): 

253 obj = _larch.symtable.get_symbol(obj) 

254 return isinstance(obj, Group) 

255 

256 

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

258 if _larch is None: 

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

260 return input(msg) 

261 

262def _sleep(t=0): 

263 return time.sleep(t) 

264_sleep.__doc__ = time.sleep.__doc__ 

265 

266def _time(): 

267 return time.time() 

268_time.__doc__ = time.time.__doc__ 

269 

270def _strftime(format, *args): 

271 return time.strftime(format, *args) 

272_strftime.__doc__ = time.strftime.__doc__ 

273 

274 

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

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

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

278 

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

280 """show history of larch commands""" 

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

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

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

284 

285def init_display_group(_larch): 

286 symtab = _larch.symtable 

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

288 symtab.new_group('_sys.display') 

289 colors = {} 

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

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

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

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

294 display = symtab._sys.display 

295 display.colors = colors 

296 display.use_color = True 

297 display.terminal = 'xterm' 

298 

299 

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

301 exists=_exists, isgroup=_isgroup, 

302 subgroups=_subgroups, group_items=_groupitems, 

303 parse_group_args=parse_group_args, pause=_pause, 

304 sleep=_sleep, systime=_time, clock=_time, 

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

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

307 show_version=show_version, 

308 save_history=save_history, 

309 show_history=show_history) 

310 

311_main_builtins.update(utils._larch_builtins) 

312_main_builtins.update(show_builtins) 

313 

314 

315# names to fill in the larch namespace at startup 

316init_builtins = dict(_builtin=_main_builtins) 

317 

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

319init_funcs = [init_display_group] 

320 

321# group/classes to register for save-restore 

322init_moddocs = {} 

323 

324for cmod in __core_modules: 

325 if cmod is None: 

326 continue 

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

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

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

330 

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

332 if doc is not None: 

333 init_moddocs[cmodname] = doc 

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

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

336 

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

338 if bkey not in init_builtins: 

339 init_builtins[bkey] = bval 

340 else: 

341 init_builtins[bkey].update(bval) 

342 

343 if init_fcn is not None: 

344 init_funcs.append(init_fcn) 

345 

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

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