Example #1
0
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
Example #2
0
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
Example #3
0
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