… add an affix-function to a standard name table during runtime?#

If you are using the standard name convention, you are familiar with transformation functions like “derivative_of_<SN1>wrt<SN2>” or “square_of_<SN>”.

Now, you want to add your custom transformation function without changing the package code. Say, you want to add the transformation “maximum_of_”, referring to the maximum value of your data.

Here is the current state, which fails as expected:

import h5rdmtoolbox as h5tbx
from h5rdmtoolbox.convention.standard_names.transformation import Transformation
from h5rdmtoolbox.convention.standard_names import StandardName

snt = h5tbx.convention.standard_names.StandardNameTable.from_zenodo(doi_or_recid=10428795)

# check if the problem really exists:
try:
    snt['maximum_of_pressure']
except h5tbx.errors.StandardNameError as e:
    print(e)
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[1], line 5
      2 from h5rdmtoolbox.convention.standard_names.transformation import Transformation
      3 from h5rdmtoolbox.convention.standard_names import StandardName
----> 5 snt = h5tbx.convention.standard_names.StandardNameTable.from_zenodo(doi_or_recid=10428795)
      7 # check if the problem really exists:
      8 try:

File ~/checkouts/readthedocs.org/user_builds/h5rdmtoolbox/checkouts/v1.4.1/h5rdmtoolbox/convention/standard_names/table.py:755, in StandardNameTable.from_zenodo(source, doi_or_recid)
    752 z = zenodo.ZenodoRecord(rec_id)
    753 assert z.exists()
--> 755 filenames = [file.download(target_folder=UserDir['standard_name_tables']) for file in z.files.values()]
    756 # filenames = z.download_files(target_folder=UserDir['standard_name_tables'])
    757 assert len(filenames) == 1

File ~/checkouts/readthedocs.org/user_builds/h5rdmtoolbox/checkouts/v1.4.1/h5rdmtoolbox/repository/zenodo/core.py:602, in ZenodoRecord.files(self)
    595 @property
    596 def files(self) -> Dict[str, RepositoryFile]:
    597     # def _parse_download_url(filename):
    598     #     if filename is None:
    599     #         return filename
    600     #     return f"{self.rec_url}/{self.rec_id}/files/{filename}"
--> 602     is_submitted = self.submitted()
    604     def _parse_download_url(url, filename):
    605         if url is None:

File ~/checkouts/readthedocs.org/user_builds/h5rdmtoolbox/checkouts/v1.4.1/h5rdmtoolbox/repository/zenodo/core.py:558, in ZenodoRecord.is_published(self)
    556 def is_published(self) -> bool:
    557     """Check if the deposit is published."""
--> 558     return self.json()['submitted']

KeyError: 'submitted'

Implementing a new transformation function#

We need to do two things:

  1. write a function which takes a regex result and generates the new standard name

  2. init a Transformation object which performs the regex match

The respective regex pattern to the above is ^maximum_of_(.*)$.

The respective function is implemented in the following. It takes the result from a re.match() call and the standard name table object. The function then constructs a new standard name and returns it. Even if the regex match succeeded, it is still possible, that the function raises an error because the base standard_name may not exist.

def maximum_of(match, snt):
    # match is the result of `re.match(`^maximum_of_(.*)$, <user_input_value>)`
    groups = match.groups()
    assert len(groups) == 1
    sn = snt[groups[0]]
    new_description = f"Maximum of {sn.name}. {sn.description}"
    return StandardName(match.string, sn.units, new_description)

The actual transformation is managed by the class Transformation. It takes the above defined function and the respective regex pattern:

max_of = Transformation(r"^maximum_of_(.*)$", maximum_of)

We can already check if the pattern matching works:

max_of.match('maximum_static_pressure') is None
True
max_of.match('maximum_of_static_pressure') is None
False

Add it to an existing standard name table during runtime:#

snt.add_transformation(max_of)
snt['maximum_of_static_pressure']
    • units : Pa
    • description : Maximum of static_pressure. Static pressure refers to the force per unit area exerted by a fluid. Pressure is a scalar quantity.
snt.transformations[-1] == max_of
True