Source code for aac.context.definition_parser

"""Definition Parser class for AaC, contains a load_definition function that handles loading of definition files."""
from typing import Any, Type
from enum import Enum, auto
from aac.context.language_error import LanguageError
from aac.context.definition import Definition
from aac.context.lexeme import Lexeme
from aac.context.util import get_python_module_name, get_python_class_name


[docs] class DefinitionParser(): """Definition Parser class, responsible for loading definition files."""
[docs] def find_definitions_by_name(self, name: str) -> list[Definition]: """ Method to find a definition by name. Args: name (str): The name of the definition being searched for. Returns: The definition with the given name. """ result = [] for definition in self.context.get_definitions(): if definition.name == name: result.append(definition) # if we didn't find any definitions in the context, check the parsed definitions if len(result) == 0: for definition in self.parsed_definitions: if definition.name == name: result.append(definition) return result
[docs] def get_location_str(self, lexeme_value: str, lexemes: list[Lexeme]) -> str: """ Method to find the file name and line number for a requested Lexeme value. Args: lexeme_value (str): The Lexeme to match. lexemes (list[Lexeme]): A list of definition Lexemes. Returns: The file name and line number of the requested Lexeme value. """ lexeme = [] for lex in lexemes: # This is just a way to account for different variations of true and false. if lexeme_value is True and (lex.value == "True" or lex.value == "true" or lex.value == "yes"): lexeme.append(lex) if lexeme_value is False and (lex.value == "False" or lex.value == "false"): lexeme.append(lex) # The normal found case. lexeme_value is being cast as a string because all values are stored in lexemes as strings. elif lex.value == str(lexeme_value): lexeme.append(lex) location_str = ( "Unable to identify source and location" # this is the 'not found' case ) if len(lexeme) == 1: # this is the single match case source_str = lexeme[0].source line_str = lexeme[0].location.line + 1 location_str = f"File: {source_str} Line: {line_str}" elif len(lexeme) > 1: # this is the ambiguous match case # check to see if location source is the same for all matches if all( [ lexeme[0].source == lexeme[i].source for i in range(1, len(lexeme)) ] ): source_str = lexeme[0].source location_str = f"File: {source_str} Possible Lines: {', '.join([str(lex.location.line+1) for lex in lexeme])}" else: # if not, just list each possible location location_str = "Unable to identify unique location - " for lex in lexeme: location_str += ( f"File: {lex.source} Line: {lex.location.line+1} " ) return location_str
[docs] def get_inheritance_parents(self, definition: Definition) -> list[Type]: """ Looks up the inheritance parent classes for the given definition and returns them as a list of Python classes. Args: definition (Definition): The definition whose parent class(es) is being searched for. Returns: The parent class(es) as a list of Python classes. """ inheritance_parents = [] if "extends" in definition.structure[definition.get_root_key()]: for parent in definition.structure[definition.get_root_key()][ "extends" ]: # I need to find the definition referenced by the extends parent_package = parent["package"] parent_name = parent["name"] parent_fully_qualified_name = "" try: parent_fully_qualified_name = f"{get_python_module_name(parent_package)}.{get_python_class_name(parent_name)}" except LanguageError as e: raise LanguageError( f"Failed to establish parent fully qualified name from parent_package {parent_package} and parent_name {parent_name}: {e.message}", self.get_location_str(parent_name, definition.lexemes) ) if ( parent_fully_qualified_name in self.context.context_instance.fully_qualified_name_to_class ): inheritance_parents.append( self.context.context_instance.fully_qualified_name_to_class[ parent_fully_qualified_name ] ) else: # there is a chance that processing order just means we haven't gotten to the parent yet parent_definition = None if ( parent_fully_qualified_name in self.fully_qualified_name_to_definition ): parent_definition = self.fully_qualified_name_to_definition[ parent_fully_qualified_name ] if not parent_definition: raise LanguageError( f"Cannot find parent definition {parent_fully_qualified_name} for {definition.name}", self.get_location_str(parent_name, definition.lexemes), ) if parent_definition.get_root_key() == "schema": inheritance_parents.append( self.create_schema_class(parent_definition) ) else: # AaC only supports schema inheritance raise LanguageError( f"AaC extension is only supported for schema. Unable to create parent class with AaC root: {parent_definition.get_root_key()}", self.get_location_str(parent_name, definition.lexemes), ) return inheritance_parents
[docs] def create_enum_class(self, enum_definition: Definition) -> Enum: """ Creates an enum class from a given enum definition. Args: enum_definition (Definition): An enum definition to convert to a class. Returns: The created class. """ if enum_definition.get_root_key() != "enum": raise LanguageError( f"Definition {enum_definition.name} is not an enum", self.get_location_str( enum_definition.get_root_key(), enum_definition.lexemes ) ) try: fully_qualified_name = enum_definition.get_fully_qualified_name() except LanguageError as e: raise LanguageError( f"Failed to create fully qualified name for definition {enum_definition.name}: {e.message}", self.get_location_str(enum_definition.name, enum_definition.lexemes), ) if ( fully_qualified_name in self.context.context_instance.fully_qualified_name_to_class ): # we've already created the class, so nothing to do here return self.context.context_instance.fully_qualified_name_to_class[ fully_qualified_name ] # Note: trying to allow extension with Enums fails, so I just removed it # but we can revisit and try to find a solution in the future if needed values = {} if "values" in enum_definition.structure["enum"]: for value in enum_definition.structure["enum"]["values"]: values[value] = auto() # create the enum class instance_class = None try: instance_class = Enum( enum_definition.get_python_class_name(), values, module=enum_definition.get_python_module_name(), ) except LanguageError as e: raise LanguageError( f"Failed to create Enum instance_class for {enum_definition.name}: {e.message}", self.get_location_str(enum_definition.name, enum_definition.lexemes), ) self.context.context_instance.fully_qualified_name_to_class[ fully_qualified_name ] = instance_class return instance_class
[docs] def add_field_to_class(self, field: dict, instance_class: Type, schema_definition: Definition) -> Type: """ Creates an attribute within the instance class and adds the field name and type to it. Args: field (dict): The field being loaded into the instance class. instance_class (Type): The instance class being loaded with field definitions. schema_definition (Definition): The schema definition containing the fields being iterated through and loaded. Returns: the instance class after being loaded with field definitions. """ field_name = field["name"] field_type = field["type"] is_list = False clean_field_type = field_type if field_type.endswith("[]"): is_list = True clean_field_type = field_type[:-2] if "(" in clean_field_type: clean_field_type = clean_field_type[: clean_field_type.find("(")] # let's make sure the type of the field is known, or create it if it's not potential_definitions = self.find_definitions_by_name(clean_field_type) if len(potential_definitions) != 1: if len(potential_definitions) == 0: raise LanguageError( f"Could not find AaC definition for type {clean_field_type} while loading {schema_definition.name}", self.get_location_str(field_type, schema_definition.lexemes), ) else: raise LanguageError( f"Discovered multiple AaC definitions for type {clean_field_type} while loading {schema_definition.name}. You may need to add a package name to differentiate.", self.get_location_str(field_type, schema_definition.lexemes), ) parsed_definition = potential_definitions[0] self.create_schema_class(parsed_definition) # since python is dynamically typed, we really don't have to worry about setting a type when we create the field # we just need to make sure a reasonable default value is used, so for us that means an empty list or None # Question: is there ever a case where we may need a dict value? if is_list: setattr(instance_class, field_name, []) else: setattr(instance_class, field_name, None) return instance_class
[docs] def create_instance_class(self, inheritance_parents: list, schema_definition: Definition) -> Type: """ Method to create an instance class type for the given definition. Args: inheritance_parents (list[Type]): Types that this definition inherits from. schema_definition (Definition): The definition being converted to an instance class. Returns: The created instance class. """ if len(inheritance_parents) == 0: base_content = [object] else: base_content = inheritance_parents try: instance_class = type( schema_definition.get_python_class_name(), tuple(base_content), {"__module__": schema_definition.get_python_module_name()} ) except LanguageError as e: raise LanguageError( f"Failed to create instance_class for {schema_definition.name}: {e.message}", self.get_location_str( schema_definition.name, schema_definition.lexemes ) ) return instance_class
[docs] def create_schema_class(self, schema_definition: Definition) -> Type: """ Creates a schema class from a given schema definition. Args: schema_definition (Definition): A schema definition to convert to a class. Returns: The created class. """ try: fully_qualified_name = schema_definition.get_fully_qualified_name() except LanguageError as e: raise LanguageError( f"Failed to create fully qualified name for definition {schema_definition.name}: {e.message}", self.get_location_str(schema_definition.name, schema_definition.lexemes), ) if schema_definition.get_root_key() == "primitive": # this is a primitive, so there's no structure to create, just return the python type return eval(self.primitive_name_to_py_type[schema_definition.name]) elif schema_definition.get_root_key() == "enum": # this is an enum, so create the enum class return self.create_enum_class(schema_definition) elif schema_definition.get_root_key() != "schema": raise LanguageError( f"Definition {schema_definition.name} is not a schema", self.get_location_str( schema_definition.get_root_key(), schema_definition.lexemes ) ) if ( fully_qualified_name in self.context.context_instance.fully_qualified_name_to_class ): # we've already created the class, so nothing to do here return self.context.context_instance.fully_qualified_name_to_class[ fully_qualified_name ] inheritance_parents = self.get_inheritance_parents(schema_definition) instance_class = self.create_instance_class(inheritance_parents, schema_definition) # now add the fields to the class for field in schema_definition.structure["schema"]["fields"]: instance_class = self.add_field_to_class(field, instance_class, schema_definition) # finally store the class in the context self.context.context_instance.fully_qualified_name_to_class[ fully_qualified_name ] = instance_class return instance_class
[docs] def create_object_instance(self, type_class: Type, fields: dict) -> Any: """ Creates an instance object from the given fields. Args: type_class (Type): The class created from the field type. fields (dict): Given fields to create instances from. Returns: The created instance object. """ result = type_class() for field_name, field_value in fields.items(): setattr(result, field_name, field_value) return result
[docs] def get_defined_fields(self, package: str, name: str) -> list[str]: """ Returns a list of defined fields for the given definition. Args: package (str): The definition package. name (str): The definition name. Returns: A list of definition fields. """ result = [] defining_definition = None for definition in self.context.get_definitions() + self.parsed_definitions: if definition.name == name and definition.package == package: defining_definition = definition break if ( "extends" in defining_definition.structure[defining_definition.get_root_key()] ): for parent in defining_definition.structure[ defining_definition.get_root_key() ]["extends"]: result.extend(self.get_defined_fields(parent["package"], parent["name"])) if "fields" in defining_definition.structure[definition.get_root_key()]: result.extend( [ field["name"] for field in definition.structure[definition.get_root_key()][ "fields" ] ] ) return result
[docs] def populate_sub_fields(self, subfields: dict, defining_definition: Definition, item: dict, lexemes: list[Lexeme], definition: Definition) -> dict: """ Method used to populate sub-fields in an instance class field. Args: subfields (dict): dictionary containing relevant sub-fields. defining_definition (Definition): The definition of the field type. item (dict): The current field definition which contains sub-fields. lexemes (List[Lexeme]): A list of definition Lexemes. definition (Definition): The overall definition containing the field. Returns: The populated dictionary of sub-fields. """ for subfield in defining_definition.structure["schema"][ "fields" ]: subfield_name = subfield["name"] subfield_type = subfield["type"] subfield_is_required = False if "is_required" in subfield: subfield_is_required = subfield["is_required"] subfield_value = None if subfield_name in item: subfield_value = item[subfield_name] else: if "default" in subfield: # let's see if we need to cast the value subfield_default_str = subfield["default"] if isinstance(subfield_default_str, str): type_map = { "int": int, "number": float, "bool": lambda x: x.lower() in ("yes", "true", "t", "1"), "string": str, } if subfield_type in type_map: subfield_value = type_map[ subfield_type ](subfield_default_str) else: subfield_value = subfield_default_str # we need to eliminate previously covered lexemes, so go through the list until we find subfield_name then add it and everything else found = False sub_lexemes = [] for lex in lexemes: if lex.value == subfield_name: found = True sub_lexemes.append(lex) if found: sub_lexemes.append(lex) subfields[subfield_name] = self.create_field_instance( subfield_name, subfield_type, subfield_is_required, subfield_value, sub_lexemes, definition, ) return subfields
[docs] def field_instance_creator_list(self, lexemes: list, field_value: Any, field_name: str, defining_definition: Definition, instance: list, instance_class: Type, definition: Definition) -> list: """ Method to create instance fields from list type fields. Args: lexemes (List[Lexeme]): A list of definition Lexemes. field_value (Any): Value stored in the field. field_name (str): The name of the field. defining_definition (Definition): Definition of the field type. instance (list[Any]: The instance that will contain the created field) instance_class (Type): The instance type class definition (Definition): Definition containing the field being checked. Returns: The updated instance containing the created field. """ for item in field_value: if not isinstance(item, dict): raise LanguageError( f"Invalid parsed value for field '{field_name}'. Expected type 'dict', but found '{type(item)}'. Value = {item}", self.get_location_str(field_name, lexemes), ) # go through the fields and create instances for each subfields = {} if "fields" not in defining_definition.structure["schema"]: raise LanguageError( f"Schema '{defining_definition.name}' does not contain any fields.", self.get_location_str(field_name, lexemes), ) # make sure there are no undefined fields defined_field_names = self.get_defined_fields( defining_definition.package, defining_definition.name ) item_field_names = [field for field in item.keys()] for item_field_name in item_field_names: if item_field_name not in defined_field_names: raise LanguageError( f"Found undefined field name '{item_field_name}' when expecting {defined_field_names} as defined in {defining_definition.name}", self.get_location_str(item_field_name, lexemes), ) subfields = self.populate_sub_fields(subfields, defining_definition, item, lexemes, definition) instance.append( self.create_object_instance(instance_class, subfields) ) return instance
[docs] def field_instance_creator_not_list(self, lexemes: list, field_value: Any, field_name: str, defining_definition: Definition, instance: list, instance_class: Type, definition: Definition) -> list: """ Method to create instance fields from non-list type fields. Args: lexemes (List[Lexeme]): A list of definition Lexemes. field_value (Any): Value stored in the field. field_name (str): The name of the field. defining_definition (Definition): Definition of the field type. instance (list[Any]): The instance that will contain the created field instance_class (Type): The instance type class definition (Definition): Definition containing the field being checked. Returns: The updated instance containing the created field """ defined_field_names = self.get_defined_fields( defining_definition.package, defining_definition.name ) item_field_names = [field for field in field_value.keys()] for item_field_name in item_field_names: if item_field_name not in defined_field_names: raise LanguageError( f"Found undefined field name '{item_field_name}' when expecting {defined_field_names} as defined in {defining_definition.name}", self.get_location_str(item_field_name, lexemes), ) subfields = {} if "fields" not in defining_definition.structure["schema"]: raise LanguageError( f"Schema '{defining_definition.name}' does not contain any fields.", self.get_location_str(field_name, lexemes), ) subfields = self.populate_sub_fields(subfields, defining_definition, field_value, lexemes, definition) instance = self.create_object_instance(instance_class, subfields) return instance
[docs] def field_instance_check(self, is_list: bool, field_value: Any, field_name: str, is_required: bool, lexemes: list[Lexeme], defining_definition: Definition, instance_class: Type, definition: Definition) -> list: """ Method used to check if a field is a list, and to call the corresponding field instance creator method. Args: is_list (bool): Boolean value determining if the field type is a list. field_value (Any): Value stored in the field. field_name (str): The name of the field. lexemes (List[Lexeme]): A list of definition Lexemes. defining_definition (Definition): Definition of the field type. instance_class (Type): The class type of the instance being created. definition (Definition): Definition containing the field being checked. Returns: The created instance list. """ if is_list: instance = [] if not field_value: if is_required: raise LanguageError( message=f"Missing required field {field_name}", location=self.get_location_str(definition.name, lexemes) ) else: if not isinstance(field_value, list): if is_required: raise LanguageError( f"Invalid parsed value for field '{field_name}'. Expected type 'list', but found '{type(field_value)}'. Value = {field_value}", self.get_location_str(field_name, lexemes), ) else: return instance instance = self.field_instance_creator_list(lexemes, field_value, field_name, defining_definition, instance, instance_class, definition) else: instance = None if not field_value: if is_required: raise LanguageError( f"Missing required field {field_name}", self.get_location_str(field_name, lexemes), ) else: return instance if not isinstance(field_value, dict): # this is a complex type defined by a schema, with a field value so it should be a dict raise LanguageError( f"Invalid parsed value for field '{field_name}'. Expected type 'dict', but found '{type(field_value)}'. Value = {field_value}", self.get_location_str(field_name, lexemes), ) # make sure there are no undefined fields instance = self.field_instance_creator_not_list(lexemes, field_value, field_name, defining_definition, instance, instance_class, definition) return instance
[docs] def primitive_field_value_check(self, is_list: bool, field_value: Any, field_name: str, is_required: bool, lexemes: list, defining_definition: Definition, definition: Definition) -> Any: """ Method used to ensure primitive type field definitions have valid values. Args: is_list (bool): Boolean value determining if the field type is a list. field_value (Any): Value stored in the field. field_name (str): The name of the field. is_required (bool): Boolean value determining if the field is required. lexemes (List[Lexeme]): A list of definition Lexemes. defining_definition (Definition): Definition defining the field type. definition (Definition): Definition containing the field being checked. Returns: The content of the primitive type field value. """ python_type = defining_definition.structure["primitive"]["python_type"] if not field_value: if is_required: raise LanguageError(message=f"Missing required field {field_name}.", location=self.get_location_str(definition.name, lexemes)) if is_list: field_value = [] elif is_list: for item in field_value: if not isinstance(item, eval(python_type)): raise LanguageError( message=f"Invalid value for field '{field_name}'. Expected type '{python_type}', but found '{type(item)}'", location=self.get_location_str(field_value, lexemes), ) else: if "Any" != python_type: if not isinstance(field_value, eval(python_type)): raise LanguageError( f"Invalid value for field '{field_name}'. Expected type '{python_type}', but found '{type(field_value)}'", self.get_location_str(field_value, lexemes), ) return field_value
[docs] def enum_field_list_check(self, field_value: Any, field_name: str, lexemes: list, defining_definition: Definition, enum_class: str) -> list: """ Method used to ensure each item in a list of enum fields have valid values. Args: field_value (Any): Value stored in the field. field_name (str): The name of the field. lexemes (List[Lexeme]): A list of definition Lexemes. defining_definition (Definition): Definition containing the field being checked. enum_class (str): The name of the enums defining definition Returns: The list of valid enum field values. """ result = [] for item in field_value: if not isinstance(item, str): raise LanguageError( f"Invalid value for field '{field_name}'. Expected type 'str', but found '{type(item)}'", self.get_location_str(field_name, lexemes), ) try: result.append(getattr(enum_class, item)) except ValueError: raise LanguageError( f"{item} is not a valid value for enum {defining_definition.name}", self.get_location_str(item, lexemes), ) return result
[docs] def enum_field_value_check(self, is_list: bool, field_value: Any, field_name: str, lexemes: list, defining_definition: Definition) -> list: """ Method used to ensure enum type field definitions have valid values. Args: is_list (bool): Boolean value determining if the field type is a list. field_value (Any): Value stored in the field. field_name (str): The name of the field. lexemes (List[Lexeme]): A list of definition Lexemes. defining_definition (Definition): Definition containing the field being checked. Returns: The list of valid enum field values. """ try: enum_class = self.context.context_instance.fully_qualified_name_to_class[ defining_definition.get_fully_qualified_name() ] except LanguageError as e: raise LanguageError( f"Failed to create Enum instance_class for {defining_definition.name}: {e.message}", self.get_location_str(defining_definition.name, defining_definition.lexemes), ) if not enum_class: enum_class = self.create_enum_class(defining_definition) if is_list: return self.enum_field_list_check(field_value, field_name, lexemes, defining_definition, enum_class) else: if not field_value: return [None] try: return self.context.create_aac_enum( defining_definition.get_fully_qualified_name(), field_value ) except ValueError: raise LanguageError( f"{field_value} is not a valid value for enum {defining_definition.name}", self.get_location_str(field_value, lexemes), )
[docs] def schema_field_value_check(self, is_list: bool, field_value: Any, field_name: str, is_required: bool, lexemes: list, defining_definition: Definition, definition: Definition) -> list: """ Method used to ensure schema type field definitions have valid values. Args: is_list (bool): Boolean value determining if the field type is a list. field_value (Any): Value stored in the field. field_name (str): The name of the field. lexemes (List[Lexeme]): A list of definition Lexemes. defining_definition (Definition): Definition of the field type. definition (Definition): Definition containing the field being checked. Returns: The List of valid schema defined field values. """ try: field_fully_qualified_name = ( defining_definition.get_fully_qualified_name() ) except LanguageError as e: raise LanguageError( f"Failed to create fully qualified name for definition {defining_definition.name}: {e.message}", self.get_location_str(defining_definition.name, defining_definition.lexemes), ) instance_class = self.context.context_instance.fully_qualified_name_to_class[ field_fully_qualified_name ] if not instance_class: if defining_definition.get_root_key() == "schema": instance_class = self.create_schema_class(defining_definition) else: raise LanguageError( f"Unable to process AaC definition of type {field_fully_qualified_name} with root {defining_definition.get_root_key()}", self.get_location_str(field_name, lexemes), ) instance = self.field_instance_check(is_list, field_value, field_name, is_required, lexemes, defining_definition, instance_class, definition) return instance
[docs] def create_field_instance( self, field_name: str, field_type: str, is_required: bool, field_value: Any, lexemes: list[Lexeme], definition: Definition ) -> Any: """ Adds an entry to the instance attribute of a definition for the given field. Args: field_name (str): Name of the field. field_type (str): Type of the field. is_required (bool): Contents of the is_required field for the specified field. field_value (Any): The value for the specified field. lexemes (list[Lexeme]): A list of definition Lexemes. definition (Definition): Definition containing the field instance being created Returns: The instance field value. """ is_list = False clean_field_type = field_type if field_type.endswith("[]"): is_list = True clean_field_type = field_type[:-2] if "(" in clean_field_type: clean_field_type = clean_field_type[: clean_field_type.find("(")] # now get the defining definition from the clean_field_type defining_definitions = self.find_definitions_by_name(clean_field_type) if not defining_definitions or len(defining_definitions) == 0: raise LanguageError( f"Could not find definition for '{clean_field_type}'.", self.get_location_str(field_type, lexemes), ) elif len(defining_definitions) > 1: raise LanguageError( f"Found multiple definitions for '{clean_field_type}'.", self.get_location_str(field_type, lexemes), ) defining_definition = defining_definitions[0] if defining_definition.get_root_key() == "primitive": # this is a primitive, so ensure the parsed value aligns with the type and return it return self.primitive_field_value_check(is_list, field_value, field_name, is_required, lexemes, defining_definition, definition) elif defining_definition.get_root_key() == "enum": # this is an enum, so ensure the parsed value aligns with the type and return it return self.enum_field_value_check(is_list, field_value, field_name, lexemes, defining_definition) else: # this isn't a primitive and isn't an enum, so it must be a schema return self.schema_field_value_check(is_list, field_value, field_name, is_required, lexemes, defining_definition, definition)
[docs] def create_definition_instance(self, definition: Definition) -> Any: """ Populates the instance field of a given definition. Args: definition (Definition): The given definition being populated. Returns: The populated instance for the given definition. """ instance = None defining_definition = None for item in self.context.get_definitions() + self.parsed_definitions: if item.get_root_key() == "schema": if "root" in item.structure["schema"]: if ( definition.get_root_key() == item.structure["schema"]["root"] ): defining_definition = item if not defining_definition: raise LanguageError( f"Could not find definition for {definition.name} with root {definition.get_root_key()}", self.get_location_str(definition.get_root_key(), definition.lexemes), ) if defining_definition.get_root_key() == "schema": # since schemas are how we define "all the things" the root key of the defining definition should be 'schema' self.create_schema_class(defining_definition) else: raise LanguageError( f"Definition for root key '{defining_definition.get_root_key()}' is not a Schema.", self.get_location_str(definition.get_root_key(), definition.lexemes), ) instance = self.create_field_instance( "root", defining_definition.name, True, definition.structure[definition.get_root_key()], definition.lexemes, definition, ) definition.instance = instance return instance
[docs] def set_qualified_name(self, definition: Definition): """ Method to set the fully qualified name for a definition. Args: definition (Definition): The definition whose fully qualified name will be set. """ if definition.get_root_key() == "primitive": self.primitive_name_to_py_type[definition.name] = definition.structure["primitive"]["python_type"] if "package" in definition.structure[definition.get_root_key()]: try: fully_qualified_name = definition.get_fully_qualified_name() except LanguageError as e: raise LanguageError( f"Failed to create fully qualified name for the definition {definition.name}: {e.message}", self.get_location_str(definition.name, definition.lexemes), ) # This is so requirements specifically do not get overwritten. Although other definition types may still get overwritten, so we may need to find a better solution eventually. if definition.get_root_key() == "req": req_id = definition.structure["req"]["id"] fully_qualified_name = f"{fully_qualified_name}_{req_id}" self.fully_qualified_name_to_definition[fully_qualified_name] = definition
# Start the load_definition function code here
[docs] def load_definitions( self, context, parsed_definitions: list[Definition] ) -> list[Definition]: """ Loads the given definitions into the context and populates the instance with a python object. Args: context (LanguageContext): An instance of the active LanguageContext. parsed_definitions: (list[Definition]): The parsed contents of a definition file. Returns: The parsed definitions to load into the LanguageContext. """ # Maintainer note: Yes, this function is a bit of a monster...sorry about that. # I wanted to keep all this stuff together because if it all works out this should be the # only place where we have to deal with navigating the structure of the definitions and # not using the python objects. In order for this to work, any changes in here should # avoid the use of he definition instance...other than actually creating it. schema_defs_by_root = {} self.context = context self.parsed_definitions = parsed_definitions self.primitive_name_to_py_type = {} self.fully_qualified_name_to_definition = {} for definition in self.parsed_definitions + self.context.get_definitions(): self.set_qualified_name(definition) for definition in self.context.get_definitions(): if definition.get_root_key() == "schema": if definition.instance.root: schema_defs_by_root[definition.instance.root] = definition result = [] for definition in self.parsed_definitions: # create and register the instance self.create_definition_instance(definition) definition.source.is_loaded_in_context = True result.append(definition) self.context.context_instance.definitions.add(definition) fully_qualified_name = f"{definition.package}.{definition.name}" # This is so requirements specifically do not get overwritten. Although other definition types may still get overwritten, so we may need to find a better solution eventually. if definition.get_root_key() == "req": req_id = definition.structure["req"]["id"] fully_qualified_name = f"{fully_qualified_name}_{req_id}" self.context.context_instance.fully_qualified_name_to_definition[ fully_qualified_name ] = definition return result