Source code for pyiron_contrib.protocol.utils.types

# coding: utf-8
# Copyright (c) Max-Planck-Institut für Eisenforschung GmbH - Computational Materials Design (CM) Department
# Distributed under the terms of "New BSD License", see the LICENSE file.

from pyiron_contrib.protocol.utils.misc import getLogger
from abc import ABCMeta
import sys

"""
Utility function to inject subclasses of pyiron_contrib.protocol.generic.Protocol as JobTypes into pyiron
"""

__author__ = "Dominik Gehringer, Liam Huber"
__copyright__ = "Copyright 2019, Max-Planck-Institut für Eisenforschung GmbH " \
                "- Computational Materials Design (CM) Department"
__version__ = "0.0"
__maintainer__ = "Liam Huber"
__email__ = "huber@mpie.de"
__status__ = "development"
__date__ = "December 10, 2019"


# we have to use ABC as parent metatype otherwise we will run into a metaclass conflict however for Protocol that is
#exactly what we want since one is not allowed to instantiate a protocol
[docs]class PyironJobTypeRegistryMetaType(ABCMeta): """ Metatype which keeps track of all its subclasses """ __registry = {} __wrapped = {}
[docs] @staticmethod def inject_dynamic_types(): """ Sets all the dynimically created classes as attributes to the current module object, however with the original name. Updates pyiron JobTypeChoice's JOB_CLASS_DICT """ # fetch the current module name module_name = PyironJobTypeRegistryMetaType.__module__ if module_name not in sys.modules: # throw a info message if the module is no loaded yes -> could possibly happen but is very unlikely getLogger('PyironJobTypeRegistryMetaType').info('Skipping not module "%s" not loaded yet. Please call PyironJobTypeRegistryMetaType.inject_dynamic_types manually') else: # get the module object module = sys.modules[module_name] updates = {} # register all dynamically created subclasses of (cls, GenericJob) as attributes for (origin_module, wrapped_name), tp in PyironJobTypeRegistryMetaType.__wrapped.items(): if not hasattr(module, wrapped_name): setattr(module, wrapped_name, tp) # information needed for pyiron.base.job.jobtype.JOB_CLASS_DICT updates[wrapped_name] = module_name # inject it into pyiron # adding it to JOB_CLASS_DICT also enables it for autocomplete from pyiron_base import JOB_CLASS_DICT # make sure that it affects all instances of pyiron.base.job.jobtype.JobTypeChoice JOB_CLASS_DICT.update(updates)
def __init__(cls, name, bases, nmspc): """ type initialize for type of this metaclass Args: name: (str) class name bases: (tuple of type) the base classes nmspc: (dict) the attribute of the tpye """ super(PyironJobTypeRegistryMetaType, cls).__init__(name, bases, nmspc) # that's a little bit ugly but we want to exclude this types and do not want to wrap them if name in ('PyironJobTypeRegistry', 'Protocol', 'PyironJobTypeRegistryMetaType'): return # convenience function to obtain the full class qualifier fullname = lambda : '%s.%s' %( cls.__module__, cls.__name__) class_name = cls.__name__ class_module = cls.__module__ key = (class_module, class_name) # construct the new class name new_class_name = class_name # we place a `__artificial__` attribute in the type information to indicate that it is a dynamically created type # when calling `type(new_class_name, new_bases, new_spec)` we construct a subclass of cls, thus it is a # recsursive call to this method, we have to avoid that # otherwise we wrap the wrapper again and agin if '__artificial__' not in nmspc: from pyiron_base import GenericJob new_bases = (cls, GenericJob) # edit the metainformation new_spec = nmspc.copy() new_spec['__qualname__'] = new_class_name new_spec['__artificial__'] = True new_spec['__module__'] = PyironJobTypeRegistryMetaType.__module__ # this bad guy caused some troubles if '__classcell__' in new_spec: del new_spec['__classcell__'] try: new_type = type(new_class_name, new_bases, new_spec) except TypeError as e: # if creating the type goes wrong we are really screwed up getLogger(fullname()).exception(fullname(), exc_info=e) raise # register everything nicely PyironJobTypeRegistryMetaType.__registry[key] = cls PyironJobTypeRegistryMetaType.__wrapped[key] = new_type PyironJobTypeRegistryMetaType.wrapped = PyironJobTypeRegistryMetaType.__wrapped # try to inject it -> in case of dynamically created subclasses PyironJobTypeRegistryMetaType.inject_dynamic_types()
[docs]class PyironJobTypeRegistry(metaclass=PyironJobTypeRegistryMetaType): """ Convenience class as it is ABC in the abc module """ pass