diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index b0ae4bb1..22008fe8 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -9,7 +9,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.11", "3.12", "3.13", "3.14"] + python-version: ["3.12", "3.13", "3.14"] runs-on: ${{ matrix.os }} @@ -122,7 +122,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.11", "3.12", "3.13"] # TODO: add "3.14" once stable + python-version: ["3.12", "3.13"] # TODO: add "3.14" once https://github.com/prospector-dev/prospector/issues/825 fixed steps: - uses: actions/checkout@v4 @@ -151,7 +151,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.11", "3.12", "3.13", "3.14"] + python-version: ["3.12", "3.13", "3.14"] steps: - uses: actions/checkout@v4 diff --git a/.readthedocs.yaml b/.readthedocs.yaml index ba1bf446..7e7b78c8 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -8,7 +8,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.11" + python: "3.13" apt_packages: - graphviz diff --git a/pyproject.toml b/pyproject.toml index 416d2898..618802ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "py-uds" description = "UDS (Unified Diagnostic Services) protocol handler." -requires-python = ">=3.11" +requires-python = ">=3.12" readme = "README.rst" license = "MIT" license-files = ["LICENSE"] @@ -16,7 +16,6 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", diff --git a/tests/software_tests/translator/data_record/test_conditional_data_record.py b/tests/software_tests/translator/data_record/test_conditional_data_record.py index 74caf6ae..4122efdc 100644 --- a/tests/software_tests/translator/data_record/test_conditional_data_record.py +++ b/tests/software_tests/translator/data_record/test_conditional_data_record.py @@ -6,11 +6,11 @@ DEFAULT_DIAGNOSTIC_MESSAGE_CONTINUATION, AbstractConditionalDataRecord, AbstractDataRecord, - AliasMessageStructure, Callable, ConditionalFormulaDataRecord, ConditionalMappingDataRecord, Mapping, + MessageStructureAlias, Sequence, ) from uds.utilities import InconsistencyError @@ -531,7 +531,7 @@ class TestConditionalFormulaDataRecordIntegration: """Integration tests for `ConditionalFormulaDataRecord` class.""" def setup_class(self): - def continuation_length_formula(raw_value: int) -> AliasMessageStructure: + def continuation_length_formula(raw_value: int) -> MessageStructureAlias: if raw_value <= 0 or raw_value > 20: raise ValueError return [RawDataRecord(name="Entries", diff --git a/tests/system_tests/abstract_system_tests.py b/tests/system_tests/abstract_system_tests.py index 3c496ce6..f0847de7 100644 --- a/tests/system_tests/abstract_system_tests.py +++ b/tests/system_tests/abstract_system_tests.py @@ -4,7 +4,6 @@ from abc import ABC from threading import Timer from time import sleep -from typing import List, Optional from uds.message import UdsMessage, UdsMessageRecord from uds.packet import AbstractPacket, AbstractPacketRecord @@ -19,20 +18,20 @@ class BaseSystemTests(ABC): TASK_TIMING_TOLERANCE: TimeMillisecondsAlias = 30 TIMESTAMP_TOLERANCE: TimeMillisecondsAlias = 1 - sent_messages: List[UdsMessageRecord] - received_messages: List[UdsMessageRecord] - sent_packets: List[AbstractPacketRecord] - _timers: List[Timer] + sent_messages: list[UdsMessageRecord] + received_messages: list[UdsMessageRecord] + sent_packets: list[AbstractPacketRecord] + _timers: list[Timer] def setup_method(self): """ Common setup: - define common variables """ - self.sent_messages: List[UdsMessageRecord] = [] - self.received_messages: List[UdsMessageRecord] = [] - self.sent_packets: List[AbstractPacketRecord] = [] - self._timers: List[Timer] = [] + self.sent_messages: list[UdsMessageRecord] = [] + self.received_messages: list[UdsMessageRecord] = [] + self.sent_packets: list[AbstractPacketRecord] = [] + self._timers: list[Timer] = [] def teardown_method(self): """ @@ -77,7 +76,7 @@ def _send_packet(): async def async_send_packet(transport_interface: AbstractTransportInterface, packet: AbstractPacket, delay: TimeMillisecondsAlias, - loop: Optional[asyncio.AbstractEventLoop] = None) -> AbstractPacketRecord: + loop: None | asyncio.AbstractEventLoop = None) -> AbstractPacketRecord: """ Send a packet asynchronously over Transport Interface. @@ -94,8 +93,8 @@ async def async_send_packet(transport_interface: AbstractTransportInterface, def receive_message(self, transport_interface: AbstractTransportInterface, - start_timeout: Optional[TimeMillisecondsAlias], - end_timeout: Optional[TimeMillisecondsAlias], + start_timeout: None | TimeMillisecondsAlias, + end_timeout: None | TimeMillisecondsAlias, delay: TimeMillisecondsAlias) -> Timer: """ Receive UDS message over Transport Interface. @@ -146,7 +145,7 @@ def _send_message(): async def async_send_message(transport_interface: AbstractTransportInterface, message: UdsMessage, delay: TimeMillisecondsAlias, - loop: Optional[asyncio.AbstractEventLoop] = None) -> UdsMessageRecord: + loop: None | asyncio.AbstractEventLoop = None) -> UdsMessageRecord: """ Send UDS message asynchronously over Transport Interface. diff --git a/tests/system_tests/can/python_can/python_can.py b/tests/system_tests/can/python_can/python_can.py index 19f6379f..3221472f 100644 --- a/tests/system_tests/can/python_can/python_can.py +++ b/tests/system_tests/can/python_can/python_can.py @@ -2,7 +2,6 @@ from abc import ABC, abstractmethod from threading import Timer from time import perf_counter, sleep -from typing import List import pytest from tests.system_tests import BaseSystemTests @@ -36,7 +35,7 @@ class AbstractPythonCanTests(BaseSystemTests, ABC): can_interface_1: Bus can_interface_2: Bus - sent_packets: List[CanPacketRecord] + sent_packets: list[CanPacketRecord] @abstractmethod def _define_interfaces(self): diff --git a/uds/__init__.py b/uds/__init__.py index d7ca60dc..cb1938e9 100644 --- a/uds/__init__.py +++ b/uds/__init__.py @@ -53,7 +53,7 @@ import importlib import sys -from typing import Sequence +from collections.abc import Sequence def __getattr__(name: str) -> object: # noqa: vulture diff --git a/uds/addressing/abstract_addressing_information.py b/uds/addressing/abstract_addressing_information.py index a9ef805b..2f9c608b 100644 --- a/uds/addressing/abstract_addressing_information.py +++ b/uds/addressing/abstract_addressing_information.py @@ -3,8 +3,9 @@ __all__ = ["AbstractAddressingInformation"] from abc import ABC, abstractmethod +from collections.abc import Mapping from types import MappingProxyType -from typing import Any, Dict, Mapping, Optional +from typing import Any from uds.utilities import ReassignmentError @@ -140,11 +141,11 @@ def _validate_addressing_information(self) -> None: """Check whether the provided addressing information are valid.""" @abstractmethod - def validate_addressing_params(self, **addressing_params: Any) -> Dict[str, Any]: + def validate_addressing_params(self, **addressing_params: Any) -> dict[str, Any]: """Check whether the provided parameters are complete and correct.""" @abstractmethod - def is_input_packet(self, **frame_attributes: Any) -> Optional[AddressingType]: # noqa: vulture + def is_input_packet(self, **frame_attributes: Any) -> None | AddressingType: # noqa: vulture """ Check if a frame with provided attributes is an input packet for this UDS Entity. diff --git a/uds/can/addressing/abstract_addressing_information.py b/uds/can/addressing/abstract_addressing_information.py index 860c7adc..0918f7c2 100644 --- a/uds/can/addressing/abstract_addressing_information.py +++ b/uds/can/addressing/abstract_addressing_information.py @@ -3,7 +3,7 @@ __all__ = ["AbstractCanAddressingInformation", "CANAddressingParams"] from abc import ABC, abstractmethod -from typing import Any, Optional, TypedDict +from typing import Any, TypedDict from uds.addressing import AddressingType from uds.addressing.abstract_addressing_information import AbstractAddressingInformation @@ -17,9 +17,9 @@ class CANAddressingParams(TypedDict, total=True): addressing_format: CanAddressingFormat addressing_type: AddressingType can_id: int - target_address: Optional[int] - source_address: Optional[int] - address_extension: Optional[int] + target_address: None | int + source_address: None | int + address_extension: None | int class AbstractCanAddressingInformation(AbstractAddressingInformation, ABC): @@ -29,17 +29,17 @@ class InputAIParams(TypedDict, total=False): """:ref:`Addressing Information ` configuration parameters.""" can_id: int - target_address: Optional[int] - source_address: Optional[int] - address_extension: Optional[int] + target_address: None | int + source_address: None | int + address_extension: None | int class CanIdAIParams(TypedDict, total=True): """ref:`Addressing Information ` parameters that are carried by CAN Identifier.""" - addressing_type: Optional[AddressingType] - target_address: Optional[int] - source_address: Optional[int] - priority: Optional[int] + addressing_type: None | AddressingType + target_address: None | int + source_address: None | int + priority: None | int class DataBytesAIParamsAlias(TypedDict, total=False): """Alias of :ref:`Addressing Information ` parameters encoded in data field.""" @@ -50,10 +50,10 @@ class DataBytesAIParamsAlias(TypedDict, total=False): class DecodedAIParamsAlias(TypedDict, total=True): """Alias of :ref:`Addressing Information ` parameters encoded in CAN ID and data field.""" - addressing_type: Optional[AddressingType] - target_address: Optional[int] - source_address: Optional[int] - address_extension: Optional[int] + addressing_type: None | AddressingType + target_address: None | int + source_address: None | int + address_extension: None | int ADDRESSING_FORMAT: CanAddressingFormat """CAN Addressing Format used.""" @@ -84,10 +84,10 @@ def __init__(self, def validate_addressing_params(cls, # type: ignore # pylint: disable=arguments-differ addressing_type: AddressingType, addressing_format: CanAddressingFormat, - can_id: Optional[int] = None, - target_address: Optional[int] = None, - source_address: Optional[int] = None, - address_extension: Optional[int] = None) -> CANAddressingParams: + can_id: None | int = None, + target_address: None | int = None, + source_address: None | int = None, + address_extension: None | int = None) -> CANAddressingParams: """ Validate Addressing Information parameters of a CAN packet. @@ -108,7 +108,7 @@ def validate_addressing_params(cls, # type: ignore # pylint: disable=arguments @staticmethod @abstractmethod def is_compatible_can_id(can_id: int, - addressing_type: Optional[AddressingType]) -> bool: + addressing_type: None | AddressingType) -> bool: """ Check whether provided CAN ID is consistent with this CAN Addressing Format. @@ -163,8 +163,8 @@ def decode_frame_ai_params(cls, can_id: int, raw_frame_data: RawBytesAlias) -> D @classmethod @abstractmethod def encode_ai_data_bytes(cls, - target_address: Optional[int] = None, - address_extension: Optional[int] = None) -> bytearray: + target_address: None | int = None, + address_extension: None | int = None) -> bytearray: """ Generate data bytes that carry Addressing Information. @@ -177,7 +177,7 @@ def encode_ai_data_bytes(cls, def is_input_packet(self, # type: ignore # pylint: disable=arguments-differ can_id: int, raw_frame_data: RawBytesAlias, - **_: Any) -> Optional[AddressingType]: + **_: Any) -> None | AddressingType: """ Check if a frame with provided attributes is an input packet for this UDS Entity. diff --git a/uds/can/addressing/addressing_information.py b/uds/can/addressing/addressing_information.py index 4b3de831..094cdd56 100644 --- a/uds/can/addressing/addressing_information.py +++ b/uds/can/addressing/addressing_information.py @@ -6,8 +6,6 @@ __all__ = ["CanAddressingInformation"] -from typing import Dict, Optional, Type - from uds.addressing import AddressingType from uds.utilities import InconsistencyError, RawBytesAlias, validate_raw_bytes @@ -22,7 +20,7 @@ class CanAddressingInformation: """CAN Entity (either server or client) Addressing Information.""" - ADDRESSING_INFORMATION_MAPPING: Dict[CanAddressingFormat, Type[AbstractCanAddressingInformation]] = { + ADDRESSING_INFORMATION_MAPPING: dict[CanAddressingFormat, type[AbstractCanAddressingInformation]] = { CanAddressingFormat.NORMAL_ADDRESSING: NormalCanAddressingInformation, CanAddressingFormat.NORMAL_FIXED_ADDRESSING: NormalFixedCanAddressingInformation, CanAddressingFormat.EXTENDED_ADDRESSING: ExtendedCanAddressingInformation, @@ -93,10 +91,10 @@ def validate_ai_data_bytes(cls, addressing_format: CanAddressingFormat, ai_data_ def validate_addressing_params(cls, addressing_format: CanAddressingFormat, addressing_type: AddressingType, - can_id: Optional[int] = None, - target_address: Optional[int] = None, - source_address: Optional[int] = None, - address_extension: Optional[int] = None) -> CANAddressingParams: + can_id: None | int = None, + target_address: None | int = None, + source_address: None | int = None, + address_extension: None | int = None) -> CANAddressingParams: """ Validate Addressing Information parameters of a CAN packet. @@ -122,7 +120,7 @@ def validate_addressing_params(cls, def is_compatible_can_id(cls, addressing_format: CanAddressingFormat, can_id: int, - addressing_type: Optional[AddressingType] = None) -> bool: + addressing_type: None | AddressingType = None) -> bool: """ Check whether provided CAN ID is consistent the provided CAN Addressing Format. @@ -223,8 +221,8 @@ def encode_can_id(cls, @classmethod def encode_ai_data_bytes(cls, addressing_format: CanAddressingFormat, - target_address: Optional[int] = None, - address_extension: Optional[int] = None) -> bytearray: + target_address: None | int = None, + address_extension: None | int = None) -> bytearray: """ Generate data bytes that carry Addressing Information. diff --git a/uds/can/addressing/extended_addressing.py b/uds/can/addressing/extended_addressing.py index 69416787..673b4955 100644 --- a/uds/can/addressing/extended_addressing.py +++ b/uds/can/addressing/extended_addressing.py @@ -2,7 +2,6 @@ __all__ = ["ExtendedCanAddressingInformation"] -from typing import Optional from uds.addressing import AddressingType from uds.can.addressing.abstract_addressing_information import AbstractCanAddressingInformation, CANAddressingParams @@ -38,10 +37,10 @@ def _validate_addressing_information(self) -> None: def validate_addressing_params(cls, # type: ignore addressing_type: AddressingType, addressing_format: CanAddressingFormat = ADDRESSING_FORMAT, - can_id: Optional[int] = None, - target_address: Optional[int] = None, - source_address: Optional[int] = None, - address_extension: Optional[int] = None) -> CANAddressingParams: + can_id: None | int = None, + target_address: None | int = None, + source_address: None | int = None, + address_extension: None | int = None) -> CANAddressingParams: """ Validate Addressing Information parameters of a CAN packet that uses Extended Addressing format. @@ -77,7 +76,7 @@ def validate_addressing_params(cls, # type: ignore @staticmethod def is_compatible_can_id(can_id: int, - addressing_type: Optional[AddressingType] = None) -> bool: + addressing_type: None | AddressingType = None) -> bool: """ Check whether provided CAN ID is consistent with Extended Addressing format. @@ -112,8 +111,8 @@ def decode_data_bytes_ai_params( @classmethod def encode_ai_data_bytes(cls, - target_address: Optional[int] = None, - address_extension: Optional[int] = None) -> bytearray: + target_address: None | int = None, + address_extension: None | int = None) -> bytearray: """ Generate data bytes that carry Addressing Information. diff --git a/uds/can/addressing/mixed_addressing.py b/uds/can/addressing/mixed_addressing.py index 11a881be..6a71dfbf 100644 --- a/uds/can/addressing/mixed_addressing.py +++ b/uds/can/addressing/mixed_addressing.py @@ -2,7 +2,6 @@ __all__ = ["Mixed11BitCanAddressingInformation", "Mixed29BitCanAddressingInformation"] -from typing import Optional from uds.addressing import AddressingType from uds.can.addressing.abstract_addressing_information import AbstractCanAddressingInformation, CANAddressingParams @@ -44,10 +43,10 @@ def _validate_addressing_information(self) -> None: def validate_addressing_params(cls, # type: ignore addressing_type: AddressingType, addressing_format: CanAddressingFormat = ADDRESSING_FORMAT, - can_id: Optional[int] = None, - target_address: Optional[int] = None, - source_address: Optional[int] = None, - address_extension: Optional[int] = None) -> CANAddressingParams: + can_id: None | int = None, + target_address: None | int = None, + source_address: None | int = None, + address_extension: None | int = None) -> CANAddressingParams: """ Validate Addressing Information parameters in Mixed 11-bit Addressing format. @@ -83,7 +82,7 @@ def validate_addressing_params(cls, # type: ignore @staticmethod def is_compatible_can_id(can_id: int, - addressing_type: Optional[AddressingType] = None) -> bool: + addressing_type: None | AddressingType = None) -> bool: """ Check whether provided CAN ID is consistent with Normal Addressing Format. @@ -124,8 +123,8 @@ def decode_data_bytes_ai_params( @classmethod def encode_ai_data_bytes(cls, - target_address: Optional[int] = None, - address_extension: Optional[int] = None) -> bytearray: + target_address: None | int = None, + address_extension: None | int = None) -> bytearray: """ Generate data bytes that carry Addressing Information. @@ -171,10 +170,10 @@ def _validate_addressing_information(self) -> None: def validate_addressing_params(cls, # type: ignore addressing_type: AddressingType, addressing_format: CanAddressingFormat = ADDRESSING_FORMAT, - can_id: Optional[int] = None, - target_address: Optional[int] = None, - source_address: Optional[int] = None, - address_extension: Optional[int] = None) -> CANAddressingParams: + can_id: None | int = None, + target_address: None | int = None, + source_address: None | int = None, + address_extension: None | int = None) -> CANAddressingParams: """ Validate Addressing Information parameters of a CAN packet that uses Mixed 29-bit Addressing format. @@ -227,7 +226,7 @@ def validate_addressing_params(cls, # type: ignore @staticmethod def is_compatible_can_id(can_id: int, - addressing_type: Optional[AddressingType] = None) -> bool: + addressing_type: None | AddressingType = None) -> bool: """ Check whether provided CAN ID is consistent with Mixed 29-bit Addressing format. @@ -321,8 +320,8 @@ def encode_can_id(cls, @classmethod def encode_ai_data_bytes(cls, - target_address: Optional[int] = None, - address_extension: Optional[int] = None) -> bytearray: + target_address: None | int = None, + address_extension: None | int = None) -> bytearray: """ Generate data bytes that carry Addressing Information. diff --git a/uds/can/addressing/normal_addressing.py b/uds/can/addressing/normal_addressing.py index 55a66cfe..31be5b34 100644 --- a/uds/can/addressing/normal_addressing.py +++ b/uds/can/addressing/normal_addressing.py @@ -2,7 +2,6 @@ __all__ = ["NormalCanAddressingInformation", "NormalFixedCanAddressingInformation"] -from typing import Optional from uds.addressing import AddressingType from uds.can.addressing.addressing_format import CanAddressingFormat @@ -39,10 +38,10 @@ def _validate_addressing_information(self) -> None: def validate_addressing_params(cls, # type: ignore addressing_type: AddressingType, addressing_format: CanAddressingFormat = ADDRESSING_FORMAT, - can_id: Optional[int] = None, - target_address: Optional[int] = None, - source_address: Optional[int] = None, - address_extension: Optional[int] = None) -> CANAddressingParams: + can_id: None | int = None, + target_address: None | int = None, + source_address: None | int = None, + address_extension: None | int = None) -> CANAddressingParams: """ Validate Addressing Information parameters in Normal Addressing format. @@ -77,7 +76,7 @@ def validate_addressing_params(cls, # type: ignore @staticmethod def is_compatible_can_id(can_id: int, - addressing_type: Optional[AddressingType] = None) -> bool: + addressing_type: None | AddressingType = None) -> bool: """ Check whether provided CAN ID is consistent with Normal Addressing format. @@ -117,8 +116,8 @@ def decode_data_bytes_ai_params( @classmethod def encode_ai_data_bytes(cls, - target_address: Optional[int] = None, - address_extension: Optional[int] = None) -> bytearray: + target_address: None | int = None, + address_extension: None | int = None) -> bytearray: """ Generate data bytes that carry Addressing Information. @@ -157,10 +156,10 @@ def _validate_addressing_information(self) -> None: def validate_addressing_params(cls, # type: ignore addressing_type: AddressingType, addressing_format: CanAddressingFormat = ADDRESSING_FORMAT, - can_id: Optional[int] = None, - target_address: Optional[int] = None, - source_address: Optional[int] = None, - address_extension: Optional[int] = None) -> CANAddressingParams: + can_id: None | int = None, + target_address: None | int = None, + source_address: None | int = None, + address_extension: None | int = None) -> CANAddressingParams: """ Validate Addressing Information parameters of a CAN packet that uses Normal Fixed Addressing format. @@ -216,7 +215,7 @@ def validate_addressing_params(cls, # type: ignore @staticmethod def is_compatible_can_id(can_id: int, - addressing_type: Optional[AddressingType] = None) -> bool: + addressing_type: None | AddressingType = None) -> bool: """ Check whether provided CAN ID is consistent with Normal Fixed Addressing format. @@ -317,8 +316,8 @@ def encode_can_id(cls, @classmethod def encode_ai_data_bytes(cls, - target_address: Optional[int] = None, - address_extension: Optional[int] = None) -> bytearray: + target_address: None | int = None, + address_extension: None | int = None) -> bytearray: """ Generate data bytes that carry Addressing Information. diff --git a/uds/can/frame.py b/uds/can/frame.py index a208a7e8..af743915 100644 --- a/uds/can/frame.py +++ b/uds/can/frame.py @@ -10,7 +10,6 @@ __all__ = ["CanVersion", "CanIdHandler", "CanDlcHandler", "DEFAULT_FILLER_BYTE"] from bisect import bisect_left -from typing import Dict, Optional, Set, Tuple from uds.utilities import ValidatedEnum @@ -106,7 +105,7 @@ def is_extended_can_id(cls, can_id: int) -> bool: return isinstance(can_id, int) and cls.MIN_EXTENDED_VALUE <= can_id <= cls.MAX_EXTENDED_VALUE @classmethod - def validate_can_id(cls, value: int, extended_can_id: Optional[bool] = None) -> None: + def validate_can_id(cls, value: int, extended_can_id: None | bool = None) -> None: """ Validate whether provided value is either Standard or Extended CAN ID. @@ -167,11 +166,11 @@ class CanDlcHandler: - 0x9-0xF - discrete range which is supported by CAN FD only """ - __DLC_VALUES: Tuple[int, ...] = tuple(range(0x10)) - __DATA_BYTES_NUMBERS: Tuple[int, ...] = (0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64) - __DLC_MAPPING: Dict[int, int] = dict(zip(__DLC_VALUES, __DATA_BYTES_NUMBERS)) - __DATA_BYTES_NUMBER_MAPPING: Dict[int, int] = dict(zip(__DATA_BYTES_NUMBERS, __DLC_VALUES)) - __DLC_SPECIFIC_FOR_CAN_FD: Set[int] = set(dlc for dlc in __DLC_VALUES if dlc > 8) + __DLC_VALUES: tuple[int, ...] = tuple(range(0x10)) + __DATA_BYTES_NUMBERS: tuple[int, ...] = (0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64) + __DLC_MAPPING: dict[int, int] = dict(zip(__DLC_VALUES, __DATA_BYTES_NUMBERS)) + __DATA_BYTES_NUMBER_MAPPING: dict[int, int] = dict(zip(__DATA_BYTES_NUMBERS, __DLC_VALUES)) + __DLC_SPECIFIC_FOR_CAN_FD: set[int] = set(dlc for dlc in __DLC_VALUES if dlc > 8) MIN_DATA_BYTES_NUMBER: int = min(__DATA_BYTES_NUMBERS) """Minimum number of data bytes in a CAN frame.""" diff --git a/uds/can/packet/__init__.py b/uds/can/packet/__init__.py index f237e94d..618eb39d 100644 --- a/uds/can/packet/__init__.py +++ b/uds/can/packet/__init__.py @@ -1,6 +1,6 @@ """Packets implementation for :ref:`Diagnostics over CAN (ISO 15765) `.""" -from .abstract_container import AbstractCanPacketContainer, CanPacketsContainersSequence +from .abstract_container import AbstractCanPacketContainer, CanPacketsContainersSequenceAlias from .can_packet import CanPacket from .can_packet_record import CanPacketRecord from .can_packet_type import CanPacketType diff --git a/uds/can/packet/abstract_container.py b/uds/can/packet/abstract_container.py index a74315b5..09d68fb2 100644 --- a/uds/can/packet/abstract_container.py +++ b/uds/can/packet/abstract_container.py @@ -1,9 +1,9 @@ """Abstract definition of a container for a CAN packet.""" -__all__ = ["AbstractCanPacketContainer", "CanPacketsContainersSequence"] +__all__ = ["AbstractCanPacketContainer", "CanPacketsContainersSequenceAlias"] from abc import ABC, abstractmethod -from typing import Optional, Sequence +from collections.abc import Sequence from uds.addressing import AddressingType from uds.packet.abstract_packet import AbstractPacketContainer @@ -41,7 +41,7 @@ def addressing_format(self) -> CanAddressingFormat: """CAN addressing format used by this CAN packet.""" @property - def target_address(self) -> Optional[int]: + def target_address(self) -> None | int: """ Target Address (TA) value of this CAN Packet. @@ -58,7 +58,7 @@ def target_address(self) -> Optional[int]: raw_frame_data=self.raw_frame_data)["target_address"] @property - def source_address(self) -> Optional[int]: + def source_address(self) -> None | int: """ Source Address (SA) value of this CAN Packet. @@ -74,7 +74,7 @@ def source_address(self) -> Optional[int]: raw_frame_data=self.raw_frame_data)["source_address"] @property - def address_extension(self) -> Optional[int]: + def address_extension(self) -> None | int: """ Address Extension (AE) value of this CAN Packet. @@ -96,7 +96,7 @@ def packet_type(self) -> CanPacketType: return CanPacketType(self.raw_frame_data[ai_data_bytes_number] >> 4) @property - def data_length(self) -> Optional[int]: + def data_length(self) -> None | int: """ Payload bytes number of a diagnostic message that is carried by this CAN packet. @@ -124,7 +124,7 @@ def data_length(self) -> Optional[int]: f"{self.packet_type}.") @property - def sequence_number(self) -> Optional[int]: + def sequence_number(self) -> None | int: """ Sequence Number carried by this CAN packet. @@ -147,7 +147,7 @@ def sequence_number(self) -> Optional[int]: raise NotImplementedError("No handling for given CAN Packet Packet Type.") @property - def flow_status(self) -> Optional[CanFlowStatus]: + def flow_status(self) -> None | CanFlowStatus: """ Flow Status carried by this CAN packet. @@ -169,7 +169,7 @@ def flow_status(self) -> Optional[CanFlowStatus]: raise NotImplementedError("No handling for given CAN Packet Packet Type.") @property - def block_size(self) -> Optional[int]: + def block_size(self) -> None | int: """ Block Size value carried by this CAN packet. @@ -191,7 +191,7 @@ def block_size(self) -> Optional[int]: raise NotImplementedError("No handling for given CAN Packet Packet Type.") @property - def st_min(self) -> Optional[int]: + def st_min(self) -> None | int: """ Separation Time minimum (STmin) value carried by this CAN packet. @@ -218,7 +218,7 @@ def addressing_type(self) -> AddressingType: """Addressing type for which this CAN packet is relevant.""" @property - def payload(self) -> Optional[bytes]: + def payload(self) -> None | bytes: """ Diagnostic message payload carried by this CAN packet. @@ -252,5 +252,5 @@ def payload(self) -> Optional[bytes]: raise NotImplementedError("No handling for given CAN Packet Packet Type.") -CanPacketsContainersSequence = Sequence[AbstractPacketContainer] +CanPacketsContainersSequenceAlias = Sequence[AbstractPacketContainer] """Alias for a sequence filled with CAN packet or packet record objects.""" diff --git a/uds/can/packet/can_packet.py b/uds/can/packet/can_packet.py index 28011603..acc681bf 100644 --- a/uds/can/packet/can_packet.py +++ b/uds/can/packet/can_packet.py @@ -2,7 +2,7 @@ __all__ = ["CanPacket"] -from typing import Any, Optional +from typing import Any from uds.addressing import AddressingType from uds.packet import AbstractPacket @@ -32,11 +32,11 @@ def __init__(self, *, addressing_format: CanAddressingFormat, packet_type: CanPacketType, addressing_type: AddressingType, - can_id: Optional[int] = None, - target_address: Optional[int] = None, - source_address: Optional[int] = None, - address_extension: Optional[int] = None, - dlc: Optional[int] = None, + can_id: None | int = None, + target_address: None | int = None, + source_address: None | int = None, + address_extension: None | int = None, + dlc: None | int = None, **packet_type_specific_kwargs: Any) -> None: """ Create a storage for a single CAN packet. @@ -135,10 +135,10 @@ def addressing_type(self) -> AddressingType: def set_addressing_information(self, *, addressing_type: AddressingType, - can_id: Optional[int] = None, - target_address: Optional[int] = None, - source_address: Optional[int] = None, - address_extension: Optional[int] = None) -> None: + can_id: None | int = None, + target_address: None | int = None, + source_address: None | int = None, + address_extension: None | int = None) -> None: """ Change addressing information for this CAN packet. @@ -171,7 +171,7 @@ def set_addressing_information(self, *, def set_packet_data(self, *, packet_type: CanPacketType, - dlc: Optional[int] = None, + dlc: None | int = None, **packet_type_specific_kwargs: Any) -> None: """ Change packet type and data field of this CAN packet. diff --git a/uds/can/packet/can_packet_record.py b/uds/can/packet/can_packet_record.py index bc3e718c..3278a65c 100644 --- a/uds/can/packet/can_packet_record.py +++ b/uds/can/packet/can_packet_record.py @@ -3,7 +3,7 @@ __all__ = ["CanPacketRecord", "CanFrameAlias"] from datetime import datetime -from typing import Any, Union +from typing import Any from can import Message as PythonCanFrame from uds.addressing import AddressingType, TransmissionDirection @@ -14,7 +14,7 @@ from .abstract_container import AbstractCanPacketContainer from .can_packet_type import CanPacketType -CanFrameAlias = Union[PythonCanFrame] +CanFrameAlias = PythonCanFrame """Alias of supported CAN frames objects.""" diff --git a/uds/can/packet/consecutive_frame.py b/uds/can/packet/consecutive_frame.py index a87bba91..3e828ca2 100644 --- a/uds/can/packet/consecutive_frame.py +++ b/uds/can/packet/consecutive_frame.py @@ -6,8 +6,6 @@ "get_consecutive_frame_min_dlc", "get_consecutive_frame_max_payload_size", "extract_sequence_number", "encode_sequence_number"] -from typing import Optional - from uds.utilities import InconsistencyError, RawBytesAlias, validate_nibble, validate_raw_byte, validate_raw_bytes from ..addressing import CanAddressingFormat, CanAddressingInformation @@ -59,10 +57,10 @@ def validate_consecutive_frame_data(addressing_format: CanAddressingFormat, raw_ def create_consecutive_frame_data(addressing_format: CanAddressingFormat, payload: RawBytesAlias, sequence_number: int, - dlc: Optional[int] = None, + dlc: None | int = None, filler_byte: int = DEFAULT_FILLER_BYTE, - target_address: Optional[int] = None, - address_extension: Optional[int] = None) -> bytearray: + target_address: None | int = None, + address_extension: None | int = None) -> bytearray: """ Create a data field of a CAN frame that carries a valid Consecutive Frame packet. @@ -119,8 +117,8 @@ def generate_consecutive_frame_data(addressing_format: CanAddressingFormat, sequence_number: int, dlc: int, filler_byte: int = DEFAULT_FILLER_BYTE, - target_address: Optional[int] = None, - address_extension: Optional[int] = None) -> bytearray: + target_address: None | int = None, + address_extension: None | int = None) -> bytearray: """ Generate CAN frame data field that carries any combination of Consecutive Frame packet data parameters. @@ -204,7 +202,7 @@ def get_consecutive_frame_min_dlc(addressing_format: CanAddressingFormat, payloa def get_consecutive_frame_max_payload_size(addressing_format: CanAddressingFormat, - dlc: Optional[int] = None) -> int: + dlc: None | int = None) -> int: """ Get the maximum payload size that could be carried by a Consecutive Frame. diff --git a/uds/can/packet/first_frame.py b/uds/can/packet/first_frame.py index dc17e33b..3c32556b 100644 --- a/uds/can/packet/first_frame.py +++ b/uds/can/packet/first_frame.py @@ -7,7 +7,6 @@ "extract_first_frame_payload", "extract_ff_dl", "get_first_frame_payload_size", "extract_ff_dl_data_bytes", "encode_ff_dl", "generate_ff_dl_bytes", "validate_ff_dl"] -from typing import Optional from uds.can.frame import CanDlcHandler from uds.utilities import InconsistencyError, RawBytesAlias, bytes_to_int, int_to_bytes, validate_raw_bytes @@ -74,8 +73,8 @@ def create_first_frame_data(addressing_format: CanAddressingFormat, payload: RawBytesAlias, dlc: int, data_length: int, - target_address: Optional[int] = None, - address_extension: Optional[int] = None) -> bytearray: + target_address: None | int = None, + address_extension: None | int = None) -> bytearray: """ Create a data field of a CAN frame that carries a valid First Frame packet. @@ -117,8 +116,8 @@ def generate_first_frame_data(addressing_format: CanAddressingFormat, dlc: int, ff_dl: int, long_ff_dl_format: bool = False, - target_address: Optional[int] = None, - address_extension: Optional[int] = None) -> bytearray: + target_address: None | int = None, + address_extension: None | int = None) -> bytearray: """ Generate CAN frame data field that carries any combination of First Frame packet data parameters. @@ -282,9 +281,9 @@ def generate_ff_dl_bytes(ff_dl: int, long_ff_dl_format: bool) -> bytearray: def validate_ff_dl(ff_dl: int, - ff_dl_bytes_number: Optional[int] = None, - dlc: Optional[int] = None, - addressing_format: Optional[CanAddressingFormat] = None) -> None: + ff_dl_bytes_number: None | int = None, + dlc: None | int = None, + addressing_format: None | CanAddressingFormat = None) -> None: """ Validate a value of First Frame Data Length. diff --git a/uds/can/packet/flow_control.py b/uds/can/packet/flow_control.py index a29611b8..11f1fc48 100644 --- a/uds/can/packet/flow_control.py +++ b/uds/can/packet/flow_control.py @@ -19,7 +19,6 @@ from abc import ABC, abstractmethod from copy import deepcopy -from typing import Optional, Tuple from warnings import warn from aenum import unique @@ -222,12 +221,12 @@ def validate_flow_control_data(addressing_format: CanAddressingFormat, raw_frame def create_flow_control_data(addressing_format: CanAddressingFormat, flow_status: CanFlowStatus, - block_size: Optional[int] = None, - st_min: Optional[int] = None, - dlc: Optional[int] = None, + block_size: None | int = None, + st_min: None | int = None, + dlc: None | int = None, filler_byte: int = DEFAULT_FILLER_BYTE, - target_address: Optional[int] = None, - address_extension: Optional[int] = None) -> bytearray: + target_address: None | int = None, + address_extension: None | int = None) -> bytearray: """ Create a data field of a CAN frame that carries a valid Flow Control packet. @@ -289,11 +288,11 @@ def create_flow_control_data(addressing_format: CanAddressingFormat, def generate_flow_control_data(addressing_format: CanAddressingFormat, flow_status: int, dlc: int, - block_size: Optional[int] = None, - st_min: Optional[int] = None, + block_size: None | int = None, + st_min: None | int = None, filler_byte: int = DEFAULT_FILLER_BYTE, - target_address: Optional[int] = None, - address_extension: Optional[int] = None) -> bytearray: + target_address: None | int = None, + address_extension: None | int = None) -> bytearray: """ Generate CAN frame data field that carries any combination of Flow Control packet data parameters. @@ -427,7 +426,7 @@ def generate_flow_status(flow_status: int) -> bytearray: return bytearray([(FLOW_CONTROL_N_PCI << 4) + flow_status]) -FlowControlParametersAlias = Tuple[CanFlowStatus, Optional[int], Optional[int]] +FlowControlParametersAlias = tuple[CanFlowStatus, None | int, None | int] """Alias of :ref:`Flow Control ` parameters which contain: - :ref:`Flow Status ` - :ref:`Block Size ` @@ -474,7 +473,7 @@ def __init__(self, block_size: int = 0, st_min: int = 0, wait_count: int = 0, re self.st_min = st_min self.wait_count = wait_count self.repeat_wait = repeat_wait - self._remaining_wait: Optional[int] = None + self._remaining_wait: None | int = None def __iter__(self) -> "DefaultFlowControlParametersGenerator": """Get iterator object.""" diff --git a/uds/can/packet/single_frame.py b/uds/can/packet/single_frame.py index afe0517b..c15b25cf 100644 --- a/uds/can/packet/single_frame.py +++ b/uds/can/packet/single_frame.py @@ -7,7 +7,6 @@ "extract_sf_dl_data_bytes", "get_sf_dl_bytes_number", "encode_sf_dl", "generate_sf_dl_bytes", "validate_sf_dl"] -from typing import Optional from warnings import warn from uds.utilities import ( @@ -92,10 +91,10 @@ def validate_single_frame_data(addressing_format: CanAddressingFormat, raw_frame def create_single_frame_data(addressing_format: CanAddressingFormat, payload: RawBytesAlias, - dlc: Optional[int] = None, + dlc: None | int = None, filler_byte: int = DEFAULT_FILLER_BYTE, - target_address: Optional[int] = None, - address_extension: Optional[int] = None) -> bytearray: + target_address: None | int = None, + address_extension: None | int = None) -> bytearray: """ Create data field of a CAN frame that carries a valid Single Frame packet. @@ -149,10 +148,10 @@ def generate_single_frame_data(addressing_format: CanAddressingFormat, payload: RawBytesAlias, dlc: int, sf_dl_short: int, - sf_dl_long: Optional[int] = None, + sf_dl_long: None | int = None, filler_byte: int = DEFAULT_FILLER_BYTE, - target_address: Optional[int] = None, - address_extension: Optional[int] = None) -> bytearray: + target_address: None | int = None, + address_extension: None | int = None) -> bytearray: """ Generate CAN frame data field that carries any combination of Single Frame packet data parameters. @@ -237,7 +236,7 @@ def extract_sf_dl(addressing_format: CanAddressingFormat, raw_frame_data: RawByt def get_max_sf_dl(addressing_format: CanAddressingFormat, - dlc: Optional[int] = None) -> int: + dlc: None | int = None) -> int: """ Get the maximum value Single Frame Data Length. @@ -333,7 +332,7 @@ def encode_sf_dl(addressing_format: CanAddressingFormat, return generate_sf_dl_bytes(sf_dl_long=sf_dl) -def generate_sf_dl_bytes(sf_dl_short: int = 0, sf_dl_long: Optional[int] = None) -> bytearray: +def generate_sf_dl_bytes(sf_dl_short: int = 0, sf_dl_long: None | int = None) -> bytearray: """ Create Single Frame bytes containing Single Frame Data Length and N_PCI values. diff --git a/uds/can/segmenter.py b/uds/can/segmenter.py index 19e54a77..458dbf1f 100644 --- a/uds/can/segmenter.py +++ b/uds/can/segmenter.py @@ -2,7 +2,6 @@ __all__ = ["CanSegmenter"] -from typing import Optional, Tuple, Type, Union from warnings import warn from uds.addressing import AbstractAddressingInformation, AddressingType @@ -19,7 +18,7 @@ CanFlowStatus, CanPacket, CanPacketRecord, - CanPacketsContainersSequence, + CanPacketsContainersSequenceAlias, CanPacketType, get_consecutive_frame_max_payload_size, get_consecutive_frame_min_dlc, @@ -34,7 +33,7 @@ class CanSegmenter(AbstractSegmenter): def __init__(self, *, addressing_information: AbstractCanAddressingInformation, dlc: int = CanDlcHandler.MIN_BASE_UDS_DLC, - min_dlc: Optional[int] = None, + min_dlc: None | int = None, use_data_optimization: bool = False, filler_byte: int = DEFAULT_FILLER_BYTE) -> None: """ @@ -58,17 +57,17 @@ def __init__(self, *, self.filler_byte = filler_byte @property - def supported_addressing_information_class(self) -> Type[AbstractAddressingInformation]: + def supported_addressing_information_class(self) -> type[AbstractAddressingInformation]: """Addressing Information class supported by this segmenter.""" return AbstractCanAddressingInformation @property - def supported_packet_class(self) -> Type[AbstractPacket]: + def supported_packet_class(self) -> type[AbstractPacket]: """Packet class supported by CAN segmenter.""" return CanPacket @property - def supported_packet_record_class(self) -> Type[AbstractPacketRecord]: + def supported_packet_record_class(self) -> type[AbstractPacketRecord]: """Packet Record class supported by CAN segmenter.""" return CanPacketRecord @@ -108,7 +107,7 @@ def dlc(self, value: int) -> None: self.min_dlc = value @property - def min_dlc(self) -> Optional[int]: + def min_dlc(self) -> None | int: """ Value of minimal CAN DLC to use for CAN Packets during Data Optimization. @@ -119,7 +118,7 @@ def min_dlc(self) -> Optional[int]: return self.__min_dlc @min_dlc.setter - def min_dlc(self, value: Optional[int]) -> None: + def min_dlc(self, value: None | int) -> None: """ Set value of minimal CAN DLC to use for CAN Packets during Data Optimization. @@ -132,7 +131,7 @@ def min_dlc(self, value: Optional[int]) -> None: if value > self.dlc: raise ValueError(f"Min DLC must be less or equal than base DLC. DLC = {self.dlc}. " f"Actual value: {value}") - self.__min_dlc: Optional[int] = value + self.__min_dlc: None | int = value @property def use_data_optimization(self) -> bool: @@ -163,7 +162,7 @@ def filler_byte(self, value: int) -> None: validate_raw_byte(value) self.__filler_byte: int = value - def __physical_segmentation(self, message: UdsMessage) -> Tuple[CanPacket, ...]: + def __physical_segmentation(self, message: UdsMessage) -> tuple[CanPacket, ...]: """ Segment physically addressed diagnostic message. @@ -226,7 +225,7 @@ def __physical_segmentation(self, message: UdsMessage) -> Tuple[CanPacket, ...]: consecutive_frames.append(consecutive_frame) return first_frame, *consecutive_frames - def __functional_segmentation(self, message: UdsMessage) -> Tuple[CanPacket, ...]: + def __functional_segmentation(self, message: UdsMessage) -> tuple[CanPacket, ...]: """ Segment functionally addressed diagnostic message. @@ -256,7 +255,7 @@ def __functional_segmentation(self, message: UdsMessage) -> Tuple[CanPacket, ... **self.addressing_information.tx_functional_params) return (single_frame,) - def is_desegmented_message(self, packets: CanPacketsContainersSequence) -> bool: + def is_desegmented_message(self, packets: CanPacketsContainersSequenceAlias) -> bool: """ Check whether provided packets are full sequence of packets that form exactly one diagnostic message. @@ -296,8 +295,8 @@ def is_desegmented_message(self, packets: CanPacketsContainersSequence) -> bool: def get_flow_control_packet(self, flow_status: CanFlowStatus, - block_size: Optional[int] = None, - st_min: Optional[int] = None) -> CanPacket: + block_size: None | int = None, + st_min: None | int = None) -> CanPacket: """ Create Flow Control CAN packet. @@ -317,7 +316,7 @@ def get_flow_control_packet(self, dlc=None if self.use_data_optimization else self.dlc, **self.addressing_information.tx_physical_params) - def desegmentation(self, packets: CanPacketsContainersSequence) -> Union[UdsMessage, UdsMessageRecord]: + def desegmentation(self, packets: CanPacketsContainersSequenceAlias) -> UdsMessage | UdsMessageRecord: """ Perform desegmentation of CAN packets. @@ -346,7 +345,7 @@ def desegmentation(self, packets: CanPacketsContainersSequence) -> Union[UdsMess raise SegmentationError("Unexpectedly, something went wrong...") raise NotImplementedError("Missing implementation for the provided CAN Packet type.") - def segmentation(self, message: UdsMessage) -> Tuple[CanPacket, ...]: + def segmentation(self, message: UdsMessage) -> tuple[CanPacket, ...]: """ Perform segmentation of a diagnostic message. diff --git a/uds/can/transport_interface/common.py b/uds/can/transport_interface/common.py index 02e4e973..f5691d3f 100644 --- a/uds/can/transport_interface/common.py +++ b/uds/can/transport_interface/common.py @@ -4,7 +4,7 @@ from abc import ABC, abstractmethod from asyncio import AbstractEventLoop -from typing import Any, Optional, Tuple +from typing import Any from warnings import warn from uds.addressing import TransmissionDirection @@ -41,7 +41,7 @@ class AbstractCanTransportInterface(AbstractTransportInterface, ABC): """Timeout value of :ref:`N_Cr ` time parameter according to ISO 15765-2.""" DEFAULT_N_BR: TimeMillisecondsAlias = 0 """Default value for :ref:`N_Br ` time parameter.""" - DEFAULT_N_CS: Optional[TimeMillisecondsAlias] = None + DEFAULT_N_CS: None | TimeMillisecondsAlias = None """Default value for :ref:`N_Cs ` time parameter.""" DEFAULT_FLOW_CONTROL_PARAMETERS = DefaultFlowControlParametersGenerator() """Default values generator for :ref:`Flow Control ` parameters @@ -59,7 +59,7 @@ def __init__(self, n_bs_timeout: TimeMillisecondsAlias = N_BS_TIMEOUT, n_cr_timeout: TimeMillisecondsAlias = N_CR_TIMEOUT, n_br: TimeMillisecondsAlias = DEFAULT_N_BR, - n_cs: Optional[TimeMillisecondsAlias] = DEFAULT_N_CS, + n_cs: None | TimeMillisecondsAlias = DEFAULT_N_CS, flow_control_parameters_generator: AbstractFlowControlParametersGenerator = DEFAULT_FLOW_CONTROL_PARAMETERS, can_version: CanVersion = CanVersion.CLASSIC_CAN, @@ -90,10 +90,10 @@ def __init__(self, :ref:`CAN Frame Data Padding `. """ super().__init__(network_manager=network_manager) - self.__n_ar_measured: Optional[TimeMillisecondsAlias] = None - self.__n_as_measured: Optional[TimeMillisecondsAlias] = None - self.__n_bs_measured: Optional[Tuple[TimeMillisecondsAlias, ...]] = None - self.__n_cr_measured: Optional[Tuple[TimeMillisecondsAlias, ...]] = None + self.__n_ar_measured: None | TimeMillisecondsAlias = None + self.__n_as_measured: None | TimeMillisecondsAlias = None + self.__n_bs_measured: None | tuple[TimeMillisecondsAlias, ...] = None + self.__n_cr_measured: None | tuple[TimeMillisecondsAlias, ...] = None self.n_as_timeout = n_as_timeout self.n_ar_timeout = n_ar_timeout self.n_bs_timeout = n_bs_timeout @@ -182,7 +182,7 @@ def dlc(self, value: int) -> None: self.segmenter.dlc = value @property - def min_dlc(self) -> Optional[int]: + def min_dlc(self) -> None | int: """ Value of minimal CAN DLC to use for CAN Packets during Data Optimization. @@ -193,7 +193,7 @@ def min_dlc(self) -> Optional[int]: return self.segmenter.min_dlc @min_dlc.setter - def min_dlc(self, value: Optional[int]) -> None: + def min_dlc(self, value: None | int) -> None: """ Set value of minimal CAN DLC to use for CAN Packets during Data Optimization. @@ -289,7 +289,7 @@ def n_as_timeout(self, value: TimeMillisecondsAlias) -> None: self.__n_as_timeout = value @property - def n_as_measured(self) -> Optional[TimeMillisecondsAlias]: + def n_as_measured(self) -> None | TimeMillisecondsAlias: """ Get the last measured value of :ref:`N_As ` time parameter. @@ -326,7 +326,7 @@ def n_ar_timeout(self, value: TimeMillisecondsAlias) -> None: self.__n_ar_timeout = value @property - def n_ar_measured(self) -> Optional[TimeMillisecondsAlias]: + def n_ar_measured(self) -> None | TimeMillisecondsAlias: """ Get the last measured value of :ref:`N_Ar ` time parameter. @@ -363,7 +363,7 @@ def n_bs_timeout(self, value: TimeMillisecondsAlias) -> None: self.__n_bs_timeout = value @property - def n_bs_measured(self) -> Optional[Tuple[TimeMillisecondsAlias, ...]]: + def n_bs_measured(self) -> None | tuple[TimeMillisecondsAlias, ...]: """ Get the last measured values of :ref:`N_Bs ` time parameter. @@ -416,7 +416,7 @@ def n_br_max(self) -> TimeMillisecondsAlias: return 0.9 * self.n_bs_timeout - n_ar_measured @property - def n_cs(self) -> Optional[TimeMillisecondsAlias]: + def n_cs(self) -> None | TimeMillisecondsAlias: """ Get the value of :ref:`N_Cs ` time parameter which is currently set. @@ -426,7 +426,7 @@ def n_cs(self) -> Optional[TimeMillisecondsAlias]: return self.__n_cs @n_cs.setter - def n_cs(self, value: Optional[TimeMillisecondsAlias]) -> None: + def n_cs(self, value: None | TimeMillisecondsAlias) -> None: """ Set the value of :ref:`N_Cs ` time parameter to use. @@ -485,7 +485,7 @@ def n_cr_timeout(self, value: TimeMillisecondsAlias) -> None: self.__n_cr_timeout = value @property - def n_cr_measured(self) -> Optional[Tuple[TimeMillisecondsAlias, ...]]: + def n_cr_measured(self) -> None | tuple[TimeMillisecondsAlias, ...]: """ Get the last measured values of :ref:`N_Cr ` time parameter. @@ -603,7 +603,7 @@ def send_packet(self, packet: CanPacket) -> CanPacketRecord: # type: ignore @abstractmethod async def async_send_packet(self, packet: CanPacket, # type: ignore - loop: Optional[AbstractEventLoop] = None) -> CanPacketRecord: + loop: None | AbstractEventLoop = None) -> CanPacketRecord: """ Transmit CAN packet asynchronously. @@ -614,7 +614,7 @@ async def async_send_packet(self, """ @abstractmethod - def receive_packet(self, timeout: Optional[TimeMillisecondsAlias] = None) -> CanPacketRecord: + def receive_packet(self, timeout: None | TimeMillisecondsAlias = None) -> CanPacketRecord: """ Receive CAN packet. @@ -628,8 +628,8 @@ def receive_packet(self, timeout: Optional[TimeMillisecondsAlias] = None) -> Can @abstractmethod async def async_receive_packet(self, - timeout: Optional[TimeMillisecondsAlias] = None, - loop: Optional[AbstractEventLoop] = None) -> CanPacketRecord: + timeout: None | TimeMillisecondsAlias = None, + loop: None | AbstractEventLoop = None) -> CanPacketRecord: """ Receive CAN packet asynchronously. diff --git a/uds/can/transport_interface/python_can.py b/uds/can/transport_interface/python_can.py index 349c3e59..812a5b07 100644 --- a/uds/can/transport_interface/python_can.py +++ b/uds/can/transport_interface/python_can.py @@ -8,7 +8,7 @@ from asyncio.exceptions import TimeoutError as AsyncioTimeoutError from datetime import datetime from time import perf_counter, sleep -from typing import Any, List, Optional, Tuple, Union +from typing import Any from warnings import warn from can import AsyncBufferedReader, BufferedReader, BusABC @@ -51,8 +51,8 @@ class PythonCanTransportInterface(AbstractCanTransportInterface): def __init__(self, network_manager: BusABC, addressing_information: AbstractCanAddressingInformation, - notifier: Optional[Notifier] = None, - async_notifier: Optional[Notifier] = None, + notifier: None | Notifier = None, + async_notifier: None | Notifier = None, **configuration_params: Any) -> None: """ Create Transport Interface that uses python-can package to control CAN bus. @@ -112,12 +112,12 @@ def __del__(self) -> None: self.__async_fc_frames_buffer.stop() @property - def notifier(self) -> Optional[Notifier]: + def notifier(self) -> None | Notifier: """Notifier used by python-can for reporting received and sent CAN Frames to listeners.""" return self.__notifier @notifier.setter - def notifier(self, value: Optional[Notifier]) -> None: + def notifier(self, value: None | Notifier) -> None: """ Set notifier for reporting received and sent CAN Frames to listeners. @@ -138,12 +138,12 @@ def notifier(self, value: Optional[Notifier]) -> None: raise TypeError(f"Provided value is not None neither Notifier type. Actual type: {type(value)}.") @property - def async_notifier(self) -> Optional[Notifier]: + def async_notifier(self) -> None | Notifier: """Notifier used by python-can for reporting received and sent CAN Frames to async listeners.""" return self.__async_notifier @async_notifier.setter - def async_notifier(self, value: Optional[Notifier]) -> None: + def async_notifier(self, value: None | Notifier) -> None: """ Set notifier for reporting received and sent CAN Frames to async listeners. @@ -251,7 +251,7 @@ def __teardown_async_listening(self, suppress_warning: bool = False) -> None: category=UserWarning) @staticmethod - def __validate_timeout(value: Optional[TimeMillisecondsAlias]) -> None: + def __validate_timeout(value: None | TimeMillisecondsAlias) -> None: """ Validate value of a timeout. @@ -267,9 +267,9 @@ def __validate_timeout(value: Optional[TimeMillisecondsAlias]) -> None: raise ValueError(f"Provided timeout value is less or equal to 0. Actual value: {value}") def _send_cf_packets_block(self, - cf_packets_block: List[CanPacket], + cf_packets_block: list[CanPacket], delay: TimeMillisecondsAlias, - fc_transmission_timestamp: float) -> Tuple[CanPacketRecord, ...]: + fc_transmission_timestamp: float) -> tuple[CanPacketRecord, ...]: """ Send block of Consecutive Frame CAN packets. @@ -291,10 +291,10 @@ def _send_cf_packets_block(self, return tuple(packet_records) async def _async_send_cf_packets_block(self, - cf_packets_block: List[CanPacket], + cf_packets_block: list[CanPacket], delay: TimeMillisecondsAlias, fc_transmission_timestamp: float, - loop: AbstractEventLoop) -> Tuple[CanPacketRecord, ...]: + loop: AbstractEventLoop) -> tuple[CanPacketRecord, ...]: """ Send block of Consecutive Frame CAN packets asynchronously. @@ -353,7 +353,7 @@ async def _async_wait_for_flow_control(self, last_packet_transmission_timestamp: def _wait_for_rx_packet(self, buffer: BufferedReader, - timeout: Optional[TimeMillisecondsAlias] = None) -> CanPacketRecord: + timeout: None | TimeMillisecondsAlias = None) -> CanPacketRecord: """ Wait till CAN Packet is received. @@ -390,7 +390,7 @@ def _wait_for_rx_packet(self, async def _async_wait_for_rx_packet(self, buffer: AsyncBufferedReader, - timeout: Optional[TimeMillisecondsAlias] = None) -> CanPacketRecord: + timeout: None | TimeMillisecondsAlias = None) -> CanPacketRecord: """ Wait till CAN Packet is received. @@ -502,8 +502,8 @@ def _receive_cf_packets_block(self, sequence_number: int, block_size: int, remaining_data_length: int, - timestamp_end: Optional[TimestampAlias] - ) -> Union[UdsMessageRecord, Tuple[CanPacketRecord, ...]]: + timestamp_end: None | TimestampAlias + ) -> UdsMessageRecord | tuple[CanPacketRecord, ...]: """ Receive block of :ref:`Consecutive Frames `. @@ -524,7 +524,7 @@ def _receive_cf_packets_block(self, """ timestamp_start = perf_counter() timeout_end_ms = float("inf") - received_cf: List[CanPacketRecord] = [] + received_cf: list[CanPacketRecord] = [] received_payload_size: int = 0 while received_payload_size < remaining_data_length and (len(received_cf) != block_size or block_size == 0): timestamp_now = perf_counter() @@ -560,9 +560,9 @@ async def _async_receive_cf_packets_block(self, sequence_number: int, block_size: int, remaining_data_length: int, - timestamp_end: Optional[TimestampAlias], + timestamp_end: None | TimestampAlias, loop: AbstractEventLoop - ) -> Union[UdsMessageRecord, Tuple[CanPacketRecord, ...]]: + ) -> UdsMessageRecord | tuple[CanPacketRecord, ...]: """ Receive asynchronously block of :ref:`Consecutive Frames `. @@ -580,7 +580,7 @@ async def _async_receive_cf_packets_block(self, """ timestamp_start = perf_counter() timeout_end_ms = float("inf") - received_cf: List[CanPacketRecord] = [] + received_cf: list[CanPacketRecord] = [] received_payload_size: int = 0 while received_payload_size < remaining_data_length and (len(received_cf) != block_size or block_size == 0): timestamp_now = perf_counter() @@ -616,7 +616,7 @@ async def _async_receive_cf_packets_block(self, def _receive_consecutive_frames(self, first_frame: CanPacketRecord, - timestamp_end: Optional[TimestampAlias]) -> UdsMessageRecord: + timestamp_end: None | TimestampAlias) -> UdsMessageRecord: """ Receive Consecutive Frames after reception of First Frame. @@ -628,7 +628,7 @@ def _receive_consecutive_frames(self, :return: Record of UDS message that was formed provided First Frame and received Consecutive Frames. """ - packets_records: List[CanPacketRecord] = [first_frame] + packets_records: list[CanPacketRecord] = [first_frame] message_data_length: int = first_frame.data_length # type: ignore received_data_length: int = len(first_frame.payload) # type: ignore sequence_number: int = 1 @@ -676,7 +676,7 @@ def _receive_consecutive_frames(self, async def _async_receive_consecutive_frames(self, first_frame: CanPacketRecord, - timestamp_end: Optional[TimestampAlias], + timestamp_end: None | TimestampAlias, loop: AbstractEventLoop) -> UdsMessageRecord: """ Receive asynchronously Consecutive Frames after reception of First Frame. @@ -692,7 +692,7 @@ async def _async_receive_consecutive_frames(self, :return: Record of UDS message that was formed provided First Frame and received Consecutive Frames. """ - packets_records: List[CanPacketRecord] = [first_frame] + packets_records: list[CanPacketRecord] = [first_frame] message_data_length: int = first_frame.data_length # type: ignore received_data_length: int = len(first_frame.payload) # type: ignore sequence_number: int = 1 @@ -742,7 +742,7 @@ async def _async_receive_consecutive_frames(self, def _message_receive_start(self, initial_packet: CanPacketRecord, - timestamp_end: Optional[TimestampAlias]) -> UdsMessageRecord: + timestamp_end: None | TimestampAlias) -> UdsMessageRecord: """ Continue to receive message after receiving initial packet. @@ -762,7 +762,7 @@ def _message_receive_start(self, async def _async_message_receive_start(self, initial_packet: CanPacketRecord, - timestamp_end: Optional[TimestampAlias], + timestamp_end: None | TimestampAlias, loop: AbstractEventLoop) -> UdsMessageRecord: """ Continue to receive message asynchronously after receiving initial packet. @@ -882,7 +882,7 @@ def send_packet(self, packet: CanPacket) -> CanPacketRecord: # type: ignore async def async_send_packet(self, packet: CanPacket, # type: ignore - loop: Optional[AbstractEventLoop] = None) -> CanPacketRecord: + loop: None | AbstractEventLoop = None) -> CanPacketRecord: """ Transmit asynchronously CAN packet. @@ -941,7 +941,7 @@ async def async_send_packet(self, transmission_time=datetime.fromtimestamp(sent_can_frame.timestamp), transmission_timestamp=transmission_timestamp) - def receive_packet(self, timeout: Optional[TimeMillisecondsAlias] = None) -> CanPacketRecord: + def receive_packet(self, timeout: None | TimeMillisecondsAlias = None) -> CanPacketRecord: """ Receive CAN packet. @@ -957,8 +957,8 @@ def receive_packet(self, timeout: Optional[TimeMillisecondsAlias] = None) -> Can return self._wait_for_rx_packet(buffer=self.__rx_frames_buffer, timeout=timeout) async def async_receive_packet(self, - timeout: Optional[TimeMillisecondsAlias] = None, - loop: Optional[AbstractEventLoop] = None) -> CanPacketRecord: + timeout: None | TimeMillisecondsAlias = None, + loop: None | AbstractEventLoop = None) -> CanPacketRecord: """ Receive asynchronously CAN packet. @@ -1018,7 +1018,7 @@ def send_message(self, message: UdsMessage) -> UdsMessageRecord: async def async_send_message(self, message: UdsMessage, - loop: Optional[AbstractEventLoop] = None) -> UdsMessageRecord: + loop: None | AbstractEventLoop = None) -> UdsMessageRecord: """ Transmit asynchronously UDS message over CAN. @@ -1063,8 +1063,8 @@ async def async_send_message(self, return message_records def receive_message(self, - start_timeout: Optional[TimeMillisecondsAlias] = None, - end_timeout: Optional[TimeMillisecondsAlias] = None) -> UdsMessageRecord: + start_timeout: None | TimeMillisecondsAlias = None, + end_timeout: None | TimeMillisecondsAlias = None) -> UdsMessageRecord: """ Receive UDS message over CAN. @@ -1113,9 +1113,9 @@ def receive_message(self, category=UnexpectedPacketReceptionWarning) async def async_receive_message(self, - start_timeout: Optional[TimeMillisecondsAlias] = None, - end_timeout: Optional[TimeMillisecondsAlias] = None, - loop: Optional[AbstractEventLoop] = None) -> UdsMessageRecord: + start_timeout: None | TimeMillisecondsAlias = None, + end_timeout: None | TimeMillisecondsAlias = None, + loop: None | AbstractEventLoop = None) -> UdsMessageRecord: """ Receive asynchronously UDS message over CAN. diff --git a/uds/client.py b/uds/client.py index dce812bf..1f446ec6 100644 --- a/uds/client.py +++ b/uds/client.py @@ -2,10 +2,10 @@ __all__ = ["Client"] +from collections.abc import Sequence from queue import Empty, Queue from threading import Event, Lock, Thread from time import perf_counter, sleep -from typing import List, Optional, Sequence, Tuple, Union from warnings import warn from uds.addressing import AddressingType @@ -65,10 +65,10 @@ def __init__(self, :param s3_client: Value of S3Client time parameter. """ # TIMING PARAMETERS - self.__p2_client_measured: Optional[TimeMillisecondsAlias] = None - self.__p2_ext_client_measured: Optional[Tuple[TimeMillisecondsAlias, ...]] = None - self.__p6_client_measured: Optional[TimeMillisecondsAlias] = None - self.__p6_ext_client_measured: Optional[TimeMillisecondsAlias] = None + self.__p2_client_measured: None | TimeMillisecondsAlias = None + self.__p2_ext_client_measured: None | tuple[TimeMillisecondsAlias, ...] = None + self.__p6_client_measured: None | TimeMillisecondsAlias = None + self.__p6_ext_client_measured: None | TimeMillisecondsAlias = None # set default values to avoid errors on values assignment self.__p2_client_timeout = self.DEFAULT_P2_CLIENT_TIMEOUT self.__p2_ext_client_timeout = self.DEFAULT_P2_EXT_CLIENT_TIMEOUT @@ -89,12 +89,12 @@ def __init__(self, # tasks and threads self.__tester_present_task_event: Event = Event() self.__tester_present_task_event.clear() - self.__tester_present_thread: Optional[Thread] = None + self.__tester_present_thread: None | Thread = None self.__background_receiving_task_event: Event = Event() self.__background_receiving_task_event.clear() self.__break_in_background_receiving_event: Event = Event() self.__break_in_background_receiving_event.clear() - self.__background_receiving_thread: Optional[Thread] = None + self.__background_receiving_thread: None | Thread = None self.__send_and_receive_not_in_progress_event: Event = Event() self.__send_and_receive_not_in_progress_event.set() self.__receiving_not_in_progress_event: Event = Event() @@ -107,11 +107,11 @@ def __init__(self, self.__functional_transmission_lock: Lock = Lock() # other self.__response_queue: Queue[UdsMessageRecord] = Queue() - self.__last_physical_request: Optional[UdsMessageRecord] = None - self.__last_physical_response: Optional[UdsMessageRecord] = None - self.__last_functional_request: Optional[UdsMessageRecord] = None - self.__last_functional_response: Optional[UdsMessageRecord] = None - self.__last_tester_present_requests: List[UdsMessageRecord] = [] + self.__last_physical_request: None | UdsMessageRecord = None + self.__last_physical_response: None | UdsMessageRecord = None + self.__last_functional_request: None | UdsMessageRecord = None + self.__last_functional_response: None | UdsMessageRecord = None + self.__last_tester_present_requests: list[UdsMessageRecord] = [] def __del__(self) -> None: """Safely finish all tasks.""" @@ -176,7 +176,7 @@ def p2_client_timeout(self, value: TimeMillisecondsAlias) -> None: self.p6_client_timeout = value @property # noqa: vulture - def p2_client_measured(self) -> Optional[TimeMillisecondsAlias]: + def p2_client_measured(self) -> None | TimeMillisecondsAlias: """ Get last measured value of P2Client parameter. @@ -210,7 +210,7 @@ def p2_ext_client_timeout(self, value: TimeMillisecondsAlias) -> None: self.p6_ext_client_timeout = value @property # noqa: vulture - def p2_ext_client_measured(self) -> Optional[Tuple[TimeMillisecondsAlias, ...]]: + def p2_ext_client_measured(self) -> None | tuple[TimeMillisecondsAlias, ...]: """ Get last measured values of P2*Client parameter. @@ -306,7 +306,7 @@ def p6_client_timeout(self, value: TimeMillisecondsAlias) -> None: self.p6_ext_client_timeout = value @property # noqa: vulture - def p6_client_measured(self) -> Optional[TimeMillisecondsAlias]: + def p6_client_measured(self) -> None | TimeMillisecondsAlias: """ Get last measured value of P6Client parameter. @@ -342,7 +342,7 @@ def p6_ext_client_timeout(self, value: TimeMillisecondsAlias) -> None: self.__p6_ext_client_timeout = value @property # noqa: vulture - def p6_ext_client_measured(self) -> Optional[TimeMillisecondsAlias]: + def p6_ext_client_measured(self) -> None | TimeMillisecondsAlias: """ Get last measured value of P6*Client parameter. @@ -379,12 +379,12 @@ def s3_client(self, value: TimeMillisecondsAlias) -> None: self.__s3_client = value @property # noqa: vulture - def last_sent_tester_present_requests(self) -> Tuple[UdsMessageRecord, ...]: + def last_sent_tester_present_requests(self) -> tuple[UdsMessageRecord, ...]: """Get records with the last few request with Tester Present messages.""" return tuple(self.__last_tester_present_requests) @property - def last_sent_request(self) -> Optional[UdsMessageRecord]: + def last_sent_request(self) -> None | UdsMessageRecord: """Get record with the last request message sent.""" records = [] if self.__last_physical_request is not None: @@ -396,7 +396,7 @@ def last_sent_request(self) -> Optional[UdsMessageRecord]: return max(records, key=lambda record: record.transmission_end_timestamp) @property # noqa: vulture - def last_received_response(self) -> Optional[UdsMessageRecord]: + def last_received_response(self) -> None | UdsMessageRecord: """ Get record with the last response message sent. @@ -673,7 +673,7 @@ def _receive_response(self, self._update_last_response(response_record) return response_record - def _receive_initial_response(self, request_record: UdsMessageRecord) -> Optional[UdsMessageRecord]: + def _receive_initial_response(self, request_record: UdsMessageRecord) -> None | UdsMessageRecord: """ Receive the first UDS response to a request message. @@ -751,7 +751,7 @@ def _receive_following_response(self, raise TimeoutError("P6*Client timeout exceeded.") @staticmethod - def is_response_pending_message(response_message: Union[UdsMessage, UdsMessageRecord], + def is_response_pending_message(response_message: UdsMessage | UdsMessageRecord, request_sid: RequestSID) -> bool: """ Check if provided UDS message is Response Pending Message to a diagnostic service of given SID. @@ -776,8 +776,8 @@ def is_response_pending_message(response_message: Union[UdsMessage, UdsMessageRe and response_message.payload[2] == NRC.RequestCorrectlyReceived_ResponsePending) def is_response_to_request(self, - response_message: Union[UdsMessage, UdsMessageRecord], - request_message: Union[UdsMessage, UdsMessageRecord]) -> bool: + response_message: UdsMessage | UdsMessageRecord, + request_message: UdsMessage | UdsMessageRecord) -> bool: """ Check if provided UDS message is a response message to a diagnostic service of given SID. @@ -854,7 +854,7 @@ def wait_till_ready_for_transmission(self, request: UdsMessage) -> None: raise NotImplementedError("Request message with unexpected `addressing_type` attribute value was provided: " f"{request.addressing_type!r}") - def get_response(self, timeout: Optional[TimeMillisecondsAlias] = None) -> Optional[UdsMessageRecord]: + def get_response(self, timeout: None | TimeMillisecondsAlias = None) -> None | UdsMessageRecord: """ Wait for the first received response message. @@ -883,7 +883,7 @@ def get_response(self, timeout: Optional[TimeMillisecondsAlias] = None) -> Optio except Empty: return None - def get_response_no_wait(self) -> Optional[UdsMessageRecord]: + def get_response_no_wait(self) -> None | UdsMessageRecord: """ Get the first received response message, but do not wait for its arrival. @@ -973,7 +973,7 @@ def stop_background_receiving(self) -> None: category=UserWarning) def send_request_receive_responses(self, - request: UdsMessage) -> Tuple[UdsMessageRecord, Tuple[UdsMessageRecord, ...]]: + request: UdsMessage) -> tuple[UdsMessageRecord, tuple[UdsMessageRecord, ...]]: """ Send diagnostic request and receive all responses (till the final one). @@ -991,7 +991,7 @@ def send_request_receive_responses(self, raise TypeError(f"Provided request value is not an instance of UdsMessage class. " f"Actual type: {type(request)}.") sid = RequestSID(request.payload[0]) - response_records: List[UdsMessageRecord] = [] + response_records: list[UdsMessageRecord] = [] self.__send_and_receive_not_in_progress_event.clear() if self.is_background_receiving: self.__receiving_not_in_progress_event.wait(timeout=self.p6_ext_client_timeout) diff --git a/uds/diagnostic_configuration/ecu_configuration.py b/uds/diagnostic_configuration/ecu_configuration.py index f95b8dee..b685748f 100644 --- a/uds/diagnostic_configuration/ecu_configuration.py +++ b/uds/diagnostic_configuration/ecu_configuration.py @@ -1,8 +1,9 @@ """Implementation for diagnostic ECU Configuration.""" +from collections.abc import Collection, Mapping from operator import getitem from types import MappingProxyType -from typing import Any, Collection, Mapping, Optional, Set +from typing import Any from uds.message import ( SERVICES_WITH_DID, @@ -65,7 +66,7 @@ def __getitem__(self, item: str) -> State: return self.states_mapping[item] @property - def states(self) -> Set[State]: + def states(self) -> set[State]: """Get :ref:`ECU states ` relevant for diagnostic communication.""" return self.__states @@ -84,7 +85,7 @@ def states(self, states: Collection[State]) -> None: self.__states_mapping = {state.name: state for state in self.__states} @property - def states_names(self) -> Set[str]: + def states_names(self) -> set[str]: """Get names of all ECU states.""" return self.__states_names @@ -248,14 +249,14 @@ def __validate_required_states(self, required_states: RequiredStatesAlias) -> Re return MappingProxyType(mapping) @staticmethod - def __extract_subfunction(message_payload: RawBytesAlias) -> Optional[int]: + def __extract_subfunction(message_payload: RawBytesAlias) -> None | int: """Extract subfunction from message payload.""" if message_payload[0] in SERVICES_WITH_SUBFUNCTION and len(message_payload) > 1: return message_payload[1] & SUBFUNCTION_MASK return None @staticmethod - def __extract_dids(decoded_message: DecodedMessageAlias) -> Set[int]: + def __extract_dids(decoded_message: DecodedMessageAlias) -> set[int]: """Extract DIDs from decoded message.""" dids = set() if decoded_message[0]["raw_value"] in SERVICES_WITH_DID: @@ -270,7 +271,7 @@ def __extract_dids(decoded_message: DecodedMessageAlias) -> Set[int]: return dids @staticmethod - def __extract_rids(decoded_message: DecodedMessageAlias) -> Set[int]: + def __extract_rids(decoded_message: DecodedMessageAlias) -> set[int]: """Extract RIDs from decoded message.""" rids = set() if decoded_message[0]["raw_value"] in SERVICES_WITH_RID: diff --git a/uds/diagnostic_configuration/state.py b/uds/diagnostic_configuration/state.py index 9fb5d042..85a5bac0 100644 --- a/uds/diagnostic_configuration/state.py +++ b/uds/diagnostic_configuration/state.py @@ -2,7 +2,8 @@ __all__ = ["State"] -from typing import Any, Collection, FrozenSet, Optional +from collections.abc import Collection +from typing import Any from warnings import warn @@ -27,7 +28,7 @@ def __init__(self, name: str, possible_values: Collection[Any]) -> None: """ self.name = name self.possible_values = possible_values - self.__current_value: Optional[Any] = None + self.__current_value: None | Any = None @property def name(self) -> str: @@ -57,7 +58,7 @@ def name(self, name: str) -> None: self.__name = stripped_name @property - def possible_values(self) -> FrozenSet[Any]: + def possible_values(self) -> frozenset[Any]: """Get set with all values that can be assigned to this state.""" return self.__possible_values @@ -68,12 +69,12 @@ def possible_values(self, values: Collection[Any]) -> None: self.__current_value = None # if possible values are change, then the current state is also affected @property - def current_value(self) -> Optional[Any]: + def current_value(self) -> None | Any: """Get currently assigned value.""" return self.__current_value @current_value.setter - def current_value(self, value: Optional[Any]) -> None: + def current_value(self, value: None | Any) -> None: """ Set currently assigned value. diff --git a/uds/message/service_identifiers.py b/uds/message/service_identifiers.py index d72488d4..657e415f 100644 --- a/uds/message/service_identifiers.py +++ b/uds/message/service_identifiers.py @@ -14,7 +14,6 @@ "define_service", ] -from typing import Tuple, Union from warnings import warn from aenum import unique @@ -192,7 +191,7 @@ def is_response_sid(cls, value: int) -> bool: return False -SidAlias = Union[RequestSID, ResponseSID, int] +SidAlias = RequestSID | ResponseSID | int """Alias for Request SID or Response SID value.""" @@ -246,7 +245,7 @@ def is_response_sid(cls, value: int) -> bool: in their message format.""" -def define_service(sid: int, name: str) -> Tuple[RequestSID, ResponseSID]: +def define_service(sid: int, name: str) -> tuple[RequestSID, ResponseSID]: """ Define SID and RSID values for a non-standard service. diff --git a/uds/message/uds_message.py b/uds/message/uds_message.py index 43234ee6..2ece8642 100644 --- a/uds/message/uds_message.py +++ b/uds/message/uds_message.py @@ -11,11 +11,11 @@ ] from abc import ABC, abstractmethod +from collections.abc import Sequence from datetime import datetime -from typing import Sequence, Union from uds.addressing import AddressingType, TransmissionDirection -from uds.packet import AbstractPacketRecord, PacketsRecordsSequence, PacketsRecordsTuple +from uds.packet import AbstractPacketRecord, PacketsRecordsSequenceAlias, PacketsRecordsTupleAlias from uds.utilities import RawBytesAlias, ReassignmentError, bytes_to_hex, validate_raw_bytes NEGATIVE_RESPONSE_MESSAGE_LENGTH: int = 3 @@ -43,7 +43,7 @@ def __eq__(self, other: object) -> bool: @property @abstractmethod - def payload(self) -> Union[bytes, bytearray]: + def payload(self) -> bytes | bytearray: """Raw payload bytes carried by this diagnostic message.""" @property @@ -121,7 +121,7 @@ def addressing_type(self, value: AddressingType) -> None: class UdsMessageRecord(AbstractUdsMessageContainer): """Storage for historic information about a diagnostic message that was either received or transmitted.""" - def __init__(self, packets_records: PacketsRecordsSequence) -> None: + def __init__(self, packets_records: PacketsRecordsSequenceAlias) -> None: """ Create a record of historic information about a diagnostic message. @@ -159,7 +159,7 @@ def __str__(self) -> str: f"transmission_end_timestamp={self.transmission_end_timestamp})") @staticmethod - def __validate_packets_records(value: PacketsRecordsSequence) -> None: + def __validate_packets_records(value: PacketsRecordsSequenceAlias) -> None: """ Validate whether the argument contains records with packets. @@ -176,7 +176,7 @@ def __validate_packets_records(value: PacketsRecordsSequence) -> None: f"Actual value: {value}.") @property - def packets_records(self) -> PacketsRecordsTuple: + def packets_records(self) -> PacketsRecordsTupleAlias: """ Sequence (in transmission order) of packets records that carried this diagnostic message. @@ -186,7 +186,7 @@ def packets_records(self) -> PacketsRecordsTuple: return self.__packets_records @packets_records.setter - def packets_records(self, value: PacketsRecordsSequence) -> None: + def packets_records(self, value: PacketsRecordsSequenceAlias) -> None: """ Assign records value of packets that carried this diagnostic message . diff --git a/uds/packet/__init__.py b/uds/packet/__init__.py index a583ce0d..46ba4a77 100644 --- a/uds/packet/__init__.py +++ b/uds/packet/__init__.py @@ -12,9 +12,9 @@ AbstractPacket, AbstractPacketContainer, AbstractPacketRecord, - PacketsContainersSequence, - PacketsRecordsSequence, - PacketsRecordsTuple, - PacketsTuple, + PacketsContainersSequenceAlias, + PacketsRecordsSequenceAlias, + PacketsRecordsTupleAlias, + PacketsTupleAlias, ) from .abstract_packet_type import AbstractPacketType diff --git a/uds/packet/abstract_packet.py b/uds/packet/abstract_packet.py index 28936fa5..c02595d4 100644 --- a/uds/packet/abstract_packet.py +++ b/uds/packet/abstract_packet.py @@ -1,12 +1,14 @@ """Abstract definition of packets that is common for all bus/network types.""" __all__ = ["AbstractPacketContainer", "AbstractPacket", "AbstractPacketRecord", - "PacketsContainersSequence", "PacketsTuple", "PacketsRecordsTuple", "PacketsRecordsSequence"] + "PacketsContainersSequenceAlias", "PacketsTupleAlias", "PacketsRecordsTupleAlias", + "PacketsRecordsSequenceAlias"] from abc import ABC, abstractmethod +from collections.abc import Sequence from datetime import datetime from time import perf_counter -from typing import Any, Optional, Sequence, Tuple +from typing import Any from warnings import warn from uds.addressing import AddressingType, TransmissionDirection @@ -38,7 +40,7 @@ def packet_type(self) -> AbstractPacketType: @property @abstractmethod - def data_length(self) -> Optional[int]: + def data_length(self) -> None | int: """Payload bytes number of a diagnostic message.""" @property @@ -48,7 +50,7 @@ def addressing_type(self) -> AddressingType: @property @abstractmethod - def payload(self) -> Optional[bytes]: + def payload(self) -> None | bytes: """Diagnostic message payload carried by this packet.""" @@ -195,12 +197,12 @@ def _validate_attributes(self) -> None: """Validate whether attributes that were set are a valid for a Packet record.""" -PacketsContainersSequence = Sequence[AbstractPacketContainer] +PacketsContainersSequenceAlias = Sequence[AbstractPacketContainer] """Alias for a sequence filled with packet or packet record objects.""" -PacketsTuple = Tuple[AbstractPacket, ...] +PacketsTupleAlias = tuple[AbstractPacket, ...] """Alias for a packet objects tuple.""" -PacketsRecordsTuple = Tuple[AbstractPacketRecord, ...] +PacketsRecordsTupleAlias = tuple[AbstractPacketRecord, ...] """Alias for a packet record objects tuple.""" -PacketsRecordsSequence = Sequence[AbstractPacketRecord] +PacketsRecordsSequenceAlias = Sequence[AbstractPacketRecord] """Alias for a packet record objects sequence.""" diff --git a/uds/segmentation/abstract_segmenter.py b/uds/segmentation/abstract_segmenter.py index 3b7fed99..25f77ff4 100644 --- a/uds/segmentation/abstract_segmenter.py +++ b/uds/segmentation/abstract_segmenter.py @@ -3,7 +3,7 @@ __all__ = ["SegmentationError", "AbstractSegmenter"] from abc import ABC, abstractmethod -from typing import Sequence, Type, Union +from collections.abc import Sequence from uds.addressing import AbstractAddressingInformation from uds.message import UdsMessage, UdsMessageRecord @@ -11,8 +11,8 @@ AbstractPacket, AbstractPacketContainer, AbstractPacketRecord, - PacketsContainersSequence, - PacketsTuple, + PacketsContainersSequenceAlias, + PacketsTupleAlias, ) @@ -42,17 +42,17 @@ def __init__(self, addressing_information: AbstractAddressingInformation) -> Non @property @abstractmethod - def supported_addressing_information_class(self) -> Type[AbstractAddressingInformation]: + def supported_addressing_information_class(self) -> type[AbstractAddressingInformation]: """Addressing Information class supported by this segmenter.""" @property @abstractmethod - def supported_packet_class(self) -> Type[AbstractPacket]: + def supported_packet_class(self) -> type[AbstractPacket]: """Packet class supported by this segmenter.""" @property @abstractmethod - def supported_packet_record_class(self) -> Type[AbstractPacketRecord]: + def supported_packet_record_class(self) -> type[AbstractPacketRecord]: """Packet Record class supported by this segmenter.""" @property @@ -102,7 +102,7 @@ def is_supported_packets_sequence_type(self, packets: Sequence[AbstractPacketCon return len({type(packet) for packet in packets}) == 1 @abstractmethod - def is_desegmented_message(self, packets: PacketsContainersSequence) -> bool: + def is_desegmented_message(self, packets: PacketsContainersSequenceAlias) -> bool: """ Check whether provided packets are full sequence of packets that form exactly one diagnostic message. @@ -113,7 +113,7 @@ def is_desegmented_message(self, packets: PacketsContainersSequence) -> bool: """ @abstractmethod - def desegmentation(self, packets: PacketsContainersSequence) -> Union[UdsMessage, UdsMessageRecord]: + def desegmentation(self, packets: PacketsContainersSequenceAlias) -> UdsMessage | UdsMessageRecord: """ Perform desegmentation of packets. @@ -125,7 +125,7 @@ def desegmentation(self, packets: PacketsContainersSequence) -> Union[UdsMessage """ @abstractmethod - def segmentation(self, message: UdsMessage) -> PacketsTuple: + def segmentation(self, message: UdsMessage) -> PacketsTupleAlias: """ Perform segmentation of a diagnostic message. diff --git a/uds/translator/data_record/__init__.py b/uds/translator/data_record/__init__.py index 653ba8c0..a43186e5 100644 --- a/uds/translator/data_record/__init__.py +++ b/uds/translator/data_record/__init__.py @@ -18,9 +18,9 @@ from .conditional_data_record import ( DEFAULT_DIAGNOSTIC_MESSAGE_CONTINUATION, AbstractConditionalDataRecord, - AliasMessageStructure, ConditionalFormulaDataRecord, ConditionalMappingDataRecord, + MessageStructureAlias, ) from .formula_data_record import CustomFormulaDataRecord, LinearFormulaDataRecord from .mapping_data_record import MappingAndLinearFormulaDataRecord, MappingDataRecord diff --git a/uds/translator/data_record/abstract_data_record.py b/uds/translator/data_record/abstract_data_record.py index ef4556ee..ef61f465 100644 --- a/uds/translator/data_record/abstract_data_record.py +++ b/uds/translator/data_record/abstract_data_record.py @@ -7,11 +7,12 @@ from abc import ABC, abstractmethod from collections import OrderedDict -from typing import List, Mapping, Optional, Sequence, Tuple, TypedDict, Union +from collections.abc import Mapping, Sequence +from typing import TypedDict from uds.utilities import InconsistencyError, ReassignmentError -SinglePhysicalValueAlias = Union[int, float, str] +SinglePhysicalValueAlias = int | float | str """ Physical value from a single Data Record occurrence. @@ -21,7 +22,7 @@ - float: Scaled/calculated values (e.g., 25.5°C after scaling) - str: Mapped labels (e.g., "Active", "Inactive", "Warning") """ -MultiplePhysicalValuesAlias = Union[str, Tuple[SinglePhysicalValueAlias, ...]] +MultiplePhysicalValuesAlias = str | tuple[SinglePhysicalValueAlias, ...] """ Physical values from multiple Data Record occurrences. @@ -31,9 +32,9 @@ (e.g. ASCII, UTF-8) - tuple: Individual values per occurrence """ -PhysicalValueAlias = Union[SinglePhysicalValueAlias, MultiplePhysicalValuesAlias] +PhysicalValueAlias = SinglePhysicalValueAlias | MultiplePhysicalValuesAlias """Alias for all physical values.""" -ChildrenValuesAlias = Mapping[str, Union[int, "ChildrenValuesAlias"]] +type ChildrenValuesAlias = Mapping[str, int | ChildrenValuesAlias] """Alias for children values mapping.""" @@ -53,8 +54,8 @@ class SingleOccurrenceInfo(TypedDict, total=True): length: int raw_value: int physical_value: SinglePhysicalValueAlias - children: Tuple["SingleOccurrenceInfo", ...] - unit: Optional[str] + children: tuple["SingleOccurrenceInfo", ...] + unit: None | str class MultipleOccurrencesInfo(TypedDict, total=True): @@ -72,13 +73,13 @@ class MultipleOccurrencesInfo(TypedDict, total=True): name: str length: int - raw_value: Tuple[int, ...] + raw_value: tuple[int, ...] physical_value: MultiplePhysicalValuesAlias - children: Tuple[Tuple["SingleOccurrenceInfo", ...], ...] - unit: Optional[str] + children: tuple[tuple["SingleOccurrenceInfo", ...], ...] + unit: None | str -DataRecordInfoAlias = Union[SingleOccurrenceInfo, MultipleOccurrencesInfo] +DataRecordInfoAlias = SingleOccurrenceInfo | MultipleOccurrencesInfo """Comprehensive information Data Record occurrence(s).""" @@ -103,8 +104,8 @@ def __init__(self, length: int, children: Sequence["AbstractDataRecord"], min_occurrences: int, - max_occurrences: Optional[int], - unit: Optional[str] = None, + max_occurrences: None | int, + unit: None | str = None, enforce_reoccurring: bool = False) -> None: """ Initialize common part for all Data Records. @@ -188,7 +189,7 @@ def length(self, value: int) -> None: self.__length = value @property - def children(self) -> Tuple["AbstractDataRecord", ...]: + def children(self) -> tuple["AbstractDataRecord", ...]: """Get Data Records contained by this Data Record.""" return self.__children @@ -245,7 +246,7 @@ def min_occurrences(self, value: int) -> None: self.__min_occurrences = value @property - def max_occurrences(self) -> Optional[int]: + def max_occurrences(self) -> None | int: """ Maximal number of occurrences for this Data Record. @@ -254,7 +255,7 @@ def max_occurrences(self) -> Optional[int]: return self.__max_occurrences @max_occurrences.setter - def max_occurrences(self, value: Optional[int]) -> None: + def max_occurrences(self, value: None | int) -> None: """ Set maximal number of occurrences. @@ -275,12 +276,12 @@ def max_occurrences(self, value: Optional[int]) -> None: self.__max_occurrences = value @property - def unit(self) -> Optional[str]: + def unit(self) -> None | str: """Get unit in which Physical Value is presented. None if unused.""" return self.__unit @unit.setter - def unit(self, value: Optional[str]) -> None: + def unit(self, value: None | str) -> None: """ Set unit in which Physical Value is presented. @@ -369,7 +370,7 @@ def get_children_values(self, raw_value: int) -> OrderedDict[str, int]: children_values[child.name] = child_value return children_values - def get_children_occurrence_info(self, raw_value: int) -> Tuple[SingleOccurrenceInfo, ...]: + def get_children_occurrence_info(self, raw_value: int) -> tuple[SingleOccurrenceInfo, ...]: """ Get occurrence information for all children. @@ -378,7 +379,7 @@ def get_children_occurrence_info(self, raw_value: int) -> Tuple[SingleOccurrence :return: Children occurrence information. """ children_values = self.get_children_values(raw_value) - children_occurrence_info: List[SingleOccurrenceInfo] \ + children_occurrence_info: list[SingleOccurrenceInfo] \ = [child.get_occurrence_info(children_values[child.name]) for child in self.children] # type: ignore return tuple(children_occurrence_info) diff --git a/uds/translator/data_record/conditional_data_record.py b/uds/translator/data_record/conditional_data_record.py index 34e459b4..2e56f2cd 100644 --- a/uds/translator/data_record/conditional_data_record.py +++ b/uds/translator/data_record/conditional_data_record.py @@ -1,25 +1,25 @@ """Conditional Data Records implementation.""" -__all__ = ["DEFAULT_DIAGNOSTIC_MESSAGE_CONTINUATION", "AliasMessageStructure", +__all__ = ["DEFAULT_DIAGNOSTIC_MESSAGE_CONTINUATION", "MessageStructureAlias", "AbstractConditionalDataRecord", "ConditionalMappingDataRecord", "ConditionalFormulaDataRecord"] from abc import ABC, abstractmethod +from collections.abc import Callable, Mapping, Sequence from inspect import signature from operator import getitem from types import MappingProxyType -from typing import Callable, Mapping, Optional, Sequence, Union from uds.utilities import InconsistencyError from .abstract_data_record import AbstractDataRecord from .raw_data_record import RawDataRecord -AliasMessageStructure = Sequence[Union[AbstractDataRecord, "AbstractConditionalDataRecord"]] +type MessageStructureAlias = Sequence[AbstractDataRecord | AbstractConditionalDataRecord] """Alias of Diagnostic Message Structure used by databases to interpret Diagnostic Messages parameters. The sequence contains `AbstractDataRecord` instances and may include conditional records. The total length (min/max) must always be divisible by 8.""" -DEFAULT_DIAGNOSTIC_MESSAGE_CONTINUATION: AliasMessageStructure = ( +DEFAULT_DIAGNOSTIC_MESSAGE_CONTINUATION: MessageStructureAlias = ( RawDataRecord(name="Generic Diagnostic Message Continuation", length=8, min_occurrences=0, @@ -37,7 +37,7 @@ class AbstractConditionalDataRecord(ABC): - Contains logic of diagnostic message continuation building. """ - def __init__(self, default_message_continuation: Optional[AliasMessageStructure]) -> None: + def __init__(self, default_message_continuation: None | MessageStructureAlias) -> None: """ Initialize the common part for all Conditional Data Records. @@ -47,7 +47,7 @@ def __init__(self, default_message_continuation: Optional[AliasMessageStructure] self.default_message_continuation = default_message_continuation @abstractmethod - def __getitem__(self, raw_value: int) -> AliasMessageStructure: + def __getitem__(self, raw_value: int) -> MessageStructureAlias: """ Get Data Record with diagnostic message continuation. @@ -59,7 +59,7 @@ def __getitem__(self, raw_value: int) -> AliasMessageStructure: """ @property - def default_message_continuation(self) -> Optional[AliasMessageStructure]: + def default_message_continuation(self) -> None | MessageStructureAlias: """ Get default diagnostic message continuation. @@ -71,7 +71,7 @@ def default_message_continuation(self) -> Optional[AliasMessageStructure]: return self.__default_message_continuation @default_message_continuation.setter - def default_message_continuation(self, value: Optional[AliasMessageStructure]) -> None: + def default_message_continuation(self, value: None | MessageStructureAlias) -> None: """ Set default diagnostic message continuation. @@ -86,7 +86,7 @@ def default_message_continuation(self, value: Optional[AliasMessageStructure]) - self.__default_message_continuation = tuple(value) @staticmethod - def validate_message_continuation(value: AliasMessageStructure) -> None: + def validate_message_continuation(value: MessageStructureAlias) -> None: """ Validate whether the provided value is structure of diagnostic message continuation. @@ -119,7 +119,7 @@ def validate_message_continuation(value: AliasMessageStructure) -> None: raise InconsistencyError("Total length of diagnostic message continuation must always be divisible by 8. " f"Min length: {min_total_length}. Max length: {max_total_length}.") - def get_message_continuation(self, raw_value: int) -> AliasMessageStructure: + def get_message_continuation(self, raw_value: int) -> MessageStructureAlias: """ Get Data Record with diagnostic message continuation. @@ -147,9 +147,9 @@ class ConditionalMappingDataRecord(AbstractConditionalDataRecord): """ def __init__(self, - mapping: Mapping[int, AliasMessageStructure], - default_message_continuation: Optional[AliasMessageStructure] = None, - value_mask: Optional[int] = None) -> None: + mapping: Mapping[int, MessageStructureAlias], + default_message_continuation: None | MessageStructureAlias = None, + value_mask: None | int = None) -> None: """ Define logic for this Conditional Data Record. @@ -163,7 +163,7 @@ def __init__(self, self.value_mask = value_mask super().__init__(default_message_continuation=default_message_continuation) - def __getitem__(self, raw_value: int) -> AliasMessageStructure: + def __getitem__(self, raw_value: int) -> MessageStructureAlias: """ Get diagnostic message continuation for given raw value based on mapping only. @@ -181,12 +181,12 @@ def __getitem__(self, raw_value: int) -> AliasMessageStructure: return self.mapping[raw_value if self.value_mask is None else raw_value & self.value_mask] @property - def mapping(self) -> Mapping[int, AliasMessageStructure]: + def mapping(self) -> Mapping[int, MessageStructureAlias]: """Get the mapping with diagnostic message continuation selection.""" return self.__mapping @mapping.setter - def mapping(self, mapping: Mapping[int, AliasMessageStructure]) -> None: + def mapping(self, mapping: Mapping[int, MessageStructureAlias]) -> None: """ Set the mapping for diagnostic message continuation selection. @@ -206,12 +206,12 @@ def mapping(self, mapping: Mapping[int, AliasMessageStructure]) -> None: self.__mapping = MappingProxyType(mapping) @property - def value_mask(self) -> Optional[int]: + def value_mask(self) -> None | int: """Get the mask to apply on a raw value of the proceeding Data Record.""" return self.__value_mask @value_mask.setter - def value_mask(self, value: Optional[int]) -> None: + def value_mask(self, value: None | int) -> None: """ Set the mask to apply on a raw value of the proceeding Data Record. @@ -235,8 +235,8 @@ class ConditionalFormulaDataRecord(AbstractConditionalDataRecord): """ def __init__(self, - formula: Callable[[int], AliasMessageStructure], - default_message_continuation: Optional[AliasMessageStructure] = None) -> None: + formula: Callable[[int], MessageStructureAlias], + default_message_continuation: None | MessageStructureAlias = None) -> None: """ Define logic for this Conditional Data Record. @@ -247,7 +247,7 @@ def __init__(self, self.formula = formula super().__init__(default_message_continuation=default_message_continuation) - def __getitem__(self, raw_value: int) -> AliasMessageStructure: + def __getitem__(self, raw_value: int) -> MessageStructureAlias: """ Get diagnostic message continuation for given raw value based on formula only. @@ -265,12 +265,12 @@ def __getitem__(self, raw_value: int) -> AliasMessageStructure: return self.formula(raw_value) @property - def formula(self) -> Callable[[int], AliasMessageStructure]: + def formula(self) -> Callable[[int], MessageStructureAlias]: """Get the formula for assessing the structure of diagnostic message continuation.""" return self.__formula @formula.setter - def formula(self, formula: Callable[[int], AliasMessageStructure]) -> None: + def formula(self, formula: Callable[[int], MessageStructureAlias]) -> None: """ Set the formula for assessing the structure of diagnostic message continuation. diff --git a/uds/translator/data_record/formula_data_record.py b/uds/translator/data_record/formula_data_record.py index 9e16e758..33b87ce9 100644 --- a/uds/translator/data_record/formula_data_record.py +++ b/uds/translator/data_record/formula_data_record.py @@ -2,21 +2,18 @@ __all__ = ["CustomFormulaDataRecord", "LinearFormulaDataRecord"] -from typing import Callable, Optional, Sequence, Union +from collections.abc import Callable, Sequence from .abstract_data_record import AbstractDataRecord -AliasPhysicalValueEncodingFormula = Union[ - Callable[[int], int], - Callable[[float], int], - Callable[[Union[int, float]], int], -] +AliasPhysicalValueEncodingFormula = (Callable[[int], int] + | Callable[[float], int] + | Callable[[int | float], int]) """Type alias for encoding formulas that convert physical values to raw values.""" -AliasPhysicalValueDecodingFormula = Union[ - Callable[[int], int], - Callable[[int], float], - Callable[[int], Union[int, float]], -] + +AliasPhysicalValueDecodingFormula = (Callable[[int], int] + | Callable[[int], float] + | Callable[[int], int | float]) """Type alias for decoding formulas that convert raw values to physical values.""" @@ -43,11 +40,11 @@ class LinearFormulaDataRecord(AbstractDataRecord): def __init__(self, name: str, length: int, - factor: Union[float, int], - offset: Union[float, int], + factor: float | int, + offset: float | int, min_occurrences: int = 1, - max_occurrences: Optional[int] = 1, - unit: Optional[str] = None, + max_occurrences: None | int = 1, + unit: None | str = None, enforce_reoccurring: bool = False) -> None: """ Configure Linear Formula Data Record. @@ -73,12 +70,12 @@ def __init__(self, enforce_reoccurring=enforce_reoccurring) @property - def factor(self) -> Union[float, int]: + def factor(self) -> float | int: """Get the factor value for the linear transformation.""" return self.__factor @factor.setter - def factor(self, value: Union[float, int]) -> None: + def factor(self, value: float | int) -> None: """ Set the factor value for the linear transformation. @@ -94,12 +91,12 @@ def factor(self, value: Union[float, int]) -> None: self.__factor = value @property - def offset(self) -> Union[float, int]: + def offset(self) -> float | int: """Get the offset value for the linear transformation.""" return self.__offset @offset.setter - def offset(self, value: Union[float, int]) -> None: + def offset(self, value: float | int) -> None: """ Set the offset value for the linear transformation. @@ -112,18 +109,18 @@ def offset(self, value: Union[float, int]) -> None: self.__offset = value @property # noqa: vulture - def min_physical_value(self) -> Union[float, int]: + def min_physical_value(self) -> float | int: """Get the minimum physical value.""" raw_value = self.min_raw_value if self.factor > 0 else self.max_raw_value return (raw_value * self.factor) + self.offset @property # noqa: vulture - def max_physical_value(self) -> Union[float, int]: + def max_physical_value(self) -> float | int: """Get the maximum physical value.""" raw_value = self.max_raw_value if self.factor > 0 else self.min_raw_value return (raw_value * self.factor) + self.offset - def get_physical_value(self, raw_value: int) -> Union[float, int]: + def get_physical_value(self, raw_value: int) -> float | int: """ Get physical value representing provided raw value. @@ -136,7 +133,7 @@ def get_physical_value(self, raw_value: int) -> Union[float, int]: self._validate_raw_value(raw_value) return (raw_value * self.factor) + self.offset - def get_raw_value(self, physical_value: Union[float, int]) -> int: # type: ignore + def get_raw_value(self, physical_value: float | int) -> int: # type: ignore """ Get raw value that represents provided physical value. @@ -190,8 +187,8 @@ def __init__(self, decoding_formula: AliasPhysicalValueDecodingFormula, children: Sequence[AbstractDataRecord] = tuple(), min_occurrences: int = 1, - max_occurrences: Optional[int] = 1, - unit: Optional[str] = None, + max_occurrences: None | int = 1, + unit: None | str = None, enforce_reoccurring: bool = False) -> None: """ Configure custom formula Data Record. @@ -252,7 +249,7 @@ def decoding_formula(self, value: AliasPhysicalValueDecodingFormula) -> None: raise TypeError(f"Decoding formula must be callable. Actual type: {type(value)}.") self.__decoding_formula = value - def get_physical_value(self, raw_value: int) -> Union[float, int]: + def get_physical_value(self, raw_value: int) -> float | int: """ Get physical value representing provided raw value. @@ -263,7 +260,7 @@ def get_physical_value(self, raw_value: int) -> Union[float, int]: self._validate_raw_value(raw_value) return self.decoding_formula(raw_value) - def get_raw_value(self, physical_value: Union[float, int]) -> int: # type: ignore + def get_raw_value(self, physical_value: float | int) -> int: # type: ignore """ Get raw value that represents provided physical value. diff --git a/uds/translator/data_record/mapping_data_record.py b/uds/translator/data_record/mapping_data_record.py index 3f2b06f6..4d588920 100644 --- a/uds/translator/data_record/mapping_data_record.py +++ b/uds/translator/data_record/mapping_data_record.py @@ -3,8 +3,8 @@ __all__ = ["MappingDataRecord", "MappingAndLinearFormulaDataRecord"] from abc import ABC, abstractmethod +from collections.abc import Sequence from types import MappingProxyType -from typing import Dict, Optional, Sequence, Union from warnings import warn from uds.utilities import ValueWarning @@ -17,7 +17,7 @@ class AbstractMappingDataRecord(ABC): """Mapping functionality for Data Records.""" - def __init__(self, values_mapping: Dict[int, str]) -> None: + def __init__(self, values_mapping: dict[int, str]) -> None: """ Define mapping to use by this Data Record. @@ -32,7 +32,7 @@ def values_mapping(self) -> MappingProxyType[int, str]: return self.__values_mapping @values_mapping.setter - def values_mapping(self, value: Dict[int, str]) -> None: + def values_mapping(self, value: dict[int, str]) -> None: """ Set the mapping between raw values and their labels. @@ -89,11 +89,11 @@ class MappingDataRecord(RawDataRecord, AbstractMappingDataRecord): def __init__(self, name: str, length: int, - values_mapping: Dict[int, str], + values_mapping: dict[int, str], children: Sequence[AbstractDataRecord] = tuple(), min_occurrences: int = 1, - max_occurrences: Optional[int] = 1, - unit: Optional[str] = None, + max_occurrences: None | int = 1, + unit: None | str = None, enforce_reoccurring: bool = False) -> None: """ Create Mapping Data Record. @@ -120,7 +120,7 @@ def __init__(self, AbstractMappingDataRecord.__init__(self, values_mapping=values_mapping) - def get_physical_value(self, raw_value: int) -> Union[str, int]: # type: ignore + def get_physical_value(self, raw_value: int) -> str | int: # type: ignore """ Get physical value representing provided raw value. @@ -135,7 +135,7 @@ def get_physical_value(self, raw_value: int) -> Union[str, int]: # type: ignore stacklevel=2) return super().get_physical_value(raw_value) - def get_raw_value(self, physical_value: Union[str, int]) -> int: # type: ignore + def get_raw_value(self, physical_value: str | int) -> int: # type: ignore """ Get raw value that represents provided physical value. @@ -175,12 +175,12 @@ class MappingAndLinearFormulaDataRecord(LinearFormulaDataRecord, AbstractMapping def __init__(self, name: str, length: int, - values_mapping: Dict[int, str], - factor: Union[float, int], - offset: Union[float, int], + values_mapping: dict[int, str], + factor: float | int, + offset: float | int, min_occurrences: int = 1, - max_occurrences: Optional[int] = 1, - unit: Optional[str] = None, + max_occurrences: None | int = 1, + unit: None | str = None, enforce_reoccurring: bool = False) -> None: """ Create Mapping and Linear Formula Data Record. @@ -209,7 +209,7 @@ def __init__(self, AbstractMappingDataRecord.__init__(self, values_mapping=values_mapping) - def get_physical_value(self, raw_value: int) -> Union[str, int, float]: # type: ignore + def get_physical_value(self, raw_value: int) -> str | int | float: # type: ignore """ Get physical value representing provided raw value. @@ -221,7 +221,7 @@ def get_physical_value(self, raw_value: int) -> Union[str, int, float]: # type: return self.values_mapping[raw_value] return super().get_physical_value(raw_value) - def get_raw_value(self, physical_value: Union[str, int, float]) -> int: + def get_raw_value(self, physical_value: str | int | float) -> int: """ Get raw value that represents provided physical value. diff --git a/uds/translator/data_record/raw_data_record.py b/uds/translator/data_record/raw_data_record.py index 2e674ca8..fab4f20d 100644 --- a/uds/translator/data_record/raw_data_record.py +++ b/uds/translator/data_record/raw_data_record.py @@ -2,7 +2,7 @@ __all__ = ["RawDataRecord"] -from typing import Optional, Sequence +from collections.abc import Sequence from .abstract_data_record import AbstractDataRecord @@ -24,8 +24,8 @@ def __init__(self, length: int, children: Sequence[AbstractDataRecord] = tuple(), min_occurrences: int = 1, - max_occurrences: Optional[int] = 1, - unit: Optional[str] = None, + max_occurrences: None | int = 1, + unit: None | str = None, enforce_reoccurring: bool = False) -> None: """ Create Raw Data Record. diff --git a/uds/translator/data_record/text_data_record.py b/uds/translator/data_record/text_data_record.py index 9b6518df..7153c737 100644 --- a/uds/translator/data_record/text_data_record.py +++ b/uds/translator/data_record/text_data_record.py @@ -2,7 +2,8 @@ __all__ = ["TextDataRecord", "TextEncoding"] -from typing import Callable, Dict, Optional, TypedDict +from collections.abc import Callable +from typing import TypedDict from uds.utilities import MAX_DTC_VALUE, ValidatedEnum, int_to_obd_dtc, obd_dtc_to_int @@ -91,7 +92,7 @@ class _EncodingInfo(TypedDict): encode: Callable[[int], str] # noqa: vulture decode: Callable[[str], int] - __ENCODINGS: Dict[TextEncoding, _EncodingInfo] = { + __ENCODINGS: dict[TextEncoding, _EncodingInfo] = { TextEncoding.ASCII: _EncodingInfo(length=8, encode=chr, decode=decode_ascii), @@ -107,7 +108,7 @@ def __init__(self, name: str, encoding: TextEncoding, min_occurrences: int = 1, - max_occurrences: Optional[int] = None, + max_occurrences: None | int = None, enforce_reoccurring: bool = True) -> None: """ Configure Text Data Record. diff --git a/uds/translator/data_record_definitions/conditional.py b/uds/translator/data_record_definitions/conditional.py index 752c9dfa..6ecc3b14 100644 --- a/uds/translator/data_record_definitions/conditional.py +++ b/uds/translator/data_record_definitions/conditional.py @@ -82,9 +82,9 @@ from uds.utilities import REPEATED_DATA_RECORDS_NUMBER from ..data_record import ( - AliasMessageStructure, ConditionalFormulaDataRecord, ConditionalMappingDataRecord, + MessageStructureAlias, RawDataRecord, ) from .did import ( @@ -635,7 +635,7 @@ """Definition of optional conditional (compatible with ISO 14229-1:2013) `controlEnableMask` Data Record.""" -def get_input_output_control_by_identifier_request_2020(did: int) -> AliasMessageStructure: +def get_input_output_control_by_identifier_request_2020(did: int) -> MessageStructureAlias: """ Get message continuation (after DID Data Record) for InputOutputControlByIdentifier request. @@ -655,7 +655,7 @@ def get_input_output_control_by_identifier_request_2020(did: int) -> AliasMessag })) -def get_input_output_control_by_identifier_request_2013(did: int) -> AliasMessageStructure: +def get_input_output_control_by_identifier_request_2013(did: int) -> MessageStructureAlias: """ Get continuation (after DID Data Record) of InputOutputControlByIdentifier request message. @@ -675,7 +675,7 @@ def get_input_output_control_by_identifier_request_2013(did: int) -> AliasMessag })) -def get_input_output_control_by_identifier_response_2020(did: int) -> AliasMessageStructure: +def get_input_output_control_by_identifier_response_2020(did: int) -> MessageStructureAlias: """ Get message continuation (after DID Data Record) for InputOutputControlByIdentifier positive response. @@ -695,7 +695,7 @@ def get_input_output_control_by_identifier_response_2020(did: int) -> AliasMessa })) -def get_input_output_control_by_identifier_response_2013(did: int) -> AliasMessageStructure: +def get_input_output_control_by_identifier_response_2013(did: int) -> MessageStructureAlias: """ Get message continuation (after DID Data Record) for InputOutputControlByIdentifier positive response. diff --git a/uds/translator/data_record_definitions/did.py b/uds/translator/data_record_definitions/did.py index 777b4a61..b31897a3 100644 --- a/uds/translator/data_record_definitions/did.py +++ b/uds/translator/data_record_definitions/did.py @@ -17,8 +17,6 @@ ] -from typing import Dict, Tuple - from uds.utilities import ( DID_BIT_LENGTH, DID_MAPPING_2013, @@ -32,11 +30,11 @@ # Shared -DID_DATA_MAPPING_2020: Dict[int, Tuple[AbstractDataRecord, ...]] = { +DID_DATA_MAPPING_2020: dict[int, tuple[AbstractDataRecord, ...]] = { 0xF186: (RESERVED_BIT, ACTIVE_DIAGNOSTIC_SESSION), } """DID values mapping (compatible with ISO 14229-1:2020) to DID data message structure.""" -DID_DATA_MAPPING_2013: Dict[int, Tuple[AbstractDataRecord, ...]] = { +DID_DATA_MAPPING_2013: dict[int, tuple[AbstractDataRecord, ...]] = { 0xF186: DID_DATA_MAPPING_2020[0xF186], } """DID values mapping (compatible with ISO 14229-1:2013) to DID data message structure.""" diff --git a/uds/translator/data_record_definitions/formula.py b/uds/translator/data_record_definitions/formula.py index 21087d3a..c8a4e8cf 100644 --- a/uds/translator/data_record_definitions/formula.py +++ b/uds/translator/data_record_definitions/formula.py @@ -46,8 +46,8 @@ "get_activated_events_2020", "get_activated_events_2013", ] +from collections.abc import Callable from decimal import Decimal -from typing import Callable, List, Optional, Tuple, Union from uds.utilities import ( DID_BIT_LENGTH, @@ -66,11 +66,11 @@ from ..data_record import ( AbstractDataRecord, - AliasMessageStructure, ConditionalFormulaDataRecord, ConditionalMappingDataRecord, CustomFormulaDataRecord, MappingDataRecord, + MessageStructureAlias, RawDataRecord, TextDataRecord, TextEncoding, @@ -106,7 +106,7 @@ def get_raw_data_record_with_length_formula(data_record_name: str, accept_zero_length: bool - ) -> Callable[[int], Union[Tuple[RawDataRecord], Tuple[()]]]: + ) -> Callable[[int], tuple[RawDataRecord] | tuple[()]]: """ Get formula for Conditional Data Record that returns Raw Data Record with length of proceeding value. @@ -115,7 +115,7 @@ def get_raw_data_record_with_length_formula(data_record_name: str, :return: Formula for creating Raw Data Record that is following (bytes) length parameter. """ - def get_raw_data_record(length: int) -> Union[Tuple[RawDataRecord], Tuple[()]]: + def get_raw_data_record(length: int) -> tuple[RawDataRecord] | tuple[()]: if accept_zero_length and length == 0: return () if length > 0: @@ -221,7 +221,7 @@ def get_did_data_2020(name: str = "DID data") -> ConditionalFormulaDataRecord: min_occurrences=1, max_occurrences=None) - def _get_did_data(did: int) -> Tuple[RawDataRecord]: + def _get_did_data(did: int) -> tuple[RawDataRecord]: data_records = DID_DATA_MAPPING_2020.get(did, None) if data_records is None: raise ValueError(f"No data structure defined for DID 0x{did:04X}.") @@ -254,7 +254,7 @@ def get_did_data_2013(name: str = "DID data") -> ConditionalFormulaDataRecord: min_occurrences=1, max_occurrences=None) - def _get_did_data(did: int) -> Tuple[RawDataRecord]: + def _get_did_data(did: int) -> tuple[RawDataRecord]: data_records = DID_DATA_MAPPING_2013.get(did, None) if data_records is None: raise ValueError(f"No data structure defined for DID 0x{did:04X}.") @@ -275,8 +275,8 @@ def _get_did_data(did: int) -> Tuple[RawDataRecord]: def get_did_record_2020(did_count: int, - record_number: Optional[int], - optional: bool = False) -> Tuple[Union[MappingDataRecord, ConditionalFormulaDataRecord], ...]: + record_number: None | int, + optional: bool = False) -> tuple[MappingDataRecord | ConditionalFormulaDataRecord, ...]: """ Get DID record (e.g. for DTC Snapshot or DTC Stored Data) with DID numbers and data. @@ -289,7 +289,7 @@ def get_did_record_2020(did_count: int, :return: Data Records that are part of the DID record. """ - data_records: List[Union[MappingDataRecord, ConditionalFormulaDataRecord]] = [] + data_records: list[MappingDataRecord | ConditionalFormulaDataRecord] = [] for did_number in range(1, did_count + 1): name = f"DID#{did_number}" if record_number is None else f"DID#{record_number}_{did_number}" data_records.append(get_did_2020(name=name, optional=optional)) @@ -298,8 +298,8 @@ def get_did_record_2020(did_count: int, def get_did_record_2013(did_count: int, - record_number: Optional[int], - optional: bool = False) -> Tuple[Union[MappingDataRecord, ConditionalFormulaDataRecord], ...]: + record_number: None | int, + optional: bool = False) -> tuple[MappingDataRecord | ConditionalFormulaDataRecord, ...]: """ Get DID record (e.g. for DTC Snapshot or DTC Stored Data) with DID numbers and data. @@ -312,7 +312,7 @@ def get_did_record_2013(did_count: int, :return: Data Records that are part of the DID record. """ - data_records: List[Union[MappingDataRecord, ConditionalFormulaDataRecord]] = [] + data_records: list[MappingDataRecord | ConditionalFormulaDataRecord] = [] for did_number in range(1, did_count + 1): name = f"DID#{did_number}" if record_number is None else f"DID#{record_number}_{did_number}" data_records.append(get_did_2013(name=name, optional=optional)) @@ -321,7 +321,7 @@ def get_did_record_2013(did_count: int, def get_memory_size_and_memory_address(address_and_length_format_identifier: int - ) -> Tuple[RawDataRecord, RawDataRecord]: + ) -> tuple[RawDataRecord, RawDataRecord]: """ Get `memoryAddress` and `memorySize` Data Records for given `addressAndLengthFormatIdentifier` value. @@ -343,7 +343,7 @@ def get_memory_size_and_memory_address(address_and_length_format_identifier: int RawDataRecord(name="memorySize", length=8 * memory_size_length, unit="bytes")) -def get_max_number_of_block_length(length_format_identifier: int) -> Tuple[RawDataRecord]: +def get_max_number_of_block_length(length_format_identifier: int) -> tuple[RawDataRecord]: """ Get `maxNumberOfBlockLength` Data Record for given `lengthFormatIdentifier` value. @@ -368,7 +368,7 @@ def get_max_number_of_block_length(length_format_identifier: int) -> Tuple[RawDa # SID 0x19 -def get_did_records_formula_2020(record_number: Optional[int]) -> Callable[[int], AliasMessageStructure]: +def get_did_records_formula_2020(record_number: None | int) -> Callable[[int], MessageStructureAlias]: """ Get formula that can be used by Conditional Data Record for getting DID related Data Records. @@ -383,7 +383,7 @@ def get_did_records_formula_2020(record_number: Optional[int]) -> Callable[[int] record_number=record_number) -def get_did_records_formula_2013(record_number: Optional[int]) -> Callable[[int], AliasMessageStructure]: +def get_did_records_formula_2013(record_number: None | int) -> Callable[[int], MessageStructureAlias]: """ Get formula that can be used by Conditional Data Record for getting DID related Data Records. @@ -402,8 +402,7 @@ def get_did_records_formula_2013(record_number: Optional[int]) -> Callable[[int] def get_scaling_byte_extension(scaling_byte: int, - scaling_byte_number: int - ) -> Tuple[Union[RawDataRecord, ConditionalFormulaDataRecord], ...]: + scaling_byte_number: int) -> tuple[RawDataRecord | ConditionalFormulaDataRecord, ...]: """ Get `scalingByteExtension` Data Records for given `scalingByte` value. @@ -439,7 +438,7 @@ def get_scaling_byte_extension(scaling_byte: int, return () -def get_scaling_byte_extension_formula(scaling_byte_number: int) -> Callable[[int], AliasMessageStructure]: +def get_scaling_byte_extension_formula(scaling_byte_number: int) -> Callable[[int], MessageStructureAlias]: """ Get formula that can be used by Conditional Data Record for getting `scalingByteExtension` Data Records. @@ -451,7 +450,7 @@ def get_scaling_byte_extension_formula(scaling_byte_number: int) -> Callable[[in scaling_byte_number=scaling_byte_number) -def get_coefficients(formula_identifier: int, scaling_byte_number: int) -> Tuple[CustomFormulaDataRecord, ...]: +def get_coefficients(formula_identifier: int, scaling_byte_number: int) -> tuple[CustomFormulaDataRecord, ...]: """ Get coefficients' Data Records for formula type parameter. @@ -482,7 +481,7 @@ def get_coefficients(formula_identifier: int, scaling_byte_number: int) -> Tuple raise ValueError(f"Unknown formula identifier was provided: 0x{formula_identifier:02X}.") -def get_coefficients_formula(scaling_byte_number: int) -> Callable[[int], Tuple[CustomFormulaDataRecord, ...]]: +def get_coefficients_formula(scaling_byte_number: int) -> Callable[[int], tuple[CustomFormulaDataRecord, ...]]: """ Get formula that can be used by Conditional Data Record for getting formula coefficients. @@ -497,7 +496,7 @@ def get_coefficients_formula(scaling_byte_number: int) -> Callable[[int], Tuple[ # SID 0x27 -def get_security_access_request(subfunction: int) -> Tuple[RawDataRecord]: +def get_security_access_request(subfunction: int) -> tuple[RawDataRecord]: """ Get Data Records that are part of SecurityAccess request message. @@ -510,7 +509,7 @@ def get_security_access_request(subfunction: int) -> Tuple[RawDataRecord]: return (SECURITY_KEY,) -def get_security_access_response(subfunction: int) -> Union[Tuple[RawDataRecord], Tuple[()]]: +def get_security_access_response(subfunction: int) -> tuple[RawDataRecord] | tuple[()]: """ Get Data Records that are part of SecurityAccess response message. @@ -526,7 +525,7 @@ def get_security_access_response(subfunction: int) -> Union[Tuple[RawDataRecord] # SID 0x2C -def get_data_from_memory(address_and_length_format_identifier: int) -> Tuple[RawDataRecord]: +def get_data_from_memory(address_and_length_format_identifier: int) -> tuple[RawDataRecord]: """ Get `Data from Memory` Data Record for given `addressAndLengthFormatIdentifier` value. @@ -578,7 +577,7 @@ def _get_mask_data_record(data_record: AbstractDataRecord) -> RawDataRecord: min_occurrences=data_record.min_occurrences, max_occurrences=data_record.max_occurrences) - def _get_did_data_mask(did: int) -> Tuple[RawDataRecord]: + def _get_did_data_mask(did: int) -> tuple[RawDataRecord]: data_records = DID_DATA_MAPPING_2020.get(did, None) if data_records is None: raise ValueError(f"No data structure defined for DID 0x{did:04X}.") @@ -623,7 +622,7 @@ def _get_mask_data_record(data_record: AbstractDataRecord) -> RawDataRecord: min_occurrences=data_record.min_occurrences, max_occurrences=data_record.max_occurrences) - def _get_did_data_mask(did: int) -> Tuple[RawDataRecord]: + def _get_did_data_mask(did: int) -> tuple[RawDataRecord]: data_records = DID_DATA_MAPPING_2013.get(did, None) if data_records is None: raise ValueError(f"No data structure defined for DID 0x{did:04X}.") @@ -648,7 +647,7 @@ def _get_did_data_mask(did: int) -> Tuple[RawDataRecord]: # SID 0x38 -def get_file_path_and_name(file_path_and_name_length: int) -> Tuple[TextDataRecord]: +def get_file_path_and_name(file_path_and_name_length: int) -> tuple[TextDataRecord]: """ Get `filePathAndName` Data Record of given bytes length. @@ -667,7 +666,7 @@ def get_file_path_and_name(file_path_and_name_length: int) -> Tuple[TextDataReco enforce_reoccurring=True),) -def get_file_sizes(file_size_parameter_length: int) -> Tuple[RawDataRecord, RawDataRecord]: +def get_file_sizes(file_size_parameter_length: int) -> tuple[RawDataRecord, RawDataRecord]: """ Get `fileSizeUnCompressed` and `fileSizeCompressed` Data Records of given bytes length. @@ -687,7 +686,7 @@ def get_file_sizes(file_size_parameter_length: int) -> Tuple[RawDataRecord, RawD unit="bytes")) -def get_file_sizes_or_dir_info(file_size_or_dir_info_parameter_length: int) -> Tuple[RawDataRecord, RawDataRecord]: +def get_file_sizes_or_dir_info(file_size_or_dir_info_parameter_length: int) -> tuple[RawDataRecord, RawDataRecord]: """ Get fileSizeUncompressedOrDirInfoLength` and `fileSizeCompressed` Data Records of given bytes length. @@ -708,7 +707,7 @@ def get_file_sizes_or_dir_info(file_size_or_dir_info_parameter_length: int) -> T unit="bytes")) -def get_dir_info(file_size_or_dir_info_parameter_length: int) -> Tuple[RawDataRecord]: +def get_dir_info(file_size_or_dir_info_parameter_length: int) -> tuple[RawDataRecord]: """ Get `fileSizeUncompressedOrDirInfoLength` Data Record of given bytes length. @@ -726,7 +725,7 @@ def get_dir_info(file_size_or_dir_info_parameter_length: int) -> Tuple[RawDataRe unit="bytes"),) -def get_max_number_of_block_length_file_transfer(length_format_identifier: int) -> Tuple[RawDataRecord]: +def get_max_number_of_block_length_file_transfer(length_format_identifier: int) -> tuple[RawDataRecord]: """ Get `maxNumberOfBlockLength` Data Record of given bytes length. @@ -747,7 +746,7 @@ def get_max_number_of_block_length_file_transfer(length_format_identifier: int) # SID 0x3D -def get_data(memory_size_length: int) -> Tuple[RawDataRecord]: +def get_data(memory_size_length: int) -> tuple[RawDataRecord]: """ Get `data` Data Record of given bytes length. @@ -768,9 +767,9 @@ def get_data(memory_size_length: int) -> Tuple[RawDataRecord]: # SID 0x84 -def get_secured_data_transmission_request(signature_length: int) -> Union[ - Tuple[RawDataRecord, RawDataRecord, RawDataRecord, RawDataRecord], - Tuple[RawDataRecord, RawDataRecord, RawDataRecord]]: +def get_secured_data_transmission_request(signature_length: int) -> ( + tuple[RawDataRecord, RawDataRecord, RawDataRecord, RawDataRecord] + | tuple[RawDataRecord, RawDataRecord, RawDataRecord]): """ Get Data Records that are part of SecuredDataTransmission request message. @@ -793,9 +792,9 @@ def get_secured_data_transmission_request(signature_length: int) -> Union[ signature) -def get_secured_data_transmission_response(signature_length: int) -> Union[ - Tuple[RawDataRecord, RawDataRecord, RawDataRecord, RawDataRecord], - Tuple[RawDataRecord, RawDataRecord, RawDataRecord]]: +def get_secured_data_transmission_response(signature_length: int) -> ( + tuple[RawDataRecord, RawDataRecord, RawDataRecord, RawDataRecord] + | tuple[RawDataRecord, RawDataRecord, RawDataRecord]): """ Get Data Records that are part of SecuredDataTransmission response message. @@ -821,7 +820,7 @@ def get_secured_data_transmission_response(signature_length: int) -> Union[ # SID 0x86 -def get_event_window_2020(event_number: Optional[int] = None) -> MappingDataRecord: +def get_event_window_2020(event_number: None | int = None) -> MappingDataRecord: """ Get `eventWindowTime` Data Record (compatible with ISO 14229-1:2020). @@ -835,7 +834,7 @@ def get_event_window_2020(event_number: Optional[int] = None) -> MappingDataReco values_mapping=EVENT_WINDOW_TIME_MAPPING_2020) -def get_event_window_2013(event_number: Optional[int] = None) -> MappingDataRecord: +def get_event_window_2013(event_number: None | int = None) -> MappingDataRecord: """ Get `eventWindowTime` Data Record (compatible with ISO 14229-1:2013). @@ -877,7 +876,7 @@ def get_event_type_of_active_event_2013(event_number: int) -> RawDataRecord: EVENT_TYPE_2013)) -def get_event_type_record_01(event_number: Optional[int] = None) -> RawDataRecord: +def get_event_type_record_01(event_number: None | int = None) -> RawDataRecord: """ Get `eventTypeRecord` Data Record for `event` equal to 0x01. @@ -891,7 +890,7 @@ def get_event_type_record_01(event_number: Optional[int] = None) -> RawDataRecor children=(DTC_STATUS_MASK,)) -def get_event_type_record_02_2013(event_number: Optional[int] = None) -> RawDataRecord: +def get_event_type_record_02_2013(event_number: None | int = None) -> RawDataRecord: """ Get `eventTypeRecord` Data Record (compatible with ISO 14229-1:2013) for `event` equal to 0x02. @@ -905,7 +904,7 @@ def get_event_type_record_02_2013(event_number: Optional[int] = None) -> RawData children=(TIMER_SCHEDULE_2013,)) -def get_event_type_record_03_2020(event_number: Optional[int] = None) -> RawDataRecord: +def get_event_type_record_03_2020(event_number: None | int = None) -> RawDataRecord: """ Get `eventTypeRecord` Data Record (compatible with ISO 14229-1:2020) for `event` equal to 0x03. @@ -919,7 +918,7 @@ def get_event_type_record_03_2020(event_number: Optional[int] = None) -> RawData children=(DID_2020,)) -def get_event_type_record_03_2013(event_number: Optional[int] = None) -> RawDataRecord: +def get_event_type_record_03_2013(event_number: None | int = None) -> RawDataRecord: """ Get `eventTypeRecord` Data Record (compatible with ISO 14229-1:2013) for `event` equal to 0x03. @@ -933,7 +932,7 @@ def get_event_type_record_03_2013(event_number: Optional[int] = None) -> RawData children=(DID_2013,)) -def get_event_type_record_07_2020(event_number: Optional[int] = None) -> RawDataRecord: +def get_event_type_record_07_2020(event_number: None | int = None) -> RawDataRecord: """ Get `eventTypeRecord` Data Record (compatible with ISO 14229-1:2020) for `event` equal to 0x07. @@ -951,7 +950,7 @@ def get_event_type_record_07_2020(event_number: Optional[int] = None) -> RawData LOCALIZATION)) -def get_event_type_record_07_2013(event_number: Optional[int] = None) -> RawDataRecord: +def get_event_type_record_07_2013(event_number: None | int = None) -> RawDataRecord: """ Get `eventTypeRecord` Data Record (compatible with ISO 14229-1:2013) for `event` equal to 0x07. @@ -969,7 +968,7 @@ def get_event_type_record_07_2013(event_number: Optional[int] = None) -> RawData LOCALIZATION)) -def get_event_type_record_08_2020(event_number: Optional[int] = None) -> RawDataRecord: +def get_event_type_record_08_2020(event_number: None | int = None) -> RawDataRecord: """ Get `eventTypeRecord` Data Record (compatible with ISO 14229-1:2020) for `event` equal to 0x08. @@ -984,7 +983,7 @@ def get_event_type_record_08_2020(event_number: Optional[int] = None) -> RawData REPORT_TYPE_2020)) -def get_event_type_record_09_2020(event_number: Optional[int] = None) -> RawDataRecord: +def get_event_type_record_09_2020(event_number: None | int = None) -> RawDataRecord: """ Get `eventTypeRecord` Data Record (compatible with ISO 14229-1:2020) for `event` equal to 0x09. @@ -1000,7 +999,7 @@ def get_event_type_record_09_2020(event_number: Optional[int] = None) -> RawData REPORT_TYPE_2020)) -def get_event_type_record_09_2020_continuation(event_number: Optional[int] = None) -> ConditionalMappingDataRecord: +def get_event_type_record_09_2020_continuation(event_number: None | int = None) -> ConditionalMappingDataRecord: """ Get continuation for `eventTypeRecord` Data Record (`event` equal to 0x09). @@ -1042,7 +1041,7 @@ def get_event_type_record_09_2020_continuation(event_number: Optional[int] = Non value_mask=0x7F) -def get_service_to_respond(event_number: Optional[int] = None) -> RawDataRecord: +def get_service_to_respond(event_number: None | int = None) -> RawDataRecord: """ Get `serviceToRespondToRecord` Data Record. @@ -1058,8 +1057,9 @@ def get_service_to_respond(event_number: Optional[int] = None) -> RawDataRecord: max_occurrences=None) -def get_activated_events_2020(number_of_activated_events: int - ) -> Tuple[Union[RawDataRecord, MappingDataRecord, ConditionalMappingDataRecord], ...]: +def get_activated_events_2020(number_of_activated_events: int) -> tuple[RawDataRecord + | MappingDataRecord + | ConditionalMappingDataRecord, ...]: """ Get activated events (compatible with ISO 14229-1:2020). @@ -1067,7 +1067,7 @@ def get_activated_events_2020(number_of_activated_events: int :return: Data Records for activated events. """ - data_records: List[Union[RawDataRecord, MappingDataRecord, ConditionalMappingDataRecord]] = [] + data_records: list[RawDataRecord | MappingDataRecord | ConditionalMappingDataRecord] = [] for event_number in range(1, number_of_activated_events + 1): event_window = get_event_window_2020(event_number) service_to_respond = get_service_to_respond(event_number) @@ -1092,8 +1092,9 @@ def get_activated_events_2020(number_of_activated_events: int return tuple(data_records) -def get_activated_events_2013(number_of_activated_events: int - ) -> Tuple[Union[RawDataRecord, MappingDataRecord, ConditionalMappingDataRecord], ...]: +def get_activated_events_2013(number_of_activated_events: int) -> tuple[RawDataRecord + | MappingDataRecord + | ConditionalMappingDataRecord, ...]: """ Get activated events (compatible with ISO 14229-1:2013). @@ -1101,7 +1102,7 @@ def get_activated_events_2013(number_of_activated_events: int :return: Data Records for activated events. """ - data_records: List[Union[RawDataRecord, MappingDataRecord, ConditionalMappingDataRecord]] = [] + data_records: list[RawDataRecord | MappingDataRecord | ConditionalMappingDataRecord] = [] for event_number in range(1, number_of_activated_events + 1): event_window = get_event_window_2013(event_number) service_to_respond = get_service_to_respond(event_number) diff --git a/uds/translator/service.py b/uds/translator/service.py index c10f3296..7e6c5b75 100644 --- a/uds/translator/service.py +++ b/uds/translator/service.py @@ -3,8 +3,8 @@ __all__ = ["Service", "DecodedMessageAlias", "DataRecordsValuesAlias", "DataRecordValueAlias", "MultipleDataRecordValueAlias", "SingleDataRecordValueAlias"] +from collections.abc import Collection, Mapping, Sequence from copy import deepcopy -from typing import Collection, Dict, List, Mapping, Optional, Sequence, Set, Tuple, Union from warnings import warn from uds.message import NEGATIVE_RESPONSE_MESSAGE_LENGTH, NRC, RESPONSE_REQUEST_SID_DIFF, RequestSID, ResponseSID @@ -13,21 +13,21 @@ from .data_record import ( AbstractConditionalDataRecord, AbstractDataRecord, - AliasMessageStructure, ChildrenValuesAlias, DataRecordInfoAlias, + MessageStructureAlias, SingleOccurrenceInfo, ) -SingleDataRecordValueAlias = Optional[Union[int, ChildrenValuesAlias]] +SingleDataRecordValueAlias = None | int | ChildrenValuesAlias """Alias for a single occurrence Data Record. Either: - int type - a single raw value - mapping type - children values - None - no occurrence""" -MultipleDataRecordValueAlias = Sequence[Union[int, ChildrenValuesAlias]] +MultipleDataRecordValueAlias = Sequence[int | ChildrenValuesAlias] """Alias for a multiple occurrences Data Record. It is a sequence where each element represents a single occurrence. Each element is either raw value (int type) or children values (mapping type).""" -DataRecordValueAlias = Union[SingleDataRecordValueAlias, MultipleDataRecordValueAlias] +DataRecordValueAlias = SingleDataRecordValueAlias | MultipleDataRecordValueAlias """Alias for a Data Record value that can be used in the Data Records Mapping.""" DataRecordsValuesAlias = Mapping[str, DataRecordValueAlias] """Alias for Data Records values mapping. @@ -35,7 +35,7 @@ Mapping values are corresponding Data Records values. """ -DecodedMessageAlias = Tuple[DataRecordInfoAlias, ...] +DecodedMessageAlias = tuple[DataRecordInfoAlias, ...] """Alias for decoded information about a Diagnostic Message.""" @@ -54,8 +54,8 @@ class Service: def __init__(self, request_sid: RequestSID, - request_structure: AliasMessageStructure, - response_structure: AliasMessageStructure, + request_structure: MessageStructureAlias, + response_structure: MessageStructureAlias, supported_nrc: Collection[NRC] = tuple(NRC)) -> None: """ Define a translator for a single diagnostic service. @@ -99,12 +99,12 @@ def response_sid(self) -> ResponseSID: return self.__response_sid @property - def request_structure(self) -> AliasMessageStructure: + def request_structure(self) -> MessageStructureAlias: """Get Data Records used for translating request messages for this diagnostic service.""" return self.__request_structure @request_structure.setter - def request_structure(self, request_structure: AliasMessageStructure) -> None: + def request_structure(self, request_structure: MessageStructureAlias) -> None: """ Set Data Records to use for translating request messages for this diagnostic service. @@ -114,12 +114,12 @@ def request_structure(self, request_structure: AliasMessageStructure) -> None: self.__request_structure = tuple(request_structure) @property - def response_structure(self) -> AliasMessageStructure: + def response_structure(self) -> MessageStructureAlias: """Get Data Records used for translating positive response messages for this diagnostic service.""" return self.__response_structure @response_structure.setter - def response_structure(self, response_structure: AliasMessageStructure) -> None: + def response_structure(self, response_structure: MessageStructureAlias) -> None: """ Set Data Records used for translating positive response messages for this diagnostic service. @@ -129,7 +129,7 @@ def response_structure(self, response_structure: AliasMessageStructure) -> None: self.__response_structure = tuple(response_structure) @property - def supported_nrc(self) -> Set[NRC]: + def supported_nrc(self) -> set[NRC]: """Get NRC codes that are supported by this diagnostic service.""" return self.__supported_nrc @@ -193,7 +193,7 @@ def _get_nrc_info(nrc: NRC) -> SingleOccurrenceInfo: @staticmethod def _get_single_data_record_occurrence(data_record: AbstractDataRecord, - value: SingleDataRecordValueAlias) -> List[int]: + value: SingleDataRecordValueAlias) -> list[int]: """ Get occurrence value for a single occurrence Data Record. @@ -226,7 +226,7 @@ def _get_single_data_record_occurrence(data_record: AbstractDataRecord, @staticmethod def _get_reoccurring_data_record_occurrences(data_record: AbstractDataRecord, - value: MultipleDataRecordValueAlias) -> List[int]: + value: MultipleDataRecordValueAlias) -> list[int]: """ Get occurrences values for multiple occurrences Data Record. @@ -247,7 +247,7 @@ def _get_reoccurring_data_record_occurrences(data_record: AbstractDataRecord, f"Data Record min occurrences number = {data_record.min_occurrences}. " f"Data Record max occurrences number = {data_record.max_occurrences}. " f"Provided sequence = {value}.") - raw_values: List[int] = [] + raw_values: list[int] = [] for occurrence_value in value: if isinstance(occurrence_value, int): if not data_record.min_raw_value <= occurrence_value <= data_record.max_raw_value: @@ -268,7 +268,7 @@ def _get_reoccurring_data_record_occurrences(data_record: AbstractDataRecord, @classmethod def _get_data_record_occurrences(cls, data_record: AbstractDataRecord, - value: DataRecordValueAlias) -> List[int]: + value: DataRecordValueAlias) -> list[int]: """ Get raw values of all occurrences provided as value. @@ -283,7 +283,7 @@ def _get_data_record_occurrences(cls, return cls._get_single_data_record_occurrence(data_record=data_record, value=value) # type: ignore @staticmethod - def _get_remaining_length(message_structure: AliasMessageStructure) -> int: + def _get_remaining_length(message_structure: MessageStructureAlias) -> int: """ Get minimal remaining length for the provided message structure. @@ -306,7 +306,7 @@ def _get_remaining_length(message_structure: AliasMessageStructure) -> int: @classmethod def _decode_payload(cls, # pylint: disable=too-many-branches payload: RawBytesAlias, - message_structure: AliasMessageStructure, + message_structure: MessageStructureAlias, check_remaining_length: bool = True) -> DecodedMessageAlias: """ Decode information for given message structure and payload. @@ -325,7 +325,7 @@ def _decode_payload(cls, # pylint: disable=too-many-branches decoded_message_continuation = [] remaining_length = 8 * len(payload) payload_int = bytes_to_int(bytes_list=payload, endianness=Endianness.BIG_ENDIAN) if payload else 0 - raw_values: List[int] = [] + raw_values: list[int] = [] for i, data_record in enumerate(message_structure): if isinstance(data_record, AbstractDataRecord): if data_record.is_reoccurring and not data_record.fixed_total_length: @@ -378,8 +378,8 @@ def _decode_payload(cls, # pylint: disable=too-many-branches @classmethod def _encode_message(cls, # pylint: disable=too-many-branches - data_records_values: Dict[str, DataRecordValueAlias], - message_structure: AliasMessageStructure, + data_records_values: dict[str, DataRecordValueAlias], + message_structure: MessageStructureAlias, check_unused_data_record_values: bool = True) -> bytearray: """ Encode payload of a diagnostic message. @@ -441,7 +441,7 @@ def _encode_message(cls, # pylint: disable=too-many-branches endianness=Endianness.BIG_ENDIAN)) @staticmethod - def validate_message_structure(value: AliasMessageStructure) -> None: + def validate_message_structure(value: MessageStructureAlias) -> None: """ Validate whether the provided value is a structure of diagnostic message. @@ -573,8 +573,8 @@ def encode_negative_response(self, nrc: NRC) -> bytearray: def encode(self, data_records_values: DataRecordsValuesAlias, - sid: Optional[RequestSID] = None, - rsid: Optional[ResponseSID] = None) -> bytearray: + sid: None | RequestSID = None, + rsid: None | ResponseSID = None) -> bytearray: """ Encode diagnostic message payload for this service. diff --git a/uds/translator/translator.py b/uds/translator/translator.py index 2d29739e..8b1fef4a 100644 --- a/uds/translator/translator.py +++ b/uds/translator/translator.py @@ -2,10 +2,10 @@ __all__ = ["Translator"] +from collections.abc import Collection, Mapping from types import MappingProxyType -from typing import Collection, Dict, FrozenSet, Mapping, Optional, Union -from uds.message import NEGATIVE_RESPONSE_MESSAGE_LENGTH, RequestSID, ResponseSID +from uds.message import NEGATIVE_RESPONSE_MESSAGE_LENGTH, RequestSID, ResponseSID, SidAlias from uds.utilities import InconsistencyError, RawBytesAlias, bytes_to_hex, validate_raw_bytes from .service import DataRecordsValuesAlias, DecodedMessageAlias, Service @@ -30,7 +30,7 @@ def __init__(self, services: Collection[Service]) -> None: self.services = services @property - def services(self) -> FrozenSet[Service]: + def services(self) -> frozenset[Service]: """Get diagnostic services translators.""" return self.__services @@ -47,7 +47,7 @@ def services(self, value: Collection[Service]) -> None: """ if not isinstance(value, Collection): raise TypeError(f"Provided value is not a collection. Actual type: {type(value)}.") - services_mapping: Dict[Union[RequestSID, ResponseSID], Service] = {} + services_mapping: dict[SidAlias, Service] = {} for service in value: if not isinstance(service, Service): raise ValueError("At least one collection element is not instance of Service class.") @@ -60,14 +60,14 @@ def services(self, value: Collection[Service]) -> None: self.__services_mapping = MappingProxyType(services_mapping) @property - def services_mapping(self) -> Mapping[Union[int, RequestSID, ResponseSID], Service]: + def services_mapping(self) -> Mapping[SidAlias, Service]: """Get mapping from SID/RSID values to corresponding Service Translators.""" - return self.__services_mapping # type: ignore + return self.__services_mapping def encode(self, data_records_values: DataRecordsValuesAlias, - sid: Optional[RequestSID] = None, - rsid: Optional[ResponseSID] = None) -> bytearray: + sid: None | RequestSID = None, + rsid: None | ResponseSID = None) -> bytearray: """ Encode diagnostic message payload from data records values. diff --git a/uds/transport_interface/abstract_transport_interface.py b/uds/transport_interface/abstract_transport_interface.py index 4a23075d..abc876e6 100644 --- a/uds/transport_interface/abstract_transport_interface.py +++ b/uds/transport_interface/abstract_transport_interface.py @@ -4,7 +4,7 @@ from abc import ABC, abstractmethod from asyncio import AbstractEventLoop -from typing import Any, Optional +from typing import Any from uds.addressing import AbstractAddressingInformation from uds.message import UdsMessage, UdsMessageRecord @@ -108,7 +108,7 @@ def send_packet(self, packet: AbstractPacket) -> AbstractPacketRecord: @abstractmethod async def async_send_packet(self, packet: AbstractPacket, - loop: Optional[AbstractEventLoop] = None) -> AbstractPacketRecord: + loop: None | AbstractEventLoop = None) -> AbstractPacketRecord: """ Transmit packet asynchronously. @@ -119,7 +119,7 @@ async def async_send_packet(self, """ @abstractmethod - def receive_packet(self, timeout: Optional[TimeMillisecondsAlias] = None) -> AbstractPacketRecord: + def receive_packet(self, timeout: None | TimeMillisecondsAlias = None) -> AbstractPacketRecord: """ Receive packet. @@ -133,8 +133,8 @@ def receive_packet(self, timeout: Optional[TimeMillisecondsAlias] = None) -> Abs @abstractmethod async def async_receive_packet(self, - timeout: Optional[TimeMillisecondsAlias] = None, - loop: Optional[AbstractEventLoop] = None) -> AbstractPacketRecord: + timeout: None | TimeMillisecondsAlias = None, + loop: None | AbstractEventLoop = None) -> AbstractPacketRecord: """ Receive packet asynchronously. @@ -161,7 +161,7 @@ def send_message(self, message: UdsMessage) -> UdsMessageRecord: @abstractmethod async def async_send_message(self, message: UdsMessage, - loop: Optional[AbstractEventLoop] = None) -> UdsMessageRecord: + loop: None | AbstractEventLoop = None) -> UdsMessageRecord: """ Transmit asynchronously UDS message. @@ -173,8 +173,8 @@ async def async_send_message(self, @abstractmethod def receive_message(self, - start_timeout: Optional[TimeMillisecondsAlias] = None, - end_timeout: Optional[TimeMillisecondsAlias] = None) -> UdsMessageRecord: + start_timeout: None | TimeMillisecondsAlias = None, + end_timeout: None | TimeMillisecondsAlias = None) -> UdsMessageRecord: """ Receive UDS message. @@ -193,9 +193,9 @@ def receive_message(self, @abstractmethod async def async_receive_message(self, - start_timeout: Optional[TimeMillisecondsAlias] = None, - end_timeout: Optional[TimeMillisecondsAlias] = None, - loop: Optional[AbstractEventLoop] = None) -> UdsMessageRecord: + start_timeout: None | TimeMillisecondsAlias = None, + end_timeout: None | TimeMillisecondsAlias = None, + loop: None | AbstractEventLoop = None) -> UdsMessageRecord: """ Receive asynchronously UDS message. diff --git a/uds/transport_interface/logger.py b/uds/transport_interface/logger.py index 988b4200..9ad568f7 100644 --- a/uds/transport_interface/logger.py +++ b/uds/transport_interface/logger.py @@ -2,11 +2,12 @@ __all__ = ["TransportLogger"] +from collections.abc import Callable from copy import copy from functools import wraps from inspect import iscoroutinefunction from logging import INFO, Logger, getLogger -from typing import Any, Callable, Optional, Type, Union +from typing import Any from uds.message import UdsMessageRecord from uds.packet import AbstractPacketRecord @@ -17,7 +18,7 @@ class TransportLogger: """Configurable logger for Transport Interface objects.""" - TransportInterfaceAlias = Union[AbstractTransportInterface, Type[AbstractTransportInterface]] + TransportInterfaceAlias = AbstractTransportInterface | type[AbstractTransportInterface] """Alias of Transport Interface (either class or instance).""" DECORATED_CLASS_NAME_SUFFIX = "WithLogger" @@ -28,9 +29,9 @@ class TransportLogger: def __init__(self, *, - logger_name: Optional[str] = None, - message_logging_level: Optional[int] = INFO, - packet_logging_level: Optional[int] = INFO, + logger_name: None | str = None, + message_logging_level: None | int = INFO, + packet_logging_level: None | int = INFO, log_sending: bool = True, log_receiving: bool = True, message_log_format: str = DEFAULT_LOG_FORMAT, @@ -69,12 +70,12 @@ def logger(self) -> Logger: return self.__logger @property - def message_logging_level(self) -> Optional[int]: + def message_logging_level(self) -> None | int: """Get logging level to use for UDS Messages logging.""" return self.__message_logging_level @message_logging_level.setter - def message_logging_level(self, value: Optional[int]) -> None: + def message_logging_level(self, value: None | int) -> None: """ Set logging level to use for UDS Messages logging. @@ -87,12 +88,12 @@ def message_logging_level(self, value: Optional[int]) -> None: self.__message_logging_level = value @property - def packet_logging_level(self) -> Optional[int]: + def packet_logging_level(self) -> None | int: """Get logging level to use for Packets logging.""" return self.__packet_logging_level @packet_logging_level.setter - def packet_logging_level(self, value: Optional[int]) -> None: + def packet_logging_level(self, value: None | int) -> None: """ Set logging level to use for Packets logging. @@ -162,7 +163,7 @@ def packet_log_format(self, value: str) -> None: raise TypeError(f"Provided value is not str type. Actual type: {type(value)}.") self.__packet_log_format = value - def _decorate_class(self, cls: Type[AbstractTransportInterface]) -> Type[AbstractTransportInterface]: + def _decorate_class(self, cls: type[AbstractTransportInterface]) -> type[AbstractTransportInterface]: """Decorate Transport Interface class.""" attributes_to_overwrite = {} if self.log_sending: diff --git a/uds/utilities/common_types.py b/uds/utilities/common_types.py index cf9d0493..17ae098c 100644 --- a/uds/utilities/common_types.py +++ b/uds/utilities/common_types.py @@ -4,19 +4,17 @@ "RawBytesAlias", "RawBytesTupleAlias", "RawBytesListAlias", "RawBytesSetAlias", "validate_nibble", "validate_raw_byte", "validate_raw_2byte_value", "validate_raw_bytes"] -from typing import List, Set, Tuple, Union - -TimeMillisecondsAlias = Union[int, float] +TimeMillisecondsAlias = int | float """Alias of a time value in milliseconds.""" TimestampAlias = float """Alias of a timestamp value in seconds (used by :func:`~time.perf_counter`).""" -RawBytesTupleAlias = Tuple[int, ...] +RawBytesTupleAlias = tuple[int, ...] """Alias of a tuple filled with byte values.""" -RawBytesSetAlias = Set[int] +RawBytesSetAlias = set[int] """Alias of a set filled with byte values.""" -RawBytesListAlias = List[int] +RawBytesListAlias = list[int] """Alias of a list filled with byte values.""" -RawBytesAlias = Union[bytes, bytearray, RawBytesTupleAlias, RawBytesListAlias] +RawBytesAlias = bytes | bytearray | RawBytesTupleAlias | RawBytesListAlias """Alias of a sequence filled with byte values.""" diff --git a/uds/utilities/constants/did.py b/uds/utilities/constants/did.py index d661db93..ca94be19 100644 --- a/uds/utilities/constants/did.py +++ b/uds/utilities/constants/did.py @@ -6,7 +6,6 @@ "DID_MAPPING_2020", "DID_MAPPING_2013", ] -from typing import Dict DID_BIT_LENGTH = 16 """Number of bits used for :ref:`DID `""" @@ -17,7 +16,7 @@ PERIODIC_DID_OFFSET = 0xF200 """Offset used by `periodicDataIdentifiers`""" -DID_MAPPING_2020: Dict[int, str] = { +DID_MAPPING_2020: dict[int, str] = { 0xF180: "BootSoftwareIdentificationDataIdentifier", 0xF181: "applicationSoftwareIdentificationDataIdentifier", 0xF182: "applicationDataIdentificationDataIdentifier", @@ -58,7 +57,7 @@ } """:ref:`Data Identifiers mapping according to ISO 14229-1:2020 `.""" -DID_MAPPING_2013: Dict[int, str] = { +DID_MAPPING_2013: dict[int, str] = { 0xF180: "BootSoftwareIdentificationDataIdentifier", 0xF181: "applicationSoftwareIdentificationDataIdentifier", 0xF182: "applicationDataIdentificationDataIdentifier", diff --git a/uds/utilities/constants/dtc.py b/uds/utilities/constants/dtc.py index 5112f524..17105102 100644 --- a/uds/utilities/constants/dtc.py +++ b/uds/utilities/constants/dtc.py @@ -11,14 +11,13 @@ "DTC_FUNCTIONAL_GROUP_IDENTIFIER_MAPPING", ] -from typing import Dict MIN_DTC_VALUE = 0x000000 """Minimum DTC value.""" MAX_DTC_VALUE = 0xFFFFFF """Maximum DTC value.""" -DTC_CHARACTERS_MAPPING: Dict[str, int] = { +DTC_CHARACTERS_MAPPING: dict[str, int] = { "P": 0b00, # Powertrain "C": 0b01, # Chassis "B": 0b10, # Body @@ -26,28 +25,28 @@ } """Mapping of the first DTC character in :ref:`OBD format ` to bits.""" -BITS_TO_DTC_CHARACTER_MAPPING: Dict[int, str] = { +BITS_TO_DTC_CHARACTER_MAPPING: dict[int, str] = { value: key for key, value in DTC_CHARACTERS_MAPPING.items() } """Mapping of the first two DTC bits to :ref:`OBD format ` character.""" -DTC_SNAPSHOT_RECORD_NUMBER_MAPPING: Dict[int, str] = { +DTC_SNAPSHOT_RECORD_NUMBER_MAPPING: dict[int, str] = { 0xFF: "all" } """Values mapping for `DTCSnapshotRecordNumber` Data Record.""" -DTC_EXTENDED_DATA_RECORD_NUMBER_MAPPING: Dict[int, str] = { +DTC_EXTENDED_DATA_RECORD_NUMBER_MAPPING: dict[int, str] = { 0xFE: "all regulated emissions data", 0xFF: "all", } """Values mapping for `DTCExtDataRecordNumber` Data Record.""" -DTC_STORED_DATA_RECORD_NUMBER_MAPPING: Dict[int, str] = { +DTC_STORED_DATA_RECORD_NUMBER_MAPPING: dict[int, str] = { 0xFF: "all", } """Values mapping for `DTCStoredDataRecordNumber` Data Record.""" -GROUP_OF_DTC_MAPPING: Dict[int, str] = { +GROUP_OF_DTC_MAPPING: dict[int, str] = { 0xFFFF33: "Emissions-system group", 0xFFFFD0: "Safety-system group", 0xFFFFFE: "VOBD system group", @@ -55,7 +54,7 @@ } """Values mapping for `groupOfDTC` Data Record.""" -DTC_FORMAT_IDENTIFIER_MAPPING: Dict[int, str] = { +DTC_FORMAT_IDENTIFIER_MAPPING: dict[int, str] = { 0x00: "SAE J2012-DA DTC Format 00", 0x01: "ISO 14229-1 DTC Format", 0x02: "SAE J1939-73 DTC Format", diff --git a/uds/utilities/constants/other.py b/uds/utilities/constants/other.py index e15fdc15..8119df99 100644 --- a/uds/utilities/constants/other.py +++ b/uds/utilities/constants/other.py @@ -35,29 +35,28 @@ "LINK_CONTROL_MODE_IDENTIFIER_MAPPING", ] -from typing import Dict # Shared REPEATED_DATA_RECORDS_NUMBER: int = 100 -NO_YES_MAPPING: Dict[int, str] = {0: "no", 1: "yes"} +NO_YES_MAPPING: dict[int, str] = {0: "no", 1: "yes"} """Generic `no` and `yes` values mapping.""" -OFF_ON_MAPPING: Dict[int, str] = {0: "OFF", 1: "ON"} +OFF_ON_MAPPING: dict[int, str] = {0: "OFF", 1: "ON"} """Generic `OFF` and `ON` values mapping.""" -COMPRESSION_METHOD_MAPPING: Dict[int, str] = ({0: "no compression"} +COMPRESSION_METHOD_MAPPING: dict[int, str] = ({0: "no compression"} | {value: f"compression #{value}" for value in range(1, 0x10)}) """Values mapping for compressionMethod Data Record that is part of messages for multiple services.""" -ENCRYPTION_METHOD_MAPPING: Dict[int, str] = ({0: "no encryption"} +ENCRYPTION_METHOD_MAPPING: dict[int, str] = ({0: "no encryption"} | {value: f"encryption #{value}" for value in range(1, 0x10)}) """Values mapping for encryptingMethod Data Record that is part of messages for multiple services.""" # SID 0x11 -POWER_DOWN_TIME_MAPPING: Dict[int, str] = { +POWER_DOWN_TIME_MAPPING: dict[int, str] = { 0xFF: "failure or time unavailable" } """Values mapping for `powerDownTime` Data Record that is part of @@ -73,7 +72,7 @@ """Number of bits used for constant's mantissa value by :ref:`ReadScalingDataByIdentifier service `""" -SCALING_BYTE_TYPE_MAPPING: Dict[int, str] = { +SCALING_BYTE_TYPE_MAPPING: dict[int, str] = { 0x0: "unSignedNumeric", 0x1: "signedNumeric", 0x2: "bitMappedReportedWithOutMask", @@ -90,7 +89,7 @@ """Values mapping for (scalingByte) `type` Data Record that is part of :ref:`ReadScalingDataByIdentifier ` message.""" -FORMULA_IDENTIFIER_MAPPING: Dict[int, str] = { +FORMULA_IDENTIFIER_MAPPING: dict[int, str] = { 0x00: "y = C0 * x + C1", 0x01: "y = C0 * (x + C1)", 0x02: "y = C0 / (x + C1) + C2", @@ -105,7 +104,7 @@ """Values mapping for `formulaIdentifier` Data Record that is part of :ref:`ReadScalingDataByIdentifier ` message.""" -UNIT_OR_FORMAT_MAPPING: Dict[int, str] = { +UNIT_OR_FORMAT_MAPPING: dict[int, str] = { 0x00: "No unit, no prefix", 0x01: "Meter [m] - length", 0x02: "Foot [ft] - length", @@ -201,7 +200,7 @@ """Values mapping for `unit/format` Data Record that is part of :ref:`ReadScalingDataByIdentifier ` message.""" -STATE_AND_CONNECTION_TYPE_TYPE_MAPPING: Dict[int, str] = { +STATE_AND_CONNECTION_TYPE_TYPE_MAPPING: dict[int, str] = { 0x0: "Internal signal", 0x1: "2 states (low by default)", 0x2: "2 states (high by default)", @@ -210,14 +209,14 @@ """Values mapping for (stateAndConnectionType) `type` Data Record that is part of :ref:`ReadScalingDataByIdentifier ` message.""" -STATE_AND_CONNECTION_TYPE_DIRECTION_MAPPING: Dict[int, str] = { +STATE_AND_CONNECTION_TYPE_DIRECTION_MAPPING: dict[int, str] = { 0x0: "Input signal", 0x1: "Output signal", } """Values mapping for (stateAndConnectionType) `direction` Data Record that is part of :ref:`ReadScalingDataByIdentifier ` message.""" -STATE_AND_CONNECTION_TYPE_LEVEL_MAPPING: Dict[int, str] = { +STATE_AND_CONNECTION_TYPE_LEVEL_MAPPING: dict[int, str] = { 0x0: "Signal at low level (ground)", 0x1: "Signal at middle level (between ground and +)", 0x2: "Signal at high level (+)", @@ -225,7 +224,7 @@ """Values mapping for (stateAndConnectionType) `level` Data Record that is part of :ref:`ReadScalingDataByIdentifier ` message.""" -STATE_AND_CONNECTION_TYPE_STATE_MAPPING: Dict[int, str] = { +STATE_AND_CONNECTION_TYPE_STATE_MAPPING: dict[int, str] = { 0x0: "Not Active", 0x1: "Active, function 1", 0x2: "Error detected", @@ -237,7 +236,7 @@ # SID 0x28 -MESSAGE_TYPE_MAPPING: Dict[int, str] = { +MESSAGE_TYPE_MAPPING: dict[int, str] = { 0: "reserved", 1: "normalCommunicationMessages", 2: "networkManagementCommunicationMessages", @@ -246,13 +245,13 @@ """Values mapping for `messagesType` Data Record that is part of :ref:`CommunicationControl ` message.""" -NETWORKS_MAPPING: Dict[int, str] = ({0x0: "all connected networks", +NETWORKS_MAPPING: dict[int, str] = ({0x0: "all connected networks", 0xF: "network on which this request is received"} | {raw_value: f"subnet {raw_value}" for raw_value in range(1, 0xF)}) """Values mapping for `networks` Data Record that is part of :ref:`CommunicationControl ` message.""" -NODE_IDENTIFICATION_NUMBER_MAPPING: Dict[int, str] = { +NODE_IDENTIFICATION_NUMBER_MAPPING: dict[int, str] = { 0: "reserved" } """Values mapping for `nodeIdentificationNumber` Data Record that is part of @@ -260,7 +259,7 @@ # SID 0x29 -AUTHENTICATION_RETURN_PARAMETER_MAPPING: Dict[int, str] = { +AUTHENTICATION_RETURN_PARAMETER_MAPPING: dict[int, str] = { 0x00: "RequestAccepted", 0x01: "GeneralReject", 0x02: "AuthenticationConfiguration", @@ -276,7 +275,7 @@ # SID 0x2A -TRANSMISSION_MODE_MAPPING: Dict[int, str] = { +TRANSMISSION_MODE_MAPPING: dict[int, str] = { 0x01: "sendAtSlowRate", 0x02: "sendAtMediumRate", 0x03: "sendAtFastRate", @@ -287,7 +286,7 @@ # SID 0x2F -INPUT_OUTPUT_CONTROL_PARAMETER_MAPPING: Dict[int, str] = { +INPUT_OUTPUT_CONTROL_PARAMETER_MAPPING: dict[int, str] = { 0x00: "returnControlToECU", 0x01: "resetToDefault", 0x02: "freezeCurrentState", @@ -298,7 +297,7 @@ # SID 0x38 -MODE_OF_OPERATION_MAPPING_2020: Dict[int, str] = { +MODE_OF_OPERATION_MAPPING_2020: dict[int, str] = { 0x01: "AddFile", 0x02: "DeleteFile", 0x03: "ReplaceFile", @@ -308,7 +307,7 @@ } """Values mapping for `modeOfOperation` Data Record (compatible with ISO 14229-1:2020) that is part of :ref:`RequestFileTransfer ` message.""" -MODE_OF_OPERATION_MAPPING_2013: Dict[int, str] = { +MODE_OF_OPERATION_MAPPING_2013: dict[int, str] = { 0x01: "AddFile", 0x02: "DeleteFile", 0x03: "ReplaceFile", @@ -320,7 +319,7 @@ # SID 0x86 -EVENT_WINDOW_TIME_MAPPING_2020: Dict[int, str] = { +EVENT_WINDOW_TIME_MAPPING_2020: dict[int, str] = { 0x02: "infiniteTimeToResponse", 0x03: "shortEventWindowTime", 0x04: "mediumEventWindowTime", @@ -331,13 +330,13 @@ } """Values mapping for `eventWindowTime` Data Record (compatible with ISO 14229-1:2020) that is part of :ref:`ResponseOnEvent ` message.""" -EVENT_WINDOW_TIME_MAPPING_2013: Dict[int, str] = { +EVENT_WINDOW_TIME_MAPPING_2013: dict[int, str] = { 0x02: "infiniteTimeToResponse" } """Values mapping for `eventWindowTime` Data Record (compatible with ISO 14229-1:2013) that is part of :ref:`ResponseOnEvent ` message.""" -COMPARISON_LOGIC_MAPPING: Dict[int, str] = { +COMPARISON_LOGIC_MAPPING: dict[int, str] = { 0x01: "<", 0x02: ">", 0x03: "=", @@ -346,14 +345,14 @@ """Values mapping for `Comparison logic` Data Record that is part of :ref:`ResponseOnEvent ` message.""" -COMPARE_SIGN_MAPPING: Dict[int, str] = { +COMPARE_SIGN_MAPPING: dict[int, str] = { 0: "Comparison without sign", 1: "Comparison with sign", } """Values mapping for `Compare Sign` Data Record that is part of :ref:`ResponseOnEvent ` message.""" -TIMER_SCHEDULE_MAPPING_2013: Dict[int, str] = { +TIMER_SCHEDULE_MAPPING_2013: dict[int, str] = { 0x01: "Slow rate", 0x02: "Medium rate", 0x03: "Fast rate", @@ -363,7 +362,7 @@ # SID 0x87 -LINK_CONTROL_MODE_IDENTIFIER_MAPPING: Dict[int, str] = { +LINK_CONTROL_MODE_IDENTIFIER_MAPPING: dict[int, str] = { 0x01: "PC9600Baud", 0x02: "PC19200Baud", 0x03: "PC38400Baud", diff --git a/uds/utilities/constants/rid.py b/uds/utilities/constants/rid.py index f4a6b486..fa2b32ea 100644 --- a/uds/utilities/constants/rid.py +++ b/uds/utilities/constants/rid.py @@ -5,11 +5,10 @@ "RID_MAPPING", ] -from typing import Dict RID_BIT_LENGTH = 16 -RID_MAPPING: Dict[int, str] = { +RID_MAPPING: dict[int, str] = { 0xE200: "Execute SPL", 0xE201: "Execute DeployLoopRoutineID", 0xFF00: "eraseMemory", diff --git a/uds/utilities/constants/subfunctions.py b/uds/utilities/constants/subfunctions.py index 51ddcf12..589aa5b8 100644 --- a/uds/utilities/constants/subfunctions.py +++ b/uds/utilities/constants/subfunctions.py @@ -17,7 +17,6 @@ "LINK_CONTROL_TYPE_MAPPING", # SID 0x87 ] -from typing import Dict SPRMIB_MASK = 0x80 """Bit mask of suppressPosRspMsgIndicationBit in SubFunction byte.""" @@ -26,7 +25,7 @@ # SID 0x10 -DIAGNOSTIC_SESSION_TYPE_MAPPING: Dict[int, str] = { +DIAGNOSTIC_SESSION_TYPE_MAPPING: dict[int, str] = { 0x01: "defaultSession", 0x02: "programmingSession", 0x03: "extendedDiagnosticSession", @@ -37,7 +36,7 @@ # SID 0x11 -RESET_TYPE_MAPPING: Dict[int, str] = { +RESET_TYPE_MAPPING: dict[int, str] = { 0x01: "hardReset", 0x02: "keyOffOnReset", 0x03: "softReset", @@ -49,7 +48,7 @@ # SID 0x19 -REPORT_TYPE_MAPPING_2020: Dict[int, str] = { +REPORT_TYPE_MAPPING_2020: dict[int, str] = { 0x01: "reportNumberOfDTCByStatusMask", 0x02: "reportDTCByStatusMask", 0x03: "reportDTCSnapshotIdentification", @@ -77,7 +76,7 @@ } """Values mapping for `reportType` Data Record (compatible with ISO 14229-1:2020) that is part of :ref:`ReadDTCInformation ` SubFunction.""" -REPORT_TYPE_MAPPING_2013: Dict[int, str] = { +REPORT_TYPE_MAPPING_2013: dict[int, str] = { 0x01: "reportNumberOfDTCByStatusMask", 0x02: "reportDTCByStatusMask", 0x03: "reportDTCSnapshotIdentification", @@ -134,7 +133,7 @@ # SID 0x28 -CONTROL_TYPE_MAPPING: Dict[int, str] = { +CONTROL_TYPE_MAPPING: dict[int, str] = { 0x00: "enableRxAndTx", 0x01: "enableRxAndDisableTx", 0x02: "disableRxAndEnableTx", @@ -147,7 +146,7 @@ # SID 0x29 -AUTHENTICATION_TASK_MAPPING: Dict[int, str] = { +AUTHENTICATION_TASK_MAPPING: dict[int, str] = { 0x00: "deAuthenticate", 0x01: "verifyCertificateUnidirectional", 0x02: "verifyCertificateBidirectional", @@ -163,7 +162,7 @@ # SID 0x2C -DEFINITION_TYPE_MAPPING: Dict[int, str] = { +DEFINITION_TYPE_MAPPING: dict[int, str] = { 0x01: "defineByIdentifier", 0x02: "defineByMemoryAddress", 0x03: "clearDynamicallyDefinedDataIdentifier", @@ -173,7 +172,7 @@ # SID 0x31 -ROUTINE_CONTROL_TYPE_MAPPING: Dict[int, str] = { +ROUTINE_CONTROL_TYPE_MAPPING: dict[int, str] = { 0x01: "startRoutine", 0x02: "stopRoutine", 0x03: "requestRoutineResults", @@ -183,7 +182,7 @@ # SID 0x3E -ZERO_SUBFUNCTION_MAPPING: Dict[int, str] = { +ZERO_SUBFUNCTION_MAPPING: dict[int, str] = { 0x00: "zeroSubFunction", } """Values mapping for `zeroSubFunction` Data Record that is part of @@ -191,7 +190,7 @@ # SID 0x83 -TIMING_PARAMETER_ACCESS_TYPE_MAPPING_2013: Dict[int, str] = { +TIMING_PARAMETER_ACCESS_TYPE_MAPPING_2013: dict[int, str] = { 0x01: "readExtendedTimingParameterSet", 0x02: "setTimingParametersToDefaultValues", 0x03: "readCurrentlyActiveTimingParameters", @@ -202,7 +201,7 @@ # SID 0x85 -DTC_SETTING_TYPE_MAPPING: Dict[int, str] = { +DTC_SETTING_TYPE_MAPPING: dict[int, str] = { 0x01: "on", 0x02: "off", } @@ -211,7 +210,7 @@ # SID 0x86 -EVENT_MAPPING_2020: Dict[int, str] = { +EVENT_MAPPING_2020: dict[int, str] = { 0x00: "stopResponseOnEvent", 0x01: "onDTCStatusChange", 0x03: "onChangeOfDataIdentifier", @@ -224,7 +223,7 @@ } """Values mapping for `event` Data Record (compatible with ISO 14229-1:2020) that is part of :ref:`ResponseOnEvent ` SubFunction.""" -EVENT_MAPPING_2013: Dict[int, str] = { +EVENT_MAPPING_2013: dict[int, str] = { 0x00: "stopResponseOnEvent", 0x01: "onDTCStatusChange", 0x02: "onTimerInterrupt", @@ -237,7 +236,7 @@ """Values mapping for `event` Data Record (compatible with ISO 14229-1:2013) that is part of :ref:`ResponseOnEvent ` SubFunction.""" -STORAGE_STATE_MAPPING: Dict[int, str] = { +STORAGE_STATE_MAPPING: dict[int, str] = { 0x00: "doNotStoreEvent", 0x01: "storeEvent", } @@ -246,7 +245,7 @@ # SID 0x87 -LINK_CONTROL_TYPE_MAPPING: Dict[int, str] = { +LINK_CONTROL_TYPE_MAPPING: dict[int, str] = { 0x01: "verifyModeTransitionWithFixedParameter", 0x02: "verifyModeTransitionWithSpecificParameter", 0x03: "transitionMode", diff --git a/uds/utilities/conversions.py b/uds/utilities/conversions.py index 15e33a28..d09e0328 100644 --- a/uds/utilities/conversions.py +++ b/uds/utilities/conversions.py @@ -8,8 +8,9 @@ ] import re +from collections.abc import Callable from time import perf_counter, time -from typing import Any, Callable, Optional, Union +from typing import Any from .common_types import RawBytesAlias, validate_raw_bytes from .constants import BITS_TO_DTC_CHARACTER_MAPPING, DTC_CHARACTERS_MAPPING, MAX_DTC_VALUE, MIN_DTC_VALUE @@ -49,7 +50,7 @@ def bytes_to_int(bytes_list: RawBytesAlias, endianness: Endianness = Endianness. def int_to_bytes(int_value: int, - size: Optional[int] = None, + size: None | int = None, endianness: Endianness = Endianness.BIG_ENDIAN) -> bytes: """ Convert integer value to a list of bytes. @@ -190,8 +191,8 @@ class TimeSync: """Default expiration time (in seconds) of the offset calculated during last synchronization.""" def __init__(self, - samples_number: Optional[int] = None, - sync_expiration: Optional[Union[int, float]] = None) -> None: + samples_number: None | int = None, + sync_expiration: None | int | float = None) -> None: """ Get time synchronization object. @@ -205,9 +206,9 @@ def __init__(self, if not hasattr(self, "_TimeSync__sync_expiration"): self.sync_expiration = self.DEFAULT_SYNC_EXPIRATION_S if not hasattr(self, "_TimeSync__last_sync_timestamp"): - self.__last_sync_timestamp: Optional[float] = None + self.__last_sync_timestamp: None | float = None if not hasattr(self, "_TimeSync__offset"): - self.__offset: Optional[float] = None + self.__offset: None | float = None if samples_number is not None: self.samples_number = samples_number if sync_expiration is not None: @@ -246,7 +247,7 @@ def sync_expiration(self) -> float: return self.__sync_expiration @sync_expiration.setter - def sync_expiration(self, value: Union[int, float]) -> None: + def sync_expiration(self, value: float | int) -> None: """ Set time in seconds after which synchronization value is considered outdated. @@ -262,7 +263,7 @@ def sync_expiration(self, value: Union[int, float]) -> None: self.__sync_expiration = float(value) @property - def last_sync_timestamp(self) -> Optional[float]: + def last_sync_timestamp(self) -> None | float: """Value of performance counter for the last synchronization point.""" return self.__last_sync_timestamp @@ -274,7 +275,7 @@ def is_sync_outdated(self) -> bool: return perf_counter() - self.last_sync_timestamp > self.sync_expiration @property - def offset(self) -> Optional[float]: + def offset(self) -> None | float: """Difference between wall clock and performance counter.""" return self.__offset @@ -296,8 +297,8 @@ def sync(self) -> float: def time_to_perf_counter(self, time_value: float, - min_value: Optional[float] = None, - max_value: Optional[float] = None) -> float: + min_value: None | float = None, + max_value: None | float = None) -> float: """ Convert wall clock time to performance counter. @@ -318,8 +319,8 @@ def time_to_perf_counter(self, def perf_counter_to_time(self, perf_counter_value: float, - min_value: Optional[float] = None, - max_value: Optional[float] = None) -> float: + min_value: None | float = None, + max_value: None | float = None) -> float: """ Convert performance counter to wall clock time.