|
| 1 | +import numpy as np |
| 2 | + |
| 3 | +def custom_eval(obj, named_objs=None): |
| 4 | + """Parse user input to allow simple math. |
| 5 | +
|
| 6 | + This allows certain user input to be treated as a simplified subset of |
| 7 | + Python. In particular, this is intended to allow simple arithmetic. It |
| 8 | + allows use of the modules numpy (as ``np``) and math, which provide |
| 9 | + potentially useful functions (e.g., ``cos``) as well as constants (e.g., |
| 10 | + ``pi``). |
| 11 | + """ |
| 12 | + string = str(obj) |
| 13 | + # TODO: check that the only attribute access comes from a whitelist |
| 14 | + # (parse the AST for that) |
| 15 | + namespace = { |
| 16 | + 'np': __import__('numpy'), |
| 17 | + 'math': __import__('math'), |
| 18 | + } |
| 19 | + return eval(string, namespace) |
| 20 | + |
| 21 | + |
| 22 | +class UnknownAtomsError(RuntimeError): |
| 23 | + pass |
| 24 | + |
| 25 | +def mdtraj_parse_atomlist(inp_str, n_atoms, topology=None): |
| 26 | + """ |
| 27 | + n_atoms: int |
| 28 | + number of atoms expected |
| 29 | + """ |
| 30 | + # TODO: change n_atoms to the shape desired? |
| 31 | + # TODO: enable the parsing of either string-like atom labels or numeric |
| 32 | + indices = custom_eval(inp_str) |
| 33 | + |
| 34 | + arr = np.array(indices) |
| 35 | + if arr.dtype != int: |
| 36 | + raise TypeError("Input is not integers") |
| 37 | + if arr.shape != (1, n_atoms): |
| 38 | + # try to clean it up |
| 39 | + if len(arr.shape) == 1 and arr.shape[0] == n_atoms: |
| 40 | + arr.shape = (1, n_atoms) |
| 41 | + else: |
| 42 | + raise TypeError(f"Invalid input. Requires {n_atoms} " |
| 43 | + "atoms.") |
| 44 | + |
| 45 | + return arr |
0 commit comments