def get_controller(wf_ex, wf_spec=None): """Gets a workflow controller instance by given workflow execution object. :param wf_ex: Workflow execution object. :param wf_spec: Workflow specification object. If passed, the method works faster. :returns: Workflow controller class. """ if not wf_spec: wf_spec = spec_parser.get_workflow_spec_by_execution_id(wf_ex.id) wf_type = wf_spec.get_type() ctrl_cls = None for cls in u.iter_subclasses(WorkflowController): if cls.__workflow_type__ == wf_type: ctrl_cls = cls break if not ctrl_cls: raise exc.MistralError( 'Failed to find a workflow controller [type=%s]' % wf_type) return ctrl_cls(wf_ex, wf_spec)
def register_secure_model_hooks(): # Make sure 'project_id' is always properly set. for sec_model_class in utils.iter_subclasses(MistralSecureModelBase): if '__abstract__' not in sec_model_class.__dict__: event.listen(sec_model_class.project_id, 'set', _set_project_id, retval=True)
def register_name_validator(): """Register an event listener on the attribute. This event listener will validate that name of object does not contains spaces every time a 'set' occurs. """ for cls in utils.iter_subclasses(Definition): event.listen(getattr(cls, "name"), 'set', lambda t, v, o, i: validate_name_has_no_spaces(v))
def register_length_validator(attr_name): """Register an event listener on the attribute. This event listener will validate the size every time a 'set' occurs. """ for cls in utils.iter_subclasses(Execution): if hasattr(cls, attr_name): event.listen( getattr(cls, attr_name), 'set', lambda t, v, o, i: validate_long_type_length( cls, attr_name, v))
def test_itersubclasses(self): class A(object): pass class B(A): pass class C(A): pass class D(C): pass self.assertEqual([B, C, D], list(utils.iter_subclasses(A)))
def instantiate_spec(spec_cls, data, validate=False): """Instantiates specification accounting for specification hierarchies. :param spec_cls: Specification concrete or base class. In case if base class or the hierarchy is provided this method relies on attributes _polymorphic_key and _polymorphic_value in order to find a concrete class that needs to be instantiated. :param data: Raw specification data as a dictionary. :type data: dict :param validate: If it's False then semantics and schema validation will be skipped. :type validate: bool """ if issubclass(spec_cls, BaseSpecList): # Ignore polymorphic search for specification lists because # it doesn't make sense for them. return spec_cls(data, validate) if not hasattr(spec_cls, '_polymorphic_key'): spec = spec_cls(data, validate) if validate: spec.validate_semantics() return spec # In order to do polymorphic search we need to make sure that # a spec is backed by a dictionary. Otherwise we can't extract # a polymorphic key. if not isinstance(data, dict): raise exc.InvalidModelException( "A specification with polymorphic key must be backed by" " a dictionary [spec_cls=%s, data=%s]" % (spec_cls, data) ) key = spec_cls._polymorphic_key if not isinstance(key, tuple): key_name = key key_default = None else: key_name = key[0] key_default = key[1] polymorphic_val = data.get(key_name, key_default) global _POLYMORPHIC_CACHE cache_key = (spec_cls, polymorphic_val) concrete_spec_cls = _POLYMORPHIC_CACHE.get(cache_key) if concrete_spec_cls is None: for cls in utils.iter_subclasses(spec_cls): if not hasattr(cls, '_polymorphic_value'): raise exc.DSLParsingException( "Class '%s' is expected to have attribute" " '_polymorphic_value' because it's a part of" " specification hierarchy inherited " "from class '%s'." % (cls, spec_cls) ) if cls._polymorphic_value == polymorphic_val: concrete_spec_cls = cls _POLYMORPHIC_CACHE[cache_key] = concrete_spec_cls if concrete_spec_cls is None: raise exc.DSLParsingException( 'Failed to find a specification class to instantiate ' '[spec_cls=%s, data=%s]' % (spec_cls, data) ) spec = concrete_spec_cls(data, validate) if validate: spec.validate_semantics() return spec
@property def executions(self): return (self.action_executions if not self.spec.get('workflow') else self.workflow_executions) def to_dict(self): d = super(TaskExecution, self).to_dict() utils.datetime_to_str_in_dict(d, 'started_at') utils.datetime_to_str_in_dict(d, 'finished_at') return d for cls in utils.iter_subclasses(Execution): event.listen( # Catch and trim Execution.state_info to always fit allocated size. # Note that the limit is 65500 which is less than 65535 (2^16 -1). # The reason is that utils.cut() is not exactly accurate in case if # the value is not a string, but, for example, a dictionary. If we # limit it exactly to 65535 then once in a while it may go slightly # beyond the allowed maximum size. It may depend on the order of # keys in a string representation and other things that are hidden # inside utils.cut_dict() method. cls.state_info, 'set', lambda t, v, o, i: utils.cut(v, 65500), retval=True) # Many-to-one for 'ActionExecution' and 'TaskExecution'.