spec2nexus.plugin#

An extensible plugin architecture is used to handle the different possible control line control lines (such as #F, #E, #S, …) in a SPEC data file.

A SPEC control line provides metadata about the SPEC scan or SPEC data file.

Plugins can be used to parse or ignore certain control lines in SPEC data files. Through this architecture, it is possible to support custom control lines, such as #U (SPEC standard control line for any user data). One example is support for the UNICAT-style of metadata provided in the scan header.

Plugins are now used to handle all control lines in spec2nexus.spec. Any control line encountered but not recognized will be placed as text in a NeXus NXnote group named unrecognized_NNN (where NNN is from 1 to the maximum number of unrecognized control lines).

Supplied spec plugin modules#

These plugin modules are supplied:

spec_common

SPEC data file standard control lines

fallback

Fallback handling for any SPEC data file control lines not recognized by other handlers

apstools_specwriter

#MD : Bluesky metadata from apstools SpecWriterCallback.

unicat

#H & #V - Metadata in SPEC data files as defined by APS UNICAT

uim

#UIM : Image header information from EPICS areaDetector

uxml

#UXML: UXML structured metadata

XPCS

SPEC data file control lines unique to the APS XPCS instrument

Writing a custom plugin#

While spec2nexus provides a comprehensive set of plugins to handle the common SPEC control line control lines, custom control lines are used at many facilities to write additional scan data and scan metadata into the SPEC data file. Custom plugins are written to process these additions. See the How to write a custom control line handling plugin module for spec section for details.

Overview of the supplied spec plugins#

Plugins for these control lines [1] are provided in spec2nexus:

SPEC_File

#F -- original data file name (starts a file header block)

SPEC_Epoch

#E -- the UNIX epoch (seconds from 00:00 GMT 1/1/70)

SPEC_Date

#D -- date/time stamp

SPEC_Comment

#C -- any comment either in the scan header or somewhere in the scan

SPEC_Geometry

#G -- diffractometer geometry (numbered rows: #G0, #G1, ...)

SPEC_NormalizingFactor

#I -- intensity normalizing factor

SPEC_CounterNames

#J -- names of counters (each separated by two spaces) (new with SPEC v6)

SPEC_CounterMnemonics

#j -- mnemonics of counter (new with SPEC v6)

SPEC_Labels

#L -- data column labels

SPEC_Monitor

#M -- counting against this constant monitor count (see #T)

SPEC_NumColumns

#N -- number of columns of data [ num2 sets per row ]

SPEC_PositionerNames

#O -- positioner names (numbered rows: #O0, #O1, ...)

SPEC_PositionerMnemonics

#o -- positioner mnemonics (new with SPEC v6)

SPEC_Positioners

#P -- positioner values at start of scan (numbered rows: #P0, #P1, ...)

SPEC_HKL

#Q -- \(Q\) (\(hkl\)) at start of scan

SPEC_Scan

#S -- SPEC scan

SPEC_CountTime

#T -- counting against this constant number of seconds (see #M)

SPEC_UserReserved

#U -- Reserved for user-defined information

SPEC_TemperatureSetPoint

#X -- Temperature Set Point (desired temperature)

SPEC_DataLine

(scan_data) -- scan data line

SPEC_MCA

#@MCA -- MCA data formatting declaration (ignored for now)

SPEC_MCA_Array

@A -- MCA Array data

SPEC_MCA_Calibration

#@CALIB -- coefficients to compute a scale based on the MCA channel number

SPEC_MCA_ChannelInformation

#@CHANN -- MCA channel information

SPEC_MCA_CountTime

#@CTIME -- MCA count times

SPEC_MCA_RegionOfInterest

#@ROI -- MCA ROI (Region Of Interest) channel information

UnrecognizedControlLine

unrecognized control line

UNICAT_MetadataMnemonics

#H -- UNICAT metadata names (numbered rows: #H0, #H1, ...)

UNICAT_MetadataValues

#V -- UNICAT metadata values (numbered rows: #V0, #V1, ...)

UIM_generic

#UIM -- various image header information

XPCS_VA

#VA

XPCS_VD

#VD

XPCS_VE

#VE

source code documentation#

Python plugin support for handling SPEC control lines (such as #S, #D, …).

ControlLineBase()

Base class for SPEC data file control line handler plugins.

install_user_plugin(plugin_file)

Install plugin(s) from a Python file.

REGISTRATION SUPPORT (internal use only)

PluginMounter(name, bases, attrs)

(internal) Register and initiate all plugins subclassed from PluginBase.

# from: https://gist.github.com/will-hart/5899567 # a simple Python plugin loading system # see: http://stackoverflow.com/questions/14510286/plugin-architecture-plugin-manager-vs-inspecting-from-plugins-import

class spec2nexus.plugin_core.ControlLineBase[source]#

Bases: object

Base class for SPEC data file control line handler plugins.

Define a subclass of ControlLineBase for each different type of control line. Refer to the supplied plugins (such as spec2nexus.plugins.spec_common) for examples. In each such class, it is necessary to:

  • define a string value for the key (class attribute)

  • override the definition of process()

As each subclass is imported, the metaclass keyword argument above automatically registers the plugin handler and its associated control line key.

It is optional to:

PARAMETERS

key str :

regular expression to match a control line key, up to the first space

scan_attributes_defined [str] :

list of scan attributes defined in this class

returns:

None

process(text, spec_obj, *args, **kwargs)

required: Handle this line from a SPEC data file.

postprocess(header, *args, **kws)

optional: More processing deferred until after data file has been read.

writer(h5parent, writer, scan[, nxclass])

optional: Describe how to store this data in a NeXus HDF5 file.

match_key(text)

Test if this handler's key matches text.

EXAMPLE of match_key method:

Declaration of the match_key method is optional in a subclass. This is used to test a given line from a SPEC data file against the key of each ControlLineBase.

If this method is defined in the subclass, it will be called instead of match_key(). This is the example used by SPEC_DataLine:

def match_key(self, text):
    try:
        float( text.strip().split()[0] )
        return True
    except ValueError:
        return False
key = <object object>#
known_keys = {'#@CHANN': <spec2nexus.plugins.spec_common.SPEC_MCA_ChannelInformation object>, '#@CTIME': <spec2nexus.plugins.spec_common.SPEC_MCA_CountTime object>, '#@MCA': <spec2nexus.plugins.spec_common.SPEC_MCA object>, '#@ROI': <spec2nexus.plugins.spec_common.SPEC_MCA_RegionOfInterest object>, '#@[cC][aA][lL][iI][bB]': <spec2nexus.plugins.spec_common.SPEC_MCA_Calibration object>, '#C': <spec2nexus.plugins.spec_common.SPEC_Comment object>, '#CCD': <spec2nexus.plugins.XPCS.XPCS_CCD object>, '#D': <spec2nexus.plugins.spec_common.SPEC_Date object>, '#E': <spec2nexus.plugins.spec_common.SPEC_Epoch object>, '#F': <spec2nexus.plugins.spec_common.SPEC_File object>, '#G\\d+': <spec2nexus.plugins.spec_common.SPEC_Geometry object>, '#H\\d+': <unicat.UNICAT_MetadataMnemonics object>, '#I': <spec2nexus.plugins.spec_common.SPEC_NormalizingFactor object>, '#J\\d+': <spec2nexus.plugins.spec_common.SPEC_CounterNames object>, '#L': <spec2nexus.plugins.spec_common.SPEC_Labels object>, '#M': <spec2nexus.plugins.spec_common.SPEC_Monitor object>, '#MD\\w*': <spec2nexus.plugins.apstools_specwriter.MD_apstools object>, '#N': <spec2nexus.plugins.spec_common.SPEC_NumColumns object>, '#O\\d+': <spec2nexus.plugins.spec_common.SPEC_PositionerNames object>, '#P\\d+': <spec2nexus.plugins.spec_common.SPEC_Positioners object>, '#Q': <spec2nexus.plugins.spec_common.SPEC_HKL object>, '#R': <spec2nexus.plugins.spec_common.SPEC_UserResults object>, '#S': <spec2nexus.plugins.spec_common.SPEC_Scan object>, '#T': <spec2nexus.plugins.spec_common.SPEC_CountTime object>, '#U': <spec2nexus.plugins.spec_common.SPEC_UserReserved object>, '#UIM\\w*': <spec2nexus.plugins.uim.UIM_generic object>, '#UXML': <uxml.UXML_metadata object>, '#VA\\d+': <spec2nexus.plugins.XPCS.XPCS_VA object>, '#VD\\d+': <spec2nexus.plugins.XPCS.XPCS_VD object>, '#VE\\d+': <spec2nexus.plugins.XPCS.XPCS_VE object>, '#V\\d+': <unicat.UNICAT_MetadataValues object>, '#X': <spec2nexus.plugins.spec_common.SPEC_TemperatureSetPoint object>, '#XPCS': <spec2nexus.plugins.XPCS.XPCS_XPCS object>, '#j\\d+': <spec2nexus.plugins.spec_common.SPEC_CounterMnemonics object>, '#o\\d+': <spec2nexus.plugins.spec_common.SPEC_PositionerMnemonics object>, '@A\\d*': <spec2nexus.plugins.spec_common.SPEC_MCA_Array object>, 'scan_data': <spec2nexus.plugins.spec_common.SPEC_DataLine object>, 'unrecognized_control_line': <spec2nexus.plugins.fallback.UnrecognizedControlLine object>}#
lazy_attributes = ['H', 'V', 'metadata', 'UXML', 'UXML_root', 'MD', '_unrecognized', 'UIM', 'comments', 'G', 'diffractometer', 'I', 'J', 'j', 'L', 'column_first', 'column_last', 'M', 'monitor_name', 'N', 'O', 'o', 'P', 'positioner', 'Q', 'R', 'T', 'time_name', 'U', 'TEMP_SP', 'DEGC_SP', 'data', 'data_lines', 'MCA', 'VA', 'VD', 'VE', 'XPCS', 'CCD']#
match_key(text)[source]#

Test if this handler’s key matches text.

Parameters:

text (str) – first word on the line, up to but not including the first whitespace

Returns:

key or None

Applies a regular expression match using each handler’s key as the regular expression to match with text.

plugins = [<spec2nexus.plugins.unicat.UNICAT_MetadataMnemonics object>, <spec2nexus.plugins.unicat.UNICAT_MetadataValues object>, <spec2nexus.plugins.uxml.UXML_metadata object>, <apstools_specwriter.MD_apstools object>, <fallback.UnrecognizedControlLine object>, <unicat.UNICAT_MetadataMnemonics object>, <unicat.UNICAT_MetadataValues object>, <uxml.UXML_metadata object>, <uim.UIM_generic object>, <spec_common.SPEC_File object>, <spec_common.SPEC_Epoch object>, <spec_common.SPEC_Date object>, <spec_common.SPEC_Comment object>, <spec_common.SPEC_Scan object>, <spec_common.SPEC_Geometry object>, <spec_common.SPEC_NormalizingFactor object>, <spec_common.SPEC_CounterNames object>, <spec_common.SPEC_CounterMnemonics object>, <spec_common.SPEC_Labels object>, <spec_common.SPEC_Monitor object>, <spec_common.SPEC_NumColumns object>, <spec_common.SPEC_PositionerNames object>, <spec_common.SPEC_PositionerMnemonics object>, <spec_common.SPEC_Positioners object>, <spec_common.SPEC_HKL object>, <spec_common.SPEC_UserResults object>, <spec_common.SPEC_CountTime object>, <spec_common.SPEC_UserReserved object>, <spec_common.SPEC_TemperatureSetPoint object>, <spec_common.SPEC_DataLine object>, <spec_common.SPEC_MCA object>, <spec_common.SPEC_MCA_Array object>, <spec_common.SPEC_MCA_Calibration object>, <spec_common.SPEC_MCA_ChannelInformation object>, <spec_common.SPEC_MCA_CountTime object>, <spec_common.SPEC_MCA_RegionOfInterest object>, <XPCS.XPCS_VA object>, <XPCS.XPCS_VD object>, <XPCS.XPCS_VE object>, <XPCS.XPCS_XPCS object>, <XPCS.XPCS_CCD object>, <spec2nexus.plugins.uim.UIM_generic object>, <spec2nexus.plugins.apstools_specwriter.MD_apstools object>, <spec2nexus.plugins.XPCS.XPCS_VA object>, <spec2nexus.plugins.XPCS.XPCS_VD object>, <spec2nexus.plugins.XPCS.XPCS_VE object>, <spec2nexus.plugins.XPCS.XPCS_XPCS object>, <spec2nexus.plugins.XPCS.XPCS_CCD object>, <spec2nexus.plugins.fallback.UnrecognizedControlLine object>, <spec2nexus.plugins.spec_common.SPEC_File object>, <spec2nexus.plugins.spec_common.SPEC_Epoch object>, <spec2nexus.plugins.spec_common.SPEC_Date object>, <spec2nexus.plugins.spec_common.SPEC_Comment object>, <spec2nexus.plugins.spec_common.SPEC_Scan object>, <spec2nexus.plugins.spec_common.SPEC_Geometry object>, <spec2nexus.plugins.spec_common.SPEC_NormalizingFactor object>, <spec2nexus.plugins.spec_common.SPEC_CounterNames object>, <spec2nexus.plugins.spec_common.SPEC_CounterMnemonics object>, <spec2nexus.plugins.spec_common.SPEC_Labels object>, <spec2nexus.plugins.spec_common.SPEC_Monitor object>, <spec2nexus.plugins.spec_common.SPEC_NumColumns object>, <spec2nexus.plugins.spec_common.SPEC_PositionerNames object>, <spec2nexus.plugins.spec_common.SPEC_PositionerMnemonics object>, <spec2nexus.plugins.spec_common.SPEC_Positioners object>, <spec2nexus.plugins.spec_common.SPEC_HKL object>, <spec2nexus.plugins.spec_common.SPEC_UserResults object>, <spec2nexus.plugins.spec_common.SPEC_CountTime object>, <spec2nexus.plugins.spec_common.SPEC_UserReserved object>, <spec2nexus.plugins.spec_common.SPEC_TemperatureSetPoint object>, <spec2nexus.plugins.spec_common.SPEC_DataLine object>, <spec2nexus.plugins.spec_common.SPEC_MCA object>, <spec2nexus.plugins.spec_common.SPEC_MCA_Array object>, <spec2nexus.plugins.spec_common.SPEC_MCA_Calibration object>, <spec2nexus.plugins.spec_common.SPEC_MCA_ChannelInformation object>, <spec2nexus.plugins.spec_common.SPEC_MCA_CountTime object>, <spec2nexus.plugins.spec_common.SPEC_MCA_RegionOfInterest object>]#
postprocess(header, *args, **kws)[source]#

optional: More processing deferred until after data file has been read.

process(text, spec_obj, *args, **kwargs)[source]#

required: Handle this line from a SPEC data file.

PARAMETERS

text str:

?raw text?

spec_obj obj:

Instance of SpecDataFile, SpecDataFileHeader, or SpecDataFileScan

scan_attributes_defined = []#
writer(h5parent, writer, scan, nxclass=None, *args, **kws)[source]#

optional: Describe how to store this data in a NeXus HDF5 file.

exception spec2nexus.plugin_core.DuplicateKeyError[source]#

Bases: KeyError

Cannot add more than one plugin for the same control key.

add_note()#

Exception.add_note(note) – add a note to the exception

args#
with_traceback()#

Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.

class spec2nexus.plugin_core.PluginMounter(name, bases, attrs)[source]#

Bases: type

(internal) Register and initiate all plugins subclassed from PluginBase.

_enroll(plugin)

Add the plugin to the plugin list and perform any registration logic.

Acts as a metaclass which creates anything inheriting from PluginBase. A plugin mount point derived from: http://martyalchin.com/2008/jan/10/simple-plugin-framework/

_enroll(plugin)[source]#

Add the plugin to the plugin list and perform any registration logic.

Expects to find these attributes:

  • .key (str)

  • .scan_attributes_defined (list of str)

mro()#

Return a type’s method resolution order.

spec2nexus.plugin_core.install_user_plugin(plugin_file)[source]#

Install plugin(s) from a Python file.

Potentially dangerous since this is an import of a user-created file.