Source code for dtfabric.runtime.runtime

# -*- coding: utf-8 -*-
"""Run-time objects."""

try:
  import __builtin__ as builtins
except ImportError:
  import builtins

import keyword
import sys

from dtfabric import data_types
from dtfabric import definitions


[docs]class StructureValuesClassFactory(object): """Structure values class factory.""" _CLASS_TEMPLATE = '\n'.join([ 'class {type_name:s}(object):', ' """{type_description:s}.', '', ' Attributes:', '{class_attributes_description:s}', ' """', '', ' def __init__(self, {init_arguments:s}):', ' """Initializes an instance of {type_name:s}."""', ' super({type_name:s}, self).__init__()', '{instance_attributes:s}', '']) _PYTHON_NATIVE_TYPES = { definitions.TYPE_INDICATOR_BOOLEAN: 'bool', definitions.TYPE_INDICATOR_CHARACTER: 'str', definitions.TYPE_INDICATOR_FLOATING_POINT: 'float', definitions.TYPE_INDICATOR_INTEGER: 'int', definitions.TYPE_INDICATOR_STREAM: 'bytes', definitions.TYPE_INDICATOR_STRING: 'str', definitions.TYPE_INDICATOR_UUID: 'uuid.UUID'} @classmethod def _CreateClassTemplate(cls, data_type_definition): """Creates the class template. Args: data_type_definition (DataTypeDefinition): data type definition. Returns: str: class template. """ type_name = data_type_definition.name type_description = data_type_definition.description or type_name while type_description.endswith('.'): type_description = type_description[:-1] class_attributes_description = [] init_arguments = [] instance_attributes = [] for member_definition in data_type_definition.members: attribute_name = member_definition.name description = member_definition.description or attribute_name while description.endswith('.'): description = description[:-1] member_data_type = getattr(member_definition, 'member_data_type', '') if isinstance(member_definition, data_types.MemberDataTypeDefinition): member_definition = member_definition.member_data_type_definition member_type_indicator = member_definition.TYPE_INDICATOR if member_type_indicator == definitions.TYPE_INDICATOR_SEQUENCE: element_type_indicator = member_definition.element_data_type member_type_indicator = f'tuple[{element_type_indicator:s}]' else: member_type_indicator = cls._PYTHON_NATIVE_TYPES.get( member_type_indicator, member_data_type) argument = f'{attribute_name:s}=None' definition = f' self.{attribute_name:s} = {attribute_name:s}' description = ( f' {attribute_name:s} ({member_type_indicator:s}): ' f'{description:s}.') class_attributes_description.append(description) init_arguments.append(argument) instance_attributes.append(definition) class_attributes_description = '\n'.join( sorted(class_attributes_description)) init_arguments = ', '.join(init_arguments) instance_attributes = '\n'.join(sorted(instance_attributes)) template_values = { 'class_attributes_description': class_attributes_description, 'init_arguments': init_arguments, 'instance_attributes': instance_attributes, 'type_description': type_description, 'type_name': type_name} return cls._CLASS_TEMPLATE.format(**template_values) @classmethod def _IsIdentifier(cls, string): """Checks if a string contains an identifier. Args: string (str): string to check. Returns: bool: True if the string contains an identifier, False otherwise. """ return ( string and not string[0].isdigit() and all(character.isalnum() or character == '_' for character in string)) @classmethod def _ValidateDataTypeDefinition(cls, data_type_definition): """Validates the data type definition. Args: data_type_definition (DataTypeDefinition): data type definition. Raises: ValueError: if the data type definition is not considered valid. """ if not cls._IsIdentifier(data_type_definition.name): raise ValueError( f'Data type definition name: {data_type_definition.name!s} not ' f'a valid identifier') if keyword.iskeyword(data_type_definition.name): raise ValueError( f'Data type definition name: {data_type_definition.name!s} matches ' f'keyword') members = getattr(data_type_definition, 'members', None) if not members: raise ValueError( f'Data type definition name: {data_type_definition.name!s} missing ' f'members') defined_attribute_names = set() for member_definition in members: attribute_name = member_definition.name if not cls._IsIdentifier(attribute_name): raise ValueError( f'Attribute name: {attribute_name!s} not a valid identifier') if attribute_name.startswith('_'): raise ValueError( f'Attribute name: {attribute_name!s} starts with underscore') if keyword.iskeyword(attribute_name): raise ValueError( f'Attribute name: {attribute_name!s} matches keyword') if attribute_name in defined_attribute_names: raise ValueError( f'Attribute name: {attribute_name!s} already defined') defined_attribute_names.add(attribute_name)
[docs] @classmethod def CreateClass(cls, data_type_definition): """Creates a new structure values class. Args: data_type_definition (DataTypeDefinition): data type definition. Returns: class: structure values class. """ cls._ValidateDataTypeDefinition(data_type_definition) class_definition = cls._CreateClassTemplate(data_type_definition) namespace = { '__builtins__' : { 'object': builtins.object, 'super': builtins.super}, '__name__': f'{data_type_definition.name:s}'} if sys.version_info[0] >= 3: # pylint: disable=no-member namespace['__builtins__']['__build_class__'] = builtins.__build_class__ exec(class_definition, namespace) # pylint: disable=exec-used return namespace[data_type_definition.name]