Skip to content

Documentation for PhotonRegistry

Helper class to manage the PHOTONAI Element Register.

Use it to add and remove items into the register. You can also retrieve information about items and its hyperparameters.

Every item in the register is encoded by a string literal that points to a python class and its namespace. You can access the python class via the string literal. The class PhotonElement imports and instantiates the class for you.

Examples:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import os
from photonai.base import PhotonRegistry

# REGISTER ELEMENT saved in folder custom_elements_folder
base_folder = os.path.dirname(os.path.abspath(__file__))
custom_elements_folder = os.path.join(base_folder, 'custom_elements')

registry = PhotonRegistry(custom_elements_folder=custom_elements_folder)
registry.register(photon_name='MyCustomEstimator',
                  class_str='custom_estimator.CustomEstimator',
                  element_type='Estimator')

registry.activate()
registry.info('MyCustomEstimator')

# get informations of other available elements
registry.info('SVC')

__init__(self, custom_elements_folder=None) special

Initialize the object.

Parameters:

Name Type Description Default
custom_elements_folder str

Path to folder with custom element in it.

None
Source code in photonai/base/registry/registry.py
def __init__(self, custom_elements_folder: str = None):
    """
    Initialize the object.

    Parameters:
        custom_elements_folder:
            Path to folder with custom element in it.

    """
    self.current_folder = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
    self.module_path = os.path.join(self.current_folder, "modules")
    if not os.path.isdir(self.module_path):
        os.mkdir(self.module_path)

    # update list with available sub_elements
    self._list_available_modules()
    PhotonRegistry.CUSTOM_ELEMENTS_FOLDER = custom_elements_folder
    self._load_custom_folder(custom_elements_folder)

    if len(PhotonRegistry.ELEMENT_DICTIONARY) == 0 or \
            PhotonRegistry.ELEMENT_DICTIONARY == PhotonRegistry.CUSTOM_ELEMENTS:
        PhotonRegistry.ELEMENT_DICTIONARY.update(self.get_package_info())

delete(self, photon_name)

Delete Element from JSON file.

Parameters:

Name Type Description Default
photon_name str

The string literal encoding the class.

required
Source code in photonai/base/registry/registry.py
def delete(self, photon_name: str):
    """
    Delete Element from JSON file.

    Parameters:
        photon_name:
            The string literal encoding the class.

    """
    if photon_name in PhotonRegistry.CUSTOM_ELEMENTS:
        del PhotonRegistry.CUSTOM_ELEMENTS[photon_name]

        self._write_to_json(PhotonRegistry.CUSTOM_ELEMENTS)
        logger.info('Removing the PipelineElement named "{0}" from CustomElements.json.'.format(photon_name))
    else:
        logger.info('Cannot remove "{0}" from CustomElements.json. Element has not been registered before.'.format(photon_name))

get_package_info(self, photon_package=['PhotonCore'])

Collect all registered elements from JSON file.

Parameters:

Name Type Description Default
photon_package list

The names of the PHOTONAI submodules for which the elements should be retrieved.

['PhotonCore']

Returns:

Type Description
dict

Dict of registered elements.

Source code in photonai/base/registry/registry.py
def get_package_info(self, photon_package: list = PHOTON_REGISTRIES) -> dict:
    """
    Collect all registered elements from JSON file.

    Parameters:
        photon_package:
            The names of the PHOTONAI submodules for which
            the elements should be retrieved.

    Returns:
        Dict of registered elements.

    """
    class_info = dict()
    for package in photon_package:

        content = self._load_json(package)

        for idx, key in enumerate(content):
            class_path, class_name = os.path.splitext(content[key][0])

            if idx == 0 and package not in ["PhotonCore", "CustomElements"]:
                # try to import something from module.
                # if that fails. drop this shit.
                try:
                    imported_module = importlib.import_module(class_path)
                    desired_class = getattr(imported_module, class_name[1:])
                    custom_element = desired_class()
                except (AttributeError, ModuleNotFoundError) as e:
                    logger.error(e)
                    logger.error("Could not import from package {}. Deleting json.".format(package))
                    self.delete_module(package)

            class_info[key] = class_path, class_name[1:]
    return class_info

info(self, photon_name)

Show information for object that is encoded by this name.

Parameters:

Name Type Description Default
photon_name str

The string literal which accesses the class.

required
Source code in photonai/base/registry/registry.py
def info(self, photon_name: str):
    """
    Show information for object that is encoded by this name.

    Parameters:
        photon_name:
            The string literal which accesses the class.

    """
    content = self.get_package_info()  # load existing json

    if photon_name in content:
        element_namespace, element_name = content[photon_name]

        print("----------------------------------")
        print("Name: " + element_name)
        print("Namespace: " + element_namespace)
        print("----------------------------------")

        try:
            imported_module = __import__(element_namespace, globals(), locals(), element_name, 0)
            desired_class = getattr(imported_module, element_name)
            base_element = desired_class()
            print("Possible Hyperparameters as derived from constructor:")
            class_args = inspect.signature(base_element.__init__)
            for item, more_info in class_args.parameters.items():
                print("{:<35} {:<75}".format(item, str(more_info)))
            print("----------------------------------")
        except Exception as e:
            logger.error(e)
            logger.error("Could not instantiate class " + element_namespace + "." + element_name)
    else:
        logger.error("Could not find element " + photon_name)

list_available_elements(self, photon_package=['PhotonCore'])

Print info about all items that are registered for the PHOTONAI submodule to the console.

Parameters:

Name Type Description Default
photon_package list

The names of the PHOTON submodules for which the elements should be retrieved.

['PhotonCore']
Source code in photonai/base/registry/registry.py
def list_available_elements(self, photon_package: list = PHOTON_REGISTRIES):
    """
    Print info about all items that are registered for the PHOTONAI
    submodule to the console.

    Parameters:
        photon_package:
            The names of the PHOTON submodules for which
            the elements should be retrieved.

    """
    if isinstance(photon_package, str):
        photon_package = [photon_package]
    for package in photon_package:
        content = self._load_json(package)
        if len(content) > 0:
            print('\n' + package)
            for k, v in sorted(content.items()):
                class_info, package_type = v
                print("{:<35} {:<75} {:<5}".format(k, class_info, package_type))

register(self, photon_name, class_str, element_type)

Save element information to the JSON file.

Parameters:

Name Type Description Default
photon_name str

The string literal with which you want to access the class.

required
class_str str

The namespace of the class, like in the import statement.

required
element_type str

Can be 'Estimator' or 'Transformer'

required
Source code in photonai/base/registry/registry.py
def register(self, photon_name: str, class_str: str, element_type: str):
    """
    Save element information to the JSON file.

    Parameters:
        photon_name:
            The string literal with which you want to access the class.

        class_str:
            The namespace of the class, like in the import statement.

        element_type:
            Can be 'Estimator' or 'Transformer'

    """
    # check if folder exists
    if not PhotonRegistry.CUSTOM_ELEMENTS_FOLDER:
        raise ValueError("To register an element, specify a custom elements folder when instantiating the registry "
                         "module. Example: registry = PhotonRegistry('/MY/CUSTOM/ELEMENTS/FOLDER)")

    if not element_type == "Estimator" and not element_type == "Transformer":
        raise ValueError("Variable element_type must be 'Estimator' or 'Transformer'")

    duplicate = self._check_duplicate(photon_name=photon_name, class_str=class_str, content=PhotonRegistry.CUSTOM_ELEMENTS)

    if not duplicate:
        python_file = os.path.join(PhotonRegistry.CUSTOM_ELEMENTS_FOLDER, class_str.split('.')[0] + '.py')
        if not os.path.isfile(python_file):
            raise FileNotFoundError("Couldn't find python file {} in your custom elements folder. "
                                    "Please copy your file into this folder first!".format(python_file))
        # add new element
        PhotonRegistry.CUSTOM_ELEMENTS[photon_name] = class_str, element_type

        # write back to file
        self._write_to_json(PhotonRegistry.CUSTOM_ELEMENTS)
        logger.info('Adding PipelineElement ' + class_str + ' to CustomElements.json as "' + photon_name + '".')

        # activate custom elements
        self.activate()

        # check custom element
        logger.info("Running tests on custom element...")
        return self._run_tests(photon_name, element_type)
    else:
        logger.error('Could not register element!')