Skip to content

Commit 012e2f5

Browse files
authored
Merge pull request #41 from dwhswenson/wizard
Simulation Setup Wizard
2 parents ba3e668 + 07b7d7c commit 012e2f5

39 files changed

Lines changed: 2251 additions & 1 deletion

‎.coveragerc‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ exclude_lines =
77
no-cov
88
def __repr__
99
raise NotImplementedError
10+
__name__ == "__main__":

‎.github/workflows/test-suite.yml‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,25 @@ jobs:
2828
- 3.8
2929
- 3.7
3030
- 3.6
31+
INTEGRATIONS: [""]
32+
include:
33+
- CONDA_PY: 3.9
34+
INTEGRATIONS: 'all-optionals'
3135

3236
steps:
3337
- uses: actions/checkout@v2
38+
with:
39+
fetch-depth: 2
3440
- uses: actions/setup-python@v2
3541
- uses: conda-incubator/setup-miniconda@v2
3642
with:
3743
auto-update-conda: true
3844
python-version: ${{ matrix.CONDA_PY }}
3945
- name: "Install testing tools"
4046
run: python -m pip install -r ./devtools/tests_require.txt
47+
- name: "Install integrations"
48+
if: matrix.INTEGRATIONS == 'all-optionals'
49+
run: conda install -c conda-forge -y openmm openmmtools mdtraj
4150
- name: "Install"
4251
run: |
4352
conda install pip
@@ -57,6 +66,8 @@ jobs:
5766
fi
5867
python autorelease_check.py --branch $BRANCH --even ${EVENT}
5968
- name: "Unit tests"
69+
env:
70+
PY_COLORS: "1"
6071
run: |
6172
python -c "import paths_cli"
6273
py.test -vv --cov --cov-report xml:cov.xml

‎docs/index.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ wrappers around well-tested OPS code.
6060
plugins
6161
parameters
6262
workflows
63+
wizard
6364
full_cli
6465
api/index
6566

‎docs/wizard.rst‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.. _wizard:
2+
3+
Writing tools for the Wizard
4+
============================
5+
6+
The Wizard API is still rapidly in flux, and we don't recommend developing
7+
custom Wizard tools at this time. However, once its API is more stable, the
8+
Wizard will be extendable by outside developers.

‎paths_cli/commands/wizard.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import click
2+
from paths_cli.wizard.two_state_tps import TWO_STATE_TPS_WIZARD
3+
4+
@click.command(
5+
'wizard',
6+
short_help="run wizard for setting up simulations",
7+
)
8+
def wizard(): # no-cov
9+
TWO_STATE_TPS_WIZARD.run_wizard()
10+
11+
CLI = wizard
12+
SECTION = "Simulation setup"

‎paths_cli/parsing/tools.py‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import pytest
2+
import numpy.testing as npt
3+
import numpy as np
4+
import math
5+
6+
from paths_cli.parsing.tools import *
7+
8+
@pytest.mark.parametrize('expr,expected', [
9+
('1+1', 2),
10+
('np.pi / 2', np.pi / 2),
11+
('math.cos(1.5)', math.cos(1.5)),
12+
])
13+
def test_custom_eval(expr, expected):
14+
npt.assert_allclose(custom_eval(expr), expected)
15+
16+
def test_mdtraj_parse_atomlist_bad_input():
17+
with pytest.raises(TypeError, match="not integers"):
18+
mdtraj_parse_atomlist("['a', 'b']", n_atoms=2)

‎paths_cli/tests/test_parameters.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ def undo_monkey_patch(stored_functions):
4242
importlib.reload(paths)
4343

4444

45-
4645
class ParameterTest(object):
4746
def test_parameter(self):
4847
# this is just a smoke test to contrast with the ValueError case

‎paths_cli/tests/utils.py‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import urllib.request
2+
3+
try:
4+
urllib.request.urlopen('https://www.google.com')
5+
except:
6+
HAS_INTERNET = False
7+
else:
8+
HAS_INTERNET = True
9+
10+
def assert_url(url):
11+
if not HAS_INTERNET:
12+
pytest.skip("Internet connection seems faulty")
13+
14+
# TODO: On a 404 this will raise a urllib.error.HTTPError. It would be
15+
# nice to give some better output to the user here.
16+
resp = urllib.request.urlopen(url)
17+
assert resp.status == 200
18+

‎paths_cli/tests/wizard/__init__.py‎

Whitespace-only changes.

0 commit comments

Comments
 (0)