def instantiate_spec(spec_cls, data): """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. """ if issubclass(spec_cls, BaseSpecList): # Ignore polymorphic search for specification lists because # it doesn't make sense for them. return spec_cls(data) if not hasattr(spec_cls, '_polymorphic_key'): spec = spec_cls(data) 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] 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 == data.get(key_name, key_default): spec = cls(data) spec.validate_semantics() return spec raise exc.DSLParsingException( 'Failed to find a specification class to instantiate ' '[spec_cls=%s, data=%s]' % (spec_cls, data))
def _get_spec_version(spec_dict): # If version is not specified it will '2.0' by default. ver = V2_0 if 'version' in spec_dict: ver = spec_dict['version'] if not ver or str(float(ver)) not in ALL_VERSIONS: raise exc.DSLParsingException('Unsupported DSL version: %s' % ver) return ver
def parse_yaml(text): """Loads a text in YAML format as dictionary object. :param text: YAML text. :return: Parsed YAML document as dictionary. """ try: return yaml.safe_load(text) or {} except error.YAMLError as e: raise exc.DSLParsingException("Definition could not be parsed: %s\n" % e)
def validate_semantics(self): super(DirectWorkflowSpec, self).validate_semantics() # Check if there are start tasks. if not self.find_start_tasks(): raise exc.DSLParsingException( 'Failed to find start tasks in direct workflow. ' 'There must be at least one task without inbound transition.' '[workflow_name=%s]' % self._name) self._check_workflow_integrity() self._check_join_tasks()
def _raise(ver): raise exc.DSLParsingException('Unsupported DSL version: %s' % ver)