scripts/collect_ad_boilerplate.py
def parse_pv_structure(driver_dir):
    """
    Reads all .template files in the specified driver directory and maps them
    to the appropriate EPICS signal class in ophyd

    Also determines if the Cam class should extend the FileBase class as well.

    Parameters
    ----------
    driver_dir : PathLike
        Path to the areaDetector driver

    Returns
    -------
    pv_to_signal_mapping : dict
        Dict mapping PVs to the EPICS signal they fall under
    include_file_base : bool
        True if the NDFile.template file is included, otherwise False
    """

    # Find the template directory following the standard areaDetector project format
    template_dir = driver_dir
    for dir in os.listdir(driver_dir):
        if os.path.isdir(os.path.join(driver_dir, dir)) and dir.endswith('App'):
            template_dir = os.path.join(template_dir, dir, 'Db')
            break
    logging.debug(f'Found template dir: {template_dir}')

    # Create a list of file paths to all template files.
    template_files = []
    for file in os.listdir(template_dir):
        file_path = os.path.join(template_dir, file)
        if os.path.isfile(file_path) and file.endswith('.template'):
            template_files.append(file_path)
            logging.debug(f'Found template file {file}')

    # Dict mapping pv name to appropriate EPICS signal, based on typical
    # PV and PV_RBV format for areaDetector
    pv_to_signal_mapping = {}
    include_file_base = False

    for file in template_files:
        logging.debug(f'Collecting pv info from {os.path.basename(file)}')
        with open(file, 'r') as fp:

            lines = fp.readlines()
            for line in lines:

                # If NDFile.template is included, we need to extend FileBase as well.
                if line.startswith('include "NDFile.template"'):
                    logging.debug(f'Driver AD{dev_name} uses the NDFile.template file.')
                    include_file_base = True

                # identify any lines that start with 'record'
                if line.startswith('record'):
                    # Get the name of the PV.
                    # Ex:
                    # record(stringin, "$(P)$(R)Description_RBV") Splits into
                    # ['record(stringin, "$(P', '$(R', 'Description_RBV"', '']
                    # The PV name is the 3rd element, so array index 2, and we remove the last character, '"'
                    pv_name = line.split(')')[2][:-1]

                    # Check if it is a readback PV
                    if pv_name.endswith('_RBV'):

                        pv_name_without_rbv = pv_name[:-len('_RBV')]
                        # If it has a partner PV, switch the signal to SignalWithRBV
                        if pv_name_without_rbv in pv_to_signal_mapping.keys():
                            logging.debug(f'Identified {pv_name_without_rbv} as a record w/ RBV')
                            pv_to_signal_mapping[pv_name_without_rbv] = 'SignalWithRBV'
                        # Otherwise, it is a read only PV, so use EpicsSignalRO
                        else:
                            logging.debug(f'Identified read-only record {pv_name}')
                            pv_to_signal_mapping[pv_name] = 'EpicsSignalRO'
                    else:
                        # Otherwise, use the default EpicsSignal
                        logging.debug(f'Found record {pv_name}')
                        pv_to_signal_mapping[pv_name] = 'EpicsSignal'

    return pv_to_signal_mapping, include_file_base

    Reads all .template files in the specified driver directory and maps them
    to the appropriate EPICS signal class in ophyd

    Also determines if the Cam class should extend the FileBase class as well.

    Parameters
    ----------
    driver_dir : PathLike
        Path to the areaDetector driver

    Returns
    -------
    pv_to_signal_mapping : dict
        Dict mapping PVs to the EPICS signal they fall under
    include_file_base : bool
        True if the NDFile.template file is included, otherwise False
    
Reads all .template files in the specified driver directory and maps them
to the appropriate EPICS signal class in ophyd

Also determines if the Cam class should extend the FileBase class as well.

Parameters

driver_dir : PathLike
Path to the areaDetector driver

Returns

pv_to_signal_mapping : dict
Dict mapping PVs to the EPICS signal they fall under
include_file_base : bool
True if the NDFile.template file is included, otherwise False
Reads all . template files in the specified driver directory and maps them to the appropriate EPICS signal class in ophyd Also determines if the Cam class should extend the FileBase class as well . Parameters driver_dir : PathLike Path to the areaDetector driver Returns pv_to_signal_mapping : dict Dict mapping PVs to the EPICS signal they fall under include_file_base : bool True if the NDFile . template file is included otherwise False
def parse_pv_structure(driver_dir):
    template_dir = driver_dir
    for dir in os.listdir(driver_dir):
        if os.path.isdir(os.path.join(driver_dir, dir)) and dir.endswith('App'):
            template_dir = os.path.join(template_dir, dir, 'Db')
            break
    logging.debug(f'Found template dir: {template_dir}')
    template_files = []
    for file in os.listdir(template_dir):
        file_path = os.path.join(template_dir, file)
        if os.path.isfile(file_path) and file.endswith('.template'):
            template_files.append(file_path)
            logging.debug(f'Found template file {file}')
    pv_to_signal_mapping = {}
    include_file_base = False
    for file in template_files:
        logging.debug(f'Collecting pv info from {os.path.basename(file)}')
        with open(file, 'r') as fp:
            lines = fp.readlines()
            for line in lines:
                if line.startswith('include "NDFile.template"'):
                    logging.debug(f'Driver AD{dev_name} uses the NDFile.template file.')
                    include_file_base = True
                if line.startswith('record'):
                    pv_name = line.split(')')[2][:-1]
                    if pv_name.endswith('_RBV'):
                        pv_name_without_rbv = pv_name[:-len('_RBV')]
                        if pv_name_without_rbv in pv_to_signal_mapping.keys():
                            logging.debug(f'Identified {pv_name_without_rbv} as a record w/ RBV')
                            pv_to_signal_mapping[pv_name_without_rbv] = 'SignalWithRBV'
                        else:
                            logging.debug(f'Identified read-only record {pv_name}')
                            pv_to_signal_mapping[pv_name] = 'EpicsSignalRO'
                    else:
                        logging.debug(f'Found record {pv_name}')
                        pv_to_signal_mapping[pv_name] = 'EpicsSignal'
    return pv_to_signal_mapping, include_file_base
def parse_pv_structure ( driver_dir ) : template_dir = driver_dir for dir in os . listdir ( driver_dir ) : if os . path . isdir ( os . path . join ( driver_dir , dir ) ) and dir . endswith ( 'App' ) : template_dir = os . path . join ( template_dir , dir , 'Db' ) break logging . debug ( f'Found template dir: {template_dir}' ) template_files = [ ] for file in os . listdir ( template_dir ) : file_path = os . path . join ( template_dir , file ) if os . path . isfile ( file_path ) and file . endswith ( '.template' ) : template_files . append ( file_path ) logging . debug ( f'Found template file {file}' ) pv_to_signal_mapping = { } include_file_base = False for file in template_files : logging . debug ( f'Collecting pv info from {os.path.basename(file)}' ) with open ( file , 'r' ) as fp : lines = fp . readlines ( ) for line in lines : if line . startswith ( 'include "NDFile.template"' ) : logging . debug ( f'Driver AD{dev_name} uses the NDFile.template file.' ) include_file_base = True if line . startswith ( 'record' ) : pv_name = line . split ( ')' ) [ 2 ] [ : - 1 ] if pv_name . endswith ( '_RBV' ) : pv_name_without_rbv = pv_name [ : - len ( '_RBV' ) ] if pv_name_without_rbv in pv_to_signal_mapping . keys ( ) : logging . debug ( f'Identified {pv_name_without_rbv} as a record w/ RBV' ) pv_to_signal_mapping [ pv_name_without_rbv ] = 'SignalWithRBV' else : logging . debug ( f'Identified read-only record {pv_name}' ) pv_to_signal_mapping [ pv_name ] = 'EpicsSignalRO' else : logging . debug ( f'Found record {pv_name}' ) pv_to_signal_mapping [ pv_name ] = 'EpicsSignal' return pv_to_signal_mapping , include_file_base
Reads all .template files in the specified driver directory and maps them
to the appropriate EPICS signal class in ophyd
Reads all . template files in the specified driver directory and maps them to the appropriate EPICS signal class in ophyd
"""
    Reads all .template files in the specified driver directory and maps them
    to the appropriate EPICS signal class in ophyd

    Also determines if the Cam class should extend the FileBase class as well.

    Parameters
    ----------
    driver_dir : PathLike
        Path to the areaDetector driver

    Returns
    -------
    pv_to_signal_mapping : dict
        Dict mapping PVs to the EPICS signal they fall under
    include_file_base : bool
        True if the NDFile.template file is included, otherwise False
    """ # Find the template directory following the standard areaDetector project format # Create a list of file paths to all template files. # Dict mapping pv name to appropriate EPICS signal, based on typical # PV and PV_RBV format for areaDetector # If NDFile.template is included, we need to extend FileBase as well. # identify any lines that start with 'record' # Get the name of the PV. # Ex: # record(stringin, "$(P)$(R)Description_RBV") Splits into # ['record(stringin, "$(P', '$(R', 'Description_RBV"', ''] # The PV name is the 3rd element, so array index 2, and we remove the last character, '"' # Check if it is a readback PV # If it has a partner PV, switch the signal to SignalWithRBV # Otherwise, it is a read only PV, so use EpicsSignalRO # Otherwise, use the default EpicsSignal
driver_dir