Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions paths_cli/tests/wizard/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@

from paths_cli.compat.openmm import HAS_OPENMM, mm, unit

from paths_cli.wizard import pause


@pytest.fixture(autouse=True, scope='session')
def pause_style_testing():
pause.set_pause_style('testing')
yield


# TODO: this isn't wizard-specific, and should be moved somwhere more
# generally useful (like, oh, maybe openpathsampling.tests.fixtures?)
@pytest.fixture
Expand Down
4 changes: 4 additions & 0 deletions paths_cli/tests/wizard/mock_wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ def input(self, content):
self.log.append(content + " " + user_input)
return user_input

def draw_hline(self):
# we don't even bother for the mock console
pass

@property
def log_text(self):
return "\n".join(self.log)
Expand Down
72 changes: 72 additions & 0 deletions paths_cli/tests/wizard/test_pause.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import pytest
import time
from paths_cli.tests.wizard.mock_wizard import mock_wizard

from paths_cli.wizard.pause import *

@pytest.fixture(autouse=True, scope="module")
def use_default_pause_style():
with pause_style('default'):
yield


def test_get_pause_style():
default_style = PAUSE_STYLES['default']
assert get_pause_style() == default_style


@pytest.mark.parametrize('input_type', ['string', 'tuple', 'PauseStyle'])
def test_set_pause_style(input_type):
# check that we have the default settings
default_style = PAUSE_STYLES['default']
test_style = PAUSE_STYLES['testing']
input_val = {
'string': 'testing',
'tuple': tuple(test_style),
'PauseStyle': PauseStyle(*test_style)
}[input_type]
assert input_val is not test_style # always a different object
assert get_pause_style() == default_style
set_pause_style(input_val)
assert get_pause_style() != default_style
assert get_pause_style() == test_style
set_pause_style('default') # explicitly reset default


def test_set_pause_bad_name():
with pytest.raises(RuntimeError, match="Unknown pause style"):
set_pause_style('foo')

# ensure we didn't break anything for later tests
assert get_pause_style() == PAUSE_STYLES['default']


def test_pause_style_context():
assert get_pause_style() == PAUSE_STYLES['default']
with pause_style('testing'):
assert get_pause_style() == PAUSE_STYLES['testing']
assert get_pause_style() == PAUSE_STYLES['default']


def _run_pause_test(func):
test_style = PAUSE_STYLES['testing']
expected = getattr(test_style, func.__name__)
wiz = mock_wizard([])
with pause_style(test_style):
start = time.time()
func(wiz)
duration = time.time() - start
assert expected <= duration < 1.1 * duration
return wiz


def test_short():
_ = _run_pause_test(short)


def test_long():
_ = _run_pause_test(long)


def test_section():
wiz = _run_pause_test(section)
2 changes: 1 addition & 1 deletion paths_cli/tests/wizard/test_volumes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
volume_ask
)


import openpathsampling as paths
from openpathsampling.experimental.storage.collective_variables import \
CoordinateFunctionCV

from openpathsampling.tests.test_helpers import make_1d_traj


def _wrap(x, period_min, period_max):
# used in testing periodic CVs
while x >= period_max:
Expand Down
72 changes: 72 additions & 0 deletions paths_cli/wizard/pause.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import time
import contextlib
from collections import namedtuple

PauseStyle = namedtuple("PauseStyle", ['short', 'long', 'section'])

PAUSE_STYLES = {
'testing': PauseStyle(0.01, 0.03, 0.05),
'default': PauseStyle(0.1, 0.5, 0.75),
'nopause': PauseStyle(0.0, 0.0, 0.0),
}

_PAUSE_STYLE = PAUSE_STYLES['default']


@contextlib.contextmanager
def pause_style(style):
"""Context manager for pause styles.

Parameters
----------
style : :class:`.PauseStyle`
pause style to use within the context
"""
old_style = get_pause_style()
try:
set_pause_style(style)
yield
finally:
set_pause_style(old_style)


def get_pause_style():
"""Get the current pause style"""
global _PAUSE_STYLE
Comment thread
dwhswenson marked this conversation as resolved.
Resolved
return _PAUSE_STYLE


def set_pause_style(style):
"""Set the pause style

Parameters
----------
pause_style : :class:`.PauseStyle` or str
pause style to use, can be a string if the style is registered in
pause.PAUSE_STYLES
"""
global _PAUSE_STYLE
if isinstance(style, str):
try:
_PAUSE_STYLE = PAUSE_STYLES[style]
except KeyError as exc:
raise RuntimeError(f"Unknown pause style: '{style}'") from exc
else:
_PAUSE_STYLE = style


def section(wizard):
"""Section break (pause and possible visual cue).
"""
time.sleep(_PAUSE_STYLE.section)
wizard.console.draw_hline()


def long(wizard):
"""Long pause from the wizard"""
time.sleep(_PAUSE_STYLE.long)


def short(wizard):
"""Short pause from the wizard"""
time.sleep(_PAUSE_STYLE.short)
2 changes: 2 additions & 0 deletions paths_cli/wizard/two_state_tps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
SINGLE_ENGINE_STEP, CVS_STEP, WizardStep
)
from paths_cli.wizard.wizard import Wizard
from paths_cli.wizard import pause

volumes = get_category_wizard('volume')
from paths_cli.wizard.volumes import _FIRST_STATE, _VOL_DESC
Expand All @@ -18,6 +19,7 @@ def two_state_tps(wizard, fixed_length=False):
]
initial_state = volumes(wizard, context={'intro': intro})
wizard.register(initial_state, 'initial state', 'states')
pause.section(wizard)
intro = [
"Next let's define your final state.",
_VOL_DESC
Expand Down
9 changes: 7 additions & 2 deletions paths_cli/wizard/volumes.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,21 @@
from paths_cli.wizard.helper import EvalHelperFunc, Helper
from paths_cli.wizard.core import interpret_req
import paths_cli.compiling.volumes
from paths_cli.wizard import pause


def _binary_func_volume(wizard, context, op):
wizard.say("Let's make the first constituent volume:")
wizard.say("Let's make the first constituent volume.")
pause.long(wizard)
new_context = volume_set_context(wizard, context, selected=None)
new_context['part'] = 1
vol1 = VOLUMES_PLUGIN(wizard, new_context)
wizard.say("Let's make the second constituent volume:")
pause.section(wizard)
wizard.say("Let's make the second constituent volume.")
pause.long(wizard)
new_context['part'] = 2
vol2 = VOLUMES_PLUGIN(wizard, new_context)
pause.section(wizard)
wizard.say("Now we'll combine those two constituent volumes...")
vol = op(vol1, vol2)
return vol
Expand Down
6 changes: 6 additions & 0 deletions paths_cli/wizard/wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from paths_cli.wizard.helper import Helper, QuitWizard
from paths_cli.compiling.tools import custom_eval

from paths_cli.wizard import pause

import shutil

class Console: # no-cov
Expand All @@ -26,6 +28,9 @@ def input(self, content):
def width(self):
return shutil.get_terminal_size((80, 24)).columns

def draw_hline(self):
self.print('═' * self.width)

class Wizard:
def __init__(self, steps):
self.steps = steps
Expand Down Expand Up @@ -299,6 +304,7 @@ def _do_one(self, step, req):
self.say("Okay, let's try that again.")
return True
self.register(obj, step.display_name, step.store_name)
pause.section(self)
requires_another, allows_another = self._req_do_another(req)
if requires_another:
do_another = True
Expand Down