From f1c5e85711b67116e545be930ec83cd312c61b07 Mon Sep 17 00:00:00 2001 From: Svein Seldal Date: Sat, 9 Nov 2024 01:38:30 +0100 Subject: [PATCH] Minor fixes to get code up to date * Use __future__ import annotation to avoid "Node" quotes * Simplify main * Add odg list --minus function --- src/objdictgen/__main__.py | 21 +++++++++++---------- src/objdictgen/eds_utils.py | 9 +++++---- src/objdictgen/gen_cfile.py | 13 +++++++------ src/objdictgen/jsonod.py | 21 +++++++++++---------- src/objdictgen/maps.py | 5 +++-- src/objdictgen/node.py | 7 ++++--- src/objdictgen/nosis.py | 5 +++-- src/objdictgen/typing.py | 3 ++- src/objdictgen/ui/commondialogs.py | 3 ++- src/objdictgen/ui/subindextable.py | 3 ++- 10 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/objdictgen/__main__.py b/src/objdictgen/__main__.py index e041122..1613b0e 100644 --- a/src/objdictgen/__main__.py +++ b/src/objdictgen/__main__.py @@ -16,10 +16,10 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # USA +from __future__ import annotations import argparse import functools -import getopt import logging import sys from dataclasses import dataclass, field @@ -27,11 +27,11 @@ from colorama import Fore, Style, init -import objdictgen -from objdictgen import jsonod +from objdictgen import ODG_PROGRAM, __version__, jsonod from objdictgen.node import Node from objdictgen.printing import format_diff_nodes, format_node from objdictgen.typing import TPath +from objdictgen.utils import exc_amend T = TypeVar('T') @@ -66,13 +66,13 @@ def inner(*args, **kw): except Exception as exc: # pylint: disable=broad-except if opts.show_debug: raise - print(f"{objdictgen.ODG_PROGRAM}: {exc.__class__.__name__}: {exc}") + print(f"{ODG_PROGRAM}: {exc.__class__.__name__}: {exc}") sys.exit(1) return inner return decorator -def open_od(fname: TPath|str, validate=True, fix=False) -> "Node": +def open_od(fname: TPath|str, validate=True, fix=False) -> Node: """ Open and validate the OD file""" try: @@ -83,7 +83,7 @@ def open_od(fname: TPath|str, validate=True, fix=False) -> "Node": return od except Exception as exc: - jsonod.exc_amend(exc, f"{fname}: ") + exc_amend(exc, f"{fname}: ") raise @@ -92,7 +92,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None): """ Main command dispatcher """ parser = argparse.ArgumentParser( - prog=objdictgen.ODG_PROGRAM, + prog=ODG_PROGRAM, description=""" A tool to read and convert object dictionary files for the CAN festival library @@ -113,7 +113,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None): opt_novalidate = dict(action='store_true', help="Don't validate input files") opt_nocolor = dict(action='store_true', help="Disable colored output") - parser.add_argument('--version', action='version', version='%(prog)s ' + objdictgen.__version__) + parser.add_argument('--version', action='version', version='%(prog)s ' + __version__) parser.add_argument('--no-color', action='store_true', help="Disable colored output") parser.add_argument('-D', '--debug', **opt_debug) # type: ignore[arg-type] @@ -214,6 +214,7 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None): else: init() + # -- HELP command -- if opts.command == "help": if opts.subcommand: @@ -288,9 +289,9 @@ def main(debugopts: DebugOpts, args: Sequence[str]|None = None): errcode = 1 if lines else 0 if errcode: - print(f"{objdictgen.ODG_PROGRAM}: '{opts.od1}' and '{opts.od2}' differ") + print(f"{ODG_PROGRAM}: '{opts.od1}' and '{opts.od2}' differ") else: - print(f"{objdictgen.ODG_PROGRAM}: '{opts.od1}' and '{opts.od2}' are equal") + print(f"{ODG_PROGRAM}: '{opts.od1}' and '{opts.od2}' are equal") if errcode: parser.exit(errcode) diff --git a/src/objdictgen/eds_utils.py b/src/objdictgen/eds_utils.py index 954e5cc..b9e9fbe 100644 --- a/src/objdictgen/eds_utils.py +++ b/src/objdictgen/eds_utils.py @@ -17,6 +17,7 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # USA +from __future__ import annotations import logging import re @@ -98,7 +99,7 @@ } -def get_default_value(node: "Node", index: int, subindex: int = -1): +def get_default_value(node: Node, index: int, subindex: int = -1): """Function that search into Node Mappings the informations about an index or a subindex and return the default value.""" infos = node.GetEntryInfos(index) @@ -484,7 +485,7 @@ def verify_value(values: dict[str, Any], section_name: str, param: str): raise ValueError(f"Error on section '[{section_name}]': '{param}' incompatible with DataType") from None -def generate_eds_content(node: "Node", filepath: TPath): +def generate_eds_content(node: Node, filepath: TPath): """Generate the EDS file content for the current node in the manager.""" filepath = Path(filepath) @@ -683,7 +684,7 @@ def generate_index_contents(name: str, entries: list[int]): return fileContent -def generate_cpj_content(nodelist: "NodeList"): +def generate_cpj_content(nodelist: NodeList): """Generate the CPJ file content for the nodelist.""" nodes = nodelist.SlaveNodes @@ -700,7 +701,7 @@ def generate_cpj_content(nodelist: "NodeList"): return filecontent -def generate_node(filepath: TPath, nodeid: int = 0) -> "Node": +def generate_node(filepath: TPath, nodeid: int = 0) -> Node: """Generate a Node from an EDS file.""" # Create a new node node = nodelib.Node(id=nodeid) diff --git a/src/objdictgen/gen_cfile.py b/src/objdictgen/gen_cfile.py index dec13fe..5dbb729 100644 --- a/src/objdictgen/gen_cfile.py +++ b/src/objdictgen/gen_cfile.py @@ -17,6 +17,7 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # USA +from __future__ import annotations import re from collections import UserDict @@ -67,20 +68,20 @@ class Text: # FIXME: Remove all %= entries, use f-strings instead, and delete this class - def __init__(self, context: "CFileContext", text: str): + def __init__(self, context: CFileContext, text: str): self.text: str = text - self.context: "CFileContext" = context + self.context: CFileContext = context - def __iadd__(self, other: "str|Text") -> "Text": + def __iadd__(self, other: str|Text) -> Text: """Add a string to the text without formatting.""" self.text += str(other) return self - def __add__(self, other: "str|Text") -> "Text": + def __add__(self, other: str|Text) -> Text: """Add a string to the text without formatting.""" return Text(self.context, self.text + str(other)) - def __imod__(self, other: str) -> "Text": + def __imod__(self, other: str) -> Text: """Add a string to the text with formatting.""" self.text += other.format(**self.context) return self @@ -813,7 +814,7 @@ def generate_file_content(node: NodeProtocol, headerfile: str, pointers_dict=Non # Main Function # ------------------------------------------------------------------------------ -def GenerateFile(filepath: TPath, node: "NodeProtocol", pointers_dict=None): +def GenerateFile(filepath: TPath, node: NodeProtocol, pointers_dict=None): """Main function to generate the C file from a object dictionary node.""" filepath = Path(filepath) headerpath = filepath.with_suffix(".h") diff --git a/src/objdictgen/jsonod.py b/src/objdictgen/jsonod.py index 07b3dea..ea98798 100644 --- a/src/objdictgen/jsonod.py +++ b/src/objdictgen/jsonod.py @@ -24,10 +24,10 @@ import logging import re from datetime import datetime -from typing import (TYPE_CHECKING, Any, Iterable, Mapping, Sequence, TypeVar, cast) +from typing import TYPE_CHECKING, Any, Iterable, Mapping, TypeVar, cast import deepdiff # type: ignore[import] # Due to missing typing stubs for deepdiff -import deepdiff.model # type: ignore[import] # Due to missing typing stubs for deepdiff +import deepdiff.model # type: ignore[import] # Due to missing typing stubs for deepdiff import jsonschema import objdictgen @@ -35,8 +35,9 @@ from objdictgen import maps from objdictgen import node as nodelib from objdictgen.maps import OD, ODMapping, ODMappingList -from objdictgen.typing import (TDiffNodes, TIndexEntry, TODJson, TODObjJson, - TODObj, TODSubObj, TODSubObjJson, TODValue, TParamEntry, TPath, TProfileMenu) +from objdictgen.typing import (TDiffNodes, TIndexEntry, TODJson, TODObj, + TODObjJson, TODSubObj, TODSubObjJson, TODValue, + TParamEntry, TPath, TProfileMenu) from objdictgen.utils import (copy_in_order, exc_amend, maybe_number, str_to_int, strip_brackets) @@ -255,7 +256,7 @@ def member_compare( def get_object_types( - node: "Node|None" = None, + node: Node|None = None, dictionary: list[TODObjJson]|None = None ) -> tuple[dict[int, str], dict[str, int]]: """ Return two dicts with the object type mapping """ @@ -320,7 +321,7 @@ def compare_profile(profilename: TPath, params: ODMapping, menu: TProfileMenu|No return False, False -def generate_jsonc(node: "Node", compact=False, sort=False, internal=False, +def generate_jsonc(node: Node, compact=False, sort=False, internal=False, validate=True, jsonc=True) -> str: """ Export a JSONC string representation of the node """ @@ -372,7 +373,7 @@ def generate_jsonc(node: "Node", compact=False, sort=False, internal=False, return text -def generate_node(contents: str|TODJson, validate: bool = True) -> "Node": +def generate_node(contents: str|TODJson, validate: bool = True) -> Node: """ Import from JSON string or objects """ if isinstance(contents, str): @@ -413,7 +414,7 @@ def generate_node(contents: str|TODJson, validate: bool = True) -> "Node": return node_fromdict(jd, objtypes_s2i) -def node_todict(node: "Node", sort=False, rich=True, internal=False, validate=True) -> TODJson: +def node_todict(node: Node, sort=False, rich=True, internal=False, validate=True) -> TODJson: """ Convert a node to dict representation for serialization. @@ -666,7 +667,7 @@ def indexentry_to_jsondict(ientry: TIndexEntry) -> TODObjJson: return obj -def rearrage_for_json(obj: TODObjJson, node: "Node", objtypes_i2s: dict[int, str], rich=True) -> TODObjJson: +def rearrage_for_json(obj: TODObjJson, node: Node, objtypes_i2s: dict[int, str], rich=True) -> TODObjJson: """ Rearrange the object to fit the wanted JSON format """ # The struct describes what kind of object structure this object have @@ -903,7 +904,7 @@ def validate_indexentry(ientry: TIndexEntry): raise ValidationError(f"Unexpexted count of subindexes in mapping object, found {len(nbmax)}") -def node_fromdict(jd: TODJson, objtypes_s2i: dict[str, int]) -> "Node": +def node_fromdict(jd: TODJson, objtypes_s2i: dict[str, int]) -> Node: """ Convert a dict jd into a Node """ # Create the node and fill the most basic data diff --git a/src/objdictgen/maps.py b/src/objdictgen/maps.py index 14c79da..5d4a747 100644 --- a/src/objdictgen/maps.py +++ b/src/objdictgen/maps.py @@ -17,6 +17,7 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # USA +from __future__ import annotations import ast import itertools @@ -500,7 +501,7 @@ def FindSubentryInfos(self, index: int, subindex: int, compute=True) -> TODSubOb return infos raise ValueError(f"Index 0x{index:04x} does not have subentries") - def FindMapVariableList(self, node: "Node", compute=True) -> Generator[tuple[int, int, int, str], None, None]: + def FindMapVariableList(self, node: Node, compute=True) -> Generator[tuple[int, int, int, str], None, None]: """ Generator of all variables that can be mapped to in pdos. It yields tuple of (index, subindex, size, name) @@ -615,7 +616,7 @@ def FindSubentryInfos(self, index: int, subindex: int, compute=True) -> TODSubOb except StopIteration: raise ValueError(f"Subindex 0x{index:04x}.{subindex:x} does not exist") from None - def FindMapVariableList(self, node: "Node", compute=True) -> Generator[tuple[int, int, int, str], None, None]: + def FindMapVariableList(self, node: Node, compute=True) -> Generator[tuple[int, int, int, str], None, None]: """ Generator of all variables that can be mapped to in pdos. It yields tuple of (index, subindex, size, name) diff --git a/src/objdictgen/node.py b/src/objdictgen/node.py index 8be1220..60b1ce2 100644 --- a/src/objdictgen/node.py +++ b/src/objdictgen/node.py @@ -17,6 +17,7 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # USA +from __future__ import annotations import copy import logging @@ -171,7 +172,7 @@ def isEds(filepath: TPath) -> bool: return header == "[FileInfo]" @staticmethod - def LoadFile(filepath: TPath, **kwargs) -> "Node": + def LoadFile(filepath: TPath, **kwargs) -> Node: """ Open a file and create a new node """ if Node.isXml(filepath): log.debug("Loading XML OD '%s'", filepath) @@ -187,7 +188,7 @@ def LoadFile(filepath: TPath, **kwargs) -> "Node": return Node.LoadJson(f.read(), **kwargs) @staticmethod - def LoadJson(contents: str, validate=True) -> "Node": + def LoadJson(contents: str, validate=True) -> Node: """ Import a new Node from a JSON string """ return jsonod.generate_node(contents, validate=validate) @@ -241,7 +242,7 @@ def asdict(self) -> dict[str, Any]: """ Return the class data as a dict """ return copy.deepcopy(self.__dict__) - def copy(self) -> "Node": + def copy(self) -> Node: """ Return a copy of the node """ diff --git a/src/objdictgen/nosis.py b/src/objdictgen/nosis.py index fe59f3c..09ed207 100644 --- a/src/objdictgen/nosis.py +++ b/src/objdictgen/nosis.py @@ -22,6 +22,7 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # USA +from __future__ import annotations import ast import io @@ -306,10 +307,10 @@ def xmldump(filehandle: io.TextIOWrapper|None, py_obj: object, return None -def xmlload(filehandle: "SupportsRead[str|bytes]|bytes|str") -> Any: +def xmlload(filehandle: SupportsRead[str|bytes]|bytes|str) -> Any: """Load pickled object from file fh.""" - fh: "SupportsRead[str|bytes]" = filehandle # type: ignore[assignment] + fh: SupportsRead[str|bytes] = filehandle # type: ignore[assignment] if isinstance(filehandle, str): fh = io.StringIO(filehandle) elif isinstance(filehandle, bytes): diff --git a/src/objdictgen/typing.py b/src/objdictgen/typing.py index 9ccc9dd..b75f08a 100644 --- a/src/objdictgen/typing.py +++ b/src/objdictgen/typing.py @@ -16,6 +16,7 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # USA +from __future__ import annotations import os from typing import TYPE_CHECKING, Iterator, Protocol, TypedDict @@ -108,7 +109,7 @@ class NodeProtocol(Protocol): ProfileName: str """Name of any loaded profiles. "None" if no profile is loaded.""" - Profile: "ODMapping" + Profile: ODMapping """Mapping containing the object definitions for the profile.""" DefaultStringSize: int diff --git a/src/objdictgen/ui/commondialogs.py b/src/objdictgen/ui/commondialogs.py index 8f8b311..a38717a 100644 --- a/src/objdictgen/ui/commondialogs.py +++ b/src/objdictgen/ui/commondialogs.py @@ -17,6 +17,7 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # USA +from __future__ import annotations import logging import os @@ -1411,7 +1412,7 @@ class DCFEntryValuesTable(wx.grid.GridTableBase): """ A custom wxGrid Table using user supplied data """ - def __init__(self, parent: "DCFEntryValuesDialog", data, colnames): + def __init__(self, parent: DCFEntryValuesDialog, data, colnames): # The base class must be initialized *first* wx.grid.GridTableBase.__init__(self) self.data = data diff --git a/src/objdictgen/ui/subindextable.py b/src/objdictgen/ui/subindextable.py index dfbbfdd..801f5ab 100644 --- a/src/objdictgen/ui/subindextable.py +++ b/src/objdictgen/ui/subindextable.py @@ -17,6 +17,7 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # USA +from __future__ import annotations import codecs import os @@ -115,7 +116,7 @@ class SubindexTable(wx.grid.GridTableBase): # Typing definitions CurrentIndex: int - def __init__(self, parent: "EditingPanel", data, editors, colnames): + def __init__(self, parent: EditingPanel, data, editors, colnames): # The base class must be initialized *first* wx.grid.GridTableBase.__init__(self) self.data = data