Skip to content

Commit

Permalink
Merge pull request #144 from ZLLentz/new-qs
Browse files Browse the repository at this point in the history
ENH: Update for new QS
  • Loading branch information
ZLLentz authored Sep 21, 2018
2 parents 8bf8788 + b1d4c60 commit e377d66
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 95 deletions.
4 changes: 2 additions & 2 deletions conda-recipe/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ requirements:
- pyyaml
- coloredlogs
- pyfiglet
- happi >=1.1.1
- happi >1.1.1
- pcdsdevices >=0.6.0
- pcdsdaq >=2.0.0
- psdm_qs_cli >=0.2.0
- psdm_qs_cli >=0.2.2
- lightpath >=0.3.0
- elog
- cookiecutter >=1.6.0
Expand Down
55 changes: 9 additions & 46 deletions hutch_python/exp_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,71 +7,34 @@
logger = logging.getLogger(__name__)


def get_exp_objs(proposal, run):
def get_exp_objs(exp_module):
"""
Load the correct experiment module.
This will import User from ``experiments.{propsal}{run}``
This will import User from ``experiments.{exp_module}``
and create ``User()``, storing it as ``x``.
Parameters
----------
proposal: ``str``
The proposal name, e.g. ``lp56``. This will be forced to
lowercase for the import.
run: ``str`` or ``int``
The run number, e.g. 16
exp_module: ``str``
The name of the experiment from the elog, without the hutch. This will
be the name of the module loaded from the experiments folder.
Returns
-------
user: ``object`` or ``SimpleNamespace``
Either the user's class instantiated or a blank namespace for other
experiment-specific objects to be attached to.
"""
logger.debug('get_exp_objs(%s, %s)', proposal, run)
expname = proposal.lower() + str(run)
module_name = 'experiments.' + expname
with safe_load(expname):
logger.debug('get_exp_objs(%s)', exp_module)
module_name = 'experiments.' + exp_module
with safe_load(exp_module):
try:
module = import_module(module_name)
return module.User()
except ImportError as exc:
if module_name in exc.msg:
logger.info('Skip missing experiment file %s.py', expname)
logger.info('Skip missing experiment file %s.py', exp_module)
else:
raise
return SimpleNamespace()


def split_expname(expname, hutch=None):
"""
Give an experiment name, split out the proposal and the run number.
This is used in the split form because certain applications take the two
separately.
Parameters
----------
expname: ``str``
The name of an experiment, e.g. xppx0112
hutch: ``str``, optional
If provided, and we find the hutch string in the expname, we'll strip
it out.
Returns
-------
proposal, run: ``tuple``, (``str``, ``str``)
e.g. ('x01', '12')
"""
expname = expname.lower()
if hutch is not None:
hutch = hutch.lower()
if expname.startswith(hutch):
expname = expname[len(hutch):]
proposal = expname[:-2]
run = expname[-2:]
logger.debug('split expname %s into proposal=%s, run=%s',
expname, proposal, run)
return proposal, run
42 changes: 19 additions & 23 deletions hutch_python/load_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from .cache import LoadCache
from .cam_load import read_camviewer_cfg
from .constants import VALID_KEYS, CAMVIEWER_CFG
from .exp_load import get_exp_objs, split_expname
from .exp_load import get_exp_objs
from .happi import get_happi_objs, get_lightpath
from .namespace import class_namespace, tree_namespace
from .qs_load import get_qs_objs
Expand Down Expand Up @@ -67,10 +67,8 @@ def load(cfg=None, args=None):
hutch_dir = conf_path.parent

if args is not None and args.exp is not None:
proposal, run = split_expname(args.exp, conf.get('hutch', None))
logger.debug('forcing proposal=%s, run=%s', proposal, run)
exp = {'proposal': proposal, 'run': run}
conf['experiment'] = exp
logger.debug('forcing experiment=%s', args.exp)
conf['experiment'] = args.exp

return load_conf(conf, hutch_dir=hutch_dir)

Expand Down Expand Up @@ -181,11 +179,9 @@ def load_conf(conf, hutch_dir=None):

try:
experiment = conf['experiment']
if (not isinstance(experiment, dict)
or 'proposal' not in experiment
or 'run' not in experiment):
logger.error(('Invalid experiment selection %s, must be a dict '
'with keys "proposal" and "run"'), experiment)
if not isinstance(experiment, str):
logger.error('Invalid experiment selection %s, must be a string '
'matching the elog experiment name.', experiment)
experiment = None
except KeyError:
experiment = None
Expand Down Expand Up @@ -275,28 +271,28 @@ def load_conf(conf, hutch_dir=None):
cache(**load_objs)

# Auto select experiment if we need to
proposal = None
if experiment is None:
if hutch is not None:
try:
# xpplp1216
expname = get_current_experiment(hutch)
logger.info('Selected active experiment %s', expname)
proposal, run = split_expname(expname, hutch)
experiment = get_current_experiment(hutch)
logger.info('Selected active experiment %s', experiment)
except Exception:
err = 'Failed to select experiment automatically'
logger.error(err)
logger.debug(err, exc_info=True)

# Experiment objects
if experiment is not None:
proposal = experiment['proposal']
run = experiment['run']

if proposal is not None:
qs_objs = get_qs_objs(proposal, run)
if hutch in experiment:
full_expname = experiment
raw_expname = experiment.replace(hutch, '', 1)
else:
full_expname = hutch + experiment
raw_expname = experiment
qs_objs = get_qs_objs(full_expname)
cache(**qs_objs)
user = get_exp_objs(proposal, run)
user = get_exp_objs(raw_expname)
for name, obj in qs_objs.items():
setattr(user, name, obj)
cache(x=user, user=user)
Expand All @@ -321,14 +317,14 @@ def load_conf(conf, hutch_dir=None):
presets_dir = Path(hutch_dir) / 'presets'
beamline_presets = presets_dir / 'beamline'
preset_paths = [presets_dir, beamline_presets]
if proposal is not None:
experiment_presets = presets_dir / (proposal + str(run))
if experiment is not None:
experiment_presets = presets_dir / raw_expname
preset_paths.append(experiment_presets)
for path in preset_paths:
if not path.exists():
path.mkdir()
path.chmod(0o777)
if proposal is None:
if experiment is None:
setup_preset_paths(hutch=beamline_presets)
else:
setup_preset_paths(hutch=beamline_presets,
Expand Down
19 changes: 8 additions & 11 deletions hutch_python/qs_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
logger = logging.getLogger(__name__)


def get_qs_objs(proposal, run):
def get_qs_objs(expname):
"""
Gather user objects from the experiment questionnaire.
Expand All @@ -35,20 +35,17 @@ def get_qs_objs(proposal, run):
Parameters
----------
proposal: ``str``
The experiment's proposal number
run: ``str``
A string representation of the run number
expname: ``str``
The experiment's name from the elog
Returns
-------
objs: ``dict``
Mapping from questionnaire ``python name`` to loaded object.
"""
logger.debug('get_qs_objs(%s, %s)', proposal, run)
logger.debug('get_qs_objs(%s)', expname)
with safe_load('questionnaire'):
proposal = proposal.upper()
expname = expname.lower()
# Determine which method of authentication we are going to use.
# Search for a configuration file, either in the current directory
# or hidden in the users home directory. If not found, attempt to
Expand All @@ -66,17 +63,17 @@ def get_qs_objs(proposal, run):
except NoOptionError as exc:
raise ValueError("Must specify password as 'pw' in "
"configuration file") from exc
qs_client = happi.Client(database=QSBackend(run, proposal,
qs_client = happi.Client(database=QSBackend(expname,
use_kerberos=False,
user=user, pw=pw))
# Kerberos
else:
qs_client = happi.Client(database=QSBackend(run, proposal,
qs_client = happi.Client(database=QSBackend(expname,
use_kerberos=True))
# Create namespace
if not qs_client.all_devices:
logger.warning("No devices found in PCDS Questionnaire for %s",
proposal)
expname)
return dict()
dev_namespace = load_devices(*qs_client.all_devices, pprint=False)
return dev_namespace.__dict__
Expand Down
4 changes: 1 addition & 3 deletions hutch_python/tests/conf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@ db: happi_db.json

load: tst.beamline

experiment:
proposal: x0
run: 10
experiment: tstx010
9 changes: 4 additions & 5 deletions hutch_python/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,8 @@ def log_queue():
class QSBackend:
empty = False

def __init__(self, run, proposal, use_kerberos=True, user=None, pw=None):
self.run = run
self.proposal = proposal
def __init__(self, expname, use_kerberos=True, user=None, pw=None):
self.expname = expname
self.user = user
self.pw = pw
self.kerberos = use_kerberos
Expand All @@ -87,11 +86,11 @@ def find(self, multiples=False, **kwargs):
'prefix': 'TST:USR:MMN:01',
'purpose': 'Injector X',
'type': 'Device',
'run': self.run,
'run': self.expname[-2:],
'user': self.user,
'pw': self.pw,
'kerberos': self.kerberos,
'proposal': self.proposal}]
'proposal': self.expname[3:-2].upper()}]
if self.empty:
return None
elif multiples:
Expand Down
4 changes: 2 additions & 2 deletions hutch_python/tests/test_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
def test_experiment_objs():
logger.debug('test_experiment_objs')

user = get_exp_objs('sample', '_expname')
user = get_exp_objs('sample_expname')
assert not isinstance(user, SimpleNamespace)

empty = get_exp_objs('q3qwer', '13241234')
empty = get_exp_objs('q3qwer')
assert isinstance(empty, SimpleNamespace)
6 changes: 3 additions & 3 deletions hutch_python/tests/test_questionnaire.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,21 @@ def test_qs_load():
logger.debug('test_qs_load')
hutch_python.qs_load.QSBackend = QSBackend
clear_happi_cache()
objs = get_qs_objs('LR12', '15')
objs = get_qs_objs('tstlr1215')
assert objs['inj_x'].run == '15'
assert objs['inj_x'].proposal == 'LR12'
assert objs['inj_x'].kerberos == 'True'
# Check that we can handle an empty Questionnaire
QSBackend.empty = True
assert get_qs_objs('LR12', '15') == dict()
assert get_qs_objs('tstlr1215') == dict()
QSBackend.empty = False


def test_ws_auth_conf(temporary_config):
logger.debug('test_ws_auth_conf')
hutch_python.qs_load.QSBackend = QSBackend
clear_happi_cache()
objs = get_qs_objs('LR12', '15')
objs = get_qs_objs('tstlr1215')
assert objs['inj_x'].kerberos == 'False'
assert objs['inj_x'].user == 'user'
assert objs['inj_x'].pw == 'pw'

0 comments on commit e377d66

Please sign in to comment.