diff --git a/vspec/model/vsstree.py b/vspec/model/vsstree.py index a04eb86e..9ceec57a 100644 --- a/vspec/model/vsstree.py +++ b/vspec/model/vsstree.py @@ -12,10 +12,9 @@ import logging import re import sys -from typing import Any, List, Optional, Set -from anytree import PreOrderIter # type: ignore[import] - +from typing import Any, Optional +from anytree import PreOrderIter # type: ignore[import] from anytree import ( # type: ignore[import] ChildResolverError, Node, @@ -45,10 +44,10 @@ class VSSNode(Node): # qualified struct name. data_type_str: str = "" # data type - enum representation if available - datatype: Optional[VSSDataType] + datatype: VSSDataType | None # The node types that the nodes can take - available_types: Set[str] = set() + available_types: set[str] = set() core_attributes = [ "type", @@ -75,9 +74,9 @@ class VSSNode(Node): # List of accepted extended attributes. In strict terminate if an attribute is # neither in core or extended, - whitelisted_extended_attributes: List[str] = [] + whitelisted_extended_attributes: list[str] = [] - unit: Optional[VSSUnit] = None + unit: VSSUnit | None = None min = "" max = "" @@ -96,15 +95,15 @@ class VSSNode(Node): constUID: str | None = None # Reference nodes for using definitions from previously existing - reference_tree: Optional['VSSNode'] = None + reference_tree: Optional["VSSNode"] = None resolver = Resolver() @classmethod - def set_reference_tree(cls, tree: Optional['VSSNode']) -> None: + def set_reference_tree(cls, tree: Optional["VSSNode"]) -> None: cls.reference_tree = tree @classmethod - def get_reference_datatype(cls, node: 'VSSNode') -> Optional[str]: + def get_reference_datatype(cls, node: "VSSNode") -> str | None: search_name = node.qualified_name() if cls.reference_tree is None: @@ -119,7 +118,7 @@ def get_reference_datatype(cls, node: 'VSSNode') -> Optional[str]: return None @classmethod - def get_reference_type(cls, node: 'VSSNode') -> Optional[str]: + def get_reference_type(cls, node: "VSSNode") -> str | None: search_name = node.qualified_name() if cls.reference_tree is None: @@ -147,7 +146,7 @@ def __init__( self, name, source_dict: dict, - available_types: Set[str], + available_types: set[str], parent=None, children=None, break_on_unknown_attribute=False, @@ -162,7 +161,7 @@ def __init__( parent: Optional parent of this node instance. children: Optional children instances of this node. break_on_unknown_attribute: Throw if the node contains attributes not in core VSS specification - break_on_name_style_vioation: Throw if this node's name is not follwing th VSS recommended style + break_on_name_style_vioation: Throw if this node's name is not following th VSS recommended style Returns: VSSNode object according to the Vehicle Signal Specification. @@ -231,9 +230,8 @@ def extractCoreAttribute(name: str): # Datatype and unit need special handling, so we do some further analysis - # Units are applicable only for primitives. Not user defined types. + # Units are applicable only for some primitives. Not user defined types. if self.has_unit(): - if not (self.is_signal() or self.is_property()): logging.error( "Item %s cannot have unit, only allowed for signal and property!", @@ -278,7 +276,6 @@ def extractCoreAttribute(name: str): # Datatype check for unit performed first when we have set the right datatype if self.has_unit(): - if not self.has_datatype(): logging.error( "Unit specified for item not using standard datatype: %s", self.name @@ -292,7 +289,7 @@ def extractCoreAttribute(name: str): sys.exit(-1) def validate_name_style(self, sourcefile): - """Checks wether this node is adhering to VSS style conventions. + """Checks whether this node is adhering to VSS style conventions. Throws NameStyleValidationException when deviations are detected. A VSS model violating this conventions can still be a valid model. @@ -382,7 +379,7 @@ def is_orphan(self) -> bool: return self.is_leaf return False - def get_struct_qualified_name(self, struct_name) -> Optional[str]: + def get_struct_qualified_name(self, struct_name) -> str | None: """ Returns whether a struct node with the given relative name is defined under the branch of this node. A relative name is the fully qualified name of the struct without the branch prefix under which it is defined. @@ -645,7 +642,7 @@ def verify_attributes(self, abort_on_unknown_attribute: bool): sys.exit(-1) @staticmethod - def get_tree_attrs(node: "VSSNode", proj_fn, filter_fn) -> List[Any]: + def get_tree_attrs(node: "VSSNode", proj_fn, filter_fn) -> list[Any]: """ Collect all attributes of tree nodes rooted at `node` by applying the specified projection and filter function. diff --git a/vspec/vspec2x.py b/vspec/vspec2x.py index e92ae03c..927e2d0d 100755 --- a/vspec/vspec2x.py +++ b/vspec/vspec2x.py @@ -1,5 +1,3 @@ - - # Copyright (c) 2016 Contributors to COVESA # # This program and the accompanying materials are made available under the @@ -12,18 +10,19 @@ # Convert vspec files to various other formats # -from vspec.model.vsstree import VSSNode -from vspec.model.constants import VSSTreeType -from vspec.loggingconfig import initLogging -from vspec.vss2x import Vss2X -from vspec.vspec2vss_config import Vspec2VssConfig import argparse import logging import sys -import vspec import importlib_metadata +import vspec +from vspec.loggingconfig import initLogging +from vspec.model.constants import VSSTreeType +from vspec.model.vsstree import VSSNode +from vspec.vspec2vss_config import Vspec2VssConfig +from vspec.vss2x import Vss2X + try: VERSION = importlib_metadata.version("vss-tools") except importlib_metadata.PackageNotFoundError: @@ -31,14 +30,14 @@ VERSION = "local" -class Vspec2X(): +class Vspec2X: """ Framework for translating from *.vspec files to first an internal VSS model, and then to something else called X. Users must provide a Vss2X generator that can generate X if they get a VSS model as input. """ - def __init__(self, generator: Vss2X, vspec2vss_config: Vspec2VssConfig): + def __init__(self, generator: Vss2X, vspec2vss_config: Vspec2VssConfig): self.generator = generator self.vspec2vss_config = vspec2vss_config @@ -46,54 +45,123 @@ def main(self, arguments): initLogging() parser = argparse.ArgumentParser(description="Convert vspec to other formats.") - parser.add_argument('--version', action='version', version=VERSION) - parser.add_argument('-I', '--include-dir', action='append', metavar='dir', type=str, default=[], - help='Add include directory to search for included vspec files.') + parser.add_argument("--version", action="version", version=VERSION) + parser.add_argument( + "-I", + "--include-dir", + action="append", + metavar="dir", + type=str, + default=[], + help="Add include directory to search for included vspec files.", + ) if self.vspec2vss_config.extended_attributes_supported: - parser.add_argument('-e', '--extended-attributes', type=str, default="", - help='Whitelisted extended attributes as comma separated list.') - parser.add_argument('-s', '--strict', action='store_true', - help='Use strict checking: Terminate when anything not covered or not recommended ' - 'by VSS language or extensions is found.') - parser.add_argument('--abort-on-unknown-attribute', action='store_true', - help="Terminate when an unknown attribute is found.") - parser.add_argument('--abort-on-name-style', action='store_true', - help="Terminate if name style does not follow VSS standard catalog naming convention.") + parser.add_argument( + "-e", + "--extended-attributes", + type=str, + default="", + help="Whitelisted extended attributes as comma separated list.", + ) + parser.add_argument( + "-s", + "--strict", + action="store_true", + help="Use strict checking: Terminate when anything not covered or not recommended " + "by VSS language or extensions is found.", + ) + parser.add_argument( + "--abort-on-unknown-attribute", + action="store_true", + help="Terminate when an unknown attribute is found.", + ) + parser.add_argument( + "--abort-on-name-style", + action="store_true", + help="Terminate if name style does not follow VSS standard catalog naming convention.", + ) if self.vspec2vss_config.uuid_supported: - parser.add_argument('--uuid', action='store_true', - help='Include uuid in generated files. (Deprecated, will be removed in VSS-tools 6.0)') - if self.vspec2vss_config.expand_model and self.vspec2vss_config.no_expand_option_supported: - parser.add_argument('--no-expand', action='store_true', - help='Do not expand tree.') - parser.add_argument('-o', '--overlays', action='append', metavar='overlays', type=str, default=[], - help='Add overlay that will be layered on top of the VSS file in the order they appear.') - parser.add_argument('-q', '--quantity-file', action='append', metavar='quantity_file', type=str, default=[], - help='Quantity file to be used for generation. Argument -q may be used multiple times.') - parser.add_argument('-u', '--unit-file', action='append', metavar='unit_file', type=str, default=[], - help='Unit file to be used for generation. Argument -u may be used multiple times.') - parser.add_argument('vspec_file', metavar='', - help='The vehicle specification file to convert.') + parser.add_argument( + "--uuid", + action="store_true", + help="Include uuid in generated files. (Deprecated, will be removed in VSS-tools 6.0)", + ) + if ( + self.vspec2vss_config.expand_model + and self.vspec2vss_config.no_expand_option_supported + ): + parser.add_argument( + "--no-expand", action="store_true", help="Do not expand tree." + ) + parser.add_argument( + "-o", + "--overlays", + action="append", + metavar="overlays", + type=str, + default=[], + help="Add overlay that will be layered on top of the VSS file in the order they appear.", + ) + parser.add_argument( + "-q", + "--quantity-file", + action="append", + metavar="quantity_file", + type=str, + default=[], + help="Quantity file to be used for generation. Argument -q may be used multiple times.", + ) + parser.add_argument( + "-u", + "--unit-file", + action="append", + metavar="unit_file", + type=str, + default=[], + help="Unit file to be used for generation. Argument -u may be used multiple times.", + ) + parser.add_argument( + "vspec_file", + metavar="", + help="The vehicle specification file to convert.", + ) if self.vspec2vss_config.output_file_required: - parser.add_argument('output_file', metavar='', - help='The file to write output to.') + parser.add_argument( + "output_file", + metavar="", + help="The file to read and write output to.", + ) if self.vspec2vss_config.type_tree_supported: - type_group = parser.add_argument_group('VSS Data Type Tree arguments', - 'Arguments related to struct/type support') - - type_group.add_argument('-vt', '--vspec-types-file', action='append', metavar='vspec_types_file', type=str, - default=[], - help='Data types file in vspec format.') + type_group = parser.add_argument_group( + "VSS Data Type Tree arguments", + "Arguments related to struct/type support", + ) + + type_group.add_argument( + "-vt", + "--vspec-types-file", + action="append", + metavar="vspec_types_file", + type=str, + default=[], + help="Data types file in vspec format.", + ) if self.vspec2vss_config.separate_output_type_file_supported: # Note we might get some odd errors if using -ot in a tool not supporting it due to conflict with -o - type_group.add_argument('-ot', '--types-output-file', metavar='', - help='Output file for writing data types from vspec file. ' + - 'If not specified, a single file is used where applicable. ' + - 'In case of JSON and YAML, the data is exported under a ' + - 'special key - "ComplexDataTypes"') - - self.generator.add_arguments(parser.add_argument_group( - "Exporter specific arguments", "")) + type_group.add_argument( + "-ot", + "--types-output-file", + metavar="", + help="Output file for writing data types from vspec file. " + + "If not specified, a single file is used where applicable. " + + "In case of JSON and YAML, the data is exported under a " + + 'special key - "ComplexDataTypes"', + ) + + self.generator.add_arguments( + parser.add_argument_group("Exporter specific arguments", "") + ) args = parser.parse_args(arguments) @@ -110,24 +178,40 @@ def main(self, arguments): if args.abort_on_name_style or args.strict: abort_on_namestyle = True - if self.vspec2vss_config.extended_attributes_supported and (len(args.extended_attributes) > 0): + if self.vspec2vss_config.extended_attributes_supported and ( + len(args.extended_attributes) > 0 + ): known_extended_attributes_list = args.extended_attributes.split(",") - vspec.model.vsstree.VSSNode.whitelisted_extended_attributes = known_extended_attributes_list - logging.info(f"Known extended attributes: {', '.join(known_extended_attributes_list)}") + vspec.model.vsstree.VSSNode.whitelisted_extended_attributes = ( + known_extended_attributes_list + ) + logging.info( + f"Known extended attributes: {', '.join(known_extended_attributes_list)}" + ) else: known_extended_attributes_list = list() - self.vspec2vss_config.generate_uuid = self.vspec2vss_config.uuid_supported and args.uuid + self.vspec2vss_config.generate_uuid = ( + self.vspec2vss_config.uuid_supported and args.uuid + ) # Follow up to https://github.com/COVESA/vehicle_signal_specification/pull/721 # Deprecate --uuid if self.vspec2vss_config.generate_uuid: - logging.warning("The argument --uuid is deprecated and the uuid feature is planned " - "to be removed in VSS-tools 6.0") - logging.info("If you need static identifiers consider using the vspec2id tool") - - self.vspec2vss_config.expand_model = (self.vspec2vss_config.expand_model and not - (self.vspec2vss_config.no_expand_option_supported and args.no_expand)) + logging.warning( + "The argument --uuid is deprecated and the uuid feature is planned " + "to be removed in VSS-tools 6.0" + ) + logging.info( + "If you need static identifiers consider using the vspec2id tool" + ) + + self.vspec2vss_config.expand_model = ( + self.vspec2vss_config.expand_model + and not ( + self.vspec2vss_config.no_expand_option_supported and args.no_expand + ) + ) vspec.load_quantities(args.vspec_file, args.quantity_file) vspec.load_units(args.vspec_file, args.unit_file) @@ -137,27 +221,41 @@ def main(self, arguments): if self.vspec2vss_config.type_tree_supported: if self.vspec2vss_config.separate_output_type_file_supported: if args.types_output_file is not None and not args.vspec_types_file: - parser.error("An output file for data types was provided. Please also provide " - "the input vspec file for data types") + parser.error( + "An output file for data types was provided. Please also provide " + "the input vspec file for data types" + ) if args.vspec_types_file: data_type_tree = self.processDataTypeTree( - parser, args, include_dirs, abort_on_namestyle) - vspec.verify_mandatory_attributes(data_type_tree, abort_on_unknown_attribute) + parser, args, include_dirs, abort_on_namestyle + ) + vspec.verify_mandatory_attributes( + data_type_tree, abort_on_unknown_attribute + ) try: logging.info(f"Loading vspec from {args.vspec_file}...") tree = vspec.load_tree( - args.vspec_file, include_dirs, VSSTreeType.SIGNAL_TREE, + args.vspec_file, + include_dirs, + VSSTreeType.SIGNAL_TREE, break_on_name_style_violation=abort_on_namestyle, - expand_inst=False, data_type_tree=data_type_tree) + expand_inst=False, + data_type_tree=data_type_tree, + ) VSSNode.set_reference_tree(tree) for overlay in args.overlays: logging.info(f"Applying VSS overlay from {overlay}...") - othertree = vspec.load_tree(overlay, include_dirs, VSSTreeType.SIGNAL_TREE, - break_on_name_style_violation=abort_on_namestyle, expand_inst=False, - data_type_tree=data_type_tree) + othertree = vspec.load_tree( + overlay, + include_dirs, + VSSTreeType.SIGNAL_TREE, + break_on_name_style_violation=abort_on_namestyle, + expand_inst=False, + data_type_tree=data_type_tree, + ) vspec.merge_tree(tree, othertree) vspec.check_type_usage(tree, VSSTreeType.SIGNAL_TREE, data_type_tree) @@ -174,21 +272,37 @@ def main(self, arguments): logging.error(f"Error: {e}") sys.exit(255) - def processDataTypeTree(self, parser: argparse.ArgumentParser, args, include_dirs, - abort_on_namestyle: bool) -> VSSNode: + def processDataTypeTree( + self, + parser: argparse.ArgumentParser, + args, + include_dirs, + abort_on_namestyle: bool, + ) -> VSSNode: """ Helper function to process command line arguments and invoke logic for processing data type information provided in vspec format """ - if self.vspec2vss_config.separate_output_type_file_supported and \ - args.types_output_file is None: - logging.info("Sensors and custom data types will be consolidated into one file.") + if ( + self.vspec2vss_config.separate_output_type_file_supported + and args.types_output_file is None + ): + logging.info( + "Sensors and custom data types will be consolidated into one file." + ) first_tree = True for type_file in args.vspec_types_file: - logging.info(f"Loading and processing struct/data type tree from {type_file}") - new_tree = vspec.load_tree(type_file, include_dirs, VSSTreeType.DATA_TYPE_TREE, - break_on_name_style_violation=abort_on_namestyle, expand_inst=False) + logging.info( + f"Loading and processing struct/data type tree from {type_file}" + ) + new_tree = vspec.load_tree( + type_file, + include_dirs, + VSSTreeType.DATA_TYPE_TREE, + break_on_name_style_violation=abort_on_namestyle, + expand_inst=False, + ) if first_tree: tree = new_tree first_tree = False