def get_qs_client(expname): """ Create a `happi.Client` from the experiment questionnaire. Connects to the questionnaire webservice via the ``happi`` ``QSBackend`` using ``psdm_qs_cli`` to collect well-defined devices. There are two possible methods of authentication to the ``QuestionnaireClient``, ``Kerberos`` and ``WS-Auth``. The first is simpler but is not possible for all users, we therefore search for a configuration file named ``web.cfg``, either hidden in the current directory or the users home directory. This should contain the username and password needed to authenticate into the ``QuestionnaireClient``. The format of this configuration file is the standard ``.ini`` structure and should define the username and password like: .. code:: ini [DEFAULT] user = MY_USERNAME pw = MY_PASSWORD Parameters ---------- expname: ``str`` The experiment's name from the elog Returns ------- qs_client: `happi.Client` Mapping from questionnaire ``python name`` to loaded object. """ # 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 # launch the client via Kerberos cfg = ConfigParser() cfgs = cfg.read([ 'qs.cfg', '.qs.cfg', os.path.expanduser('~/.qs.cfg'), 'web.cfg', '.web.cfg', os.path.expanduser('~/.web.cfg') ]) # Ws-auth if cfgs: user = cfg.get('DEFAULT', 'user', fallback=None) try: pw = cfg.get('DEFAULT', 'pw') except NoOptionError as exc: raise ValueError("Must specify password as 'pw' in " "configuration file") from exc qs_client = happi.Client( database=QSBackend(expname, use_kerberos=False, user=user, pw=pw)) # Kerberos else: qs_client = happi.Client( database=QSBackend(expname, use_kerberos=True)) return qs_client
def mockqsbackend(): # Create a very basic mock class class MockQuestionnaireClient(QuestionnaireClient): def getProposalsListForRun(self, run): return {'X534': {'Instrument': 'TST', 'proposal_id': 'X534'}, 'LR32': {'Instrument': 'TST', 'proposal_id': 'LR32'}} def getProposalDetailsForRun(self, run_no, proposal): return { 'pcdssetup-motors-enc-1-desc': '', 'pcdssetup-motors-enc-2-desc': '', 'pcdssetup-motors-enc-3-desc': '', 'pcdssetup-motors-enc-4-desc': '', 'pcdssetup-motors-setup-1-location': 'Hutch-main experimental', 'pcdssetup-motors-setup-1-name': 'sam_x', 'pcdssetup-motors-setup-1-purpose': 'sample x motion', 'pcdssetup-motors-setup-1-pvbase': 'TST:USR:MMS:01', 'pcdssetup-motors-setup-1-stageidentity': 'IMS MD23', 'pcdssetup-motors-setup-2-location': 'Hutch-main experimental', 'pcdssetup-motors-setup-2-name': 'sam_z', 'pcdssetup-motors-setup-2-purpose': 'sample z motion', 'pcdssetup-motors-setup-2-pvbase': 'TST:USR:MMS:02', 'pcdssetup-motors-setup-2-stageidentity': 'IMS MD23', 'pcdssetup-motors-setup-3-location': 'Hutch-main experimental', 'pcdssetup-motors-setup-3-name': 'sam_y', 'pcdssetup-motors-setup-3-purpose': 'sample y motion', 'pcdssetup-motors-setup-3-pvbase': 'TST:USR:MMS:03', 'pcdssetup-motors-setup-3-stageidentity': 'IMS MD32', 'pcdssetup-motors-setup-4-location': 'Hutch-main experimental', 'pcdssetup-motors-setup-4-name': 'sam_r', 'pcdssetup-motors-setup-4-purpose': 'sample rotation', 'pcdssetup-motors-setup-4-pvbase': 'TST:USR:MMS:04', 'pcdssetup-motors-setup-4-stageidentity': 'IMS MD23', 'pcdssetup-motors-setup-5-location': 'Hutch-main experimental', 'pcdssetup-motors-setup-5-name': 'sam_az', 'pcdssetup-motors-setup-5-purpose': 'sample azimuth', 'pcdssetup-motors-setup-5-pvbase': 'TST:USR:MMS:05', 'pcdssetup-motors-setup-5-stageidentity': 'IMS MD23', 'pcdssetup-motors-setup-6-location': 'Hutch-main experimental', 'pcdssetup-motors-setup-6-name': 'sam_flip', 'pcdssetup-motors-setup-6-purpose': 'sample flip', 'pcdssetup-motors-setup-6-pvbase': 'TST:USR:MMS:06', 'pcdssetup-motors-setup-6-stageidentity': 'IMS MD23'} def getExpName2URAWIProposalIDs(self): return { 'tstx53416': 'X534', 'tstlr3216': 'LR32'} with patch('happi.backends.qs_db.QuestionnaireClient') as qs_cli: # Replace QuestionnaireClient with our test version mock_qs = MockQuestionnaireClient(use_kerberos=False, user='******', pw='pw') qs_cli.return_value = mock_qs # Instantiate a fake device backend = QSBackend('tstlr3216') return backend
def mockqsbackend(): # Create a very basic mock class class MockQuestionnaireClient(QuestionnaireClient): def getProposalsListForRun(self, run): return { 'X534': { 'Instrument': 'TST', 'proposal_id': 'X534' }, 'LR32': { 'Instrument': 'TST', 'proposal_id': 'LR32' }, 'LU34': { 'Instrument': 'MFX', 'proposal_id': 'LU34' }, } def getProposalDetailsForRun(self, run_no, proposal): return { 'pcdssetup-motors-1-location': 'Hutch-main experimental', 'pcdssetup-motors-1-name': 'sam_x', 'pcdssetup-motors-1-purpose': 'sample x motion', 'pcdssetup-motors-1-pvbase': 'TST:USR:MMS:01', 'pcdssetup-motors-1-stageidentity': 'IMS MD23', 'pcdssetup-motors-2-location': 'Hutch-main experimental', 'pcdssetup-motors-2-name': 'sam_z', 'pcdssetup-motors-2-purpose': 'sample z motion', 'pcdssetup-motors-2-pvbase': 'TST:USR:MMS:02', 'pcdssetup-motors-2-stageidentity': 'IMS MD23', 'pcdssetup-motors-3-location': 'Hutch-main experimental', 'pcdssetup-motors-3-name': 'sam_y', 'pcdssetup-motors-3-purpose': 'sample y motion', 'pcdssetup-motors-3-pvbase': 'TST:USR:MMS:03', 'pcdssetup-motors-3-stageidentity': 'IMS MD32', 'pcdssetup-motors-4-location': 'Hutch-main experimental', 'pcdssetup-motors-4-name': 'sam_r', 'pcdssetup-motors-4-purpose': 'sample rotation', 'pcdssetup-motors-4-pvbase': 'TST:USR:MMS:04', 'pcdssetup-motors-4-stageidentity': 'IMS MD23', 'pcdssetup-motors-5-location': 'Hutch-main experimental', 'pcdssetup-motors-5-name': 'sam_az', 'pcdssetup-motors-5-purpose': 'sample azimuth', 'pcdssetup-motors-5-pvbase': 'TST:USR:MMS:05', 'pcdssetup-motors-5-stageidentity': 'IMS MD23', 'pcdssetup-motors-6-location': 'Hutch-main experimental', 'pcdssetup-motors-6-name': 'sam_flip', 'pcdssetup-motors-6-purpose': 'sample flip', 'pcdssetup-motors-6-pvbase': 'TST:USR:MMS:06', 'pcdssetup-motors-6-stageidentity': 'IMS MD23', 'pcdssetup-trig-1-delay': '0.00089', 'pcdssetup-trig-1-eventcode': '198', 'pcdssetup-trig-1-name': 'Overview_trig', 'pcdssetup-trig-1-polarity': 'positive', 'pcdssetup-trig-1-purpose': 'Overview', 'pcdssetup-trig-1-pvbase': 'MFX:REC:EVR:02:TRIG1', 'pcdssetup-trig-1-width': '0.00075', 'pcdssetup-trig-2-delay': '0.000894348', 'pcdssetup-trig-2-eventcode': '198', 'pcdssetup-trig-2-name': 'Meniscus_trig', 'pcdssetup-trig-2-polarity': 'positive', 'pcdssetup-trig-2-purpose': 'Meniscus', 'pcdssetup-trig-2-pvbase': 'MFX:REC:EVR:02:TRIG3', 'pcdssetup-trig-2-width': '0.0005', 'pcdssetup-ao-1-device': 'Acromag IP231 16-bit', 'pcdssetup-ao-1-name': 'irLed', 'pcdssetup-ao-1-purpose': 'IR LED', 'pcdssetup-ao-2-channel': '6', 'pcdssetup-ao-2-device': 'Acromag IP231 16-bit', 'pcdssetup-ao-2-name': 'laser_shutter_opo', 'pcdssetup-ao-2-purpose': 'OPO Shutter', 'pcdssetup-ao-3-channel': '7', 'pcdssetup-ao-3-device': 'Acromag IP231 16-bit', 'pcdssetup-ao-3-name': 'laser_shutter_evo1', 'pcdssetup-ao-3-purpose': 'EVO Shutter1', 'pcdssetup-ao-4-channel': '2', 'pcdssetup-ao-4-device': 'Acromag IP231 16-bit', 'pcdssetup-ao-4-name': 'laser_shutter_evo2', 'pcdssetup-ao-4-purpose': 'EVO Shutter2', 'pcdssetup-ao-5-channel': '3', 'pcdssetup-ao-5-device': 'Acromag IP231 16-bit', 'pcdssetup-ao-5-name': 'laser_shutter_evo3', 'pcdssetup-ao-5-purpose': 'EVO Shutter3', 'pcdssetup-ao-1-pvbase': 'MFX:USR:ao1', 'pcdssetup-ao-2-pvbase': 'MFX:USR:ao1', 'pcdssetup-ao-3-pvbase': 'MFX:USR:ao1', 'pcdssetup-ao-4-pvbase': 'MFX:USR:ao1', 'pcdssetup-ao-5-pvbase': 'MFX:USR:ao1', 'pcdssetup-ai-1-device': 'Acromag IP231 16-bit', 'pcdssetup-ai-1-name': 'irLed', 'pcdssetup-ai-1-purpose': 'IR LED', 'pcdssetup-ai-1-pvbase': 'MFX:USR:ai1', 'pcdssetup-ai-1-channel': '7', 'pcdssetup-motors-11-purpose': 'Von Hamos vertical', 'pcdssetup-motors-11-stageidentity': 'Beckhoff', 'pcdssetup-motors-11-location': 'XPP goniometer', 'pcdssetup-motors-11-pvbase': 'HXX:VON_HAMOS:MMS:01', 'pcdssetup-motors-11-name': 'vh_y', } def getExpName2URAWIProposalIDs(self): return { 'tstx53416': 'X534', 'tstlr3216': 'LR32', 'mfxlu3417': 'LU34', } with patch('happi.backends.qs_db.QuestionnaireClient') as qs_cli: # Replace QuestionnaireClient with our test version mock_qs = MockQuestionnaireClient(use_kerberos=False, user='******', pw='pw') qs_cli.return_value = mock_qs # Instantiate a fake device backend = QSBackend('tstlr3216') return backend