From e8c44e85006793aac477fa607d691f563c9b5b70 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 27 Nov 2024 16:07:14 +0100 Subject: [PATCH] Linter/Formatter updatests - Added Error suffix to all exceptions as well - Removed exceptions module in cfdp --- .github/workflows/ci.yml | 10 +- CHANGELOG.md | 14 ++ docs/api/ccsds.rst | 1 + docs/api/cfdp.rst | 11 +- docs/api/cfdp_tlv.rst | 1 + docs/api/ecss.rst | 1 + pyproject.toml | 74 +++++++- release-checklist.md | 2 +- spacepackets/__init__.py | 16 +- spacepackets/ccsds/__init__.py | 27 ++- spacepackets/ccsds/spacepacket.py | 92 +++++----- spacepackets/ccsds/time/__init__.py | 10 +- spacepackets/ccsds/time/cds.py | 48 ++--- spacepackets/ccsds/time/common.py | 11 +- spacepackets/cfdp/__init__.py | 72 ++++++-- spacepackets/cfdp/conf.py | 23 ++- spacepackets/cfdp/defs.py | 16 +- spacepackets/cfdp/exceptions.py | 18 -- spacepackets/cfdp/lv.py | 19 +- spacepackets/cfdp/pdu/__init__.py | 29 +++- spacepackets/cfdp/pdu/ack.py | 28 +-- spacepackets/cfdp/pdu/eof.py | 27 +-- spacepackets/cfdp/pdu/file_data.py | 56 +++--- spacepackets/cfdp/pdu/file_directive.py | 50 +++--- spacepackets/cfdp/pdu/finished.py | 76 ++++---- spacepackets/cfdp/pdu/header.py | 92 +++++----- spacepackets/cfdp/pdu/helper.py | 87 ++++------ spacepackets/cfdp/pdu/keep_alive.py | 28 +-- spacepackets/cfdp/pdu/metadata.py | 72 ++++---- spacepackets/cfdp/pdu/nak.py | 48 +++-- spacepackets/cfdp/pdu/prompt.py | 9 +- spacepackets/cfdp/tlv/__init__.py | 90 +++++++--- spacepackets/cfdp/tlv/base.py | 16 +- spacepackets/cfdp/tlv/defs.py | 8 + spacepackets/cfdp/tlv/holder.py | 11 +- spacepackets/cfdp/tlv/msg_to_user.py | 78 ++++----- spacepackets/cfdp/tlv/tlv.py | 106 +++++------ spacepackets/countdown.py | 17 +- spacepackets/ecss/__init__.py | 34 +++- spacepackets/ecss/exceptions.py | 2 - spacepackets/ecss/fields.py | 7 +- spacepackets/ecss/pus_17_test.py | 14 +- spacepackets/ecss/pus_1_verification.py | 106 +++++------ spacepackets/ecss/pus_verificator.py | 34 ++-- spacepackets/ecss/req_id.py | 17 +- spacepackets/ecss/tc.py | 59 +++---- spacepackets/ecss/tm.py | 118 +++++-------- spacepackets/exceptions.py | 4 +- spacepackets/seqcount.py | 17 +- spacepackets/uslp/__init__.py | 25 ++- spacepackets/uslp/defs.py | 14 +- spacepackets/uslp/frame.py | 174 ++++++++----------- spacepackets/uslp/header.py | 49 ++---- spacepackets/util.py | 154 +++++++--------- tests/ccsds/test_sp_parser.py | 30 +--- tests/ccsds/test_space_packet.py | 31 ++-- tests/ccsds/test_time.py | 13 +- tests/cfdp/pdus/test_ack_pdu.py | 17 +- tests/cfdp/pdus/test_directive.py | 2 +- tests/cfdp/pdus/test_eof_pdu.py | 12 +- tests/cfdp/pdus/test_factory.py | 30 ++-- tests/cfdp/pdus/test_file_data.py | 36 ++-- tests/cfdp/pdus/test_finished_pdu.py | 26 +-- tests/cfdp/pdus/test_keep_alive_pdu.py | 2 +- tests/cfdp/pdus/test_metadata.py | 75 ++++---- tests/cfdp/pdus/test_nak_pdu.py | 35 +--- tests/cfdp/pdus/test_pdu_holder.py | 24 +-- tests/cfdp/pdus/test_prompt_pdu.py | 6 +- tests/cfdp/test_cfdp.py | 2 +- tests/cfdp/test_header.py | 40 ++--- tests/cfdp/test_transaction_id.py | 9 +- tests/cfdp/tlvslvs/test_dir_params.py | 11 +- tests/cfdp/tlvslvs/test_entity_id.py | 10 +- tests/cfdp/tlvslvs/test_fault_handler_tlv.py | 8 +- tests/cfdp/tlvslvs/test_flow_label_tlv.py | 10 +- tests/cfdp/tlvslvs/test_fs_req_tlv.py | 24 +-- tests/cfdp/tlvslvs/test_fs_response.py | 14 +- tests/cfdp/tlvslvs/test_lvs.py | 2 +- tests/cfdp/tlvslvs/test_msg_to_user.py | 6 +- tests/cfdp/tlvslvs/test_proxy.py | 14 +- tests/cfdp/tlvslvs/test_reserved_cfdp_msg.py | 104 ++++------- tests/cfdp/tlvslvs/test_tlvs.py | 23 +-- tests/ecss/common.py | 2 +- tests/ecss/test_pus_tc.py | 12 +- tests/ecss/test_pus_tm.py | 67 +++---- tests/ecss/test_srv1.py | 56 +++--- tests/ecss/test_srv17.py | 17 +- tests/test_countdown.py | 5 +- tests/test_misc.py | 1 + tests/test_pus_verificator.py | 39 ++--- tests/test_seq_cnt_provider.py | 5 +- tests/test_uslp.py | 109 +++++------- tests/test_util.py | 10 +- 93 files changed, 1489 insertions(+), 1672 deletions(-) delete mode 100644 spacepackets/cfdp/exceptions.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 394a6d3..f76fca0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,10 +9,10 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: ['3.9', '3.10', '3.11', '3.12'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 @@ -23,7 +23,7 @@ jobs: run: | python3 -m pip install --upgrade pip setuptools wheel pip install . - + - name: Build documentation and examples run: | pip install -r docs/requirements.txt @@ -31,7 +31,7 @@ jobs: sphinx-build -b doctest docs docs/_build - name: Lint with Ruff - uses: chartboost/ruff-action@v1 + uses: astral-sh/ruff-action@v1 - name: Run tests and generate coverage data run: | @@ -39,7 +39,7 @@ jobs: coverage run -m pytest - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} flags: unittests diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ee324c..3db893a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # [unreleased] +# [v0.26.0] 2024-11-27 + +## Changed + +- `MetadataPdu` options have to be specified as an optional list of abstract TLVs now. + A new getter method `options_as_tlv` can be used to retrieve a list of concrete TLV objects. +- All exceptions has an `*Error` suffix now +- Removed `exceptions` module in CFDP and moved it to individual `defs` definition modules. + The Errors can still be directly imported from `spacepackets.cfdp` or `spacepackets.cfdp.tlv`. + +## Fixed + +- `CrcError` exception constructor was previously named `__int__` by accident. + # [v0.25.0] 2024-10-29 ## Changed diff --git a/docs/api/ccsds.rst b/docs/api/ccsds.rst index 5456116..1e51034 100644 --- a/docs/api/ccsds.rst +++ b/docs/api/ccsds.rst @@ -5,6 +5,7 @@ CCSDS Package :members: :undoc-members: :show-inheritance: + :no-index: Spacepacket Module ------------------------------------- diff --git a/docs/api/cfdp.rst b/docs/api/cfdp.rst index f7a9b73..9569c1f 100644 --- a/docs/api/cfdp.rst +++ b/docs/api/cfdp.rst @@ -1,4 +1,4 @@ -CFDP Package +CFDP Package ========================== Package Contents @@ -8,6 +8,7 @@ Package Contents :members: :undoc-members: :show-inheritance: + :no-index: PDU Submodule ---------------- @@ -43,11 +44,3 @@ Common Definitions :members: :undoc-members: :show-inheritance: - -Exceptions -------------------------------------- - -.. automodule:: spacepackets.cfdp.exceptions - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/api/cfdp_tlv.rst b/docs/api/cfdp_tlv.rst index 8ed1ea0..d4e4bd2 100644 --- a/docs/api/cfdp_tlv.rst +++ b/docs/api/cfdp_tlv.rst @@ -5,6 +5,7 @@ CFDP Type-Length-Value (TLV) Subpackage :members: :undoc-members: :show-inheritance: + :no-index: Definitions Module -------------------- diff --git a/docs/api/ecss.rst b/docs/api/ecss.rst index 5b1dbf0..8021372 100644 --- a/docs/api/ecss.rst +++ b/docs/api/ecss.rst @@ -5,6 +5,7 @@ ECSS Package :members: :undoc-members: :show-inheritance: + :no-index: .. automodule:: spacepackets.ecss.defs :members: diff --git a/pyproject.toml b/pyproject.toml index 2593148..81ea59d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,8 +6,8 @@ build-backend = "setuptools.build_meta" name = "spacepackets" description = "Various CCSDS and ECSS packet implementations" readme = "README.md" -version = "0.25.0" -requires-python = ">=3.8" +version = "0.26.0" +requires-python = ">=3.9" license = {text = "Apache-2.0"} authors = [ {name = "Robin Mueller", email = "robin.mueller.m@gmail.com"} @@ -38,7 +38,73 @@ dependencies = [ [tool.setuptools.packages] find = {} +[tool.ruff] +exclude = [ + ".git", + "venv", + "docs" +] +line-length = 100 + [tool.ruff.lint] -ignore = ["E501"] +select = [ + # See https://docs.astral.sh/ruff/rules/ + "F", # pyflakes + "E", # pycodestyle + "W", # pycodestyle + "I", # isort + "N", # pep8-naming + # "D", # pydocstyle (documentation!) + "ANN", # flake8-annotations + "UP", # pyupgrade + "ASYNC", # flake8-async + "S", # flake8-bandit + "B", # flake8-bugbear + "A", # flake8-builtins + "C4", # flake8-comprehensions + "DTZ", # flake8-datetimez + "ICN", # flake8-import-conventions + "INP", # flake8-no-pep420 + "PIE", # flake8-pie + "PYI", # flake8-pyi + "RSE", # flake8-raise + "RET", # flake8-return + "SIM", # flake8-simplify + "TID", # flake8-tidy + "TCH", # flake8-type-checking + "PERF", # Performance + "FURB", # Refurb rules + "PL", # Pylint + "RUF" # ruff specific +] +ignore = [ + "S101", # Use of assert, should be changed in the future + "ANN204", # Do not use return typing on __init__, __new__ and __call__ methods + "E111", # Recommended to be disabled when using the ruff formatter + "E114", # Recommended to be disabled when using the ruff formatter + "PLR2004" # This lint is a bit too conservative. Not every number needs to be a named constant. +] + [tool.ruff.lint.extend-per-file-ignores] -"__init__.py" = ["F401"] +"tests/*" = [ + "INP001", # Tests are implicit namespace packets + "S101", # Tests use assert + "S105", # Tests use hardcoded test credentials + "S108", # Tests use temporary files names + "S311", # Tests use random without cryptographic security requirements + "ANN", # Type hints in test are not required + "PLR0912", # Too many branches + "PLR0915", # Too many statements + "PLR2004", # Magic values in comparison are common in tests + "D" # No documentation rules in tests +] +"examples/*" = [ + "INP001", # Examples are implicit namespace packets + "S101", # Examples use assert + "S104", # Possible binding to all interfaces + "S108", # Temp files + "PLR0915" # Too many statements +] + +[tool.ruff.lint.pylint] +max-args = 10 diff --git a/release-checklist.md b/release-checklist.md index d5a955b..a2bba32 100644 --- a/release-checklist.md +++ b/release-checklist.md @@ -12,7 +12,7 @@ The steps shown here are for Ubuntu/MacOS. 3. Update `CHANGELOG.md`: Convert `unreleased` section into version section with date and new `unreleased`section. 4. Run tests with `pytest .` -5. Run auto-formatter with `black .` +5. Run auto-formatter with `ruff format .` 6. Run linter with `ruff check .` 7. Wait for CI/CD results. This also runs the tests on different operating systems diff --git a/spacepackets/__init__.py b/spacepackets/__init__.py index 7fa06c3..83a5c7a 100644 --- a/spacepackets/__init__.py +++ b/spacepackets/__init__.py @@ -1,14 +1,22 @@ import logging + from spacepackets.ccsds import ( - SpacePacketHeader, - SpHeader, - SpacePacket, PacketType, SequenceFlags, + SpacePacket, + SpacePacketHeader, + SpHeader, ) - from spacepackets.exceptions import BytesTooShortError +__all__ = [ + "BytesTooShortError", + "PacketType", + "SequenceFlags", + "SpHeader", + "SpacePacket", + "SpacePacketHeader", +] __LIB_LOGGER = logging.getLogger(__name__) diff --git a/spacepackets/ccsds/__init__.py b/spacepackets/ccsds/__init__.py index c70cc40..4071275 100644 --- a/spacepackets/ccsds/__init__.py +++ b/spacepackets/ccsds/__init__.py @@ -1,15 +1,28 @@ """This package contains all CCSDS related components""" from .spacepacket import ( - SpHeader, - SpacePacketHeader, - SpacePacket, - PacketType, - SequenceFlags, + SPACE_PACKET_HEADER_SIZE, + AbstractSpacePacket, PacketId, PacketSeqCtrl, - AbstractSpacePacket, - SPACE_PACKET_HEADER_SIZE, + PacketType, + SequenceFlags, + SpacePacket, + SpacePacketHeader, + SpHeader, get_total_space_packet_len_from_len_field, ) from .time import * # noqa: F403 # re-export + +__all__ = [ + "SPACE_PACKET_HEADER_SIZE", + "AbstractSpacePacket", + "PacketId", + "PacketSeqCtrl", + "PacketType", + "SequenceFlags", + "SpHeader", + "SpacePacket", + "SpacePacketHeader", + "get_total_space_packet_len_from_len_field", +] diff --git a/spacepackets/ccsds/spacepacket.py b/spacepackets/ccsds/spacepacket.py index c14ac0f..4b5b05b 100644 --- a/spacepackets/ccsds/spacepacket.py +++ b/spacepackets/ccsds/spacepacket.py @@ -3,14 +3,17 @@ from __future__ import annotations -from abc import abstractmethod, ABC import enum import struct - -from typing import Tuple, Deque, List, Final, Optional, Sequence +from abc import ABC, abstractmethod +from typing import TYPE_CHECKING, Final from spacepackets.exceptions import BytesTooShortError +if TYPE_CHECKING: + from collections import deque + from collections.abc import Sequence + CCSDS_HEADER_LEN: Final[int] = 6 SPACE_PACKET_HEADER_SIZE: Final[int] = CCSDS_HEADER_LEN SEQ_FLAG_MASK: Final[int] = 0xC000 @@ -39,9 +42,7 @@ class PacketSeqCtrl: def __init__(self, seq_flags: SequenceFlags, seq_count: int): if seq_count > MAX_SEQ_COUNT or seq_count < 0: - raise ValueError( - f"Sequence count larger than allowed {pow(2, 14) - 1} or negative" - ) + raise ValueError(f"Sequence count larger than allowed {pow(2, 14) - 1} or negative") self.seq_flags = seq_flags self.seq_count = seq_count @@ -68,7 +69,7 @@ def raw(self) -> int: return self.seq_flags << 14 | self.seq_count @classmethod - def empty(cls): + def empty(cls) -> PacketSeqCtrl: return cls(seq_flags=SequenceFlags.CONTINUATION_SEGMENT, seq_count=0) def __eq__(self, other: object) -> bool: @@ -77,10 +78,8 @@ def __eq__(self, other: object) -> bool: return False @classmethod - def from_raw(cls, raw: int): - return cls( - seq_flags=SequenceFlags((raw >> 14) & 0b11), seq_count=raw & ~SEQ_FLAG_MASK - ) + def from_raw(cls, raw: int) -> PacketSeqCtrl: + return cls(seq_flags=SequenceFlags((raw >> 14) & 0b11), seq_count=raw & ~SEQ_FLAG_MASK) class PacketId: @@ -89,15 +88,13 @@ class PacketId: def __init__(self, ptype: PacketType, sec_header_flag: bool, apid: int): if apid > pow(2, 11) - 1 or apid < 0: - raise ValueError( - f"Invalid APID, exceeds maximum value {pow(2, 11) - 1} or negative" - ) + raise ValueError(f"Invalid APID, exceeds maximum value {pow(2, 11) - 1} or negative") self.ptype = ptype self.sec_header_flag = sec_header_flag self.apid = apid @classmethod - def empty(cls): + def empty(cls) -> PacketId: return cls(ptype=PacketType.TM, sec_header_flag=False, apid=0) def __repr__(self): @@ -172,7 +169,8 @@ def pack(self) -> bytearray: class SpacePacketHeader(AbstractSpacePacket): - """This class encapsulates the space packet header. Packet reference: Blue Book CCSDS 133.0-B-2""" + """This class encapsulates the space packet header. Packet reference: Blue Book + CCSDS 133.0-B-2""" def __init__( self, @@ -233,9 +231,7 @@ def __init__( f" {pow(2, 16) - 1} or negative" ) self._ccsds_version = ccsds_version - self._packet_id = PacketId( - ptype=packet_type, sec_header_flag=sec_header_flag, apid=apid - ) + self._packet_id = PacketId(ptype=packet_type, sec_header_flag=sec_header_flag, apid=apid) self._psc = PacketSeqCtrl(seq_flags=seq_flags, seq_count=seq_count) self.data_len = data_len @@ -328,7 +324,7 @@ def packet_type(self) -> PacketType: return self.packet_id.ptype @packet_type.setter - def packet_type(self, packet_type): + def packet_type(self, packet_type: PacketType) -> None: self.packet_id.ptype = packet_type @property @@ -344,14 +340,14 @@ def sec_header_flag(self) -> bool: return self._packet_id.sec_header_flag @sec_header_flag.setter - def sec_header_flag(self, value): + def sec_header_flag(self, value: bool) -> None: self._packet_id.sec_header_flag = value @property - def seq_count(self): + def seq_count(self) -> int: return self._psc.seq_count - def set_data_len_from_packet_len(self, packet_len: int): + def set_data_len_from_packet_len(self, packet_len: int) -> None: """Sets the data length field from the given total packet length. The total packet length must be at least 7 bytes. @@ -365,15 +361,15 @@ def set_data_len_from_packet_len(self, packet_len: int): self.data_len = packet_len - CCSDS_HEADER_LEN - 1 @seq_count.setter - def seq_count(self, seq_cnt): + def seq_count(self, seq_cnt: int) -> None: self._psc.seq_count = seq_cnt @property - def seq_flags(self): + def seq_flags(self) -> SequenceFlags: return self._psc.seq_flags @seq_flags.setter - def seq_flags(self, value): + def seq_flags(self, value: SequenceFlags) -> None: self._psc.seq_flags = value @property @@ -381,7 +377,7 @@ def header_len(self) -> int: return CCSDS_HEADER_LEN @apid.setter - def apid(self, apid): + def apid(self, apid: int) -> None: self.packet_id.apid = apid @property @@ -449,8 +445,8 @@ class SpacePacket: def __init__( self, sp_header: SpacePacketHeader, - sec_header: Optional[bytes], - user_data: Optional[bytes], + sec_header: bytes | None, + user_data: bytes | None, ): self.sp_header = sp_header self.sec_header = sec_header @@ -476,25 +472,22 @@ def pack(self) -> bytearray: "Secondary header flag is set but no secondary header was supplied" ) packet.extend(self.sec_header) - else: - if self.user_data is None: - raise ValueError( - "Secondary header not present but no user data supplied" - ) + elif self.user_data is None: + raise ValueError("Secondary header not present but no user data supplied") if self.user_data is not None: packet.extend(self.user_data) return packet @property - def apid(self): + def apid(self) -> int: return self.sp_header.apid @property - def seq_count(self): + def seq_count(self) -> int: return self.sp_header.seq_count @property - def sec_header_flag(self): + def sec_header_flag(self) -> bool: return self.sp_header.sec_header_flag def __eq__(self, other: object): @@ -512,7 +505,7 @@ def get_space_packet_id_bytes( secondary_header_flag: bool, apid: int, version: int = 0b000, -) -> Tuple[int, int]: +) -> tuple[int, int]: """This function also includes the first three bits reserved for the version. :param version: Version field of the packet ID. Defined to be 0b000 in the space packet standard @@ -532,9 +525,7 @@ def get_space_packet_id_bytes( return byte_one, byte_two -def get_sp_packet_id_raw( - packet_type: PacketType, secondary_header_flag: bool, apid: int -) -> int: +def get_sp_packet_id_raw(packet_type: PacketType, secondary_header_flag: bool, apid: int) -> int: """Get packet identification segment of packet primary header in integer format""" return PacketId(packet_type, secondary_header_flag, apid).raw() @@ -555,7 +546,7 @@ def get_apid_from_raw_space_packet(raw_packet: bytes) -> int: return ((raw_packet[0] & 0x7) << 8) | raw_packet[1] -def get_total_space_packet_len_from_len_field(len_field: int): +def get_total_space_packet_len_from_len_field(len_field: int) -> int: """Definition of length field is: C = (Octets in data field - 1). Therefore, octets in data field in len_field plus one. The total space packet length is therefore len_field plus one plus the space packet header size (6)""" @@ -563,8 +554,8 @@ def get_total_space_packet_len_from_len_field(len_field: int): def parse_space_packets( - analysis_queue: Deque[bytearray], packet_ids: Sequence[PacketId] -) -> List[bytearray]: + analysis_queue: deque[bytearray], packet_ids: Sequence[PacketId] +) -> list[bytearray]: """Given a deque of bytearrays, parse for space packets. This funtion expects the deque to be filled on the right side, for example with :py:meth:`collections.deque.append`. If a split packet with a valid header is detected, this function will re-insert the header into @@ -611,10 +602,10 @@ def parse_space_packets( def __handle_packet_id_match( concatenated_packets: bytearray, - analysis_queue: Deque[bytearray], + analysis_queue: deque[bytearray], current_idx: int, - tm_list: List[bytearray], -) -> Tuple[int, int]: + tm_list: list[bytearray], +) -> tuple[int, int]: total_packet_len = get_total_space_packet_len_from_len_field( struct.unpack("!H", concatenated_packets[current_idx + 4 : current_idx + 6])[0] ) @@ -624,9 +615,6 @@ def __handle_packet_id_match( analysis_queue.clear() analysis_queue.append(concatenated_packets[current_idx:]) return -1, current_idx - else: - tm_list.append( - concatenated_packets[current_idx : current_idx + total_packet_len] - ) - current_idx += total_packet_len + tm_list.append(concatenated_packets[current_idx : current_idx + total_packet_len]) + current_idx += total_packet_len return 0, current_idx diff --git a/spacepackets/ccsds/time/__init__.py b/spacepackets/ccsds/time/__init__.py index 2177e01..5e6011d 100644 --- a/spacepackets/ccsds/time/__init__.py +++ b/spacepackets/ccsds/time/__init__.py @@ -1,4 +1,12 @@ """This module contains the CCSDS specific time code implementations.""" -from .common import CcsdsTimeProvider, CcsdsTimeCodeId, SECONDS_PER_DAY, MS_PER_DAY from .cds import CdsShortTimestamp +from .common import MS_PER_DAY, SECONDS_PER_DAY, CcsdsTimeCodeId, CcsdsTimeProvider + +__all__ = [ + "MS_PER_DAY", + "SECONDS_PER_DAY", + "CcsdsTimeCodeId", + "CcsdsTimeProvider", + "CdsShortTimestamp", +] diff --git a/spacepackets/ccsds/time/cds.py b/spacepackets/ccsds/time/cds.py index 2b1119b..9367e30 100644 --- a/spacepackets/ccsds/time/cds.py +++ b/spacepackets/ccsds/time/cds.py @@ -1,23 +1,23 @@ from __future__ import annotations + import datetime import enum import math import struct import time -from typing import Optional, Tuple import deprecation -from spacepackets.version import get_version -from spacepackets.exceptions import BytesTooShortError from spacepackets.ccsds.time.common import ( + MS_PER_DAY, + SECONDS_PER_DAY, + CcsdsTimeCodeId, CcsdsTimeProvider, convert_ccsds_days_to_unix_days, - SECONDS_PER_DAY, convert_unix_days_to_ccsds_days, - CcsdsTimeCodeId, - MS_PER_DAY, ) +from spacepackets.exceptions import BytesTooShortError +from spacepackets.version import get_version class LenOfDaysSegment(enum.IntEnum): @@ -45,9 +45,7 @@ class CdsShortTimestamp(CcsdsTimeProvider): CDS_SHORT_ID = 0b100 TIMESTAMP_SIZE = 7 - def __init__( - self, ccsds_days: int, ms_of_day: int, init_dt_unix_stamp: bool = True - ): + def __init__(self, ccsds_days: int, ms_of_day: int, init_dt_unix_stamp: bool = True): """Create a stamp from the contained values directly. >>> zero_stamp = CdsShortTimestamp(ccsds_days=0, ms_of_day=0) @@ -60,7 +58,7 @@ def __init__( -4383 >>> CdsShortTimestamp(0x0102, 0x03040506).pack().hex(sep=',') '40,01,02,03,04,05,06' - """ + """ # noqa: E501 self.__p_field = bytes([CdsShortTimestamp.CDS_SHORT_ID << 4]) # CCSDS recommends a 1958 Januar 1 epoch, which is different from the Unix epoch self._ccsds_days = ccsds_days @@ -69,11 +67,11 @@ def __init__( if init_dt_unix_stamp: self._setup() - def _setup(self): + def _setup(self) -> None: self._calculate_unix_seconds() self._calculate_date_time() - def _calculate_unix_seconds(self): + def _calculate_unix_seconds(self) -> None: unix_days = convert_ccsds_days_to_unix_days(self._ccsds_days) self._unix_seconds = unix_days * SECONDS_PER_DAY seconds_of_day = self._ms_of_day / 1000.0 @@ -82,7 +80,7 @@ def _calculate_unix_seconds(self): else: self._unix_seconds += seconds_of_day - def _calculate_date_time(self): + def _calculate_date_time(self) -> None: if self._unix_seconds < 0: self._datetime = datetime.datetime( 1970, 1, 1, tzinfo=datetime.timezone.utc @@ -123,7 +121,7 @@ def from_unix_days(cls, unix_days: int, ms_of_day: int) -> CdsShortTimestamp: ) @classmethod - def empty(cls, init_dt_unix_stamp: bool = True): + def empty(cls, init_dt_unix_stamp: bool = True) -> CdsShortTimestamp: """Empty instance containing only zero for all fields. :return: @@ -135,7 +133,7 @@ def unpack(cls, data: bytes) -> CdsShortTimestamp: ccsds_days, ms_of_day = CdsShortTimestamp.unpack_from_raw(data) return cls(ccsds_days=ccsds_days, ms_of_day=ms_of_day) - def read_from_raw(self, data: bytes): + def read_from_raw(self, data: bytes) -> CdsShortTimestamp: """Updates the instance from a given raw CDS short timestamp :param data: @@ -145,19 +143,15 @@ def read_from_raw(self, data: bytes): self._setup() @staticmethod - def unpack_from_raw(data: bytes) -> Tuple[int, int]: + def unpack_from_raw(data: bytes) -> tuple[int, int]: if len(data) < CdsShortTimestamp.TIMESTAMP_SIZE: raise BytesTooShortError(CdsShortTimestamp.TIMESTAMP_SIZE, len(data)) p_field = data[0] if (p_field >> 4) & 0b111 != CcsdsTimeCodeId.CDS: - raise ValueError( - f"invalid CCSDS Time Code {p_field}, expected {CcsdsTimeCodeId.CDS}" - ) + raise ValueError(f"invalid CCSDS Time Code {p_field}, expected {CcsdsTimeCodeId.CDS}") len_of_day = len_of_day_seg_from_pfield(p_field) if len_of_day != LenOfDaysSegment.DAYS_16_BITS: - raise ValueError( - f"invalid length of days field {len_of_day} for CDS short timestamp" - ) + raise ValueError(f"invalid length of days field {len_of_day} for CDS short timestamp") ccsds_days = struct.unpack("!H", data[1:3])[0] ms_of_day = struct.unpack("!I", data[3:7])[0] return ccsds_days, ms_of_day @@ -173,9 +167,7 @@ def __str__(self): def __eq__(self, other: object): if isinstance(other, CdsShortTimestamp): - return (self.ccsds_days == other.ccsds_days) and ( - self.ms_of_day == other.ms_of_day - ) + return (self.ccsds_days == other.ccsds_days) and (self.ms_of_day == other.ms_of_day) return False def __add__(self, timedelta: datetime.timedelta): @@ -248,13 +240,11 @@ def from_date_time(cls, dt: datetime.datetime) -> CdsShortTimestamp: return cls.from_datetime(dt) @staticmethod - def ms_of_today(seconds_since_epoch: Optional[float] = None): + def ms_of_today(seconds_since_epoch: float | None = None) -> int: if seconds_since_epoch is None: seconds_since_epoch = time.time() fraction_ms = seconds_since_epoch - math.floor(seconds_since_epoch) - return int( - math.floor((seconds_since_epoch % SECONDS_PER_DAY) * 1000 + fraction_ms) - ) + return int(math.floor((seconds_since_epoch % SECONDS_PER_DAY) * 1000 + fraction_ms)) def as_unix_seconds(self) -> float: return self._unix_seconds diff --git a/spacepackets/ccsds/time/common.py b/spacepackets/ccsds/time/common.py index e1b8f24..981fd58 100644 --- a/spacepackets/ccsds/time/common.py +++ b/spacepackets/ccsds/time/common.py @@ -1,11 +1,13 @@ from __future__ import annotations + import datetime import enum -from abc import abstractmethod, ABC -from spacepackets.version import get_version +from abc import ABC, abstractmethod import deprecation +from spacepackets.version import get_version + #: The day offset to convert from CCSDS days to UNIX days. DAYS_CCSDS_TO_UNIX = -4383 #: Seconds per days as integer @@ -76,7 +78,7 @@ def pack(self) -> bytes: pass @abstractmethod - def read_from_raw(self, timestamp: bytes): + def read_from_raw(self, timestamp: bytes) -> CcsdsTimeProvider: pass @abstractmethod @@ -96,13 +98,12 @@ def as_date_time(self) -> datetime.datetime: """Retrieve a :py:class:`datetime.datetime` with the :py:class:`datetime.timezone` set to utc. """ - pass def as_time_string(self) -> str: return self.as_date_time().strftime("%Y-%m-%d %H:%M:%S.%f") def ccsds_time_code(self) -> int: - if self.pfield == bytes(): + if self.pfield == b"": return 0 return (self.pfield[0] >> 4) & 0b111 diff --git a/spacepackets/cfdp/__init__.py b/spacepackets/cfdp/__init__.py index a421424..08e935d 100644 --- a/spacepackets/cfdp/__init__.py +++ b/spacepackets/cfdp/__init__.py @@ -10,36 +10,74 @@ unacknowledged file transfer on the :ref:`example ` page. """ +from .conf import PduConfig from .defs import ( - PduType, + NULL_CHECKSUM_U32, ChecksumType, - Direction, + ConditionCode, CrcFlag, + DeliveryCode, + Direction, + FaultHandlerCode, + FileStatus, + InvalidCrcError, LargeFileFlag, + PduType, SegmentationControl, SegmentMetadataFlag, - TransmissionMode, - ConditionCode, - FaultHandlerCode, TransactionId, - FileStatus, - DeliveryCode, - NULL_CHECKSUM_U32, + TransmissionMode, ) +from .lv import CfdpLv +from .pdu import DirectiveType, FinishedParams, GenericPduPacket, PduFactory, PduHolder from .tlv import ( CfdpTlv, EntityIdTlv, - TlvType, - MessageToUserTlv, - FileStoreRequestTlv, - FileStoreResponseTlv, - FlowLabelTlv, FaultHandlerOverrideTlv, FilestoreActionCode, + FileStoreRequestTlv, FilestoreResponseStatusCode, + FileStoreResponseTlv, + FlowLabelTlv, + MessageToUserTlv, TlvHolder, + TlvType, + TlvTypeMissmatchError, ) -from .lv import CfdpLv -from .conf import PduConfig -from .pdu import DirectiveType, PduHolder, PduFactory, GenericPduPacket, FinishedParams -from .exceptions import TlvTypeMissmatch, InvalidCrc + +__all__ = [ + "NULL_CHECKSUM_U32", + "CfdpLv", + "CfdpTlv", + "ChecksumType", + "ConditionCode", + "CrcFlag", + "DeliveryCode", + "Direction", + "DirectiveType", + "EntityIdTlv", + "FaultHandlerCode", + "FaultHandlerOverrideTlv", + "FileStatus", + "FileStoreRequestTlv", + "FileStoreResponseTlv", + "FilestoreActionCode", + "FilestoreResponseStatusCode", + "FinishedParams", + "FlowLabelTlv", + "GenericPduPacket", + "InvalidCrcError", + "LargeFileFlag", + "MessageToUserTlv", + "PduConfig", + "PduFactory", + "PduHolder", + "PduType", + "SegmentMetadataFlag", + "SegmentationControl", + "TlvHolder", + "TlvType", + "TlvTypeMissmatchError", + "TransactionId", + "TransmissionMode", +] diff --git a/spacepackets/cfdp/conf.py b/spacepackets/cfdp/conf.py index 27eb97b..4e2c53e 100644 --- a/spacepackets/cfdp/conf.py +++ b/spacepackets/cfdp/conf.py @@ -1,15 +1,16 @@ from __future__ import annotations + from dataclasses import dataclass -from typing import TypedDict, Tuple +from typing import TypedDict from spacepackets.cfdp.defs import ( - TransmissionMode, - LargeFileFlag, CrcFlag, Direction, + LargeFileFlag, SegmentationControl, + TransmissionMode, ) -from spacepackets.util import UnsignedByteField, ByteFieldU8, ByteFieldEmpty +from spacepackets.util import ByteFieldEmpty, ByteFieldU8, UnsignedByteField @dataclass @@ -23,9 +24,7 @@ class PduConfig: file_flag: LargeFileFlag = LargeFileFlag.NORMAL crc_flag: CrcFlag = CrcFlag.NO_CRC direction: Direction = Direction.TOWARDS_RECEIVER - seg_ctrl: SegmentationControl = ( - SegmentationControl.NO_RECORD_BOUNDARIES_PRESERVATION - ) + seg_ctrl: SegmentationControl = SegmentationControl.NO_RECORD_BOUNDARIES_PRESERVATION @classmethod def empty(cls) -> PduConfig: @@ -42,7 +41,7 @@ def empty(cls) -> PduConfig: ) @classmethod - def default(cls): + def default(cls) -> PduConfig: """Valid PDU configuration""" return PduConfig( transaction_seq_num=ByteFieldU8(0), @@ -63,19 +62,19 @@ def header_len(self) -> int: class CfdpDict(TypedDict): - source_dest_entity_ids: Tuple[bytes, bytes] + source_dest_entity_ids: tuple[bytes, bytes] # TODO: Protect dict access with a dedicated lock for thread-safety __CFDP_DICT: CfdpDict = { - "source_dest_entity_ids": (bytes(), bytes()), + "source_dest_entity_ids": (b"", b""), } -def set_entity_ids(source_entity_id: bytes, dest_entity_id: bytes): +def set_entity_ids(source_entity_id: bytes, dest_entity_id: bytes) -> None: __CFDP_DICT["source_dest_entity_ids"] = (source_entity_id, dest_entity_id) -def get_entity_ids() -> Tuple[bytes, bytes]: +def get_entity_ids() -> tuple[bytes, bytes]: """Return a tuple where the first entry is the source entity ID""" return __CFDP_DICT["source_dest_entity_ids"] diff --git a/spacepackets/cfdp/defs.py b/spacepackets/cfdp/defs.py index e119d05..db51c9b 100644 --- a/spacepackets/cfdp/defs.py +++ b/spacepackets/cfdp/defs.py @@ -1,14 +1,17 @@ from __future__ import annotations -from spacepackets.util import UnsignedByteField + import enum +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from spacepackets.util import UnsignedByteField CFDP_VERSION_2_NAME = "CCSDS 727.0-B-5" # Second version of the protocol, only this one is supported here CFDP_VERSION_2 = 0b001 -class UnsupportedCfdpVersion(Exception): +class UnsupportedCfdpVersionError(Exception): def __init__(self, version: int): self.version = version @@ -152,3 +155,12 @@ def __hash__(self): NULL_CHECKSUM_U32 = bytes([0x00, 0x00, 0x00, 0x00]) + + +class InvalidCrcError(Exception): + def __init__(self, crc16: int, message: str | None = None): + self.crc16 = crc16 + self.message = message + if self.message is None: + self.message = f"invalid crc with value {crc16:#04x} detected" + super().__init__(self.message) diff --git a/spacepackets/cfdp/exceptions.py b/spacepackets/cfdp/exceptions.py deleted file mode 100644 index 98c0949..0000000 --- a/spacepackets/cfdp/exceptions.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Optional -from spacepackets.cfdp.tlv.defs import TlvType - - -class InvalidCrc(Exception): - def __int__(self, crc16: int, message: Optional[str] = None): - self.crc16 = crc16 - self.message = message - if self.message is None: - self.message = f"invalid crc with value {crc16:#04x} detected" - super().__init__(self.message) - - -class TlvTypeMissmatch(Exception): - def __init__(self, found: TlvType, expected: TlvType): - self.found = found - self.expected = expected - super().__init__(f"Expected TLV {self.expected}, found {self.found}") diff --git a/spacepackets/cfdp/lv.py b/spacepackets/cfdp/lv.py index e440ec4..f5105a4 100644 --- a/spacepackets/cfdp/lv.py +++ b/spacepackets/cfdp/lv.py @@ -1,5 +1,9 @@ from __future__ import annotations -from pathlib import Path + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pathlib import Path class CfdpLv: @@ -26,7 +30,7 @@ def from_path(cls, path: Path) -> CfdpLv: return cls.from_str(str(path)) @property - def packet_len(self): + def packet_len(self) -> int: """Returns length of full LV packet""" return self.value_len + 1 @@ -47,17 +51,16 @@ def unpack(cls, raw_bytes: bytes) -> CfdpLv: if 1 + detected_len > len(raw_bytes): raise ValueError("Detected length exceeds size of passed bytearray") if detected_len == 0: - return cls(value=bytes()) + return cls(value=b"") return cls(value=raw_bytes[1 : 1 + detected_len]) def __repr__(self): return f"{self.__class__.__name__}(value={self.value!r})" def __str__(self): - return ( - f"CFDP LV with data 0x[{self.value.hex(sep=',')}] of length" - f" {len(self.value)}" - ) + return f"CFDP LV with data 0x[{self.value.hex(sep=',')}] of length" f" {len(self.value)}" - def __eq__(self, other): + def __eq__(self, other: object): + if not isinstance(other, CfdpLv): + return False return self.value == other.value diff --git a/spacepackets/cfdp/pdu/__init__.py b/spacepackets/cfdp/pdu/__init__.py index f828ed9..e823027 100644 --- a/spacepackets/cfdp/pdu/__init__.py +++ b/spacepackets/cfdp/pdu/__init__.py @@ -7,7 +7,7 @@ from .ack import AckPdu, TransactionStatus from .eof import EofPdu -from .file_data import FileDataPdu, FileDataParams +from .file_data import FileDataParams, FileDataPdu from .file_directive import ( AbstractFileDirectiveBase, DirectiveType, @@ -20,3 +20,30 @@ from .metadata import MetadataParams, MetadataPdu from .nak import NakPdu from .prompt import PromptPdu + +__all__ = [ + "AbstractFileDirectiveBase", + "AckPdu", + "DeliveryCode", + "DirectiveType", + "EofPdu", + "FileDataParams", + "FileDataPdu", + "FileDirectivePduBase", + "FileStatus", + "FinishedParams", + "FinishedPdu", + "GenericPduPacket", + "KeepAlivePdu", + "MetadataParams", + "MetadataPdu", + "NakPdu", + "PduConfig", + "PduFactory", + "PduHeader", + "PduHolder", + "PduType", + "PromptPdu", + "SegmentMetadataFlag", + "TransactionStatus", +] diff --git a/spacepackets/cfdp/pdu/ack.py b/spacepackets/cfdp/pdu/ack.py index ea68cf4..8f89c02 100644 --- a/spacepackets/cfdp/pdu/ack.py +++ b/spacepackets/cfdp/pdu/ack.py @@ -1,18 +1,22 @@ from __future__ import annotations -import enum + import copy +import enum import struct +from typing import TYPE_CHECKING -from spacepackets.cfdp.pdu.header import PduHeader +from spacepackets.cfdp.conf import PduConfig +from spacepackets.cfdp.defs import ConditionCode, CrcFlag, Direction from spacepackets.cfdp.pdu.file_directive import ( - FileDirectivePduBase, - DirectiveType, AbstractFileDirectiveBase, + DirectiveType, + FileDirectivePduBase, ) -from spacepackets.cfdp.defs import ConditionCode, CrcFlag, Direction -from spacepackets.cfdp.conf import PduConfig from spacepackets.crc import CRC16_CCITT_FUNC +if TYPE_CHECKING: + from spacepackets.cfdp.pdu.header import PduHeader + class TransactionStatus(enum.IntEnum): """For more detailed information: CCSDS 727.0-B-5 p.81""" @@ -46,9 +50,7 @@ def __init__( DirectiveType.FINISHED_PDU, DirectiveType.EOF_PDU, ]: - raise ValueError( - f"invalid directive code of acked PDU {directive_code_of_acked_pdu}" - ) + raise ValueError(f"invalid directive code of acked PDU {directive_code_of_acked_pdu}") self.directive_code_of_acked_pdu = directive_code_of_acked_pdu self.directive_subtype_code = 0 if self.directive_code_of_acked_pdu == DirectiveType.FINISHED_PDU: @@ -96,15 +98,13 @@ def __empty(cls) -> AckPdu: def pack(self) -> bytearray: packet = self.pdu_file_directive.pack() - packet.append( - (self.directive_code_of_acked_pdu << 4) | self.directive_subtype_code - ) + packet.append((self.directive_code_of_acked_pdu << 4) | self.directive_subtype_code) packet.append((self.condition_code_of_acked_pdu << 4) | self.transaction_status) if self.pdu_file_directive.pdu_conf.crc_flag == CrcFlag.WITH_CRC: packet.extend(struct.pack("!H", CRC16_CCITT_FUNC(packet))) return packet - def _calculate_directive_field_len(self): + def _calculate_directive_field_len(self) -> None: directive_param_field_len = 2 if self.pdu_file_directive.pdu_conf.crc_flag == CrcFlag.WITH_CRC: directive_param_field_len += 2 @@ -130,7 +130,7 @@ def unpack(cls, data: bytes) -> AckPdu: Raw data too short for expected object. ValueError Invalid directive type or data format. - InvalidCrc + InvalidCrcError PDU has a 16 bit CRC and the CRC check failed. """ diff --git a/spacepackets/cfdp/pdu/eof.py b/spacepackets/cfdp/pdu/eof.py index 0eda183..58f53ef 100644 --- a/spacepackets/cfdp/pdu/eof.py +++ b/spacepackets/cfdp/pdu/eof.py @@ -1,20 +1,23 @@ from __future__ import annotations -import struct + import copy -from typing import Optional +import struct +from typing import TYPE_CHECKING -from spacepackets.cfdp.pdu.header import PduHeader +from spacepackets.cfdp.conf import PduConfig +from spacepackets.cfdp.defs import ConditionCode, CrcFlag, Direction from spacepackets.cfdp.pdu.file_directive import ( - FileDirectivePduBase, - DirectiveType, AbstractFileDirectiveBase, + DirectiveType, + FileDirectivePduBase, ) -from spacepackets.cfdp.defs import ConditionCode, CrcFlag, Direction -from spacepackets.cfdp.conf import PduConfig from spacepackets.cfdp.tlv.tlv import EntityIdTlv from spacepackets.crc import CRC16_CCITT_FUNC from spacepackets.exceptions import BytesTooShortError +if TYPE_CHECKING: + from spacepackets.cfdp.pdu.header import PduHeader + class EofPdu(AbstractFileDirectiveBase): """Encapsulates the EOF file directive PDU, see CCSDS 727.0-B-5 p.79""" @@ -24,7 +27,7 @@ def __init__( pdu_conf: PduConfig, file_checksum: bytes, file_size: int, - fault_location: Optional[EntityIdTlv] = None, + fault_location: EntityIdTlv | None = None, condition_code: ConditionCode = ConditionCode.NO_ERROR, ): """Constructor for an EOF PDU. @@ -77,15 +80,15 @@ def packet_len(self) -> int: return self.pdu_file_directive.packet_len @property - def fault_location(self): + def fault_location(self) -> EntityIdTlv | None: return self._fault_location @fault_location.setter - def fault_location(self, fault_location: Optional[EntityIdTlv]): + def fault_location(self, fault_location: EntityIdTlv | None) -> None: self._fault_location = fault_location self._calculate_directive_param_field_len() - def _calculate_directive_param_field_len(self): + def _calculate_directive_param_field_len(self) -> None: directive_param_field_len = 9 if self.pdu_file_directive.pdu_header.large_file_flag_set: directive_param_field_len = 13 @@ -130,7 +133,7 @@ def unpack(cls, data: bytes) -> EofPdu: Raw data too short for expected object. ValueError Invalid directive type or data format. - InvalidCrc + InvalidCrcError PDU has a 16 bit CRC and the CRC check failed. """ eof_pdu = cls.__empty() diff --git a/spacepackets/cfdp/pdu/file_data.py b/spacepackets/cfdp/pdu/file_data.py index dc325c7..ee61b0c 100644 --- a/spacepackets/cfdp/pdu/file_data.py +++ b/spacepackets/cfdp/pdu/file_data.py @@ -1,25 +1,28 @@ from __future__ import annotations -import enum + import copy -from dataclasses import dataclass -from typing import Optional +import enum import struct +from dataclasses import dataclass +from typing import TYPE_CHECKING -from spacepackets.cfdp import LargeFileFlag, CrcFlag -from spacepackets.cfdp.defs import Direction, TransmissionMode -from spacepackets.cfdp.pdu.file_directive import SegmentMetadataFlag, PduType +from spacepackets.cfdp import CrcFlag, LargeFileFlag from spacepackets.cfdp.conf import PduConfig -from spacepackets.cfdp.pdu.header import PduHeader, AbstractPduBase +from spacepackets.cfdp.defs import Direction, TransmissionMode +from spacepackets.cfdp.pdu.file_directive import PduType, SegmentMetadataFlag +from spacepackets.cfdp.pdu.header import AbstractPduBase, PduHeader from spacepackets.crc import CRC16_CCITT_FUNC from spacepackets.exceptions import BytesTooShortError -from spacepackets.util import UnsignedByteField + +if TYPE_CHECKING: + from spacepackets.util import UnsignedByteField def get_max_file_seg_len_for_max_packet_len_and_pdu_cfg( pdu_conf: PduConfig, max_packet_len: int, - segment_metadata: Optional[SegmentMetadata] = None, -): + segment_metadata: SegmentMetadata | None = None, +) -> int: """This function can be used to calculate the maximum allowed file segment size for a given maximum packet length and the segment metadata if there is any.""" subtract = pdu_conf.header_len() @@ -32,9 +35,7 @@ def get_max_file_seg_len_for_max_packet_len_and_pdu_cfg( if pdu_conf.crc_flag == CrcFlag.WITH_CRC: subtract += 2 if max_packet_len < subtract: - raise ValueError( - f"max packet length {max_packet_len} can not even hold base packet" - ) + raise ValueError(f"max packet length {max_packet_len} can not even hold base packet") return max_packet_len - subtract @@ -62,11 +63,11 @@ class SegmentMetadata: class FileDataParams: file_data: bytes offset: int - segment_metadata: Optional[SegmentMetadata] = None + segment_metadata: SegmentMetadata | None = None @classmethod def empty(cls) -> FileDataParams: - return cls(file_data=bytes(), offset=0) + return cls(file_data=b"", offset=0) class FileDataPdu(AbstractPduBase): @@ -141,17 +142,17 @@ def dest_entity_id(self) -> UnsignedByteField: return self.pdu_header.dest_entity_id @property - def record_cont_state(self) -> Optional[RecordContinuationState]: + def record_cont_state(self) -> RecordContinuationState | None: if self._params.segment_metadata is None: return None return self._params.segment_metadata.record_cont_state @property - def offset(self): + def offset(self) -> int: return self._params.offset @property - def crc_flag(self): + def crc_flag(self) -> CrcFlag: return self.pdu_header.crc_flag @property @@ -159,11 +160,11 @@ def has_segment_metadata(self) -> bool: return self._pdu_header.segment_metadata_flag == SegmentMetadataFlag.PRESENT @property - def segment_metadata(self) -> Optional[SegmentMetadata]: + def segment_metadata(self) -> SegmentMetadata | None: return self._params.segment_metadata @segment_metadata.setter - def segment_metadata(self, segment_metadata: Optional[SegmentMetadata]): + def segment_metadata(self, segment_metadata: SegmentMetadata | None) -> None: self._params.segment_metadata = segment_metadata if segment_metadata is None: self._pdu_header.segment_metadata_flag = SegmentMetadataFlag.NOT_PRESENT @@ -172,15 +173,15 @@ def segment_metadata(self, segment_metadata: Optional[SegmentMetadata]): self._calculate_pdu_data_field_len() @property - def file_data(self): + def file_data(self) -> bytes: return self._params.file_data @file_data.setter - def file_data(self, file_data: bytes): + def file_data(self, file_data: bytes) -> None: self._params.file_data = file_data self._calculate_pdu_data_field_len() - def _calculate_pdu_data_field_len(self): + def _calculate_pdu_data_field_len(self) -> None: pdu_data_field_len = 0 if self.segment_metadata is not None: pdu_data_field_len = 1 + len(self.segment_metadata.metadata) @@ -199,12 +200,9 @@ def pack(self) -> bytearray: len_metadata = len(self.segment_metadata.metadata) if len_metadata > 63: raise ValueError( - f"Segment metadata length {len_metadata} invalid, larger than 63" - " bytes" + f"Segment metadata length {len_metadata} invalid, larger than 63" " bytes" ) - file_data_pdu.append( - self.segment_metadata.record_cont_state << 6 | len_metadata - ) + file_data_pdu.append(self.segment_metadata.record_cont_state << 6 | len_metadata) if len_metadata > 0: file_data_pdu.extend(self.segment_metadata.metadata) if not self.pdu_header.large_file_flag_set: @@ -262,7 +260,7 @@ def unpack(cls, data: bytes) -> FileDataPdu: return file_data_packet @property - def packet_len(self): + def packet_len(self) -> int: return self.pdu_header.packet_len def __eq__(self, other: FileDataPdu): diff --git a/spacepackets/cfdp/pdu/file_directive.py b/spacepackets/cfdp/pdu/file_directive.py index 8281356..528418e 100644 --- a/spacepackets/cfdp/pdu/file_directive.py +++ b/spacepackets/cfdp/pdu/file_directive.py @@ -1,20 +1,22 @@ from __future__ import annotations -from typing import Tuple import abc import enum import struct +from typing import TYPE_CHECKING +from spacepackets.cfdp.conf import PduConfig +from spacepackets.cfdp.defs import CrcFlag, Direction, LargeFileFlag, TransmissionMode from spacepackets.cfdp.pdu.header import ( + AbstractPduBase, PduHeader, PduType, SegmentMetadataFlag, - AbstractPduBase, ) -from spacepackets.cfdp.defs import Direction, LargeFileFlag, CrcFlag, TransmissionMode -from spacepackets.cfdp.conf import PduConfig from spacepackets.exceptions import BytesTooShortError -from spacepackets.util import UnsignedByteField + +if TYPE_CHECKING: + from spacepackets.util import UnsignedByteField class DirectiveType(enum.IntEnum): @@ -53,19 +55,19 @@ def transmission_mode(self) -> TransmissionMode: return self.pdu_header.transmission_mode @file_flag.setter - def file_flag(self, field_len: LargeFileFlag): + def file_flag(self, field_len: LargeFileFlag) -> None: self.pdu_header.file_flag = field_len @property - def crc_flag(self): + def crc_flag(self) -> CrcFlag: return self.pdu_header.crc_flag @crc_flag.setter - def crc_flag(self, crc_flag: CrcFlag): + def crc_flag(self, crc_flag: CrcFlag) -> None: self.pdu_header.crc_flag = crc_flag @property - def pdu_data_field_len(self): + def pdu_data_field_len(self) -> int: return self.pdu_header.pdu_data_field_len @property @@ -81,7 +83,7 @@ def dest_entity_id(self) -> UnsignedByteField: return self.pdu_header.dest_entity_id @pdu_data_field_len.setter - def pdu_data_field_len(self, pdu_data_field_len: int): + def pdu_data_field_len(self, pdu_data_field_len: int) -> None: self.pdu_header.pdu_data_field_len = pdu_data_field_len @property @@ -97,10 +99,7 @@ def packet_len(self) -> int: return self.pdu_header.packet_len def __eq__(self, other: AbstractFileDirectiveBase): - return ( - self.pdu_header == other.pdu_header - and self.directive_type == other.directive_type - ) + return self.pdu_header == other.pdu_header and self.directive_type == other.directive_type class FileDirectivePduBase(AbstractFileDirectiveBase): @@ -134,7 +133,7 @@ def __init__( ) self._directive_type = directive_code - def verify_length_and_checksum(self, data: bytes): + def verify_length_and_checksum(self, data: bytes) -> None: self.pdu_header.verify_length_and_checksum(data) @property @@ -150,11 +149,11 @@ def directive_type(self) -> DirectiveType: return self._directive_type @property - def directive_param_field_len(self): + def directive_param_field_len(self) -> int: return self.pdu_header.pdu_data_field_len - 1 @directive_param_field_len.setter - def directive_param_field_len(self, directive_param_field_len: int): + def directive_param_field_len(self, directive_param_field_len: int) -> None: self.pdu_header.pdu_data_field_len = directive_param_field_len + 1 @classmethod @@ -189,17 +188,14 @@ def unpack(cls, raw_packet: bytes) -> FileDirectivePduBase: file_directive._directive_type = raw_packet[header_len - 1] return file_directive - def _verify_file_len(self, file_size: int): + def _verify_file_len(self, file_size: int) -> None: """Can be used by subclasses to verify a given file size""" if self.pdu_header.file_flag == LargeFileFlag.LARGE and file_size > pow(2, 64): - raise ValueError(f"File size {file_size} larger than 64 bit field") - elif self.pdu_header.file_flag == LargeFileFlag.NORMAL and file_size > pow( - 2, 32 - ): + if self.pdu_header.file_flag == LargeFileFlag.NORMAL and file_size > pow(2, 32): raise ValueError(f"File size {file_size} larger than 32 bit field") - def parse_fss_field(self, raw_packet: bytes, current_idx: int) -> Tuple[int, int]: + def parse_fss_field(self, raw_packet: bytes, current_idx: int) -> tuple[int, int]: """Parse the FSS field, which has different size depending on the large file flag being set or not. Returns the current index incremented and the parsed file size. @@ -208,16 +204,12 @@ def parse_fss_field(self, raw_packet: bytes, current_idx: int) -> Tuple[int, int if self.pdu_header.file_flag == LargeFileFlag.LARGE: if current_idx + 8 > len(raw_packet): raise BytesTooShortError(current_idx + 8, len(raw_packet)) - file_size = struct.unpack("!Q", raw_packet[current_idx : current_idx + 8])[ - 0 - ] + file_size = struct.unpack("!Q", raw_packet[current_idx : current_idx + 8])[0] current_idx += 8 else: if current_idx + 4 > len(raw_packet): raise BytesTooShortError(current_idx + 4, len(raw_packet)) - file_size = struct.unpack("!I", raw_packet[current_idx : current_idx + 4])[ - 0 - ] + file_size = struct.unpack("!I", raw_packet[current_idx : current_idx + 4])[0] current_idx += 4 return current_idx, file_size diff --git a/spacepackets/cfdp/pdu/finished.py b/spacepackets/cfdp/pdu/finished.py index 4e8545a..dd98a3e 100644 --- a/spacepackets/cfdp/pdu/finished.py +++ b/spacepackets/cfdp/pdu/finished.py @@ -3,7 +3,7 @@ import copy import struct from dataclasses import dataclass, field -from typing import List, Optional +from typing import TYPE_CHECKING from spacepackets.cfdp.conf import PduConfig from spacepackets.cfdp.defs import ( @@ -18,20 +18,22 @@ DirectiveType, FileDirectivePduBase, ) -from spacepackets.cfdp.pdu.header import PduHeader from spacepackets.cfdp.tlv.defs import TlvType from spacepackets.cfdp.tlv.tlv import EntityIdTlv, FileStoreResponseTlv from spacepackets.crc import CRC16_CCITT_FUNC from spacepackets.exceptions import BytesTooShortError +if TYPE_CHECKING: + from spacepackets.cfdp.pdu.header import PduHeader + @dataclass class FinishedParams: condition_code: ConditionCode delivery_code: DeliveryCode file_status: FileStatus - file_store_responses: List[FileStoreResponseTlv] = field(default_factory=lambda: []) - fault_location: Optional[EntityIdTlv] = None + file_store_responses: list[FileStoreResponseTlv] = field(default_factory=list) + fault_location: EntityIdTlv | None = None @classmethod def empty(cls) -> FinishedParams: @@ -99,7 +101,7 @@ def condition_code(self) -> ConditionCode: return self._params.condition_code @condition_code.setter - def condition_code(self, condition_code: ConditionCode): + def condition_code(self, condition_code: ConditionCode) -> None: self._params.condition_code = condition_code @property @@ -115,7 +117,7 @@ def packet_len(self) -> int: return self.pdu_file_directive.packet_len @property - def file_store_responses(self) -> List[FileStoreResponseTlv]: + def file_store_responses(self) -> list[FileStoreResponseTlv]: return self._params.file_store_responses @property @@ -123,18 +125,14 @@ def finished_params(self) -> FinishedParams: return self._params @property - def might_have_fault_location(self): - if self._params.condition_code in [ + def might_have_fault_location(self) -> bool: + return self._params.condition_code not in [ ConditionCode.NO_ERROR, ConditionCode.UNSUPPORTED_CHECKSUM_TYPE, - ]: - return False - return True + ] @file_store_responses.setter - def file_store_responses( - self, file_store_responses: Optional[List[FileStoreResponseTlv]] - ): + def file_store_responses(self, file_store_responses: list[FileStoreResponseTlv] | None) -> None: """Setter function for the file store responses :param file_store_responses: :raises ValueError: TLV type is not a filestore response @@ -147,33 +145,29 @@ def file_store_responses( self._calculate_directive_field_len() @property - def file_store_responses_len(self): + def file_store_responses_len(self) -> int: if not self._params.file_store_responses: return 0 - else: - file_store_responses_len = 0 - for file_store_response in self._params.file_store_responses: - file_store_responses_len += file_store_response.packet_len - return file_store_responses_len + file_store_responses_len = 0 + for file_store_response in self._params.file_store_responses: + file_store_responses_len += file_store_response.packet_len + return file_store_responses_len @property - def fault_location(self) -> Optional[EntityIdTlv]: + def fault_location(self) -> EntityIdTlv | None: return self._params.fault_location @fault_location.setter - def fault_location(self, fault_location: Optional[EntityIdTlv]): + def fault_location(self, fault_location: EntityIdTlv | None) -> None: """Setter function for the fault location. :raises ValueError: Type ID is not entity ID (0x06) """ self._params.fault_location = fault_location self._calculate_directive_field_len() - def _calculate_directive_field_len(self): + def _calculate_directive_field_len(self) -> None: base_len = 1 - if self.fault_location is None: - fault_loc_len = 0 - else: - fault_loc_len = self.fault_location_len + fault_loc_len = 0 if self.fault_location is None else self.fault_location_len if self.pdu_file_directive.pdu_conf.crc_flag == CrcFlag.WITH_CRC: base_len += 2 self.pdu_file_directive.directive_param_field_len = ( @@ -181,11 +175,10 @@ def _calculate_directive_field_len(self): ) @property - def fault_location_len(self): + def fault_location_len(self) -> int: if self._params.fault_location is None: return 0 - else: - return self._params.fault_location.packet_len + return self._params.fault_location.packet_len @classmethod def __empty(cls) -> FinishedPdu: @@ -223,16 +216,14 @@ def unpack(cls, data: bytes) -> FinishedPdu: Raw data too short for expected object. ValueError Invalid directive type or data format. - InvalidCrc + InvalidCrcError PDU has a 16 bit CRC and the CRC check failed. """ finished_pdu = cls.__empty() finished_pdu.pdu_file_directive = FileDirectivePduBase.unpack(raw_packet=data) finished_pdu.pdu_file_directive.verify_length_and_checksum(data) if finished_pdu.pdu_file_directive.packet_len > len(data): - raise BytesTooShortError( - finished_pdu.pdu_file_directive.packet_len, len(data) - ) + raise BytesTooShortError(finished_pdu.pdu_file_directive.packet_len, len(data)) current_idx = finished_pdu.pdu_file_directive.header_len first_param_byte = data[current_idx] params = FinishedParams( @@ -244,9 +235,7 @@ def unpack(cls, data: bytes) -> FinishedPdu: finished_pdu._params = params current_idx += 1 if len(data) > current_idx: - finished_pdu._unpack_tlvs( - rest_of_packet=data[current_idx : finished_pdu.packet_len] - ) + finished_pdu._unpack_tlvs(rest_of_packet=data[current_idx : finished_pdu.packet_len]) return finished_pdu def _unpack_tlvs(self, rest_of_packet: bytes) -> int: @@ -256,16 +245,12 @@ def _unpack_tlvs(self, rest_of_packet: bytes) -> int: while True: next_tlv_code = rest_of_packet[current_idx] if next_tlv_code == TlvType.FILESTORE_RESPONSE: - next_fs_response = FileStoreResponseTlv.unpack( - data=rest_of_packet[current_idx:] - ) + next_fs_response = FileStoreResponseTlv.unpack(data=rest_of_packet[current_idx:]) current_idx += next_fs_response.packet_len fs_responses_list.append(next_fs_response) elif next_tlv_code == TlvType.ENTITY_ID: if not self.might_have_fault_location: - raise ValueError( - "Entity ID found in Finished PDU but wrong condition code" - ) + raise ValueError("Entity ID found in Finished PDU but wrong condition code") fault_loc = EntityIdTlv.unpack(data=rest_of_packet[current_idx:]) current_idx += fault_loc.packet_len else: @@ -279,10 +264,7 @@ def _unpack_tlvs(self, rest_of_packet: bytes) -> int: return current_idx def __eq__(self, other: FinishedPdu): - return ( - self._params == other._params - and self.pdu_file_directive == other.pdu_file_directive - ) + return self._params == other._params and self.pdu_file_directive == other.pdu_file_directive def __repr__(self): return ( diff --git a/spacepackets/cfdp/pdu/header.py b/spacepackets/cfdp/pdu/header.py index b267282..8a5dd3e 100644 --- a/spacepackets/cfdp/pdu/header.py +++ b/spacepackets/cfdp/pdu/header.py @@ -3,25 +3,25 @@ import abc import struct +from spacepackets.cfdp.conf import ( + PduConfig, +) from spacepackets.cfdp.defs import ( + CFDP_VERSION_2, + CrcFlag, + Direction, + InvalidCrcError, LargeFileFlag, + LenInBytes, PduType, + SegmentationControl, SegmentMetadataFlag, - CrcFlag, TransmissionMode, - Direction, - SegmentationControl, - LenInBytes, - CFDP_VERSION_2, - UnsupportedCfdpVersion, -) -from spacepackets.cfdp.conf import ( - PduConfig, + UnsupportedCfdpVersionError, ) -from spacepackets.cfdp.exceptions import InvalidCrc from spacepackets.crc import CRC16_CCITT_FUNC from spacepackets.exceptions import BytesTooShortError -from spacepackets.util import UnsignedByteField, ByteFieldGenerator +from spacepackets.util import ByteFieldGenerator, UnsignedByteField class AbstractPduBase(abc.ABC): @@ -64,7 +64,7 @@ def file_flag(self) -> LargeFileFlag: @file_flag.setter @abc.abstractmethod - def file_flag(self, file_flag: LargeFileFlag): + def file_flag(self, file_flag: LargeFileFlag) -> None: pass @property @@ -104,12 +104,12 @@ def pdu_data_field_len(self, pdu_data_field_len: int) -> int: @property @abc.abstractmethod - def crc_flag(self): + def crc_flag(self) -> CrcFlag: pass @crc_flag.setter @abc.abstractmethod - def crc_flag(self, crc_flag: CrcFlag): + def crc_flag(self, crc_flag: CrcFlag) -> None: pass @property @@ -131,7 +131,7 @@ def __eq__(self, other: AbstractPduBase): ) @staticmethod - def header_len_from_raw(data: bytes): + def header_len_from_raw(data: bytes) -> int: entity_id_len = ((data[3] >> 4) & 0b111) + 1 seq_num_len = (data[3] & 0b111) + 1 return AbstractPduBase.FIXED_LENGTH + 2 * entity_id_len + seq_num_len @@ -175,24 +175,24 @@ def pdu_type(self) -> PduType: return self._pdu_type @pdu_type.setter - def pdu_type(self, pdu_type: PduType): + def pdu_type(self, pdu_type: PduType) -> None: self._pdu_type = pdu_type @property - def source_entity_id(self): + def source_entity_id(self) -> UnsignedByteField: return self.pdu_conf.source_entity_id @property - def dest_entity_id(self): + def dest_entity_id(self) -> UnsignedByteField: return self.pdu_conf.dest_entity_id @property - def transmission_mode(self): + def transmission_mode(self) -> TransmissionMode: return self.pdu_conf.trans_mode def set_entity_ids( self, source_entity_id: UnsignedByteField, dest_entity_id: UnsignedByteField - ): + ) -> None: """Both IDs must be set at once because they must have the same length as well :param source_entity_id: :param dest_entity_id: @@ -204,55 +204,55 @@ def set_entity_ids( self.pdu_conf.dest_entity_id = dest_entity_id @property - def transaction_seq_num(self): + def transaction_seq_num(self) -> UnsignedByteField: return self.pdu_conf.transaction_seq_num @transaction_seq_num.setter - def transaction_seq_num(self, transaction_seq_num: UnsignedByteField): + def transaction_seq_num(self, transaction_seq_num: UnsignedByteField) -> None: self.pdu_conf.transaction_seq_num = transaction_seq_num @property - def file_flag(self): + def file_flag(self) -> LargeFileFlag: return self.pdu_conf.file_flag @file_flag.setter - def file_flag(self, file_flag: LargeFileFlag): + def file_flag(self, file_flag: LargeFileFlag) -> None: self.pdu_conf.file_flag = file_flag @property - def crc_flag(self): + def crc_flag(self) -> CrcFlag: return self.pdu_conf.crc_flag @crc_flag.setter - def crc_flag(self, crc_flag: CrcFlag): + def crc_flag(self, crc_flag: CrcFlag) -> None: self.pdu_conf.crc_flag = crc_flag @transmission_mode.setter - def transmission_mode(self, trans_mode: TransmissionMode): + def transmission_mode(self, trans_mode: TransmissionMode) -> None: self.pdu_conf.trans_mode = trans_mode @property - def direction(self): + def direction(self) -> Direction: return self.pdu_conf.direction @direction.setter - def direction(self, direction: Direction): + def direction(self, direction: Direction) -> None: self.pdu_conf.direction = direction @property - def seg_ctrl(self): + def seg_ctrl(self) -> SegmentationControl: return self.pdu_conf.seg_ctrl @seg_ctrl.setter - def seg_ctrl(self, seg_ctrl: SegmentationControl): + def seg_ctrl(self, seg_ctrl: SegmentationControl) -> None: self.pdu_conf.seg_ctrl = seg_ctrl @property - def pdu_data_field_len(self): + def pdu_data_field_len(self) -> int: return self._pdu_data_field_len @pdu_data_field_len.setter - def pdu_data_field_len(self, new_len: int): + def pdu_data_field_len(self, new_len: int) -> None: """Set the PDU data field length. :param new_len: @@ -320,7 +320,7 @@ def unpack(cls, data: bytes) -> PduHeader: pdu_header = cls.__empty() version_raw = (data[0] >> 5) & 0b111 if version_raw != CFDP_VERSION_2: - raise UnsupportedCfdpVersion(version_raw) + raise UnsupportedCfdpVersionError(version_raw) pdu_header._pdu_type = PduType((data[0] & 0x10) >> 4) pdu_header.direction = Direction((data[0] & 0x08) >> 3) pdu_header.transmission_mode = TransmissionMode((data[0] & 0x04) >> 2) @@ -333,9 +333,7 @@ def unpack(cls, data: bytes) -> PduHeader: expected_len_seq_num = cls.check_len_in_bytes((data[3] & 0b111) + 1) expected_remaining_len = 2 * expected_len_entity_ids + expected_len_seq_num if expected_remaining_len + cls.FIXED_LENGTH > len(data): - raise BytesTooShortError( - expected_remaining_len + cls.FIXED_LENGTH, len(data) - ) + raise BytesTooShortError(expected_remaining_len + cls.FIXED_LENGTH, len(data)) current_idx = 4 source_entity_id = ByteFieldGenerator.from_bytes( expected_len_entity_ids, @@ -351,27 +349,25 @@ def unpack(cls, data: bytes) -> PduHeader: expected_len_entity_ids, data[current_idx : current_idx + expected_len_entity_ids], ) - pdu_header.set_entity_ids( - source_entity_id=source_entity_id, dest_entity_id=dest_entity_id - ) + pdu_header.set_entity_ids(source_entity_id=source_entity_id, dest_entity_id=dest_entity_id) return pdu_header def verify_length_and_checksum(self, data: bytes) -> int: if len(data) < self.packet_len: raise BytesTooShortError(self.packet_len, len(data)) - if self.pdu_conf.crc_flag == CrcFlag.WITH_CRC: - if CRC16_CCITT_FUNC(data[: self.packet_len]) != 0: - raise InvalidCrc( - struct.unpack("!H", data[self.packet_len - 2 : self.packet_len])[0] - ) + if ( + self.pdu_conf.crc_flag == CrcFlag.WITH_CRC + and CRC16_CCITT_FUNC(data[: self.packet_len]) != 0 + ): + raise InvalidCrcError( + struct.unpack("!H", data[self.packet_len - 2 : self.packet_len])[0] + ) return self.packet_len @staticmethod def check_len_in_bytes(detected_len: int) -> LenInBytes: if detected_len not in [1, 2, 4, 8]: - raise ValueError( - "Unsupported length field detected. Must be in [1, 2, 4, 8]" - ) + raise ValueError("Unsupported length field detected. Must be in [1, 2, 4, 8]") return LenInBytes(detected_len) def __repr__(self): diff --git a/spacepackets/cfdp/pdu/helper.py b/spacepackets/cfdp/pdu/helper.py index 2dc12a9..3029c0b 100644 --- a/spacepackets/cfdp/pdu/helper.py +++ b/spacepackets/cfdp/pdu/helper.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Optional, Type, Union, cast, Any +from typing import Any, NoReturn, Union, cast import deprecation @@ -11,13 +11,13 @@ ) from spacepackets.cfdp.pdu.ack import AckPdu from spacepackets.cfdp.pdu.eof import EofPdu -from spacepackets.cfdp.pdu.keep_alive import KeepAlivePdu +from spacepackets.cfdp.pdu.file_data import FileDataPdu from spacepackets.cfdp.pdu.finished import FinishedPdu +from spacepackets.cfdp.pdu.header import AbstractPduBase +from spacepackets.cfdp.pdu.keep_alive import KeepAlivePdu from spacepackets.cfdp.pdu.metadata import MetadataPdu -from spacepackets.cfdp.pdu.file_data import FileDataPdu from spacepackets.cfdp.pdu.nak import NakPdu from spacepackets.cfdp.pdu.prompt import PromptPdu -from spacepackets.cfdp.pdu.header import AbstractPduBase from spacepackets.version import get_version GenericPduPacket = Union[AbstractFileDirectiveBase, AbstractPduBase] @@ -26,7 +26,7 @@ class PduHolder: """Helper type to store arbitrary PDU types and cast them to a concrete PDU type conveniently""" - def __init__(self, pdu: Optional[GenericPduPacket]): + def __init__(self, pdu: GenericPduPacket | None): self.pdu = pdu def pack(self) -> bytearray: @@ -40,7 +40,7 @@ def pack(self) -> bytearray: current_version=get_version(), details="use packet member instead", ) - def base(self): + def base(self) -> GenericPduPacket | None: return self.pdu @base.setter @@ -49,7 +49,7 @@ def base(self): current_version=get_version(), details="use packet member instead", ) - def base(self, base: GenericPduPacket): + def base(self, base: GenericPduPacket) -> None: self.pdu = base @property @@ -64,11 +64,11 @@ def pdu_type(self) -> PduType: return self.pdu.pdu_type @property - def is_file_directive(self): + def is_file_directive(self) -> bool: return self.pdu_type == PduType.FILE_DIRECTIVE @property - def pdu_directive_type(self) -> Optional[DirectiveType]: + def pdu_directive_type(self) -> DirectiveType | None: """If the contained type is not a PDU file directive, returns None. Otherwise, returns the directive type """ @@ -80,12 +80,10 @@ def pdu_directive_type(self) -> Optional[DirectiveType]: def __repr__(self): return f"{self.__class__.__name__}(base={self.pdu!r}" - def _raise_not_target_exception(self, pdu_type: Type[Any]): + def _raise_not_target_exception(self, pdu_type: type[Any]) -> NoReturn: raise TypeError(f"Stored PDU is not {pdu_type.__name__!r}: {self.pdu!r}") - def _cast_to_concrete_file_directive( - self, pdu_type: Type[Any], dir_type: DirectiveType - ) -> Any: + def _cast_to_concrete_file_directive(self, pdu_type: type[Any], dir_type: DirectiveType) -> Any: # noqa: ANN401 if ( isinstance(self.pdu, AbstractFileDirectiveBase) and self.pdu.pdu_type == PduType.FILE_DIRECTIVE # type: ignore @@ -94,19 +92,16 @@ def _cast_to_concrete_file_directive( if pdu_base.directive_type == dir_type: return cast(pdu_type, self.pdu) self._raise_not_target_exception(pdu_type) + return None def to_file_data_pdu(self) -> FileDataPdu: # type: ignore - if ( - isinstance(self.pdu, AbstractPduBase) - and self.pdu.pdu_type == PduType.FILE_DATA - ): + if isinstance(self.pdu, AbstractPduBase) and self.pdu.pdu_type == PduType.FILE_DATA: return cast(FileDataPdu, self.pdu) self._raise_not_target_exception(FileDataPdu) + return None def to_metadata_pdu(self) -> MetadataPdu: - return self._cast_to_concrete_file_directive( - MetadataPdu, DirectiveType.METADATA_PDU - ) + return self._cast_to_concrete_file_directive(MetadataPdu, DirectiveType.METADATA_PDU) def to_ack_pdu(self) -> AckPdu: return self._cast_to_concrete_file_directive(AckPdu, DirectiveType.ACK_PDU) @@ -115,47 +110,40 @@ def to_nak_pdu(self) -> NakPdu: return self._cast_to_concrete_file_directive(NakPdu, DirectiveType.NAK_PDU) def to_finished_pdu(self) -> FinishedPdu: - return self._cast_to_concrete_file_directive( - FinishedPdu, DirectiveType.FINISHED_PDU - ) + return self._cast_to_concrete_file_directive(FinishedPdu, DirectiveType.FINISHED_PDU) def to_eof_pdu(self) -> EofPdu: return self._cast_to_concrete_file_directive(EofPdu, DirectiveType.EOF_PDU) def to_keep_alive_pdu(self) -> KeepAlivePdu: - return self._cast_to_concrete_file_directive( - KeepAlivePdu, DirectiveType.KEEP_ALIVE_PDU - ) + return self._cast_to_concrete_file_directive(KeepAlivePdu, DirectiveType.KEEP_ALIVE_PDU) def to_prompt_pdu(self) -> PromptPdu: - return self._cast_to_concrete_file_directive( - PromptPdu, DirectiveType.PROMPT_PDU - ) + return self._cast_to_concrete_file_directive(PromptPdu, DirectiveType.PROMPT_PDU) class PduFactory: """Helper class to generate PDUs and retrieve PDU information from a raw bytestream""" @staticmethod - def from_raw(data: bytes) -> Optional[GenericPduPacket]: + def from_raw(data: bytes) -> GenericPduPacket | None: # noqa: PLR0911 if not PduFactory.is_file_directive(data): return FileDataPdu.unpack(data) - else: - directive = PduFactory.pdu_directive_type(data) - if directive == DirectiveType.EOF_PDU: - return EofPdu.unpack(data) - elif directive == DirectiveType.METADATA_PDU: - return MetadataPdu.unpack(data) - elif directive == DirectiveType.FINISHED_PDU: - return FinishedPdu.unpack(data) - elif directive == DirectiveType.ACK_PDU: - return AckPdu.unpack(data) - elif directive == DirectiveType.NAK_PDU: - return NakPdu.unpack(data) - elif directive == DirectiveType.KEEP_ALIVE_PDU: - return KeepAlivePdu.unpack(data) - elif directive == DirectiveType.PROMPT_PDU: - return PromptPdu.unpack(data) + directive = PduFactory.pdu_directive_type(data) + if directive == DirectiveType.EOF_PDU: + return EofPdu.unpack(data) + if directive == DirectiveType.METADATA_PDU: + return MetadataPdu.unpack(data) + if directive == DirectiveType.FINISHED_PDU: + return FinishedPdu.unpack(data) + if directive == DirectiveType.ACK_PDU: + return AckPdu.unpack(data) + if directive == DirectiveType.NAK_PDU: + return NakPdu.unpack(data) + if directive == DirectiveType.KEEP_ALIVE_PDU: + return KeepAlivePdu.unpack(data) + if directive == DirectiveType.PROMPT_PDU: + return PromptPdu.unpack(data) return None @staticmethod @@ -171,7 +159,7 @@ def is_file_directive(data: bytes) -> bool: return PduFactory.pdu_type(data) == PduType.FILE_DIRECTIVE @staticmethod - def pdu_directive_type(data: bytes) -> Optional[DirectiveType]: + def pdu_directive_type(data: bytes) -> DirectiveType | None: """Retrieve the PDU directive type from a raw bytestream. :raises ValueError: Invalid directive type. @@ -180,6 +168,5 @@ def pdu_directive_type(data: bytes) -> Optional[DirectiveType]: """ if not PduFactory.is_file_directive(data): return None - else: - header_len = AbstractPduBase.header_len_from_raw(data) - return DirectiveType(data[header_len]) + header_len = AbstractPduBase.header_len_from_raw(data) + return DirectiveType(data[header_len]) diff --git a/spacepackets/cfdp/pdu/keep_alive.py b/spacepackets/cfdp/pdu/keep_alive.py index 6b8049e..be04d18 100644 --- a/spacepackets/cfdp/pdu/keep_alive.py +++ b/spacepackets/cfdp/pdu/keep_alive.py @@ -1,19 +1,22 @@ from __future__ import annotations -import struct import copy +import struct +from typing import TYPE_CHECKING from spacepackets.cfdp import CrcFlag +from spacepackets.cfdp.conf import LargeFileFlag, PduConfig from spacepackets.cfdp.defs import Direction -from spacepackets.cfdp.pdu import PduHeader from spacepackets.cfdp.pdu.file_directive import ( - FileDirectivePduBase, - DirectiveType, AbstractFileDirectiveBase, + DirectiveType, + FileDirectivePduBase, ) -from spacepackets.cfdp.conf import PduConfig, LargeFileFlag from spacepackets.crc import CRC16_CCITT_FUNC +if TYPE_CHECKING: + from spacepackets.cfdp.pdu import PduHeader + class KeepAlivePdu(AbstractFileDirectiveBase): """Encapsulates the Keep Alive file directive PDU, see CCSDS 727.0-B-5 p.85""" @@ -43,11 +46,11 @@ def pdu_header(self) -> PduHeader: return self.pdu_file_directive.pdu_header @property - def file_flag(self): + def file_flag(self) -> LargeFileFlag: return self.pdu_file_directive.pdu_header.file_flag @file_flag.setter - def file_flag(self, file_size: LargeFileFlag): + def file_flag(self, file_size: LargeFileFlag) -> None: directive_param_field_len = 4 if file_size == LargeFileFlag.LARGE: directive_param_field_len = 8 @@ -68,9 +71,7 @@ def pack(self) -> bytearray: else: keep_alive_packet.extend(struct.pack("Q", self.progress)) if self.pdu_file_directive.pdu_conf.crc_flag == CrcFlag.WITH_CRC: - keep_alive_packet.extend( - struct.pack("!H", CRC16_CCITT_FUNC(keep_alive_packet)) - ) + keep_alive_packet.extend(struct.pack("!H", CRC16_CCITT_FUNC(keep_alive_packet))) return keep_alive_packet @classmethod @@ -85,7 +86,7 @@ def unpack(cls, data: bytes) -> KeepAlivePdu: Raw data too short for expected object. ValueError Invalid directive type or data format. - InvalidCrc + InvalidCrcError PDU has a 16 bit CRC and the CRC check failed. """ keep_alive_pdu = cls.__empty() @@ -105,13 +106,12 @@ def unpack(cls, data: bytes) -> KeepAlivePdu: return keep_alive_pdu @property - def packet_len(self): + def packet_len(self) -> int: return self.pdu_file_directive.packet_len def __eq__(self, other: KeepAlivePdu): return ( - self.pdu_file_directive == other.pdu_file_directive - and self.progress == other.progress + self.pdu_file_directive == other.pdu_file_directive and self.progress == other.progress ) def __repr__(self): diff --git a/spacepackets/cfdp/pdu/metadata.py b/spacepackets/cfdp/pdu/metadata.py index 27e17c7..45d2f50 100644 --- a/spacepackets/cfdp/pdu/metadata.py +++ b/spacepackets/cfdp/pdu/metadata.py @@ -1,31 +1,33 @@ from __future__ import annotations +import copy import dataclasses import struct -import copy -from typing import Optional, List +from typing import TYPE_CHECKING -from spacepackets.cfdp.pdu import PduHeader +from spacepackets.cfdp.conf import LargeFileFlag, PduConfig +from spacepackets.cfdp.defs import ChecksumType, CrcFlag, Direction +from spacepackets.cfdp.lv import CfdpLv from spacepackets.cfdp.pdu.file_directive import ( - FileDirectivePduBase, - DirectiveType, AbstractFileDirectiveBase, + DirectiveType, + FileDirectivePduBase, ) -from spacepackets.cfdp.conf import PduConfig, LargeFileFlag -from spacepackets.cfdp.tlv import CfdpTlv -from spacepackets.cfdp.lv import CfdpLv -from spacepackets.cfdp.defs import ChecksumType, CrcFlag, Direction +from spacepackets.cfdp.tlv import CfdpTlv, TlvList from spacepackets.crc import CRC16_CCITT_FUNC from spacepackets.exceptions import BytesTooShortError +if TYPE_CHECKING: + from spacepackets.cfdp.pdu import PduHeader + @dataclasses.dataclass class MetadataParams: closure_requested: bool checksum_type: ChecksumType file_size: int - source_file_name: Optional[str] - dest_file_name: Optional[str] + source_file_name: str | None + dest_file_name: str | None class MetadataPdu(AbstractFileDirectiveBase): @@ -53,17 +55,17 @@ def __init__( self, pdu_conf: PduConfig, params: MetadataParams, - options: Optional[List[CfdpTlv]] = None, + options: TlvList | None = None, ): pdu_conf = copy.copy(pdu_conf) self.params = params if params.source_file_name is None: - self._source_file_name_lv = CfdpLv(value=bytes()) + self._source_file_name_lv = CfdpLv(value=b"") else: source_file_name_as_bytes = params.source_file_name.encode("utf-8") self._source_file_name_lv = CfdpLv(value=source_file_name_as_bytes) if params.dest_file_name is None: - self._dest_file_name_lv = CfdpLv(value=bytes()) + self._dest_file_name_lv = CfdpLv(value=b"") else: dest_file_name_as_bytes = params.dest_file_name.encode("utf-8") self._dest_file_name_lv = CfdpLv(value=dest_file_name_as_bytes) @@ -109,28 +111,30 @@ def __empty(cls) -> MetadataPdu: ) @property - def options(self) -> Optional[List[CfdpTlv]]: + def options(self) -> TlvList | None: return self._options @options.setter - def options(self, options: Optional[List[CfdpTlv]]): + def options(self, options: TlvList | None) -> None: self._options = options self._calculate_directive_field_len() + def options_as_tlv(self) -> list[CfdpTlv] | None: + """Returns :py:meth:`options` converted to a list of concrete :py:class:`CfdpTlv` + objects.""" + if self.options is None: + return None + return [CfdpTlv(option.tlv_type, option.value) for option in self.options] + @property - def directive_param_field_len(self): + def directive_param_field_len(self) -> int: return self.pdu_file_directive.directive_param_field_len - def _calculate_directive_field_len(self): + def _calculate_directive_field_len(self) -> None: directive_param_field_len = ( - 5 - + self._source_file_name_lv.packet_len - + self._dest_file_name_lv.packet_len + 5 + self._source_file_name_lv.packet_len + self._dest_file_name_lv.packet_len ) - if ( - self.pdu_file_directive.pdu_header.large_file_flag_set - == LargeFileFlag.LARGE - ): + if self.pdu_file_directive.pdu_header.large_file_flag_set == LargeFileFlag.LARGE: directive_param_field_len += 4 if self._options is not None: for option in self._options: @@ -140,7 +144,7 @@ def _calculate_directive_field_len(self): self.pdu_file_directive.directive_param_field_len = directive_param_field_len @property - def source_file_name(self) -> Optional[str]: + def source_file_name(self) -> str | None: """If there is no associated source file, for example for messages used for Proxy Operations, this function will return None """ @@ -149,16 +153,16 @@ def source_file_name(self) -> Optional[str]: return self._source_file_name_lv.value.decode() @source_file_name.setter - def source_file_name(self, source_file_name: Optional[str]): + def source_file_name(self, source_file_name: str | None) -> None: if source_file_name is None: - self._source_file_name_lv = CfdpLv(value=bytes()) + self._source_file_name_lv = CfdpLv(value=b"") else: source_file_name_as_bytes = source_file_name.encode("utf-8") self._source_file_name_lv = CfdpLv(value=source_file_name_as_bytes) self._calculate_directive_field_len() @property - def dest_file_name(self) -> Optional[str]: + def dest_file_name(self) -> str | None: """If there is no associated source file, for example for messages used for Proxy Operations, this function will return None """ @@ -167,9 +171,9 @@ def dest_file_name(self) -> Optional[str]: return self._dest_file_name_lv.value.decode() @dest_file_name.setter - def dest_file_name(self, dest_file_name: Optional[str]): + def dest_file_name(self, dest_file_name: str | None) -> None: if dest_file_name is None: - self._dest_file_name_lv = CfdpLv(value=bytes()) + self._dest_file_name_lv = CfdpLv(value=b"") else: dest_file_name_as_bytes = dest_file_name.encode("utf-8") self._dest_file_name_lv = CfdpLv(value=dest_file_name_as_bytes) @@ -204,7 +208,7 @@ def unpack(cls, data: bytes) -> MetadataPdu: Raw data too short for expected object. ValueError Invalid directive type or data format. - InvalidCrc + InvalidCrcError PDU has a 16 bit CRC and the CRC check failed. """ metadata_pdu = cls.__empty() @@ -238,7 +242,7 @@ def unpack(cls, data: bytes) -> MetadataPdu: metadata_pdu._parse_options(raw_packet=data, start_idx=current_idx) return metadata_pdu - def _parse_options(self, raw_packet: bytes, start_idx: int): + def _parse_options(self, raw_packet: bytes, start_idx: int) -> None: self._options = [] current_idx = start_idx while True: @@ -250,7 +254,7 @@ def _parse_options(self, raw_packet: bytes, start_idx: int): # This can not really happen because the CFDP TLV should check the remaining packet # length as well. Still keep it for defensive programming raise ValueError - elif current_idx == len(raw_packet): + if current_idx == len(raw_packet): break def __repr__(self): diff --git a/spacepackets/cfdp/pdu/nak.py b/spacepackets/cfdp/pdu/nak.py index c721e28..3a29422 100644 --- a/spacepackets/cfdp/pdu/nak.py +++ b/spacepackets/cfdp/pdu/nak.py @@ -1,19 +1,22 @@ from __future__ import annotations + import struct -from typing import List, Tuple, Optional +from typing import TYPE_CHECKING from spacepackets.cfdp import CrcFlag +from spacepackets.cfdp.conf import PduConfig from spacepackets.cfdp.defs import Direction -from spacepackets.cfdp.pdu import PduHeader from spacepackets.cfdp.pdu.file_directive import ( AbstractFileDirectiveBase, - FileDirectivePduBase, DirectiveType, + FileDirectivePduBase, LargeFileFlag, ) -from spacepackets.cfdp.conf import PduConfig from spacepackets.crc import CRC16_CCITT_FUNC +if TYPE_CHECKING: + from spacepackets.cfdp.pdu import PduHeader + def get_max_seg_reqs_for_max_packet_size_and_pdu_cfg( max_packet_size: int, pdu_conf: PduConfig @@ -41,7 +44,7 @@ def get_max_seg_reqs_for_max_packet_size_and_pdu_cfg( max_packet_size -= base_decrement if pdu_conf.file_flag == LargeFileFlag.NORMAL: return max_packet_size // 8 - elif pdu_conf.file_flag == LargeFileFlag.LARGE: + if pdu_conf.file_flag == LargeFileFlag.LARGE: return max_packet_size // 16 raise ValueError("Invalid large file flag argument") @@ -103,7 +106,7 @@ def __init__( pdu_conf: PduConfig, start_of_scope: int, end_of_scope: int, - segment_requests: Optional[List[Tuple[int, int]]] = None, + segment_requests: list[tuple[int, int]] | None = None, ): """Create a NAK PDU object instance. @@ -138,13 +141,12 @@ def __init__( @classmethod def __empty(cls) -> NakPdu: empty_conf = PduConfig.empty() - return cls( - start_of_scope=0, end_of_scope=0, segment_requests=[], pdu_conf=empty_conf - ) + return cls(start_of_scope=0, end_of_scope=0, segment_requests=[], pdu_conf=empty_conf) def get_max_seg_reqs_for_max_packet_size(self, max_packet_size: int) -> int: - """Member method which forwards to :py:meth:`get_max_seg_reqs_for_max_packet_size_and_pdu_cfg`, - passing the internal PDU configuration field.""" + """Member method which forwards to + :py:meth:`get_max_seg_reqs_for_max_packet_size_and_pdu_cfg`, passing the internal PDU + configuration field.""" return get_max_seg_reqs_for_max_packet_size_and_pdu_cfg( max_packet_size, self.pdu_file_directive.pdu_conf ) @@ -158,17 +160,17 @@ def pdu_header(self) -> PduHeader: return self.pdu_file_directive.pdu_header @property - def file_flag(self): + def file_flag(self) -> LargeFileFlag: return self.pdu_file_directive.file_flag @file_flag.setter - def file_flag(self, file_flag: LargeFileFlag): + def file_flag(self, file_flag: LargeFileFlag) -> None: """Set the file size. This changes the length of the packet when packed as well which is handled by this function""" self.pdu_file_directive.file_flag = file_flag self._calculate_directive_field_len() - def _calculate_directive_field_len(self): + def _calculate_directive_field_len(self) -> None: if self.pdu_file_directive.file_flag == LargeFileFlag.NORMAL: directive_param_field_len = 8 + len(self._segment_requests) * 8 elif self.pdu_file_directive.file_flag == LargeFileFlag.LARGE: @@ -180,7 +182,7 @@ def _calculate_directive_field_len(self): self.pdu_file_directive.directive_param_field_len = directive_param_field_len @property - def segment_requests(self) -> List[Tuple[int, int]]: + def segment_requests(self) -> list[tuple[int, int]]: """An optional list of segment request pair tuples, where the first entry of list element is the start offset and the second entry is the end offset. If the start and end offset are both 0, the metadata is re-requested. @@ -188,13 +190,13 @@ def segment_requests(self) -> List[Tuple[int, int]]: return self._segment_requests @segment_requests.setter - def segment_requests(self, segment_requests: Optional[List[Tuple[int, int]]]): + def segment_requests(self, segment_requests: list[tuple[int, int]] | None) -> None: """Update the segment requests. This changes the length of the packet when packed as well which is handled by this function.""" if segment_requests is None: self._segment_requests = [] else: - self._segment_requests: List[Tuple[int, int]] = segment_requests # type: ignore + self._segment_requests: list[tuple[int, int]] = segment_requests # type: ignore self._calculate_directive_field_len() def pack(self) -> bytearray: @@ -204,10 +206,7 @@ def pack(self) -> bytearray: """ nak_pdu = self.pdu_file_directive.pack() if not self.pdu_file_directive.pdu_header.large_file_flag_set: - if ( - self.start_of_scope > pow(2, 32) - 1 - or self.end_of_scope > pow(2, 32) - 1 - ): + if self.start_of_scope > pow(2, 32) - 1 or self.end_of_scope > pow(2, 32) - 1: raise ValueError nak_pdu.extend(struct.pack("!I", self.start_of_scope)) nak_pdu.extend(struct.pack("!I", self.end_of_scope)) @@ -216,10 +215,7 @@ def pack(self) -> bytearray: nak_pdu.extend(struct.pack("!Q", self.end_of_scope)) for segment_request in self._segment_requests: if not self.pdu_file_directive.pdu_header.large_file_flag_set: - if ( - segment_request[0] > pow(2, 32) - 1 - or segment_request[1] > pow(2, 32) - 1 - ): + if segment_request[0] > pow(2, 32) - 1 or segment_request[1] > pow(2, 32) - 1: raise ValueError nak_pdu.extend(struct.pack("!I", segment_request[0])) nak_pdu.extend(struct.pack("!I", segment_request[1])) @@ -242,7 +238,7 @@ def unpack(cls, data: bytes) -> NakPdu: Raw data too short for expected object. ValueError Invalid directive type or data format. - InvalidCrc + InvalidCrcError PDU has a 16 bit CRC and the CRC check failed. """ nak_pdu = cls.__empty() diff --git a/spacepackets/cfdp/pdu/prompt.py b/spacepackets/cfdp/pdu/prompt.py index 510d6d5..3e7c6fb 100644 --- a/spacepackets/cfdp/pdu/prompt.py +++ b/spacepackets/cfdp/pdu/prompt.py @@ -1,13 +1,14 @@ from __future__ import annotations -import enum + import copy +import enum import struct from spacepackets.cfdp import CrcFlag -from spacepackets.cfdp.defs import Direction -from spacepackets.cfdp.pdu.file_directive import FileDirectivePduBase, DirectiveType from spacepackets.cfdp.conf import PduConfig +from spacepackets.cfdp.defs import Direction from spacepackets.cfdp.pdu import AbstractFileDirectiveBase, PduHeader +from spacepackets.cfdp.pdu.file_directive import DirectiveType, FileDirectivePduBase from spacepackets.crc import CRC16_CCITT_FUNC from spacepackets.exceptions import BytesTooShortError @@ -70,7 +71,7 @@ def unpack(cls, data: bytes) -> PromptPdu: Raw data too short for expected object. ValueError: Invalid directive type or data format. - InvalidCrc: + InvalidCrcError: PDU has a 16 bit CRC and the CRC check failed. """ prompt_pdu = cls.__empty() diff --git a/spacepackets/cfdp/tlv/__init__.py b/spacepackets/cfdp/tlv/__init__.py index 2580d13..1cdd5d2 100644 --- a/spacepackets/cfdp/tlv/__init__.py +++ b/spacepackets/cfdp/tlv/__init__.py @@ -6,42 +6,80 @@ Please note that most of the submodules of the TLV submodule are re-exported, so usually you can import everything from :py:mod:`spacepackets.cfdp.tlv`""" -from .tlv import ( - CfdpTlv, - EntityIdTlv, - FileStoreRequestTlv, - FileStoreResponseTlv, - FlowLabelTlv, - FaultHandlerOverrideTlv, - create_cfdp_proxy_and_dir_op_message_marker, - map_enum_status_code_to_int, - map_int_status_code_to_enum, - map_enum_status_code_to_action_status_code, -) +from .base import TlvList from .defs import ( - TlvType, + ORIGINATING_TRANSACTION_ID_MSG_TYPE_ID, + DirectoryOperationMessageType, FilestoreActionCode, FilestoreResponseStatusCode, - DirectoryOperationMessageType, - ORIGINATING_TRANSACTION_ID_MSG_TYPE_ID, ProxyMessageType, + TlvType, + TlvTypeMissmatchError, ) -from .base import TlvList from .holder import TlvHolder from .msg_to_user import ( + DirectoryListingParameters, + DirectoryListingRequest, + DirectoryListingResponse, + DirectoryParams, + DirListingOptions, MessageToUserTlv, - ReservedCfdpMessage, - ProxyPutRequestParams, - ProxyPutRequest, + OriginatingTransactionId, ProxyCancelRequest, ProxyClosureRequest, - ProxyTransmissionMode, + ProxyPutRequest, + ProxyPutRequestParams, ProxyPutResponse, ProxyPutResponseParams, - DirectoryParams, - DirListingOptions, - DirectoryListingRequest, - DirectoryListingResponse, - DirectoryListingParameters, - OriginatingTransactionId, + ProxyTransmissionMode, + ReservedCfdpMessage, ) +from .tlv import ( + CfdpTlv, + EntityIdTlv, + FaultHandlerOverrideTlv, + FileStoreRequestTlv, + FileStoreResponseTlv, + FlowLabelTlv, + create_cfdp_proxy_and_dir_op_message_marker, + map_enum_status_code_to_action_status_code, + map_enum_status_code_to_int, + map_int_status_code_to_enum, +) + +__all__ = [ + "ORIGINATING_TRANSACTION_ID_MSG_TYPE_ID", + "CfdpTlv", + "DirListingOptions", + "DirectoryListingParameters", + "DirectoryListingRequest", + "DirectoryListingResponse", + "DirectoryOperationMessageType", + "DirectoryParams", + "EntityIdTlv", + "FaultHandlerOverrideTlv", + "FileStoreRequestTlv", + "FileStoreResponseTlv", + "FilestoreActionCode", + "FilestoreResponseStatusCode", + "FlowLabelTlv", + "MessageToUserTlv", + "OriginatingTransactionId", + "ProxyCancelRequest", + "ProxyClosureRequest", + "ProxyMessageType", + "ProxyPutRequest", + "ProxyPutRequestParams", + "ProxyPutResponse", + "ProxyPutResponseParams", + "ProxyTransmissionMode", + "ReservedCfdpMessage", + "TlvHolder", + "TlvList", + "TlvType", + "TlvTypeMissmatchError", + "create_cfdp_proxy_and_dir_op_message_marker", + "map_enum_status_code_to_action_status_code", + "map_enum_status_code_to_int", + "map_int_status_code_to_enum", +] diff --git a/spacepackets/cfdp/tlv/base.py b/spacepackets/cfdp/tlv/base.py index 504cf2d..36f1c18 100644 --- a/spacepackets/cfdp/tlv/base.py +++ b/spacepackets/cfdp/tlv/base.py @@ -1,8 +1,12 @@ from __future__ import annotations -from typing import List + from abc import ABC, abstractmethod -from spacepackets.cfdp.exceptions import TlvTypeMissmatch -from spacepackets.cfdp.tlv.defs import TlvType +from typing import TYPE_CHECKING + +from spacepackets.cfdp.tlv.defs import TlvTypeMissmatchError + +if TYPE_CHECKING: + from spacepackets.cfdp.tlv.defs import TlvType class AbstractTlvBase(ABC): @@ -33,9 +37,9 @@ def __eq__(self, other: object): return False return self.tlv_type == other.tlv_type and self.value == other.value - def check_type(self, tlv_type: TlvType): + def check_type(self, tlv_type: TlvType) -> None: if self.tlv_type != tlv_type: - raise TlvTypeMissmatch(found=tlv_type, expected=self.tlv_type) + raise TlvTypeMissmatchError(found=tlv_type, expected=self.tlv_type) -TlvList = List[AbstractTlvBase] +TlvList = list[AbstractTlvBase] diff --git a/spacepackets/cfdp/tlv/defs.py b/spacepackets/cfdp/tlv/defs.py index 06c703b..28f039f 100644 --- a/spacepackets/cfdp/tlv/defs.py +++ b/spacepackets/cfdp/tlv/defs.py @@ -1,4 +1,5 @@ from __future__ import annotations + import enum @@ -111,3 +112,10 @@ class DirectoryOperationMessageType(enum.IntEnum): CUSTOM_LISTING_PARAMETERS = 0x15 """Custom message type not specified by the standard. Used to supply parameters like the recursive and the all option to the directory listing.""" + + +class TlvTypeMissmatchError(Exception): + def __init__(self, found: TlvType, expected: TlvType): + self.found = found + self.expected = expected + super().__init__(f"Expected TLV {self.expected}, found {self.found}") diff --git a/spacepackets/cfdp/tlv/holder.py b/spacepackets/cfdp/tlv/holder.py index ec6ca8a..b623d66 100644 --- a/spacepackets/cfdp/tlv/holder.py +++ b/spacepackets/cfdp/tlv/holder.py @@ -1,6 +1,6 @@ -from typing import Any, Optional, Type, cast +from typing import Any, Optional, cast -from spacepackets.cfdp.tlv.base import TlvType +from spacepackets.cfdp.tlv.defs import TlvType from spacepackets.cfdp.tlv.msg_to_user import MessageToUserTlv from spacepackets.cfdp.tlv.tlv import ( AbstractTlvBase, @@ -18,15 +18,16 @@ def __init__(self, tlv: Optional[AbstractTlvBase]): self.tlv = tlv @property - def tlv_type(self): + def tlv_type(self) -> None | TlvType: if self.tlv is not None: return self.tlv.tlv_type + return None def __cast_internally( self, - obj_type: Type[AbstractTlvBase], + obj_type: type[AbstractTlvBase], expected_type: TlvType, - ) -> Any: + ) -> Any: # noqa: ANN401 assert self.tlv is not None if self.tlv.tlv_type != expected_type: raise TypeError(f"Invalid object {self.tlv} for type {self.tlv.tlv_type}") diff --git a/spacepackets/cfdp/tlv/msg_to_user.py b/spacepackets/cfdp/tlv/msg_to_user.py index 6035600..0ee9f02 100644 --- a/spacepackets/cfdp/tlv/msg_to_user.py +++ b/spacepackets/cfdp/tlv/msg_to_user.py @@ -6,28 +6,30 @@ import dataclasses from pathlib import Path -from typing import Optional, Tuple +from typing import TYPE_CHECKING from spacepackets.cfdp.defs import ( - TransactionId, - TransmissionMode, ConditionCode, DeliveryCode, FileStatus, + TransactionId, + TransmissionMode, ) -from spacepackets.cfdp.exceptions import TlvTypeMissmatch from spacepackets.cfdp.lv import CfdpLv -from spacepackets.cfdp.pdu.finished import FinishedParams from spacepackets.cfdp.tlv.base import AbstractTlvBase from spacepackets.cfdp.tlv.defs import ( ORIGINATING_TRANSACTION_ID_MSG_TYPE_ID, DirectoryOperationMessageType, ProxyMessageType, TlvType, + TlvTypeMissmatchError, ) from spacepackets.cfdp.tlv.tlv import CfdpTlv from spacepackets.util import UnsignedByteField +if TYPE_CHECKING: + from spacepackets.cfdp.pdu.finished import FinishedParams + class MessageToUserTlv(AbstractTlvBase): """Message to User TLV implementation as specified in CCSDS 727.0-B-5 5.4.3""" @@ -41,7 +43,7 @@ def pack(self) -> bytearray: return self.tlv.pack() @property - def packet_len(self): + def packet_len(self) -> int: return self.tlv.packet_len @property @@ -53,11 +55,9 @@ def tlv_type(self) -> TlvType: return MessageToUserTlv.TLV_TYPE def is_reserved_cfdp_message(self) -> bool: - if len(self.tlv.value) >= 5 and self.tlv.value[0:4].decode() == "cfdp": - return True - return False + return bool(len(self.tlv.value) >= 5 and self.tlv.value[0:4].decode() == "cfdp") - def to_reserved_msg_tlv(self) -> Optional[ReservedCfdpMessage]: + def to_reserved_msg_tlv(self) -> ReservedCfdpMessage | None: """Attempt to convert to a reserved CFDP message. Please note that this operation will fail if the message if not a reserved CFDP message and will then return None. This method is especially useful to have access to the more specialized @@ -67,8 +67,8 @@ def to_reserved_msg_tlv(self) -> Optional[ReservedCfdpMessage]: return ReservedCfdpMessage(self.tlv.value[4], self.tlv.value[5:]) @classmethod - def __empty(cls): - return cls(bytes()) + def __empty(cls) -> MessageToUserTlv: + return cls(b"") @classmethod def unpack(cls, data: bytes) -> MessageToUserTlv: @@ -80,7 +80,7 @@ def unpack(cls, data: bytes) -> MessageToUserTlv: @classmethod def from_tlv(cls, cfdp_tlv: CfdpTlv) -> MessageToUserTlv: if cfdp_tlv.tlv_type != cls.TLV_TYPE: - raise TlvTypeMissmatch(cfdp_tlv.tlv_type, cls.TLV_TYPE) + raise TlvTypeMissmatchError(cfdp_tlv.tlv_type, cls.TLV_TYPE) msg_to_user_tlv = cls.__empty() msg_to_user_tlv.tlv = cfdp_tlv return msg_to_user_tlv @@ -100,7 +100,7 @@ class ReservedCfdpMessage(AbstractTlvBase): def __init__(self, msg_type: int, value: bytes): assert msg_type < pow(2, 8) - 1 - full_value = bytearray("cfdp".encode()) + full_value = bytearray(b"cfdp") full_value.append(msg_type) full_value.extend(value) self.tlv = CfdpTlv(TlvType.MESSAGE_TO_USER, full_value) @@ -115,7 +115,7 @@ def to_generic_msg_to_user_tlv(self) -> MessageToUserTlv: return MessageToUserTlv.from_tlv(self.tlv) @property - def packet_len(self): + def packet_len(self) -> int: return self.tlv.packet_len @property @@ -144,24 +144,21 @@ def is_directory_operation(self) -> bool: return False def is_originating_transaction_id(self) -> bool: - return ( - self.get_reserved_cfdp_message_type() - == ORIGINATING_TRANSACTION_ID_MSG_TYPE_ID - ) + return self.get_reserved_cfdp_message_type() == ORIGINATING_TRANSACTION_ID_MSG_TYPE_ID - def get_cfdp_proxy_message_type(self) -> Optional[ProxyMessageType]: + def get_cfdp_proxy_message_type(self) -> ProxyMessageType | None: if not self.is_cfdp_proxy_operation(): return None return ProxyMessageType(self.get_reserved_cfdp_message_type()) - def get_directory_operation_type(self) -> Optional[DirectoryOperationMessageType]: + def get_directory_operation_type(self) -> DirectoryOperationMessageType | None: if not self.is_directory_operation(): return None return DirectoryOperationMessageType(self.get_reserved_cfdp_message_type()) def get_originating_transaction_id( self, - ) -> Optional[TransactionId]: + ) -> TransactionId | None: if not self.is_originating_transaction_id(): return None if len(self.value) < 1: @@ -179,7 +176,7 @@ def get_originating_transaction_id( UnsignedByteField.from_bytes(seq_num), ) - def get_proxy_put_request_params(self) -> Optional[ProxyPutRequestParams]: + def get_proxy_put_request_params(self) -> ProxyPutRequestParams | None: """This function extract the proxy put request parameters from the raw value if applicable. If the value format is invalid, this function will return None.""" if ( @@ -203,7 +200,7 @@ def get_proxy_put_request_params(self) -> Optional[ProxyPutRequestParams]: dest_name_lv, ) - def get_proxy_put_response_params(self) -> Optional[ProxyPutResponseParams]: + def get_proxy_put_response_params(self) -> ProxyPutResponseParams | None: if ( not self.is_cfdp_proxy_operation() or self.get_cfdp_proxy_message_type() != ProxyMessageType.PUT_RESPONSE @@ -214,7 +211,7 @@ def get_proxy_put_response_params(self) -> Optional[ProxyPutResponseParams]: file_status = FileStatus(self.value[5] & 0b11) return ProxyPutResponseParams(condition_code, delivery_code, file_status) - def get_proxy_closure_requested(self) -> Optional[bool]: + def get_proxy_closure_requested(self) -> bool | None: if ( not self.is_cfdp_proxy_operation() or self.get_cfdp_proxy_message_type() != ProxyMessageType.CLOSURE_REQUEST @@ -222,7 +219,7 @@ def get_proxy_closure_requested(self) -> Optional[bool]: return None return self.value[5] & 0b1 - def get_proxy_transmission_mode(self) -> Optional[TransmissionMode]: + def get_proxy_transmission_mode(self) -> TransmissionMode | None: if ( not self.is_cfdp_proxy_operation() or self.get_cfdp_proxy_message_type() != ProxyMessageType.TRANSMISSION_MODE @@ -230,18 +227,17 @@ def get_proxy_transmission_mode(self) -> Optional[TransmissionMode]: return None return TransmissionMode(self.value[5] & 0b1) - def get_dir_listing_request_params(self) -> Optional[DirectoryParams]: + def get_dir_listing_request_params(self) -> DirectoryParams | None: if ( not self.is_directory_operation() - or self.get_directory_operation_type() - != DirectoryOperationMessageType.LISTING_REQUEST + or self.get_directory_operation_type() != DirectoryOperationMessageType.LISTING_REQUEST ): return None dir_path_lv = CfdpLv.unpack(self.value[5:]) dir_file_name_lv = CfdpLv.unpack(self.value[5 + dir_path_lv.packet_len :]) return DirectoryParams(dir_path_lv, dir_file_name_lv) - def get_dir_listing_response_params(self) -> Optional[Tuple[bool, DirectoryParams]]: + def get_dir_listing_response_params(self) -> tuple[bool, DirectoryParams] | None: """ Returns --------- @@ -251,8 +247,7 @@ def get_dir_listing_response_params(self) -> Optional[Tuple[bool, DirectoryParam """ if ( not self.is_directory_operation() - or self.get_directory_operation_type() - != DirectoryOperationMessageType.LISTING_RESPONSE + or self.get_directory_operation_type() != DirectoryOperationMessageType.LISTING_RESPONSE ): return None if len(self.value) < 1: @@ -264,7 +259,7 @@ def get_dir_listing_response_params(self) -> Optional[Tuple[bool, DirectoryParam dir_file_name_lv = CfdpLv.unpack(self.value[6 + dir_path_lv.packet_len :]) return listing_success, DirectoryParams(dir_path_lv, dir_file_name_lv) - def get_dir_listing_options(self) -> Optional[DirListingOptions]: + def get_dir_listing_options(self) -> DirListingOptions | None: if ( not self.is_directory_operation() or self.get_directory_operation_type() @@ -311,7 +306,7 @@ def __init__(self, params: ProxyPutRequestParams): class ProxyCancelRequest(ReservedCfdpMessage): def __init__(self): - super().__init__(ProxyMessageType.PUT_CANCEL, bytes()) + super().__init__(ProxyMessageType.PUT_CANCEL, b"") class ProxyClosureRequest(ReservedCfdpMessage): @@ -337,10 +332,7 @@ def __init__(self, transaction_id: TransactionId): "sequence number" ) value = bytearray( - [ - ((transaction_id.source_id.byte_len - 1) << 4) - | (transaction_id.seq_num.byte_len - 1) - ] + [((transaction_id.source_id.byte_len - 1) << 4) | (transaction_id.seq_num.byte_len - 1)] ) value.extend(transaction_id.source_id.as_bytes) value.extend(transaction_id.seq_num.as_bytes) @@ -428,9 +420,7 @@ class ProxyPutResponseParams: file_status: FileStatus @classmethod - def from_finished_params( - cls, finished_params: FinishedParams - ) -> ProxyPutResponseParams: + def from_finished_params(cls, finished_params: FinishedParams) -> ProxyPutResponseParams: return cls( condition_code=finished_params.condition_code, delivery_code=finished_params.delivery_code, @@ -443,10 +433,6 @@ def __init__(self, params: ProxyPutResponseParams): super().__init__( ProxyMessageType.PUT_RESPONSE, bytes( - [ - (params.condition_code << 4) - | (params.delivery_code << 2) - | params.file_status - ] + [(params.condition_code << 4) | (params.delivery_code << 2) | params.file_status] ), ) diff --git a/spacepackets/cfdp/tlv/tlv.py b/spacepackets/cfdp/tlv/tlv.py index 601d2a2..951aa45 100644 --- a/spacepackets/cfdp/tlv/tlv.py +++ b/spacepackets/cfdp/tlv/tlv.py @@ -1,7 +1,5 @@ from __future__ import annotations -from typing import Optional, Tuple - from spacepackets.cfdp.defs import ( ConditionCode, FaultHandlerCode, @@ -12,9 +10,9 @@ FilestoreActionCode, FilestoreResponseStatusCode, TlvType, + TlvTypeMissmatchError, ) from spacepackets.exceptions import BytesTooShortError -from spacepackets.cfdp.exceptions import TlvTypeMissmatch from spacepackets.util import UnsignedByteField @@ -24,7 +22,7 @@ def map_enum_status_code_to_int(status_code: FilestoreResponseStatusCode) -> int def map_enum_status_code_to_action_status_code( status_code_enum: FilestoreResponseStatusCode, -) -> Tuple[FilestoreActionCode, int]: +) -> tuple[FilestoreActionCode, int]: """Map a given file store response status code to the action code and the corresponding 4 bit status code. the status code will be 0x00 for a SUCCESS operation and 0b1111 if the operation was not performed. @@ -45,8 +43,7 @@ def map_int_status_code_to_enum( code was detected """ try: - status_code = FilestoreResponseStatusCode(action_code << 4 | status_code) - return status_code + return FilestoreResponseStatusCode(action_code << 4 | status_code) except (IndexError, ValueError): return FilestoreResponseStatusCode.INVALID @@ -74,11 +71,11 @@ def __init__(self, tlv_type: TlvType, value: bytes): self._value = value @property - def tlv_type(self): + def tlv_type(self) -> TlvType: return self._tlv_type @tlv_type.setter - def tlv_type(self, tlv_type: TlvType): + def tlv_type(self, tlv_type: TlvType) -> None: self._tlv_type = tlv_type @property @@ -105,11 +102,10 @@ def unpack(cls, data: bytes) -> CfdpTlv: raise BytesTooShortError(2, len(data)) try: tlv_type = TlvType(data[0]) - except ValueError: + except ValueError as err: raise ValueError( - f"TLV field invalid, found value {data[0]} is not a possible TLV" - " parameter" - ) + f"TLV field invalid, found value {data[0]} is not a possible TLV" " parameter" + ) from err value = bytearray() if len(data) > 2: @@ -124,10 +120,7 @@ def packet_len(self) -> int: return self.MINIMAL_LEN + len(self._value) def __repr__(self): - return ( - f"{self.__class__.__name__}(tlv_type={self.tlv_type!r}," - f" value={self.value!r})" - ) + return f"{self.__class__.__name__}(tlv_type={self.tlv_type!r}," f" value={self.value!r})" def __str__(self): return ( @@ -155,7 +148,7 @@ def pack(self) -> bytearray: return self.tlv.pack() @property - def packet_len(self): + def packet_len(self) -> int: return self.tlv.packet_len @property @@ -178,16 +171,14 @@ def unpack(cls, data: bytes) -> FaultHandlerOverrideTlv: fault_handler_ovr_tlv = cls.__empty() fault_handler_ovr_tlv.tlv = CfdpTlv.unpack(data=data) fault_handler_ovr_tlv.check_type(tlv_type=FaultHandlerOverrideTlv.TLV_TYPE) - fault_handler_ovr_tlv.condition_code = ( - fault_handler_ovr_tlv.tlv.value[0] & 0xF0 - ) >> 4 + fault_handler_ovr_tlv.condition_code = (fault_handler_ovr_tlv.tlv.value[0] & 0xF0) >> 4 fault_handler_ovr_tlv.handler_code = fault_handler_ovr_tlv.tlv.value[0] & 0x0F return fault_handler_ovr_tlv @classmethod def from_tlv(cls, cfdp_tlv: CfdpTlv) -> FaultHandlerOverrideTlv: if cfdp_tlv.tlv_type != cls.TLV_TYPE: - raise TlvTypeMissmatch(cfdp_tlv.tlv_type, cls.TLV_TYPE) + raise TlvTypeMissmatchError(cfdp_tlv.tlv_type, cls.TLV_TYPE) fault_handler_tlv = cls.__empty() fault_handler_tlv.tlv = cfdp_tlv fault_handler_tlv.condition_code = (cfdp_tlv.value[0] >> 4) & 0x0F @@ -199,7 +190,7 @@ def create_cfdp_proxy_and_dir_op_message_marker() -> bytes: """CCSDS 727.0-B-5 p.88: The message identifier for standard CFDP proxy and dir op messages is the presence of the ASCII characters 'cfdp' in the first four octests of each message """ - return "cfdp".encode() + return b"cfdp" class FlowLabelTlv(AbstractTlvBase): @@ -209,14 +200,14 @@ def __init__(self, flow_label: bytes): self.tlv = CfdpTlv(tlv_type=self.tlv_type, value=flow_label) @classmethod - def __empty(cls): - return cls(bytes()) + def __empty(cls) -> FlowLabelTlv: + return cls(b"") def pack(self) -> bytearray: return self.tlv.pack() @property - def packet_len(self): + def packet_len(self) -> int: return self.tlv.packet_len @property @@ -232,14 +223,14 @@ def unpack(cls, data: bytes) -> FlowLabelTlv: flow_label_tlv = cls.__empty() tlv = CfdpTlv.unpack(data=data) if tlv.tlv_type != FlowLabelTlv.TLV_TYPE: - raise TlvTypeMissmatch(tlv.tlv_type, cls.TLV_TYPE) + raise TlvTypeMissmatchError(tlv.tlv_type, cls.TLV_TYPE) flow_label_tlv.tlv = tlv return flow_label_tlv @classmethod def from_tlv(cls, cfdp_tlv: CfdpTlv) -> FlowLabelTlv: if cfdp_tlv.tlv_type != FlowLabelTlv.TLV_TYPE: - raise TlvTypeMissmatch(cfdp_tlv.tlv_type, cls.TLV_TYPE) + raise TlvTypeMissmatchError(cfdp_tlv.tlv_type, cls.TLV_TYPE) flow_label_tlv = cls.__empty() flow_label_tlv.tlv = cfdp_tlv return flow_label_tlv @@ -255,7 +246,7 @@ def __init__( self.action_code = action_code self.first_file_name = first_file_name self.second_file_name = second_file_name - self.tlv: Optional[CfdpTlv] = None + self.tlv: CfdpTlv | None = None def _common_packer(self, status_code: int) -> bytearray: tlv_value = bytearray() @@ -283,18 +274,18 @@ def common_packet_len(self) -> int: return expected_len @staticmethod - def _check_raw_tlv_field(first_byte: int, expected: TlvType): + def _check_raw_tlv_field(first_byte: int, expected: TlvType) -> None: try: raw_tlv_type = TlvType(first_byte) if raw_tlv_type != expected: - raise TlvTypeMissmatch(raw_tlv_type, expected) - except IndexError: - raise ValueError(f"No TLV type for raw field {first_byte}") + raise TlvTypeMissmatchError(raw_tlv_type, expected) + except IndexError as err: + raise ValueError(f"No TLV type for raw field {first_byte}") from err @staticmethod def _common_unpacker( raw_bytes: bytes, - ) -> Tuple[FilestoreActionCode, str, int, int, Optional[str]]: + ) -> tuple[FilestoreActionCode, str, int, int, str | None]: """Does only unpack common fields, does not unpack the filestore message of a Filestore Response package @@ -306,11 +297,10 @@ def _common_unpacker( action_code_as_int = (raw_bytes[value_idx] >> 4) & 0x0F try: action_code = FilestoreActionCode(action_code_as_int) - except ValueError: + except ValueError as err: raise ValueError( - "Invalid action code in file store response with value" - f" {action_code_as_int}" - ) + "Invalid action code in file store response with value" f" {action_code_as_int}" + ) from err status_code_as_int = raw_bytes[value_idx] & 0x0F value_idx += 1 first_lv = CfdpLv.unpack(raw_bytes=raw_bytes[value_idx:]) @@ -350,7 +340,7 @@ def __init__( second_file_name=second_file_name, ) - def generate_tlv(self): + def generate_tlv(self) -> None: if self.tlv is None: self.tlv = self._build_tlv() @@ -359,7 +349,7 @@ def pack(self) -> bytearray: return self.tlv.pack() @property - def packet_len(self): + def packet_len(self) -> int: return self.common_packet_len() @property @@ -393,16 +383,14 @@ def unpack(cls, data: bytes) -> FileStoreRequestTlv: @classmethod def from_tlv(cls, cfdp_tlv: CfdpTlv) -> FileStoreRequestTlv: if cfdp_tlv.tlv_type != cls.TLV_TYPE: - raise TlvTypeMissmatch(cfdp_tlv.tlv_type, cls.TLV_TYPE) + raise TlvTypeMissmatchError(cfdp_tlv.tlv_type, cls.TLV_TYPE) fs_response = cls.__empty() cls._set_fields(fs_response, cfdp_tlv.value) return fs_response @classmethod - def _set_fields(cls, instance: FileStoreRequestTlv, raw_data: bytes): - action_code, first_name, _, _, second_name = cls._common_unpacker( - raw_bytes=raw_data - ) + def _set_fields(cls, instance: FileStoreRequestTlv, raw_data: bytes) -> FileStoreRequestTlv: + action_code, first_name, _, _, second_name = cls._common_unpacker(raw_bytes=raw_data) instance.action_code = action_code instance.first_file_name = first_name if second_name is not None: @@ -419,8 +407,10 @@ def __init__( status_code: FilestoreResponseStatusCode, first_file_name: str, second_file_name: str = "", - filestore_msg: CfdpLv = CfdpLv(value=bytes()), + filestore_msg: None | CfdpLv = None, ): + if filestore_msg is None: + filestore_msg = CfdpLv(value=b"") super().__init__( action_code=action_code, first_file_name=first_file_name, @@ -429,7 +419,7 @@ def __init__( self.status_code = status_code self.filestore_msg = filestore_msg - def generate_tlv(self): + def generate_tlv(self) -> None: if self.tlv is None: self.tlv = self._build_tlv() @@ -443,7 +433,7 @@ def value(self) -> bytes: return self.tlv.value # type: ignore @property - def packet_len(self): + def packet_len(self) -> int: return self.common_packet_len() + self.filestore_msg.packet_len @property @@ -475,27 +465,25 @@ def unpack(cls, data: bytes) -> FileStoreResponseTlv: @classmethod def from_tlv(cls, cfdp_tlv: CfdpTlv) -> FileStoreResponseTlv: if cfdp_tlv.tlv_type != cls.TLV_TYPE: - raise TlvTypeMissmatch(cfdp_tlv.tlv_type, cls.TLV_TYPE) + raise TlvTypeMissmatchError(cfdp_tlv.tlv_type, cls.TLV_TYPE) fs_response = FileStoreResponseTlv.__empty() cls._set_fields(fs_response, cfdp_tlv.value) return fs_response @classmethod - def _set_fields(cls, instance: FileStoreResponseTlv, data: bytes): + def _set_fields(cls, instance: FileStoreResponseTlv, data: bytes) -> None: action_code, first_name, status_code, idx, second_name = cls._common_unpacker( raw_bytes=data ) instance.action_code = action_code instance.first_file_name = first_name try: - status_code_named = FilestoreResponseStatusCode( - action_code << 4 | status_code - ) - except ValueError: + status_code_named = FilestoreResponseStatusCode(action_code << 4 | status_code) + except ValueError as err: raise ValueError( "Invalid status code in file store response with value" f" {status_code} for action code {action_code}" - ) + ) from err instance.status_code = status_code_named if second_name is not None: instance.second_file_name = second_name @@ -503,8 +491,8 @@ def _set_fields(cls, instance: FileStoreResponseTlv, data: bytes): class EntityIdTlv(AbstractTlvBase): - """This helper class has a :py:meth:`__eq__` implementation which only compares the numerical value - of the entity IDs""" + """This helper class has a :py:meth:`__eq__` implementation which only compares the numerical + value of the entity IDs""" TLV_TYPE = TlvType.ENTITY_ID @@ -515,7 +503,7 @@ def pack(self) -> bytearray: return self.tlv.pack() @property - def packet_len(self): + def packet_len(self) -> int: return self.tlv.packet_len @property @@ -528,7 +516,7 @@ def value(self) -> bytes: @classmethod def __empty(cls) -> EntityIdTlv: - return cls(entity_id=bytes()) + return cls(entity_id=b"") @classmethod def unpack(cls, data: bytes) -> EntityIdTlv: @@ -540,7 +528,7 @@ def unpack(cls, data: bytes) -> EntityIdTlv: @classmethod def from_tlv(cls, cfdp_tlv: CfdpTlv) -> EntityIdTlv: if cfdp_tlv.tlv_type != cls.TLV_TYPE: - raise TlvTypeMissmatch(cfdp_tlv.tlv_type, cls.TLV_TYPE) + raise TlvTypeMissmatchError(cfdp_tlv.tlv_type, cls.TLV_TYPE) entity_id_tlv = cls.__empty() entity_id_tlv.tlv = cfdp_tlv return entity_id_tlv diff --git a/spacepackets/countdown.py b/spacepackets/countdown.py index e7676c7..a221917 100644 --- a/spacepackets/countdown.py +++ b/spacepackets/countdown.py @@ -1,7 +1,7 @@ from __future__ import annotations + import time from datetime import timedelta -from typing import Optional def time_ms() -> int: @@ -13,7 +13,7 @@ class Countdown: """Utility class for counting down time. Exposes a simple API to initiate it with an initial timeout and to check whether is has expired.""" - def __init__(self, init_timeout: Optional[timedelta]): + def __init__(self, init_timeout: timedelta | None): if init_timeout is not None: self._timeout_ms = int(init_timeout / timedelta(milliseconds=1)) self._start_time_ms = time_ms() @@ -39,28 +39,25 @@ def timeout(self) -> timedelta: return timedelta(milliseconds=self._timeout_ms) @timeout.setter - def timeout(self, timeout: timedelta): + def timeout(self, timeout: timedelta) -> None: """Set a new timeout for the countdown instance.""" self._timeout_ms = round(timeout / timedelta(milliseconds=1)) def timed_out(self) -> bool: - if round(time_ms() - self._start_time_ms) >= self._timeout_ms: - return True - else: - return False + return round(time_ms() - self._start_time_ms) >= self._timeout_ms def busy(self) -> bool: return not self.timed_out() - def reset(self, new_timeout: Optional[timedelta] = None): + def reset(self, new_timeout: timedelta | None = None) -> None: if new_timeout is not None: self.timeout = new_timeout self.start() - def start(self): + def start(self) -> None: self._start_time_ms = time_ms() - def time_out(self): + def time_out(self) -> None: self._start_time_ms = 0 def remaining_time(self) -> timedelta: diff --git a/spacepackets/ecss/__init__.py b/spacepackets/ecss/__init__.py index aa34f70..1775616 100644 --- a/spacepackets/ecss/__init__.py +++ b/spacepackets/ecss/__init__.py @@ -1,21 +1,43 @@ from crcmod.predefined import mkPredefinedCrcFun -from .tc import PusTc, PusTelecommand, PusTcDataFieldHeader -from .tm import PusTm, PusTelemetry, PusTmSecondaryHeader +from .defs import PusService, PusVersion from .fields import ( - PacketFieldEnum, PacketFieldBase, + PacketFieldEnum, PacketFieldU8, PacketFieldU16, PacketFieldU32, - Ptc, PfcReal, PfcSigned, PfcUnsigned, + Ptc, ) -from .defs import PusService, PusVersion -from .req_id import RequestId from .pus_verificator import PusVerificator +from .req_id import RequestId +from .tc import PusTc, PusTcDataFieldHeader, PusTelecommand +from .tm import PusTelemetry, PusTm, PusTmSecondaryHeader + +__all__ = [ + "PacketFieldBase", + "PacketFieldEnum", + "PacketFieldU8", + "PacketFieldU16", + "PacketFieldU32", + "PfcReal", + "PfcSigned", + "PfcUnsigned", + "Ptc", + "PusService", + "PusTc", + "PusTcDataFieldHeader", + "PusTelecommand", + "PusTelemetry", + "PusTm", + "PusTmSecondaryHeader", + "PusVerificator", + "PusVersion", + "RequestId", +] def check_pus_crc(tc_packet: bytes) -> bool: diff --git a/spacepackets/ecss/exceptions.py b/spacepackets/ecss/exceptions.py index 82be323..c48c923 100644 --- a/spacepackets/ecss/exceptions.py +++ b/spacepackets/ecss/exceptions.py @@ -4,5 +4,3 @@ class TmSrcDataTooShortError(BytesTooShortError): """Similar to the :py:class:`BytesTooShortError`, but specifies that the source data field of the PUS telemetry packet is too short.""" - - pass diff --git a/spacepackets/ecss/fields.py b/spacepackets/ecss/fields.py index 960b779..8125f8b 100644 --- a/spacepackets/ecss/fields.py +++ b/spacepackets/ecss/fields.py @@ -1,4 +1,5 @@ from __future__ import annotations + import enum import struct from dataclasses import dataclass @@ -86,20 +87,20 @@ def __init__(self, pfc: int, val: int): self.val = val @classmethod - def with_byte_size(cls, num_bytes: int, val: int): + def with_byte_size(cls, num_bytes: int, val: int) -> PacketFieldEnum: return cls(num_bytes * 8, val) def pack(self) -> bytearray: num_bytes = self.check_pfc(self.pfc) return bytearray(IntByteConversion.to_unsigned(num_bytes, self.val)) - def len(self): + def len(self) -> int: """Return the length in bytes. This will raise a ValueError for non-byte-aligned PFC values.""" return self.check_pfc(self.pfc) @classmethod - def unpack(cls, data: bytes, pfc: int): + def unpack(cls, data: bytes, pfc: int) -> PacketFieldEnum: """Construct from a raw bytestream. :raises BytesTooShortError: Raw bytestream too short. diff --git a/spacepackets/ecss/pus_17_test.py b/spacepackets/ecss/pus_17_test.py index 252039f..756d538 100644 --- a/spacepackets/ecss/pus_17_test.py +++ b/spacepackets/ecss/pus_17_test.py @@ -1,10 +1,14 @@ from __future__ import annotations + import enum +from typing import TYPE_CHECKING -from spacepackets import SpacePacketHeader -from spacepackets.ccsds.spacepacket import PacketId, PacketSeqCtrl from spacepackets.ecss.defs import PusService -from spacepackets.ecss.tm import PusTm, AbstractPusTm +from spacepackets.ecss.tm import AbstractPusTm, PusTm + +if TYPE_CHECKING: + from spacepackets import SpacePacketHeader + from spacepackets.ccsds.spacepacket import PacketId, PacketSeqCtrl class Subservice(enum.IntEnum): @@ -19,7 +23,7 @@ def __init__( subservice: int, timestamp: bytes, ssc: int = 0, - source_data: bytes = bytes(), + source_data: bytes = b"", packet_version: int = 0b000, space_time_ref: int = 0b0000, destination_id: int = 0, @@ -73,7 +77,7 @@ def pack(self) -> bytearray: @classmethod def __empty(cls) -> Service17Tm: - return cls(apid=0, subservice=0, timestamp=bytes()) + return cls(apid=0, subservice=0, timestamp=b"") @classmethod def unpack(cls, data: bytes, timestamp_len: int) -> Service17Tm: diff --git a/spacepackets/ecss/pus_1_verification.py b/spacepackets/ecss/pus_1_verification.py index 73250be..b0d5b78 100644 --- a/spacepackets/ecss/pus_1_verification.py +++ b/spacepackets/ecss/pus_1_verification.py @@ -1,21 +1,23 @@ -# -*- coding: utf-8 -*- """ECSS PUS Service 1 Verification""" + from __future__ import annotations import enum from dataclasses import dataclass -from typing import Optional +from typing import TYPE_CHECKING -from spacepackets.ccsds import SpacePacketHeader -from spacepackets.ccsds.spacepacket import PacketId, PacketSeqCtrl -from spacepackets.ecss import PusTc +from spacepackets import BytesTooShortError from spacepackets.ecss.defs import PusService from spacepackets.ecss.fields import PacketFieldEnum -from spacepackets.ecss.tm import PusTm, AbstractPusTm -from .exceptions import TmSrcDataTooShortError +from spacepackets.ecss.tm import AbstractPusTm, PusTm +from .exceptions import TmSrcDataTooShortError from .req_id import RequestId -from .. import BytesTooShortError + +if TYPE_CHECKING: + from spacepackets.ccsds import SpacePacketHeader + from spacepackets.ccsds.spacepacket import PacketId, PacketSeqCtrl + from spacepackets.ecss import PusTc class Subservice(enum.IntEnum): @@ -42,15 +44,15 @@ def __init__(self, code: ErrorCode, data: bytes): def pack(self) -> bytes: data = self.code.pack() data.extend(self.data) - return data + return bytes(data) - def len(self): + def len(self) -> int: return self.code.len() + len(self.data) @classmethod def unpack( - cls, data: bytes, num_bytes_err_code: int, num_bytes_data: Optional[int] = None - ): + cls, data: bytes, num_bytes_err_code: int, num_bytes_data: int | None = None + ) -> FailureNotice: pfc = num_bytes_err_code * 8 if num_bytes_data is None: num_bytes_data = len(data) - num_bytes_err_code @@ -76,8 +78,8 @@ class UnpackParams: @dataclass class VerificationParams: req_id: RequestId - step_id: Optional[StepId] = None - failure_notice: Optional[FailureNotice] = None + step_id: StepId | None = None + failure_notice: FailureNotice | None = None def pack(self) -> bytearray: data = bytearray(self.req_id.pack()) @@ -87,7 +89,7 @@ def pack(self) -> bytearray: data.extend(self.failure_notice.pack()) return data - def len(self): + def len(self) -> int: init_len = 4 if self.step_id is not None: init_len += self.step_id.len() @@ -95,24 +97,24 @@ def len(self): init_len += self.failure_notice.len() return init_len - def verify_against_subservice(self, subservice: Subservice): + def verify_against_subservice(self, subservice: Subservice) -> None: if subservice % 2 == 0: if self.failure_notice is None: - raise InvalidVerifParams("Failure Notice should be something") + raise InvalidVerifParamsError("Failure Notice should be something") if subservice == Subservice.TM_STEP_FAILURE and self.step_id is None: - raise InvalidVerifParams("Step ID should be something") - elif subservice != Subservice.TM_STEP_FAILURE and self.step_id is not None: - raise InvalidVerifParams("Step ID should be empty") + raise InvalidVerifParamsError("Step ID should be something") + if subservice != Subservice.TM_STEP_FAILURE and self.step_id is not None: + raise InvalidVerifParamsError("Step ID should be empty") else: if self.failure_notice is not None: - raise InvalidVerifParams("Failure Notice should be empty") + raise InvalidVerifParamsError("Failure Notice should be empty") if subservice == Subservice.TM_STEP_SUCCESS and self.step_id is None: - raise InvalidVerifParams("Step ID should be something") - elif subservice != Subservice.TM_STEP_SUCCESS and self.step_id is not None: - raise InvalidVerifParams("Step ID should be empty") + raise InvalidVerifParamsError("Step ID should be something") + if subservice != Subservice.TM_STEP_SUCCESS and self.step_id is not None: + raise InvalidVerifParamsError("Step ID should be empty") -class InvalidVerifParams(Exception): +class InvalidVerifParamsError(Exception): pass @@ -124,7 +126,7 @@ def __init__( apid: int, subservice: Subservice, timestamp: bytes, - verif_params: Optional[VerificationParams] = None, + verif_params: VerificationParams | None = None, seq_count: int = 0, packet_version: int = 0b000, space_time_ref: int = 0b0000, @@ -153,7 +155,7 @@ def pack(self) -> bytearray: @classmethod def __empty(cls) -> Service1Tm: - return cls(apid=0, subservice=Subservice.INVALID, timestamp=bytes()) + return cls(apid=0, subservice=Subservice.INVALID, timestamp=b"") @classmethod def from_tm(cls, tm: PusTm, params: UnpackParams) -> Service1Tm: @@ -174,9 +176,7 @@ def unpack(cls, data: bytes, params: UnpackParams) -> Service1Tm: :return: """ service_1_tm = cls.__empty() - service_1_tm.pus_tm = PusTm.unpack( - data=data, timestamp_len=params.timestamp_len - ) + service_1_tm.pus_tm = PusTm.unpack(data=data, timestamp_len=params.timestamp_len) cls._unpack_raw_tm(service_1_tm, params) return service_1_tm @@ -201,11 +201,11 @@ def sp_header(self) -> SpacePacketHeader: return self.pus_tm.space_packet_header @property - def service(self): + def service(self) -> int: return self.pus_tm.service @property - def subservice(self): + def subservice(self) -> int: return self.pus_tm.subservice @property @@ -213,7 +213,7 @@ def source_data(self) -> bytes: return self.pus_tm.source_data @classmethod - def _unpack_raw_tm(cls, instance: Service1Tm, params: UnpackParams): + def _unpack_raw_tm(cls, instance: Service1Tm, params: UnpackParams) -> None: tm_data = instance.pus_tm.tm_data if len(tm_data) < 4: raise TmSrcDataTooShortError(4, len(tm_data)) @@ -223,7 +223,7 @@ def _unpack_raw_tm(cls, instance: Service1Tm, params: UnpackParams): else: instance._unpack_success_verification(params) - def _unpack_failure_verification(self, unpack_cfg: UnpackParams): + def _unpack_failure_verification(self, unpack_cfg: UnpackParams) -> None: """Handle parsing a verification failure packet, subservice ID 2, 4, 6 or 8""" tm_data = self.pus_tm.tm_data subservice = self.pus_tm.subservice @@ -244,7 +244,7 @@ def _unpack_failure_verification(self, unpack_cfg: UnpackParams): tm_data[current_idx:], unpack_cfg.bytes_err_code, len(tm_data) - current_idx ) - def _unpack_success_verification(self, unpack_cfg: UnpackParams): + def _unpack_success_verification(self, unpack_cfg: UnpackParams) -> None: if self.pus_tm.subservice == Subservice.TM_STEP_SUCCESS: try: self._verif_params.step_id = StepId.unpack( @@ -252,14 +252,12 @@ def _unpack_success_verification(self, unpack_cfg: UnpackParams): data=self.pus_tm.tm_data[4 : 4 + unpack_cfg.bytes_step_id], ) except BytesTooShortError as e: - raise TmSrcDataTooShortError(e.expected_len, e.bytes_len) + raise TmSrcDataTooShortError(e.expected_len, e.bytes_len) from e elif self.pus_tm.subservice not in [1, 3, 7]: - raise ValueError( - f"invalid subservice {self.pus_tm.subservice}, not in [1, 3, 7]" - ) + raise ValueError(f"invalid subservice {self.pus_tm.subservice}, not in [1, 3, 7]") @property - def failure_notice(self) -> Optional[FailureNotice]: + def failure_notice(self) -> FailureNotice | None: return self._verif_params.failure_notice @property @@ -267,44 +265,36 @@ def has_failure_notice(self) -> bool: return (self.subservice % 2) == 0 @property - def tc_req_id(self): + def tc_req_id(self) -> RequestId: return self._verif_params.req_id @tc_req_id.setter - def tc_req_id(self, value): + def tc_req_id(self, value: RequestId) -> None: self._verif_params.req_id = value @property - def error_code(self) -> Optional[ErrorCode]: + def error_code(self) -> ErrorCode | None: if self.has_failure_notice: assert self._verif_params.failure_notice is not None return self._verif_params.failure_notice.code - else: - return None + return None @property def is_step_reply(self) -> bool: - return ( - self.subservice == Subservice.TM_STEP_FAILURE - or self.subservice == Subservice.TM_STEP_SUCCESS - ) + return self.subservice in (Subservice.TM_STEP_FAILURE, Subservice.TM_STEP_SUCCESS) @property - def step_id(self) -> Optional[StepId]: + def step_id(self) -> StepId | None: """Retrieve the step number. Returns NONE if this packet does not have a step ID""" return self._verif_params.step_id def __eq__(self, other: object): if isinstance(other, Service1Tm): - return (self.pus_tm == other.pus_tm) and ( - self._verif_params == other._verif_params - ) + return (self.pus_tm == other.pus_tm) and (self._verif_params == other._verif_params) return False -def create_acceptance_success_tm( - apid: int, pus_tc: PusTc, timestamp: bytes -) -> Service1Tm: +def create_acceptance_success_tm(apid: int, pus_tc: PusTc, timestamp: bytes) -> Service1Tm: return Service1Tm( apid=apid, subservice=Subservice.TM_ACCEPTANCE_SUCCESS, @@ -391,9 +381,7 @@ def create_step_failure_tm( ) -def create_completion_success_tm( - apid: int, pus_tc: PusTc, timestamp: bytes -) -> Service1Tm: +def create_completion_success_tm(apid: int, pus_tc: PusTc, timestamp: bytes) -> Service1Tm: return Service1Tm( apid=apid, subservice=Subservice.TM_COMPLETION_SUCCESS, diff --git a/spacepackets/ecss/pus_verificator.py b/spacepackets/ecss/pus_verificator.py index fd7b01d..5f5b64e 100644 --- a/spacepackets/ecss/pus_verificator.py +++ b/spacepackets/ecss/pus_verificator.py @@ -1,9 +1,9 @@ import enum from dataclasses import dataclass, field -from typing import Dict, Optional, List +from typing import Optional -from spacepackets.ecss import PusTc from spacepackets.ecss.pus_1_verification import RequestId, Service1Tm, Subservice +from spacepackets.ecss.tc import PusTc class StatusField(enum.IntEnum): @@ -18,11 +18,11 @@ class VerificationStatus: accepted: StatusField = StatusField.UNSET started: StatusField = StatusField.UNSET step: StatusField = StatusField.UNSET - step_list: List[int] = field(default_factory=lambda: []) + step_list: list[int] = field(default_factory=list) completed: StatusField = StatusField.UNSET -VerifDictT = Dict[RequestId, VerificationStatus] +VerifDictT = dict[RequestId, VerificationStatus] @dataclass @@ -54,8 +54,7 @@ class PusVerificator: """ def __init__(self): - self._verif_dict: VerifDictT = dict() - pass + self._verif_dict: VerifDictT = {} def add_tc(self, tc: PusTc) -> bool: req_id = RequestId.from_sp_header(tc.sp_header) @@ -70,15 +69,13 @@ def add_tm(self, pus_1_tm: Service1Tm) -> Optional[TmCheckResult]: return None verif_status = self._verif_dict.get(req_id) if pus_1_tm.subservice <= 0 or pus_1_tm.subservice > 8: - raise ValueError( - f"PUS 1 TM with invalid subservice {pus_1_tm.subservice} was passed" - ) + raise ValueError(f"PUS 1 TM with invalid subservice {pus_1_tm.subservice} was passed") res = TmCheckResult(status=VerificationStatus(), completed=False) res.status = verif_status return self._check_subservice(pus_1_tm, res, verif_status) - def _check_subservice( # noqa: C901 + def _check_subservice( self, pus_1_tm: Service1Tm, res: TmCheckResult, @@ -119,30 +116,25 @@ def _check_subservice( # noqa: C901 return res @property - def verif_dict(self): + def verif_dict(self) -> VerifDictT: return self._verif_dict def _handle_step_failure( self, verif_status: VerificationStatus, res: TmCheckResult, pus_1_tm: Service1Tm - ): + ) -> None: self._check_all_replies_recvd_after_step(verif_status) verif_status.step = StatusField.FAILURE verif_status.step_list.append(pus_1_tm.step_id.val) res.completed = True @staticmethod - def _check_all_replies_recvd_after_step(verif_stat: VerificationStatus): - if ( - verif_stat.accepted != StatusField.UNSET - and verif_stat.started != StatusField.UNSET - ): + def _check_all_replies_recvd_after_step(verif_stat: VerificationStatus) -> None: + if StatusField.UNSET not in (verif_stat.accepted, verif_stat.started): verif_stat.all_verifs_recvd = True - def remove_completed_entries(self): + def remove_completed_entries(self) -> None: self._verif_dict = { - key: val - for key, val in self._verif_dict.items() - if not val.all_verifs_recvd + key: val for key, val in self._verif_dict.items() if not val.all_verifs_recvd } def remove_entry(self, req_id: RequestId) -> bool: diff --git a/spacepackets/ecss/req_id.py b/spacepackets/ecss/req_id.py index 4bb99c6..94d891f 100644 --- a/spacepackets/ecss/req_id.py +++ b/spacepackets/ecss/req_id.py @@ -1,10 +1,13 @@ from __future__ import annotations import struct +from typing import TYPE_CHECKING from spacepackets import BytesTooShortError from spacepackets.ccsds.spacepacket import PacketId, PacketSeqCtrl, SpacePacketHeader -from spacepackets.ecss.tc import PusTc + +if TYPE_CHECKING: + from spacepackets.ecss.tc import PusTc class RequestId: @@ -23,15 +26,13 @@ class RequestId: '10,22,c0,11' """ - def __init__( - self, tc_packet_id: PacketId, tc_psc: PacketSeqCtrl, ccsds_version: int = 0b000 - ): + def __init__(self, tc_packet_id: PacketId, tc_psc: PacketSeqCtrl, ccsds_version: int = 0b000): self.tc_packet_id = tc_packet_id self.tc_psc = tc_psc self.ccsds_version = ccsds_version @classmethod - def empty(cls): + def empty(cls) -> RequestId: return cls(PacketId.empty(), PacketSeqCtrl.empty()) @classmethod @@ -47,7 +48,7 @@ def unpack(cls, tm_data: bytes) -> RequestId: ) @classmethod - def from_pus_tc(cls, pus_tc: PusTc): + def from_pus_tc(cls, pus_tc: PusTc) -> RequestId: return cls.from_sp_header(pus_tc.sp_header) @classmethod @@ -63,9 +64,9 @@ def pack(self) -> bytes: packet_id_and_version = (self.ccsds_version << 13) | self.tc_packet_id.raw() raw.extend(struct.pack("!H", packet_id_and_version)) raw.extend(struct.pack("!H", self.tc_psc.raw())) - return raw + return bytes(raw) - def as_u32(self): + def as_u32(self) -> int: packet_id_and_version = (self.ccsds_version << 13) | self.tc_packet_id.raw() return (packet_id_and_version << 16) | self.tc_psc.raw() diff --git a/spacepackets/ecss/tc.py b/spacepackets/ecss/tc.py index fe40235..bea17e1 100644 --- a/spacepackets/ecss/tc.py +++ b/spacepackets/ecss/tc.py @@ -4,26 +4,25 @@ from __future__ import annotations -from spacepackets import BytesTooShortError -from spacepackets.version import get_version import struct -from typing import Tuple, Optional import deprecation -from spacepackets.crc import CRC16_CCITT_FUNC from crcmod.predefined import PredefinedCrc +from spacepackets import BytesTooShortError from spacepackets.ccsds.spacepacket import ( - SpacePacketHeader, - PacketType, CCSDS_HEADER_LEN, - SpacePacket, AbstractSpacePacket, PacketId, PacketSeqCtrl, + PacketType, SequenceFlags, + SpacePacket, + SpacePacketHeader, ) +from spacepackets.crc import CRC16_CCITT_FUNC from spacepackets.ecss.defs import PusVersion +from spacepackets.version import get_version class PusTcDataFieldHeader: @@ -95,11 +94,11 @@ def __eq__(self, other: object): return False @classmethod - def get_header_size(cls): + def get_header_size(cls) -> int: return cls.PUS_C_SEC_HEADER_LEN -class InvalidTcCrc16(Exception): +class InvalidTcCrc16Error(Exception): def __init__(self, tc: PusTc): self.tc = tc @@ -123,7 +122,7 @@ def __init__( service: int, subservice: int, apid: int = 0, - app_data: bytes = bytes(), + app_data: bytes = b"", seq_count: int = 0, source_id: int = 0, ack_flags: int = 0b1111, @@ -161,7 +160,7 @@ def __init__( ) self._app_data = app_data self._valid = True - self._crc16: Optional[bytes] = None + self._crc16: bytes | None = None @classmethod def from_sp_header( @@ -172,7 +171,7 @@ def from_sp_header( app_data: bytes = bytes([]), source_id: int = 0, ack_flags: int = 0b1111, - ): + ) -> PusTc: pus_tc = cls.empty() sp_header.packet_type = PacketType.TC sp_header.sec_header_flag = True @@ -199,9 +198,7 @@ def from_composite_fields( ) -> PusTc: pus_tc = cls.empty() if sp_header.packet_type == PacketType.TM: - raise ValueError( - f"Invalid Packet Type {sp_header.packet_type} in CCSDS primary header" - ) + raise ValueError(f"Invalid Packet Type {sp_header.packet_type} in CCSDS primary header") pus_tc.sp_header = sp_header pus_tc.pus_tc_sec_header = sec_header pus_tc._app_data = app_data @@ -246,7 +243,7 @@ def to_space_packet(self) -> SpacePacket: user_data.extend(self._crc16) # type: ignore return SpacePacket(self.sp_header, self.pus_tc_sec_header.pack(), user_data) - def calc_crc(self): + def calc_crc(self) -> None: """Can be called to calculate the CRC16. Also sets the internal CRC16 field.""" crc = PredefinedCrc(crc_name="crc-ccitt-false") crc.update(self.sp_header.pack()) @@ -276,13 +273,11 @@ def unpack(cls, data: bytes) -> PusTc: :raises BytesTooShortError: Passed bytestream too short. :raises ValueError: Unsupported PUS version. - :raises InvalidTcCrc16: Invalid CRC16. + :raises InvalidTcCrc16Error: Invalid CRC16. """ tc_unpacked = cls.empty() tc_unpacked.sp_header = SpacePacketHeader.unpack(data=data) - tc_unpacked.pus_tc_sec_header = PusTcDataFieldHeader.unpack( - data=data[CCSDS_HEADER_LEN:] - ) + tc_unpacked.pus_tc_sec_header = PusTcDataFieldHeader.unpack(data=data[CCSDS_HEADER_LEN:]) header_len = CCSDS_HEADER_LEN + tc_unpacked.pus_tc_sec_header.get_header_size() expected_packet_len = tc_unpacked.packet_len if len(data) < expected_packet_len: @@ -290,7 +285,7 @@ def unpack(cls, data: bytes) -> PusTc: tc_unpacked._app_data = data[header_len : expected_packet_len - 2] tc_unpacked._crc16 = data[expected_packet_len - 2 : expected_packet_len] if CRC16_CCITT_FUNC(data[:expected_packet_len]) != 0: - raise InvalidTcCrc16(tc_unpacked) + raise InvalidTcCrc16Error(tc_unpacked) return tc_unpacked @property @@ -309,20 +304,18 @@ def get_data_length(app_data_len: int, secondary_header_len: int) -> int: The size of the TC packet is the size of the packet secondary header with source ID + the length of the application data + length of the CRC16 checksum - 1 """ - data_length = secondary_header_len + app_data_len + 1 - return data_length + return secondary_header_len + app_data_len + 1 @deprecation.deprecated( deprecated_in="v0.14.0rc3", current_version=get_version(), details="use pack and the class itself to build this instead", ) - def pack_command_tuple(self) -> Tuple[bytearray, PusTc]: + def pack_command_tuple(self) -> tuple[bytearray, PusTc]: """Pack a tuple consisting of the raw packet as the first entry and the class representation as the second entry """ - command_tuple = (self.pack(), self) - return command_tuple + return (self.pack(), self) @property def service(self) -> int: @@ -337,7 +330,7 @@ def source_id(self) -> int: return self.pus_tc_sec_header.source_id @source_id.setter - def source_id(self, source_id: int): + def source_id(self, source_id: int) -> None: self.pus_tc_sec_header.source_id = source_id @property @@ -365,22 +358,22 @@ def app_data(self) -> bytes: return self._app_data @app_data.setter - def app_data(self, app_data: bytes): + def app_data(self, app_data: bytes) -> None: self._app_data = app_data @property - def crc16(self) -> Optional[bytes]: + def crc16(self) -> bytes | None: """Will be the raw CRC16 if the telecommand was created using :py:meth:`unpack`, :py:meth:`pack` was called at least once or :py:meth:`calc_crc` was called at least once.""" return self._crc16 @seq_count.setter - def seq_count(self, value): + def seq_count(self, value: int) -> None: self.sp_header.seq_count = value @apid.setter - def apid(self, apid): + def apid(self, apid: int) -> None: self.sp_header.apid = apid @@ -395,7 +388,7 @@ def generate_packet_crc(tc_packet: bytearray) -> bytes: crc = CRC16_CCITT_FUNC(tc_packet[0 : len(tc_packet) - 2]) tc_packet[len(tc_packet) - 2] = (crc & 0xFF00) >> 8 tc_packet[len(tc_packet) - 1] = crc & 0xFF - return tc_packet + return bytes(tc_packet) def generate_crc(data: bytearray) -> bytes: @@ -404,4 +397,4 @@ def generate_crc(data: bytearray) -> bytes: data_with_crc += data crc = CRC16_CCITT_FUNC(data) data_with_crc.extend(struct.pack("!H", crc)) - return data_with_crc + return bytes(data_with_crc) diff --git a/spacepackets/ecss/tm.py b/spacepackets/ecss/tm.py index 4434071..b0c0fc6 100644 --- a/spacepackets/ecss/tm.py +++ b/spacepackets/ecss/tm.py @@ -4,31 +4,30 @@ from __future__ import annotations -from abc import abstractmethod import struct -from typing import Optional +from abc import abstractmethod import deprecation from crcmod.predefined import PredefinedCrc -from .exceptions import TmSrcDataTooShortError # noqa # re-export -from spacepackets.version import get_version -from spacepackets.exceptions import BytesTooShortError -from spacepackets.util import PrintFormats, get_printable_data_string from spacepackets.ccsds.spacepacket import ( - PacketSeqCtrl, - SpacePacketHeader, - SPACE_PACKET_HEADER_SIZE, CCSDS_HEADER_LEN, - get_total_space_packet_len_from_len_field, - PacketType, - SpacePacket, + SPACE_PACKET_HEADER_SIZE, AbstractSpacePacket, + PacketId, + PacketSeqCtrl, + PacketType, SequenceFlags, + SpacePacket, + SpacePacketHeader, + get_total_space_packet_len_from_len_field, ) -from spacepackets.ecss.defs import PusVersion from spacepackets.ccsds.time import CdsShortTimestamp from spacepackets.crc import CRC16_CCITT_FUNC +from spacepackets.ecss.defs import PusVersion +from spacepackets.exceptions import BytesTooShortError +from spacepackets.util import PrintFormats, get_printable_data_string +from spacepackets.version import get_version class AbstractPusTm(AbstractSpacePacket): @@ -113,7 +112,7 @@ def __empty(cls) -> PusTmSecondaryHeader: return PusTmSecondaryHeader( service=0, subservice=0, - timestamp=bytes(), + timestamp=b"", message_counter=0, ) @@ -155,13 +154,11 @@ def unpack(cls, data: bytes, timestamp_len: int) -> PusTmSecondaryHeader: current_idx += 1 secondary_header.subservice = data[current_idx] current_idx += 1 - secondary_header.message_counter = struct.unpack( - "!H", data[current_idx : current_idx + 2] - )[0] + secondary_header.message_counter = struct.unpack("!H", data[current_idx : current_idx + 2])[ + 0 + ] current_idx += 2 - secondary_header.dest_id = struct.unpack( - "!H", data[current_idx : current_idx + 2] - )[0] + secondary_header.dest_id = struct.unpack("!H", data[current_idx : current_idx + 2])[0] current_idx += 2 secondary_header.timestamp = data[current_idx : current_idx + timestamp_len] return secondary_header @@ -191,7 +188,7 @@ def header_size(self) -> int: PUS_TM_TIMESTAMP_OFFSET = CCSDS_HEADER_LEN + PusTmSecondaryHeader.MIN_LEN -class InvalidTmCrc16(Exception): +class InvalidTmCrc16Error(Exception): def __init__(self, tm: PusTm): self.tm = tm @@ -211,14 +208,14 @@ class PusTm(AbstractPusTm): The following doc example cuts off the timestamp (7 byte CDS Short) and the CRC16 from the ping packet because those change regularly. - >>> ping_tm = PusTm(service=17, subservice=2, seq_count=5, apid=0x01, timestamp=CdsShortTimestamp.now().pack()) # noqa + >>> ping_tm = PusTm(service=17, subservice=2, seq_count=5, apid=0x01, timestamp=CdsShortTimestamp.now().pack()) >>> ping_tm.service 17 >>> ping_tm.subservice 2 >>> ping_tm.pack()[:-9].hex(sep=',') '08,01,c0,05,00,0f,20,11,02,00,00,00,00' - """ + """ # noqa: E501 CDS_SHORT_SIZE = 7 PUS_TIMESTAMP_SIZE = CDS_SHORT_SIZE @@ -228,7 +225,7 @@ def __init__( service: int, subservice: int, timestamp: bytes, - source_data: bytes = bytes(), + source_data: bytes = b"", apid: int = 0, seq_count: int = 0, message_counter: int = 0, @@ -259,13 +256,11 @@ def __init__( spacecraft_time_ref=space_time_ref, timestamp=timestamp, ) - self._crc16: Optional[bytes] = None + self._crc16: bytes | None = None @classmethod def empty(cls) -> PusTm: - return PusTm( - apid=0, service=0, subservice=0, timestamp=CdsShortTimestamp.empty().pack() - ) + return PusTm(apid=0, service=0, subservice=0, timestamp=CdsShortTimestamp.empty().pack()) def pack(self, recalc_crc: bool = True) -> bytearray: """Serializes the packet into a raw bytearray. @@ -283,7 +278,7 @@ def pack(self, recalc_crc: bool = True) -> bytearray: tm_packet_raw.extend(self._crc16) return tm_packet_raw - def calc_crc(self): + def calc_crc(self) -> None: """Can be called to calculate the CRC16""" crc = PredefinedCrc(crc_name="crc-ccitt-false") crc.update(self.space_packet_header.pack()) @@ -300,7 +295,7 @@ def unpack(cls, data: bytes, timestamp_len: int) -> PusTm: you can supply None here. :raises BytesTooShortError: Passed bytestream too short. :raises ValueError: Unsupported PUS version. - :raises InvalidTmCrc16: Invalid CRC16. + :raises InvalidTmCrc16Error: Invalid CRC16. """ if data is None: raise ValueError("byte stream invalid") @@ -315,20 +310,16 @@ def unpack(cls, data: bytes, timestamp_len: int) -> PusTm: data=data[SPACE_PACKET_HEADER_SIZE:], timestamp_len=timestamp_len, ) - if ( - expected_packet_len - < pus_tm.pus_tm_sec_header.header_size + SPACE_PACKET_HEADER_SIZE - ): + if expected_packet_len < pus_tm.pus_tm_sec_header.header_size + SPACE_PACKET_HEADER_SIZE: raise ValueError("passed packet too short") pus_tm._source_data = data[ - pus_tm.pus_tm_sec_header.header_size - + SPACE_PACKET_HEADER_SIZE : expected_packet_len + pus_tm.pus_tm_sec_header.header_size + SPACE_PACKET_HEADER_SIZE : expected_packet_len - 2 ] pus_tm._crc16 = data[expected_packet_len - 2 : expected_packet_len] # CRC16-CCITT checksum if CRC16_CCITT_FUNC(data[:expected_packet_len]) != 0: - raise InvalidTmCrc16(pus_tm) + raise InvalidTmCrc16Error(pus_tm) return pus_tm @staticmethod @@ -352,9 +343,7 @@ def from_composite_fields( ) -> PusTm: pus_tm = cls.empty() if sp_header.packet_type == PacketType.TC: - raise ValueError( - f"Invalid Packet Type {sp_header.packet_type} in CCSDS primary header" - ) + raise ValueError(f"Invalid Packet Type {sp_header.packet_type} in CCSDS primary header") pus_tm.space_packet_header = sp_header pus_tm.pus_tm_sec_header = sec_header pus_tm._source_data = tm_data @@ -366,9 +355,7 @@ def to_space_packet(self) -> SpacePacket: self.calc_crc() user_data = bytearray(self._source_data) user_data.extend(self.crc16) # type: ignore - return SpacePacket( - self.space_packet_header, self.pus_tm_sec_header.pack(), user_data - ) + return SpacePacket(self.space_packet_header, self.pus_tm_sec_header.pack(), user_data) def __str__(self): return ( @@ -435,7 +422,7 @@ def tm_data(self) -> bytes: return self._source_data @tm_data.setter - def tm_data(self, data: bytes): + def tm_data(self, data: bytes) -> None: self._source_data = data stamp_len = len(self.pus_tm_sec_header.timestamp) self.space_packet_header.data_len = self.data_len_from_src_len_timestamp_len( @@ -443,29 +430,27 @@ def tm_data(self, data: bytes): ) @property - def apid(self): + def apid(self) -> int: return self.space_packet_header.apid @apid.setter - def apid(self, apid: int): + def apid(self, apid: int) -> None: self.space_packet_header.apid = apid @property - def seq_flags(self): + def seq_flags(self) -> SequenceFlags: return self.space_packet_header.seq_flags @seq_flags.setter - def seq_flags(self, seq_flags): + def seq_flags(self, seq_flags: SequenceFlags) -> None: self.space_packet_header.seq_flags = seq_flags @property - def packet_id(self): + def packet_id(self) -> PacketId: return self.space_packet_header.packet_id @staticmethod - def data_len_from_src_len_timestamp_len( - timestamp_len: int, source_data_len: int - ) -> int: + def data_len_from_src_len_timestamp_len(timestamp_len: int, source_data_len: int) -> int: """Retrieve size of TM packet data header in bytes. Only support PUS C Formula according to PUS Standard: C = (Number of octets in packet source data field) - 1. The size of the TM packet is the size of the packet secondary header with @@ -494,7 +479,7 @@ def seq_count(self) -> int: return self.space_packet_header.seq_count @property - def crc16(self) -> Optional[bytes]: + def crc16(self) -> bytes | None: """Will be the raw CRC16 if the telecommand was created using :py:meth:`unpack` or :py:meth:`pack` was called at least once.""" return self._crc16 @@ -503,13 +488,10 @@ def crc16(self) -> Optional[bytes]: deprecated_in="0.14.0rc3", current_version=get_version(), details=( - "use pack and get_printable_data_string or the hex method on bytearray" - " instead" + "use pack and get_printable_data_string or the hex method on bytearray" " instead" ), ) - def get_full_packet_string( - self, print_format: PrintFormats = PrintFormats.HEX - ) -> str: + def get_full_packet_string(self, print_format: PrintFormats = PrintFormats.HEX) -> str: packet_raw = self.pack() return get_printable_data_string(print_format=print_format, data=packet_raw) @@ -517,23 +499,19 @@ def get_full_packet_string( deprecated_in="0.14.0rc3", current_version=get_version(), details=( - "use pack and get_printable_data_string or the hex method on bytearray" - " instead" + "use pack and get_printable_data_string or the hex method on bytearray" " instead" ), ) - def print_full_packet_string(self, print_format: PrintFormats = PrintFormats.HEX): + def print_full_packet_string(self, print_format: PrintFormats = PrintFormats.HEX) -> None: """Print the full TM packet in a clean format.""" print(self.get_full_packet_string(print_format=print_format)) @deprecation.deprecated( deprecated_in="0.14.0rc3", current_version=get_version(), - details=( - "use print, the source_data property and the hex method on bytearray" - " instead" - ), + details=("use print, the source_data property and the hex method on bytearray" " instead"), ) - def print_source_data(self, print_format: PrintFormats = PrintFormats.HEX): + def print_source_data(self, print_format: PrintFormats = PrintFormats.HEX) -> None: """Prints the TM source data in a clean format""" print(self.get_source_data_string(print_format=print_format)) @@ -542,13 +520,9 @@ def print_source_data(self, print_format: PrintFormats = PrintFormats.HEX): current_version=get_version(), details="use the source_data property and the hex method on bytearray instead", ) - def get_source_data_string( - self, print_format: PrintFormats = PrintFormats.HEX - ) -> str: + def get_source_data_string(self, print_format: PrintFormats = PrintFormats.HEX) -> str: """Returns the source data string""" - return get_printable_data_string( - print_format=print_format, data=self._source_data - ) + return get_printable_data_string(print_format=print_format, data=self._source_data) PusTelemetry = PusTm diff --git a/spacepackets/exceptions.py b/spacepackets/exceptions.py index 8bc5bcb..5fb9a16 100644 --- a/spacepackets/exceptions.py +++ b/spacepackets/exceptions.py @@ -3,8 +3,6 @@ class BytesTooShortError(ValueError): short.""" def __init__(self, expected_len: int, bytes_len: int): - super().__init__( - f"bytearray with length {bytes_len} shorter than expected {expected_len}" - ) + super().__init__(f"bytearray with length {bytes_len} shorter than expected {expected_len}") self.expected_len = expected_len self.bytes_len = bytes_len diff --git a/spacepackets/seqcount.py b/spacepackets/seqcount.py index 80bb874..e5339fe 100644 --- a/spacepackets/seqcount.py +++ b/spacepackets/seqcount.py @@ -2,7 +2,7 @@ needed when working with space packet protocols. """ -from abc import abstractmethod, ABC +from abc import ABC, abstractmethod from pathlib import Path @@ -14,16 +14,14 @@ def max_bit_width(self) -> int: @max_bit_width.setter @abstractmethod - def max_bit_width(self, width: int): + def max_bit_width(self, width: int) -> None: pass @abstractmethod def get_and_increment(self) -> int: """Contract: Retrieve the current sequence count and then increment it. The first call should yield 0""" - raise NotImplementedError( - "Please use a concrete class implementing this method" - ) + raise NotImplementedError("Please use a concrete class implementing this method") def __next__(self): return self.get_and_increment() @@ -46,10 +44,10 @@ def max_bit_width(self) -> int: return self._max_bit_width @max_bit_width.setter - def max_bit_width(self, width: int): + def max_bit_width(self, width: int) -> None: self._max_bit_width = width - def create_new(self): + def create_new(self) -> None: with open(self.file_name, "w") as file: file.write("0\n") @@ -81,8 +79,7 @@ def _increment_with_rollover(self, seq_cnt: int) -> int: """CCSDS Sequence count has maximum size of 14 bit. Rollover after that size by default""" if seq_cnt >= pow(2, self.max_bit_width) - 1: return 0 - else: - return seq_cnt + 1 + return seq_cnt + 1 class CcsdsFileSeqCountProvider(FileSeqCountProvider): @@ -104,7 +101,7 @@ def max_bit_width(self) -> int: return self._max_bit_width @max_bit_width.setter - def max_bit_width(self, width: int): + def max_bit_width(self, width: int) -> None: self._max_bit_width = width def get_and_increment(self) -> int: diff --git a/spacepackets/uslp/__init__.py b/spacepackets/uslp/__init__.py index 2e8a001..019c7fa 100644 --- a/spacepackets/uslp/__init__.py +++ b/spacepackets/uslp/__init__.py @@ -1,15 +1,28 @@ +from .defs import * # noqa: F403 from .frame import ( FrameHeaderT, - TransferFrameDataField, - TransferFrame, TfdzConstructionRules, + TransferFrame, + TransferFrameDataField, UslpProtocolIdentifier, ) from .header import ( - TruncatedPrimaryHeader, + BypassSequenceControlFlag, PrimaryHeader, - SourceOrDestField, ProtocolCommandFlag, - BypassSequenceControlFlag, + SourceOrDestField, + TruncatedPrimaryHeader, ) -from .defs import * # noqa: F403 + +__all__ = [ + "BypassSequenceControlFlag", + "FrameHeaderT", + "PrimaryHeader", + "ProtocolCommandFlag", + "SourceOrDestField", + "TfdzConstructionRules", + "TransferFrame", + "TransferFrameDataField", + "TruncatedPrimaryHeader", + "UslpProtocolIdentifier", +] diff --git a/spacepackets/uslp/defs.py b/spacepackets/uslp/defs.py index 5423323..d6e943c 100644 --- a/spacepackets/uslp/defs.py +++ b/spacepackets/uslp/defs.py @@ -1,26 +1,26 @@ -class UslpInvalidFrameHeader(Exception): +class UslpInvalidFrameHeaderError(Exception): pass -class UslpInvalidRawPacketOrFrameLen(Exception): +class UslpInvalidRawPacketOrFrameLenError(Exception): pass -class UslpInvalidConstructionRules(Exception): +class UslpInvalidConstructionRulesError(Exception): pass -class UslpFhpVhopFieldMissing(Exception): +class UslpFhpVhopFieldMissingError(Exception): pass -class UslpTruncatedFrameNotAllowed(Exception): +class UslpTruncatedFrameNotAllowedError(Exception): pass -class UslpVersionMissmatch(Exception): +class UslpVersionMissmatchError(Exception): pass -class UslpTypeMissmatch(Exception): +class UslpTypeMissmatchError(Exception): pass diff --git a/spacepackets/uslp/frame.py b/spacepackets/uslp/frame.py index 47577a7..6850862 100644 --- a/spacepackets/uslp/frame.py +++ b/spacepackets/uslp/frame.py @@ -1,24 +1,24 @@ from __future__ import annotations + import enum import struct +from typing import Union +from .defs import ( + UslpFhpVhopFieldMissingError, + UslpInvalidConstructionRulesError, + UslpInvalidFrameHeaderError, + UslpInvalidRawPacketOrFrameLenError, + UslpTruncatedFrameNotAllowedError, +) from .header import ( - TruncatedPrimaryHeader, + HeaderType, PrimaryHeader, SourceOrDestField, + TruncatedPrimaryHeader, determine_header_type, - HeaderType, -) -from .defs import ( - UslpInvalidRawPacketOrFrameLen, - UslpTruncatedFrameNotAllowed, - UslpInvalidConstructionRules, - UslpInvalidFrameHeader, - UslpFhpVhopFieldMissing, ) -from typing import Union, Optional - FrameHeaderT = Union[TruncatedPrimaryHeader, PrimaryHeader] USLP_TFDF_MAX_SIZE = 65529 @@ -41,8 +41,8 @@ def __init__( self, has_insert_zone: bool, has_fecf: bool, - insert_zone_len: Optional[int] = None, - fecf_len: Optional[int] = None, + insert_zone_len: int | None = None, + fecf_len: int | None = None, ): if has_insert_zone and insert_zone_len is None: raise ValueError @@ -60,8 +60,8 @@ def __init__( fixed_len: int, has_insert_zone: bool, has_fecf: bool, - insert_zone_len: Optional[int] = None, - fecf_len: Optional[int] = None, + insert_zone_len: int | None = None, + fecf_len: int | None = None, ): """Contains properties required when unpacking fixed USLP frames. These properties can not be determined by parsing the frame. The standard refers to these properties @@ -87,8 +87,8 @@ def __init__( has_insert_zone: bool, has_fecf: bool, truncated_frame_len: int, - insert_zone_len: Optional[int] = None, - fecf_len: Optional[int] = None, + insert_zone_len: int | None = None, + fecf_len: int | None = None, ): """Contains properties required when unpacking variable USLP frames. These properties can not be determined by parsing the frame. The standard refers to these properties @@ -165,7 +165,7 @@ def __init__( tfdz_cnstr_rules: TfdzConstructionRules, uslp_ident: UslpProtocolIdentifier, tfdz: bytes, - fhp_or_lvop: Optional[int] = None, + fhp_or_lvop: int | None = None, ): """ Notes on the FHP or LVOP field. For more details, refer to CCSDS 732.1-B-2. p.92: @@ -205,23 +205,21 @@ def __init__( raise ValueError @property - def tfdz(self): + def tfdz(self) -> bytes: return self._tfdz @tfdz.setter - def tfdz(self, tfdz: bytes): + def tfdz(self, tfdz: bytes) -> None: self._tfdz = tfdz self._size = self.header_len() + len(tfdz) def header_len(self) -> int: return 1 if self.fhp_or_lvop is None else 3 - def len(self): + def len(self) -> int: return self._size - def pack( - self, truncated: bool = False, frame_type: Optional[FrameType] = None - ) -> bytearray: + def pack(self, truncated: bool = False, frame_type: FrameType | None = None) -> bytearray: packet = bytearray() packet.append(self.tfdz_contr_rules << 5 | self.uslp_ident) if frame_type is None: @@ -230,64 +228,56 @@ def pack( frame_type = FrameType.FIXED elif self.__cnstr_rules_for_vp(): frame_type = FrameType.VARIABLE - if self.should_have_fhp_or_lvp_field( - truncated=truncated, frame_type=frame_type - ): + if self.should_have_fhp_or_lvp_field(truncated=truncated, frame_type=frame_type): if self.fhp_or_lvop is None: - raise UslpFhpVhopFieldMissing + raise UslpFhpVhopFieldMissingError packet.extend(struct.pack("!H", self.fhp_or_lvop)) packet.extend(self.tfdz) return packet - def should_have_fhp_or_lvp_field( - self, truncated: bool, frame_type: Optional[FrameType] - ) -> bool: + def should_have_fhp_or_lvp_field(self, truncated: bool, frame_type: FrameType | None) -> bool: if frame_type is not None and frame_type == FrameType.VARIABLE: return False - if not truncated and self.tfdz_contr_rules in [ - TfdzConstructionRules.FpPacketSpanningMultipleFrames, - TfdzConstructionRules.FpContinuingPortionOfMapaSDU, - TfdzConstructionRules.FpFixedStartOfMapaSDU, - ]: - return True - return False + return bool( + not truncated + and self.tfdz_contr_rules + in [ + TfdzConstructionRules.FpPacketSpanningMultipleFrames, + TfdzConstructionRules.FpContinuingPortionOfMapaSDU, + TfdzConstructionRules.FpFixedStartOfMapaSDU, + ] + ) def verify_frame_type(self, frame_type: FrameType) -> bool: - if frame_type == FrameType.FIXED and self.__cnstr_rules_for_fp(): - return True - elif frame_type == FrameType.VARIABLE and self.__cnstr_rules_for_vp(): - return True - return False + return bool( + (frame_type == FrameType.FIXED and self.__cnstr_rules_for_fp()) + or (frame_type == FrameType.VARIABLE and self.__cnstr_rules_for_vp()) + ) def __cnstr_rules_for_fp(self) -> bool: - if self.tfdz_contr_rules in [ + return self.tfdz_contr_rules in [ TfdzConstructionRules.FpPacketSpanningMultipleFrames, TfdzConstructionRules.FpContinuingPortionOfMapaSDU, TfdzConstructionRules.FpFixedStartOfMapaSDU, - ]: - return True - return False + ] def __cnstr_rules_for_vp(self) -> bool: - if self.tfdz_contr_rules in [ + return self.tfdz_contr_rules in [ TfdzConstructionRules.VpContinuingSegment, TfdzConstructionRules.VpLastSegment, TfdzConstructionRules.VpOctetStream, TfdzConstructionRules.VpNoSegmentation, TfdzConstructionRules.VpStartingSegment, - ]: - return True - return False + ] @classmethod def __empty(cls) -> TransferFrameDataField: - empty = TransferFrameDataField( + return TransferFrameDataField( tfdz_cnstr_rules=TfdzConstructionRules.FpPacketSpanningMultipleFrames, uslp_ident=UslpProtocolIdentifier.SPACE_PACKETS_ENCAPSULATION_PACKETS, fhp_or_lvop=None, tfdz=bytearray(), ) - return empty @classmethod def unpack( @@ -295,7 +285,7 @@ def unpack( raw_tfdf: bytes, truncated: bool, exact_len: int, - frame_type: Optional[FrameType], + frame_type: FrameType | None, ) -> TransferFrameDataField: """Unpack a TFDF, given a raw bytearray. @@ -310,15 +300,12 @@ def unpack( """ tfdf = cls.__empty() if len(raw_tfdf) < 1: - raise UslpInvalidRawPacketOrFrameLen + raise UslpInvalidRawPacketOrFrameLenError tfdf.tfdz_contr_rules = (raw_tfdf[0] >> 5) & 0b111 tfdf.uslp_ident = raw_tfdf[0] & 0b11111 - if frame_type is not None: - if not tfdf.verify_frame_type(frame_type=frame_type): - raise UslpInvalidConstructionRules - if tfdf.should_have_fhp_or_lvp_field( - truncated=truncated, frame_type=frame_type - ): + if frame_type is not None and not tfdf.verify_frame_type(frame_type=frame_type): + raise UslpInvalidConstructionRulesError + if tfdf.should_have_fhp_or_lvp_field(truncated=truncated, frame_type=frame_type): tfdf.fhp_or_lvop = (raw_tfdf[1] << 8) | raw_tfdf[2] tfdz_start = 3 else: @@ -335,9 +322,9 @@ def __init__( self, header: FrameHeaderT, tfdf: TransferFrameDataField, - insert_zone: Optional[bytes] = None, - op_ctrl_field: Optional[bytes] = None, - fecf: Optional[bytes] = None, + insert_zone: bytes | None = None, + op_ctrl_field: bytes | None = None, + fecf: bytes | None = None, ): self.header = header self.tfdf = tfdf @@ -345,9 +332,7 @@ def __init__( self.op_ctrl_field = op_ctrl_field self.fecf = fecf - def pack( - self, truncated: bool = False, frame_type: Optional[FrameType] = None - ) -> bytearray: + def pack(self, truncated: bool = False, frame_type: FrameType | None = None) -> bytearray: frame = bytearray() frame.extend(self.header.pack()) if self.insert_zone is not None: @@ -355,25 +340,24 @@ def pack( frame.extend(self.tfdf.pack(truncated=truncated, frame_type=frame_type)) if self.op_ctrl_field: if not self.header.op_ctrl_flag: - raise UslpInvalidFrameHeader + raise UslpInvalidFrameHeaderError if len(self.op_ctrl_field) != 4: raise ValueError frame.extend(self.op_ctrl_field) - else: - if not truncated and self.header.op_ctrl_flag: - raise UslpInvalidFrameHeader + elif not truncated and self.header.op_ctrl_flag: + raise UslpInvalidFrameHeaderError if self.fecf is not None: frame.extend(self.fecf) return frame - def set_frame_len_in_header(self): + def set_frame_len_in_header(self) -> None: # According to the standard, the frame length field will contain the length of of the # frame minus 1. Also check whether this is a regular header and not a truncated one, # as the truncated one does not have the frame length field if isinstance(self.header, PrimaryHeader): self.header.frame_len = self.len() - 1 - def len(self): + def len(self) -> int: size = self.header.len() + self.tfdf.len() if self.insert_zone is not None: size += len(self.insert_zone) @@ -392,19 +376,19 @@ def __empty(cls) -> TransferFrame: tfdz_cnstr_rules=TfdzConstructionRules.FpPacketSpanningMultipleFrames, uslp_ident=UslpProtocolIdentifier.SPACE_PACKETS_ENCAPSULATION_PACKETS, fhp_or_lvop=None, - tfdz=bytearray(), + tfdz=b"", ) - empty = TransferFrame( + return TransferFrame( header=empty_header, tfdf=empty_data_field, insert_zone=None, op_ctrl_field=None, fecf=None, ) - return empty + # TODO: Fix lint by creating helper methods. @classmethod - def unpack( # noqa: C901 + def unpack( # noqa: PLR0912 too many branches cls, raw_frame: bytes, frame_type: FrameType, frame_properties: FramePropertiesT ) -> TransferFrame: """Unpack a USLP transfer frame from a raw bytearray. All managed parameters have @@ -420,18 +404,18 @@ def unpack( # noqa: C901 """ frame = cls.__empty() if len(raw_frame) < 4: - raise UslpInvalidRawPacketOrFrameLen + raise UslpInvalidRawPacketOrFrameLenError if frame_type == FrameType.FIXED: if not isinstance(frame_properties, FixedFrameProperties): raise ValueError if len(raw_frame) < frame_properties.fixed_len: - raise UslpInvalidRawPacketOrFrameLen + raise UslpInvalidRawPacketOrFrameLenError header_type = determine_header_type(header_start=raw_frame) if header_type == HeaderType.TRUNCATED: # Truncated frames are only allowed if the frame type is specified as variable # as specified by the standard on page p.161 if frame_type != FrameType.VARIABLE: - raise UslpTruncatedFrameNotAllowed + raise UslpTruncatedFrameNotAllowedError frame.header = TruncatedPrimaryHeader.unpack(raw_packet=raw_frame) else: frame.header = PrimaryHeader.unpack(raw_packet=raw_frame) @@ -439,7 +423,7 @@ def unpack( # noqa: C901 if frame_type == FrameType.FIXED and ( frame.header.frame_len + 1 != frame_properties.fixed_len ): - raise UslpInvalidRawPacketOrFrameLen + raise UslpInvalidRawPacketOrFrameLenError exact_tfdf_len = cls.__get_tfdf_len( frame_type=frame_type, header_type=header_type, @@ -448,17 +432,14 @@ def unpack( # noqa: C901 properties=frame_properties, ) if exact_tfdf_len <= 0 or header_len + exact_tfdf_len > len(raw_frame): - raise UslpInvalidRawPacketOrFrameLen + raise UslpInvalidRawPacketOrFrameLenError current_idx = header_len # Skip insert zone if present if frame_properties.insert_zone_properties.present: - if ( - header_len - + frame_properties.insert_zone_properties.size - + exact_tfdf_len - > len(raw_frame) + if header_len + frame_properties.insert_zone_properties.size + exact_tfdf_len > len( + raw_frame ): - raise UslpInvalidRawPacketOrFrameLen + raise UslpInvalidRawPacketOrFrameLenError frame.insert_zone = raw_frame[ current_idx : current_idx + frame_properties.insert_zone_properties.size ] @@ -472,7 +453,7 @@ def unpack( # noqa: C901 ) current_idx += exact_tfdf_len # Parse OCF field if present - if not header_type == HeaderType.TRUNCATED and frame.header.op_ctrl_flag: + if header_type != HeaderType.TRUNCATED and frame.header.op_ctrl_flag: frame.op_ctrl_field = raw_frame[current_idx : current_idx + 4] current_idx += 4 # Parse Frame Error Control field if present @@ -490,7 +471,7 @@ def __get_tfdf_len( raw_frame_len: int, header: UslpHeaderT, properties: FramePropertiesT, - ): + ) -> int: """This helper function calculates the initial value for expected TFDF length and subtracts all (optional) fields lengths if they are present. @@ -509,14 +490,13 @@ def __get_tfdf_len( # the transfer frame. exact_tfdf_len = header.frame_len + 1 - header_len if raw_frame_len < exact_tfdf_len: - raise UslpInvalidRawPacketOrFrameLen + raise UslpInvalidRawPacketOrFrameLenError + # Truncated frames are only allowed if the frame type is Variable. The truncated + # frame length is then a managed parameter for a specific virtual channel. + elif header_type == HeaderType.TRUNCATED: + exact_tfdf_len = properties.truncated_frame_len - header_len else: - # Truncated frames are only allowed if the frame type is Variable. The truncated - # frame length is then a managed parameter for a specific virtual channel. - if header_type == HeaderType.TRUNCATED: - exact_tfdf_len = properties.truncated_frame_len - header_len - else: - exact_tfdf_len = header.frame_len + 1 - header_len + exact_tfdf_len = header.frame_len + 1 - header_len if properties.fecf_properties.present: exact_tfdf_len -= properties.fecf_properties.size if header_type != HeaderType.TRUNCATED and header.op_ctrl_flag: diff --git a/spacepackets/uslp/header.py b/spacepackets/uslp/header.py index f6dae08..2b38330 100644 --- a/spacepackets/uslp/header.py +++ b/spacepackets/uslp/header.py @@ -1,13 +1,13 @@ from __future__ import annotations -from abc import abstractmethod -from typing import Optional, Tuple + import enum import struct +from abc import abstractmethod from .defs import ( - UslpVersionMissmatch, - UslpTypeMissmatch, - UslpInvalidRawPacketOrFrameLen, + UslpInvalidRawPacketOrFrameLenError, + UslpTypeMissmatchError, + UslpVersionMissmatchError, ) USLP_VERSION_NUMBER = 0b1100 @@ -56,11 +56,7 @@ def _pack_common_header(self, truncated: bool = False) -> bytearray: raise ValueError packet.append((USLP_VERSION_NUMBER << 4) | (self.scid >> 12) & 0b1111) packet.append((self.scid >> 4) & 0xFF) - packet.append( - ((self.scid & 0b1111) << 4) - | (self.src_dest << 3) - | (self.vcid >> 3) & 0b111 - ) + packet.append(((self.scid & 0b1111) << 4) | (self.src_dest << 3) | (self.vcid >> 3) & 0b111) packet.append((self.vcid & 0b111) << 5 | (self.map_id << 1) | truncated) return packet @@ -77,23 +73,19 @@ def _unpack_raw_header_base_fields( raw_packet: bytes, truncated: bool = False, uslp_version: int = USLP_VERSION_NUMBER, - ) -> Tuple[int, SourceOrDestField, int, int]: + ) -> tuple[int, SourceOrDestField, int, int]: if len(raw_packet) < 4: - raise UslpInvalidRawPacketOrFrameLen + raise UslpInvalidRawPacketOrFrameLenError version_number = (raw_packet[0] & 0xF0) >> 4 if version_number != uslp_version: - raise UslpVersionMissmatch - scid = ( - (raw_packet[0] & 0x0F) << 12 - | (raw_packet[1] << 4) - | ((raw_packet[2] & 0xF0) >> 4) - ) + raise UslpVersionMissmatchError + scid = (raw_packet[0] & 0x0F) << 12 | (raw_packet[1] << 4) | ((raw_packet[2] & 0xF0) >> 4) src_dest = (raw_packet[2] & 0x08) >> 3 vcid = ((raw_packet[2] & 0b111) << 3) | ((raw_packet[3] >> 5) & 0b111) map_id = (raw_packet[3] >> 1) & 0b1111 end_of_frame_primary_header = raw_packet[3] & 0b1 if end_of_frame_primary_header != truncated: - raise UslpTypeMissmatch + raise UslpTypeMissmatchError return scid, SourceOrDestField(src_dest), vcid, map_id @@ -129,7 +121,7 @@ def __empty(cls) -> TruncatedPrimaryHeader: scid=0x00, src_dest=SourceOrDestField.DEST, vcid=0x00, map_id=0x00 ) - def len(self): + def len(self) -> int: return 4 def truncated(self) -> bool: @@ -195,7 +187,7 @@ def __init__( prot_ctrl_cmd_flag: ProtocolCommandFlag, op_ctrl_flag: bool, vcf_count_len: int = 0, - vcf_count: Optional[int] = None, + vcf_count: int | None = None, ): super().__init__(scid, src_dest, vcid, map_id) self.frame_len = frame_len @@ -247,9 +239,7 @@ def __empty(cls) -> PrimaryHeader: ) @classmethod - def unpack( - cls, raw_packet: bytes, uslp_version: int = USLP_VERSION_NUMBER - ) -> PrimaryHeader: + def unpack(cls, raw_packet: bytes, uslp_version: int = USLP_VERSION_NUMBER) -> PrimaryHeader: """Unpack a regular transfer frame header from a raw bytearray :param raw_packet: @@ -259,7 +249,7 @@ def unpack( """ packet = cls.__empty() if len(raw_packet) < 7: - raise UslpInvalidRawPacketOrFrameLen + raise UslpInvalidRawPacketOrFrameLenError raw_unpacked_tuple = cls._unpack_raw_header_base_fields( raw_packet=raw_packet, truncated=False, @@ -275,7 +265,7 @@ def unpack( packet.op_ctrl_flag = (raw_packet[6] >> 3) & 0x01 packet.vcf_count_len = raw_packet[6] & 0b111 if packet.vcf_count_len > len(raw_packet) - 7: - raise UslpInvalidRawPacketOrFrameLen + raise UslpInvalidRawPacketOrFrameLenError if packet.vcf_count_len == 1: packet.vcf_count = raw_packet[7] elif packet.vcf_count_len == 2: @@ -285,12 +275,12 @@ def unpack( else: packet.vcf_count = 0 end = packet.vcf_count_len - for idx in range(0, packet.vcf_count_len): + for idx in range(packet.vcf_count_len): packet.vcf_count |= raw_packet[7 + idx] << ((end - 1) * 8) end -= 1 return packet - def len(self): + def len(self) -> int: return 7 + self.vcf_count_len @@ -304,5 +294,4 @@ def determine_header_type(header_start: bytes) -> HeaderType: raise ValueError if header_start[3] & 0x01: return HeaderType.TRUNCATED - else: - return HeaderType.NON_TRUNCATED + return HeaderType.NON_TRUNCATED diff --git a/spacepackets/util.py b/spacepackets/util.py index 220e520..d04ad1a 100644 --- a/spacepackets/util.py +++ b/spacepackets/util.py @@ -1,7 +1,7 @@ from __future__ import annotations + import enum import struct -from typing import Tuple, Union class PrintFormats(enum.IntEnum): @@ -13,27 +13,25 @@ class PrintFormats(enum.IntEnum): def get_dec_data_string(data: bytes) -> str: if len(data) == 0: return "dec []" - elif len(data) == 1: + if len(data) == 1: return f"dec [{data[0]}]" - else: - string_to_print = "dec [" - for idx in range(len(data) - 1): - string_to_print += f"{data[idx]}," - string_to_print += f"{data[len(data) - 1]}]" - return string_to_print + string_to_print = "dec [" + for idx in range(len(data) - 1): + string_to_print += f"{data[idx]}," + string_to_print += f"{data[len(data) - 1]}]" + return string_to_print def get_bin_data_string(data: bytes) -> str: if len(data) == 0: return "bin []" - elif len(data) == 1: + if len(data) == 1: return f"bin [0:{data[0]:08b}]" - else: - string_to_print = "bin [\n" - for idx in range(len(data)): - string_to_print += f"{idx}:{data[idx]:08b}\n" - string_to_print += "]" - return string_to_print + string_to_print = "bin [\n" + for idx in range(len(data)): + string_to_print += f"{idx}:{data[idx]:08b}\n" + string_to_print += "]" + return string_to_print def get_printable_data_string(print_format: PrintFormats, data: bytes) -> str: @@ -44,10 +42,11 @@ def get_printable_data_string(print_format: PrintFormats, data: bytes) -> str: data_to_print = data[:length] if print_format == PrintFormats.HEX: return f'hex [{data_to_print.hex(sep=",", bytes_per_sep=1)}]' - elif print_format == PrintFormats.DEC: + if print_format == PrintFormats.DEC: return get_dec_data_string(data) - elif print_format == PrintFormats.BIN: + if print_format == PrintFormats.BIN: return get_bin_data_string(data) + return None class IntByteConversion: @@ -55,11 +54,11 @@ class IntByteConversion: def signed_struct_specifier(byte_num: int) -> str: if byte_num == 1: return "!b" - elif byte_num == 2: + if byte_num == 2: return "!h" - elif byte_num == 4: + if byte_num == 4: return "!i" - elif byte_num == 8: + if byte_num == 8: return "!q" raise ValueError("Invalid byte number, must be one of [1, 2, 4, 8]") @@ -67,11 +66,11 @@ def signed_struct_specifier(byte_num: int) -> str: def unsigned_struct_specifier(byte_num: int) -> str: if byte_num == 1: return "!B" - elif byte_num == 2: + if byte_num == 2: return "!H" - elif byte_num == 4: + if byte_num == 4: return "!I" - elif byte_num == 8: + if byte_num == 8: return "!Q" raise ValueError(f"invalid byte number {byte_num}, must be one of [1, 2, 4, 8]") @@ -83,11 +82,9 @@ def to_signed(byte_num: int, val: int) -> bytes: if byte_num not in [0, 1, 2, 4, 8]: raise ValueError("Invalid byte number, must be one of [0, 1, 2, 4, 8]") if byte_num == 0: - return bytes() + return b"" if abs(val) > pow(2, (byte_num * 8) - 1) - 1: - raise ValueError( - f"Passed value larger than allows {pow(2, (byte_num * 8) - 1) - 1}" - ) + raise ValueError(f"Passed value larger than allows {pow(2, (byte_num * 8) - 1) - 1}") return struct.pack(IntByteConversion.signed_struct_specifier(byte_num), val) @staticmethod @@ -98,11 +95,9 @@ def to_unsigned(byte_num: int, val: int) -> bytes: if byte_num not in [0, 1, 2, 4, 8]: raise ValueError("Invalid byte number, must be one of [1, 2, 4, 8]") if byte_num == 0: - return bytes() + return b"" if val > pow(2, byte_num * 8) - 1: - raise ValueError( - f"Passed value larger than allowed {pow(2, byte_num * 8) - 1}" - ) + raise ValueError(f"Passed value larger than allowed {pow(2, byte_num * 8) - 1}") return struct.pack(IntByteConversion.unsigned_struct_specifier(byte_num), val) @@ -131,36 +126,32 @@ def __init__(self, val: int, byte_len: int): self._val_as_bytes = IntByteConversion.to_unsigned(self.byte_len, self.value) @classmethod - def from_bytes(cls, raw: bytes): + def from_bytes(cls, raw: bytes) -> UnsignedByteField: return cls( - struct.unpack(IntByteConversion.unsigned_struct_specifier(len(raw)), raw)[ - 0 - ], + struct.unpack(IntByteConversion.unsigned_struct_specifier(len(raw)), raw)[0], len(raw), ) @property - def byte_len(self): + def byte_len(self) -> int: return self._byte_len @byte_len.setter - def byte_len(self, byte_len: int): + def byte_len(self, byte_len: int) -> None: UnsignedByteField.verify_byte_len(byte_len) self._byte_len = byte_len @property - def value(self): + def value(self) -> int: return self._val @value.setter - def value(self, val: Union[int, bytes, bytearray]): + def value(self, val: int | bytes | bytearray) -> None: if isinstance(val, int): self._verify_int_value(val) self._val = val - self._val_as_bytes = IntByteConversion.to_unsigned( - self.byte_len, self.value - ) - elif isinstance(val, bytes) or isinstance(val, bytearray): + self._val_as_bytes = IntByteConversion.to_unsigned(self.byte_len, self.value) + elif isinstance(val, (bytes, bytearray)): self._val, self._val_as_bytes = self._verify_bytes_value(bytes(val)) @property @@ -168,25 +159,21 @@ def as_bytes(self) -> bytes: return self._val_as_bytes @staticmethod - def verify_byte_len(byte_len: int): + def verify_byte_len(byte_len: int) -> None: if byte_len not in [0, 1, 2, 4, 8]: # I really have no idea why anyone would use other values than these - raise ValueError( - "Only 0, 1, 2, 4 and 8 bytes are allowed as an entity ID length" - ) + raise ValueError("Only 0, 1, 2, 4 and 8 bytes are allowed as an entity ID length") - def _verify_int_value(self, val: int): + def _verify_int_value(self, val: int) -> None: if val > pow(2, self.byte_len * 8) - 1 or val < 0: raise ValueError( f"Passed value {val} larger than allowed" f" {pow(2, self.byte_len * 8) - 1} or negative" ) - def _verify_bytes_value(self, val: bytes) -> Tuple[int, bytes]: + def _verify_bytes_value(self, val: bytes) -> tuple[int, bytes]: if len(val) < self.byte_len: - raise ValueError( - f"Passed byte object {val} smaller than byte length {self.byte_len}" - ) + raise ValueError(f"Passed byte object {val} smaller than byte length {self.byte_len}") int_val = struct.unpack( IntByteConversion.unsigned_struct_specifier(self.byte_len), val[0 : self.byte_len], @@ -195,20 +182,19 @@ def _verify_bytes_value(self, val: bytes) -> Tuple[int, bytes]: return int_val, val[0 : self.byte_len] @property - def hex_str(self): + def hex_str(self) -> str | None: if self.byte_len == 1: return f"{self.value:#04x}" - elif self.byte_len == 2: + if self.byte_len == 2: return f"{self.value:#06x}" - elif self.byte_len == 4: + if self.byte_len == 4: return f"{self.value:#010x}" - elif self.byte_len == 8: + if self.byte_len == 8: return f"{self.value:#018x}" + return None def __repr__(self): - return ( - f"{self.__class__.__name__}(val={self.value!r}, byte_len={self.byte_len!r})" - ) + return f"{self.__class__.__name__}(val={self.value!r}, byte_len={self.byte_len!r})" def __str__(self): return f"dec={self.value}, hex={self.hex_str}" @@ -222,7 +208,7 @@ def __len__(self): def __eq__(self, other: object) -> bool: if isinstance(other, UnsignedByteField): return self.value == other.value and self.byte_len == other.byte_len - elif isinstance(other, bytes): + if isinstance(other, bytes): return self._val_as_bytes == other raise TypeError(f"Cannot compare {self.__class__.__name__} to {other}") @@ -230,7 +216,7 @@ def __hash__(self): """Makes all unsigned byte fields usable as dictionary keys""" return hash((self.value, self.byte_len)) - def default_string(self, prefix): + def default_string(self, prefix: str) -> str: return f"{prefix}({self.value}, 0x[{self.as_bytes.hex(sep=',')}])" @@ -248,9 +234,7 @@ def __init__(self, val: int): @classmethod def from_u8_bytes(cls, stream: bytes) -> ByteFieldU8: if len(stream) < 1: - raise ValueError( - "Passed stream not large enough, should be at least 1 byte" - ) + raise ValueError("Passed stream not large enough, should be at least 1 byte") return cls(stream[0]) def __str__(self): @@ -266,14 +250,8 @@ def __init__(self, val: int): @classmethod def from_u16_bytes(cls, stream: bytes) -> ByteFieldU16: if len(stream) < 2: - raise ValueError( - "Passed stream not large enough, should be at least 2 byte" - ) - return cls( - struct.unpack(IntByteConversion.unsigned_struct_specifier(2), stream[0:2])[ - 0 - ] - ) + raise ValueError("Passed stream not large enough, should be at least 2 byte") + return cls(struct.unpack(IntByteConversion.unsigned_struct_specifier(2), stream[0:2])[0]) def __str__(self): return self.default_string("U16") @@ -288,14 +266,8 @@ def __init__(self, val: int): @classmethod def from_u32_bytes(cls, stream: bytes) -> ByteFieldU32: if len(stream) < 4: - raise ValueError( - "passed stream not large enough, should be at least 4 bytes" - ) - return cls( - struct.unpack(IntByteConversion.unsigned_struct_specifier(4), stream[0:4])[ - 0 - ] - ) + raise ValueError("passed stream not large enough, should be at least 4 bytes") + return cls(struct.unpack(IntByteConversion.unsigned_struct_specifier(4), stream[0:4])[0]) def __str__(self): return self.default_string("U32") @@ -310,14 +282,8 @@ def __init__(self, val: int): @classmethod def from_u64_bytes(cls, stream: bytes) -> ByteFieldU64: if len(stream) < 8: - raise ValueError( - "passed stream not large enough, should be at least 8 byte" - ) - return cls( - struct.unpack(IntByteConversion.unsigned_struct_specifier(8), stream[0:8])[ - 0 - ] - ) + raise ValueError("passed stream not large enough, should be at least 8 byte") + return cls(struct.unpack(IntByteConversion.unsigned_struct_specifier(8), stream[0:8])[0]) def __str__(self): return self.default_string("U64") @@ -333,11 +299,11 @@ def from_int(byte_len: int, val: int) -> UnsignedByteField: :raise ValueError: Byte length is not one of [1, 2, 4, 8].""" if byte_len == 1: return ByteFieldU8(val) - elif byte_len == 2: + if byte_len == 2: return ByteFieldU16(val) - elif byte_len == 4: + if byte_len == 4: return ByteFieldU32(val) - elif byte_len == 8: + if byte_len == 8: return ByteFieldU64(val) raise ValueError(f"invalid byte length {byte_len}") @@ -348,11 +314,11 @@ def from_bytes(byte_len: int, stream: bytes) -> UnsignedByteField: :raise ValueError: Byte length is not one of [1, 2, 4, 8].""" if byte_len == 1: return ByteFieldU8.from_u8_bytes(stream) - elif byte_len == 2: + if byte_len == 2: return ByteFieldU16.from_u16_bytes(stream) - elif byte_len == 4: + if byte_len == 4: return ByteFieldU32.from_u32_bytes(stream) - elif byte_len == 8: + if byte_len == 8: return ByteFieldU64.from_u64_bytes(stream) raise ValueError(f"invalid byte length {byte_len}") diff --git a/tests/ccsds/test_sp_parser.py b/tests/ccsds/test_sp_parser.py index 2e0dfe1..81b6f9e 100644 --- a/tests/ccsds/test_sp_parser.py +++ b/tests/ccsds/test_sp_parser.py @@ -1,5 +1,5 @@ -from unittest import TestCase from collections import deque +from unittest import TestCase from spacepackets.ccsds import CdsShortTimestamp from spacepackets.ccsds.spacepacket import parse_space_packets @@ -22,9 +22,7 @@ def setUp(self) -> None: def test_sp_parser(self): self.packet_deque.appendleft(self.tm_packet_raw) self.packet_deque.appendleft(self.tm_packet_raw) - sp_list = parse_space_packets( - analysis_queue=self.packet_deque, packet_ids=self.packet_ids - ) + sp_list = parse_space_packets(analysis_queue=self.packet_deque, packet_ids=self.packet_ids) self.assertEqual(len(sp_list), 2) self.assertEqual(sp_list[0], self.tm_packet_raw) self.assertEqual(sp_list[1], self.tm_packet_raw) @@ -41,22 +39,16 @@ def test_sp_parser_crap_data_is_skipped(self): self.packet_deque.append(self.tm_packet_raw) self.packet_deque.append(bytearray(8)) self.packet_deque.append(other_larger_packet_raw) - sp_list = parse_space_packets( - analysis_queue=self.packet_deque, packet_ids=self.packet_ids - ) + sp_list = parse_space_packets(analysis_queue=self.packet_deque, packet_ids=self.packet_ids) self.assertEqual(len(sp_list), 2) self.assertEqual(sp_list[0], self.tm_packet_raw) self.assertEqual(sp_list[1], other_larger_packet_raw) def test_sp_parser_crap_data(self): self.packet_deque.appendleft(bytearray(3)) - sp_list = parse_space_packets( - analysis_queue=self.packet_deque, packet_ids=self.packet_ids - ) + sp_list = parse_space_packets(analysis_queue=self.packet_deque, packet_ids=self.packet_ids) self.assertEqual(len(sp_list), 0) - sp_list = parse_space_packets( - analysis_queue=self.packet_deque, packet_ids=self.packet_ids - ) + sp_list = parse_space_packets(analysis_queue=self.packet_deque, packet_ids=self.packet_ids) self.assertEqual(len(sp_list), 0) def test_broken_packet(self): @@ -64,15 +56,11 @@ def test_broken_packet(self): tm_packet_first_half = self.tm_packet_raw[:10] tm_packet_second_half = self.tm_packet_raw[10:] self.packet_deque.appendleft(tm_packet_first_half) - sp_list = parse_space_packets( - analysis_queue=self.packet_deque, packet_ids=self.packet_ids - ) + sp_list = parse_space_packets(analysis_queue=self.packet_deque, packet_ids=self.packet_ids) self.assertEqual(len(sp_list), 0) self.assertEqual(len(self.packet_deque), 1) self.packet_deque.append(tm_packet_second_half) - sp_list = parse_space_packets( - analysis_queue=self.packet_deque, packet_ids=self.packet_ids - ) + sp_list = parse_space_packets(analysis_queue=self.packet_deque, packet_ids=self.packet_ids) self.assertEqual(len(sp_list), 1) self.assertEqual(len(self.packet_deque), 0) self.assertEqual(sp_list[0], self.tm_packet_raw) @@ -82,9 +70,7 @@ def test_broken_packet_at_end(self): # slice TM packet in half tm_packet_first_half = self.tm_packet_raw[:10] self.packet_deque.append(tm_packet_first_half) - sp_list = parse_space_packets( - analysis_queue=self.packet_deque, packet_ids=self.packet_ids - ) + sp_list = parse_space_packets(analysis_queue=self.packet_deque, packet_ids=self.packet_ids) self.assertEqual(len(sp_list), 1) self.assertEqual(len(self.packet_deque), 1) self.assertEqual(self.packet_deque.pop(), tm_packet_first_half) diff --git a/tests/ccsds/test_space_packet.py b/tests/ccsds/test_space_packet.py index 6343527..d3f9585 100644 --- a/tests/ccsds/test_space_packet.py +++ b/tests/ccsds/test_space_packet.py @@ -1,13 +1,13 @@ from unittest import TestCase -from spacepackets import SequenceFlags, PacketType, SpacePacketHeader -from spacepackets.ccsds import PacketSeqCtrl, PacketId +from spacepackets import PacketType, SequenceFlags, SpacePacketHeader +from spacepackets.ccsds import PacketId, PacketSeqCtrl from spacepackets.ccsds.spacepacket import ( - get_space_packet_id_bytes, - get_sp_psc_raw, - get_sp_packet_id_raw, SpacePacket, get_apid_from_raw_space_packet, + get_sp_packet_id_raw, + get_sp_psc_raw, + get_space_packet_id_bytes, ) @@ -129,7 +129,7 @@ def test_apid_from_raw(self): def test_apid_from_raw_invalid_input(self): with self.assertRaises(ValueError): - get_apid_from_raw_space_packet(raw_packet=bytes()) + get_apid_from_raw_space_packet(raw_packet=b"") def test_unpack(self): sp_packed = self.sp_header.pack() @@ -142,9 +142,7 @@ def test_unpack(self): def test_invalid_apid(self): with self.assertRaises(ValueError): - SpacePacketHeader( - apid=982292, data_len=22, seq_count=52, packet_type=PacketType.TC - ) + SpacePacketHeader(apid=982292, data_len=22, seq_count=52, packet_type=PacketType.TC) def test_invalid_data_len(self): self.assertRaises( @@ -192,8 +190,7 @@ def test_packet_id(self): self.assertEqual(packet_id_as_num, packet_id.raw()) self.assertEqual(packet_id_as_num, packet_id_raw) self.assertFalse( - packet_id - == PacketSeqCtrl(seq_flags=SequenceFlags.UNSEGMENTED, seq_count=0x22) + packet_id == PacketSeqCtrl(seq_flags=SequenceFlags.UNSEGMENTED, seq_count=0x22) ) def test_packet_seq_ctrl(self): @@ -210,9 +207,7 @@ def test_packet_seq_ctrl(self): seq_count=0xFFFF, seq_flags=SequenceFlags.UNSEGMENTED, ) - self.assertFalse( - psc == PacketId(ptype=PacketType.TC, apid=0x3FF, sec_header_flag=True) - ) + self.assertFalse(psc == PacketId(ptype=PacketType.TC, apid=0x3FF, sec_header_flag=True)) def test_from_composite_field(self): packet_id = PacketId(ptype=PacketType.TC, apid=0x3FF, sec_header_flag=True) @@ -279,9 +274,7 @@ def test_sp_print(self): print(sp) def test_utility(self): - psc = PacketSeqCtrl( - seq_flags=SequenceFlags.UNSEGMENTED, seq_count=pow(2, 14) - 1 - ) + psc = PacketSeqCtrl(seq_flags=SequenceFlags.UNSEGMENTED, seq_count=pow(2, 14) - 1) self.assertEqual( f"{psc}", f"PSC: [Seq Flags: UNSEG, Seq Count: {pow(2, 14) - 1}]", @@ -304,9 +297,7 @@ def test_utility(self): self.assertEqual(PacketId.empty().raw(), 0) def test_equality_sp_packet(self): - sp = SpacePacket( - sp_header=self.sp_header, sec_header=None, user_data=bytes([0, 1, 2]) - ) + sp = SpacePacket(sp_header=self.sp_header, sec_header=None, user_data=bytes([0, 1, 2])) other_sp = SpacePacket( sp_header=self.sp_header, sec_header=None, user_data=bytes([0, 1, 2]) ) diff --git a/tests/ccsds/test_time.py b/tests/ccsds/test_time.py index 60b0029..4ed2a83 100644 --- a/tests/ccsds/test_time.py +++ b/tests/ccsds/test_time.py @@ -1,10 +1,11 @@ import datetime import struct from unittest import TestCase + from spacepackets.ccsds.time import ( - CdsShortTimestamp, - SECONDS_PER_DAY, MS_PER_DAY, + SECONDS_PER_DAY, + CdsShortTimestamp, ) from spacepackets.ccsds.time.common import ( convert_ccsds_days_to_unix_days, @@ -15,9 +16,7 @@ class TestTime(TestCase): def test_basic(self): empty_stamp = CdsShortTimestamp(0, 0) - self.assertEqual( - empty_stamp.pfield, bytes([CdsShortTimestamp.CDS_SHORT_ID << 4]) - ) + self.assertEqual(empty_stamp.pfield, bytes([CdsShortTimestamp.CDS_SHORT_ID << 4])) self.assertEqual(empty_stamp.ccsds_days, 0) self.assertEqual(empty_stamp.ms_of_day, 0) dt = empty_stamp.as_datetime() @@ -28,9 +27,7 @@ def test_basic(self): self.assertEqual(dt.minute, 0) self.assertEqual(dt.second, 0) unix_seconds = empty_stamp.as_unix_seconds() - self.assertEqual( - unix_seconds, convert_ccsds_days_to_unix_days(0) * SECONDS_PER_DAY - ) + self.assertEqual(unix_seconds, convert_ccsds_days_to_unix_days(0) * SECONDS_PER_DAY) def test_basic_from_dt(self): cds_stamp = CdsShortTimestamp.from_datetime( diff --git a/tests/cfdp/pdus/test_ack_pdu.py b/tests/cfdp/pdus/test_ack_pdu.py index bb65b45..5052f16 100644 --- a/tests/cfdp/pdus/test_ack_pdu.py +++ b/tests/cfdp/pdus/test_ack_pdu.py @@ -1,11 +1,10 @@ from unittest import TestCase -from spacepackets.cfdp import CrcFlag, TransmissionMode, LargeFileFlag, ConditionCode +from spacepackets.cfdp import ConditionCode, CrcFlag, LargeFileFlag, TransmissionMode from spacepackets.cfdp.conf import PduConfig from spacepackets.cfdp.defs import Direction -from spacepackets.cfdp.pdu import AckPdu, DirectiveType, TransactionStatus +from spacepackets.cfdp.pdu import AckPdu, DirectiveType, PduFactory, TransactionStatus from spacepackets.util import ByteFieldU16, ByteFieldU32 -from spacepackets.cfdp.pdu import PduFactory class TestAckPdu(TestCase): @@ -57,12 +56,8 @@ def test_ack_pdu(self): self.check_fields_packet_0(ack_pdu=ack_pdu_unpacked) pdu_conf = PduConfig( - transaction_seq_num=ByteFieldU32.from_u32_bytes( - bytes([0x50, 0x00, 0x10, 0x01]) - ), - source_entity_id=ByteFieldU32.from_u32_bytes( - bytes([0x10, 0x00, 0x01, 0x02]) - ), + transaction_seq_num=ByteFieldU32.from_u32_bytes(bytes([0x50, 0x00, 0x10, 0x01])), + source_entity_id=ByteFieldU32.from_u32_bytes(bytes([0x10, 0x00, 0x01, 0x02])), dest_entity_id=ByteFieldU32.from_u32_bytes(bytes([0x30, 0x00, 0x01, 0x03])), crc_flag=CrcFlag.WITH_CRC, trans_mode=TransmissionMode.UNACKNOWLEDGED, @@ -120,9 +115,7 @@ def test_ack_pdu(self): ) def check_fields_packet_0(self, ack_pdu: AckPdu): - self.assertEqual( - ack_pdu.directive_code_of_acked_pdu, DirectiveType.FINISHED_PDU - ) + self.assertEqual(ack_pdu.directive_code_of_acked_pdu, DirectiveType.FINISHED_PDU) self.assertEqual(ack_pdu.condition_code_of_acked_pdu, ConditionCode.NO_ERROR) self.assertEqual(ack_pdu.transaction_status, TransactionStatus.TERMINATED) self.assertEqual(ack_pdu.direction, Direction.TOWARDS_RECEIVER) diff --git a/tests/cfdp/pdus/test_directive.py b/tests/cfdp/pdus/test_directive.py index 6f152b1..39583e1 100644 --- a/tests/cfdp/pdus/test_directive.py +++ b/tests/cfdp/pdus/test_directive.py @@ -2,7 +2,7 @@ from spacepackets.cfdp import LargeFileFlag from spacepackets.cfdp.conf import PduConfig -from spacepackets.cfdp.pdu import FileDirectivePduBase, DirectiveType +from spacepackets.cfdp.pdu import DirectiveType, FileDirectivePduBase class TestDirective(TestCase): diff --git a/tests/cfdp/pdus/test_eof_pdu.py b/tests/cfdp/pdus/test_eof_pdu.py index 2549171..d668455 100644 --- a/tests/cfdp/pdus/test_eof_pdu.py +++ b/tests/cfdp/pdus/test_eof_pdu.py @@ -1,18 +1,16 @@ from unittest import TestCase -from spacepackets.cfdp import LargeFileFlag, NULL_CHECKSUM_U32, CrcFlag -from spacepackets.cfdp.tlv import EntityIdTlv +from spacepackets.cfdp import NULL_CHECKSUM_U32, CrcFlag, LargeFileFlag from spacepackets.cfdp.conf import PduConfig from spacepackets.cfdp.defs import Direction from spacepackets.cfdp.pdu import EofPdu, PduFactory +from spacepackets.cfdp.tlv import EntityIdTlv class TestEofPdu(TestCase): def setUp(self) -> None: self.pdu_conf = PduConfig.default() - self.eof_pdu = EofPdu( - file_checksum=NULL_CHECKSUM_U32, file_size=0, pdu_conf=self.pdu_conf - ) + self.eof_pdu = EofPdu(file_checksum=NULL_CHECKSUM_U32, file_size=0, pdu_conf=self.pdu_conf) def test_eof_pdu(self): self.assertEqual(self.eof_pdu.pdu_file_directive.header_len, 8) @@ -60,9 +58,7 @@ def test_large_file_flag(self): def test_with_crc(self): self.pdu_conf.crc_flag = CrcFlag.WITH_CRC - eof = EofPdu( - file_checksum=NULL_CHECKSUM_U32, file_size=0, pdu_conf=self.pdu_conf - ) + eof = EofPdu(file_checksum=NULL_CHECKSUM_U32, file_size=0, pdu_conf=self.pdu_conf) expected_packet_len = eof.header_len + 1 + 4 + 4 + 2 self.assertEqual(eof.packet_len, expected_packet_len) eof_raw = eof.pack() diff --git a/tests/cfdp/pdus/test_factory.py b/tests/cfdp/pdus/test_factory.py index 27a714e..74326e5 100644 --- a/tests/cfdp/pdus/test_factory.py +++ b/tests/cfdp/pdus/test_factory.py @@ -2,29 +2,29 @@ from spacepackets.cfdp import ( NULL_CHECKSUM_U32, + ChecksumType, ConditionCode, - PduConfig, DirectiveType, - ChecksumType, + PduConfig, ) from spacepackets.cfdp.pdu import ( + AckPdu, EofPdu, - PduFactory, FileDataPdu, - MetadataPdu, MetadataParams, - AckPdu, - TransactionStatus, + MetadataPdu, NakPdu, + PduFactory, + TransactionStatus, ) from spacepackets.cfdp.pdu.file_data import FileDataParams from spacepackets.cfdp.pdu.finished import ( - FinishedParams, DeliveryCode, FileStatus, + FinishedParams, FinishedPdu, ) -from spacepackets.cfdp.pdu.prompt import ResponseRequired, PromptPdu +from spacepackets.cfdp.pdu.prompt import PromptPdu, ResponseRequired class TestPduHolder(TestCase): @@ -40,12 +40,10 @@ def test_factory_file_directive_getter(self): pdu_conf=self.pdu_conf, ) eof_raw = eof_pdu.pack() - self.assertEqual( - self.pdu_factory.pdu_directive_type(eof_raw), DirectiveType.EOF_PDU - ) + self.assertEqual(self.pdu_factory.pdu_directive_type(eof_raw), DirectiveType.EOF_PDU) def test_factory_file_directive_on_file_data(self): - fd_params = FileDataParams(file_data=bytes(), offset=0) + fd_params = FileDataParams(file_data=b"", offset=0) file_data_pdu = FileDataPdu(self.pdu_conf, fd_params) fd_pdu_raw = file_data_pdu.pack() self.assertEqual(self.pdu_factory.pdu_directive_type(fd_pdu_raw), None) @@ -65,9 +63,7 @@ def test_metadata_pdu_creation(self): self.assertEqual(metadata_pdu, metadata_pdu_from_factory) def test_eof_pdu_creation(self): - eof_pdu = EofPdu( - file_checksum=NULL_CHECKSUM_U32, file_size=0, pdu_conf=self.pdu_conf - ) + eof_pdu = EofPdu(file_checksum=NULL_CHECKSUM_U32, file_size=0, pdu_conf=self.pdu_conf) eof_raw = eof_pdu.pack() eof_unpacked = EofPdu.unpack(eof_raw) self.assertEqual(eof_pdu, eof_unpacked) @@ -89,9 +85,7 @@ def test_finished_pdu_creation(self): def test_file_data_pdu_creation(self): file_data = "hello world" file_data_bytes = file_data.encode() - fd_params = FileDataParams( - file_data=file_data_bytes, offset=0, segment_metadata=None - ) + fd_params = FileDataParams(file_data=file_data_bytes, offset=0, segment_metadata=None) file_data_pdu = FileDataPdu(pdu_conf=self.pdu_conf, params=fd_params) fd_raw = file_data_pdu.pack() diff --git a/tests/cfdp/pdus/test_file_data.py b/tests/cfdp/pdus/test_file_data.py index d7d36cd..fb636a6 100644 --- a/tests/cfdp/pdus/test_file_data.py +++ b/tests/cfdp/pdus/test_file_data.py @@ -1,15 +1,15 @@ from unittest import TestCase from spacepackets.cfdp import CrcFlag, PduFactory +from spacepackets.cfdp.conf import LargeFileFlag, PduConfig from spacepackets.cfdp.defs import TransmissionMode from spacepackets.cfdp.pdu.file_data import ( + FileDataParams, FileDataPdu, - SegmentMetadata, RecordContinuationState, - FileDataParams, + SegmentMetadata, get_max_file_seg_len_for_max_packet_len_and_pdu_cfg, ) -from spacepackets.cfdp.conf import PduConfig, LargeFileFlag class TestFileDataPdu(TestCase): @@ -26,7 +26,7 @@ def test_max_file_seg_calculator_0(self): pdu_conf = PduConfig.default() file_seg_len = get_max_file_seg_len_for_max_packet_len_and_pdu_cfg(pdu_conf, 64) self.assertEqual(file_seg_len, 53) - fd_pdu = FileDataPdu(pdu_conf, FileDataParams(bytes(), 0)) + fd_pdu = FileDataPdu(pdu_conf, FileDataParams(b"", 0)) self.assertEqual(fd_pdu.get_max_file_seg_len_for_max_packet_len(64), 53) def test_max_file_seg_calculator_1(self): @@ -34,7 +34,7 @@ def test_max_file_seg_calculator_1(self): pdu_conf.crc_flag = CrcFlag.WITH_CRC file_seg_len = get_max_file_seg_len_for_max_packet_len_and_pdu_cfg(pdu_conf, 64) self.assertEqual(file_seg_len, 51) - fd_pdu = FileDataPdu(pdu_conf, FileDataParams(bytes(), 0)) + fd_pdu = FileDataPdu(pdu_conf, FileDataParams(b"", 0)) self.assertEqual(fd_pdu.get_max_file_seg_len_for_max_packet_len(64), 51) def test_max_file_seg_calculator_2(self): @@ -42,7 +42,7 @@ def test_max_file_seg_calculator_2(self): pdu_conf.file_flag = LargeFileFlag.LARGE file_seg_len = get_max_file_seg_len_for_max_packet_len_and_pdu_cfg(pdu_conf, 64) self.assertEqual(file_seg_len, 49) - fd_pdu = FileDataPdu(pdu_conf, FileDataParams(bytes(), 0)) + fd_pdu = FileDataPdu(pdu_conf, FileDataParams(b"", 0)) self.assertEqual(fd_pdu.get_max_file_seg_len_for_max_packet_len(64), 49) def test_max_file_seg_calculator_error(self): @@ -50,10 +50,8 @@ def test_max_file_seg_calculator_error(self): file_seg_len = get_max_file_seg_len_for_max_packet_len_and_pdu_cfg(pdu_conf, 11) self.assertEqual(file_seg_len, 0) with self.assertRaises(ValueError): - file_seg_len = get_max_file_seg_len_for_max_packet_len_and_pdu_cfg( - pdu_conf, 10 - ) - fd_pdu = FileDataPdu(pdu_conf, FileDataParams(bytes(), 0)) + file_seg_len = get_max_file_seg_len_for_max_packet_len_and_pdu_cfg(pdu_conf, 10) + fd_pdu = FileDataPdu(pdu_conf, FileDataParams(b"", 0)) with self.assertRaises(ValueError): fd_pdu.get_max_file_seg_len_for_max_packet_len(10) @@ -89,9 +87,7 @@ def test_with_seg_metadata(self): self.assertEqual(fd_pdu_with_metadata.packet_len, expected_packet_len) fd_pdu_with_metadata_raw = fd_pdu_with_metadata.pack() self.assertEqual(len(fd_pdu_with_metadata_raw), expected_packet_len) - fd_pdu_with_metadata_unpacked = fd_pdu_with_metadata.unpack( - data=fd_pdu_with_metadata_raw - ) + fd_pdu_with_metadata_unpacked = fd_pdu_with_metadata.unpack(data=fd_pdu_with_metadata_raw) self.assertEqual(fd_pdu_with_metadata_unpacked.offset, 0) self.assertEqual(fd_pdu_with_metadata_unpacked.file_data, self.file_data_bytes) self.assertEqual( @@ -99,9 +95,7 @@ def test_with_seg_metadata(self): RecordContinuationState.START_AND_END, ) assert fd_pdu_with_metadata.segment_metadata is not None - self.assertEqual( - fd_pdu_with_metadata.segment_metadata.metadata, bytes([0xAA, 0xBB]) - ) + self.assertEqual(fd_pdu_with_metadata.segment_metadata.metadata, bytes([0xAA, 0xBB])) def test_invalid_metadata(self): invalid_metadata = bytes(70) @@ -144,18 +138,14 @@ def test_large_filedata(self): fd_pdu_large_offset_unpacked.segment_metadata.metadata, bytes([0xAA, 0xBB]) ) self.assertEqual(fd_pdu_large_offset_unpacked.offset, 0) - fd_pdu_large_offset.file_data = bytes() + fd_pdu_large_offset.file_data = b"" expected_packet_len -= 11 self.assertEqual(fd_pdu_large_offset.packet_len, expected_packet_len) fd_pdu_large_offset_no_file_data_raw = fd_pdu_large_offset.pack() - fd_pdu_large_offset_no_file_data_invalid = fd_pdu_large_offset_no_file_data_raw[ - :-2 - ] + fd_pdu_large_offset_no_file_data_invalid = fd_pdu_large_offset_no_file_data_raw[:-2] with self.assertRaises(ValueError): FileDataPdu.unpack(data=fd_pdu_large_offset_no_file_data_invalid) - fd_pdu_large_offset_no_file_data_invalid = fd_pdu_large_offset_no_file_data_raw[ - :-9 - ] + fd_pdu_large_offset_no_file_data_invalid = fd_pdu_large_offset_no_file_data_raw[:-9] with self.assertRaises(ValueError): FileDataPdu.unpack(data=fd_pdu_large_offset_no_file_data_invalid) diff --git a/tests/cfdp/pdus/test_finished_pdu.py b/tests/cfdp/pdus/test_finished_pdu.py index 983d4ab..49841f2 100644 --- a/tests/cfdp/pdus/test_finished_pdu.py +++ b/tests/cfdp/pdus/test_finished_pdu.py @@ -3,18 +3,18 @@ from spacepackets.cfdp import ( ConditionCode, EntityIdTlv, - FileStoreResponseTlv, FilestoreActionCode, FilestoreResponseStatusCode, + FileStoreResponseTlv, TlvType, ) -from spacepackets.cfdp.pdu.helper import PduFactory from spacepackets.cfdp.conf import PduConfig -from spacepackets.cfdp.defs import Direction, DeliveryCode, FileStatus +from spacepackets.cfdp.defs import DeliveryCode, Direction, FileStatus from spacepackets.cfdp.pdu import FinishedPdu from spacepackets.cfdp.pdu.finished import ( FinishedParams, ) +from spacepackets.cfdp.pdu.helper import PduFactory class TestFinishedPdu(TestCase): @@ -119,9 +119,7 @@ def test_with_fault_location(self): params=params, pdu_conf=self.pdu_conf, ) - self.assertEqual( - finish_pdu_with_fault_loc.delivery_code, DeliveryCode.DATA_INCOMPLETE - ) + self.assertEqual(finish_pdu_with_fault_loc.delivery_code, DeliveryCode.DATA_INCOMPLETE) self.assertEqual( finish_pdu_with_fault_loc.file_status, FileStatus.DISCARDED_DELIBERATELY, @@ -130,9 +128,7 @@ def test_with_fault_location(self): finish_pdu_with_fault_loc.condition_code, ConditionCode.POSITIVE_ACK_LIMIT_REACHED, ) - self.assertEqual( - finish_pdu_with_fault_loc.fault_location, self.fault_location_tlv - ) + self.assertEqual(finish_pdu_with_fault_loc.fault_location, self.fault_location_tlv) # 4 additional bytes because the entity ID in the TLV has 2 bytes self.assertEqual(finish_pdu_with_fault_loc.packet_len, 13) self.assertEqual(len(finish_pdu_with_fault_loc.pack()), 13) @@ -171,9 +167,7 @@ def test_with_fs_response(self): pdu_with_response = FinishedPdu(params=params, pdu_conf=self.pdu_conf) self.assertEqual(pdu_with_response.packet_len, 22) pdu_with_response_raw = pdu_with_response.pack() - expected_array = bytearray( - [0x28, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x05, 0x44] - ) + expected_array = bytearray([0x28, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x05, 0x44]) expected_array.extend(filestore_response_1_packed) self.assertEqual(expected_array, pdu_with_response_raw) pdu_with_response_unpacked = FinishedPdu.unpack(data=pdu_with_response_raw) @@ -207,18 +201,14 @@ def test_finished_pdu(self): file_store_responses=[self.filestore_reponse_1, filestore_reponse_2], fault_location=self.fault_location_tlv, ) - finish_pdu_two_responses_one_fault_loc = FinishedPdu( - params=params, pdu_conf=self.pdu_conf - ) + finish_pdu_two_responses_one_fault_loc = FinishedPdu(params=params, pdu_conf=self.pdu_conf) # length should be 13 (response 1) + 23 (response 2) + 4 (fault loc) + 9 (base) self.assertEqual(finish_pdu_two_responses_one_fault_loc.packet_len, 49) fs_responses = finish_pdu_two_responses_one_fault_loc.file_store_responses self.assertEqual(len(fs_responses), 2) complex_pdu_raw = finish_pdu_two_responses_one_fault_loc.pack() complex_pdu_unpacked = FinishedPdu.unpack(data=complex_pdu_raw) - self.assertEqual( - complex_pdu_unpacked.fault_location.pack(), self.fault_location_tlv.pack() - ) + self.assertEqual(complex_pdu_unpacked.fault_location.pack(), self.fault_location_tlv.pack()) self.assertEqual(self.filestore_reponse_1.pack(), fs_responses[0].pack()) self.assertEqual(filestore_reponse_2.pack(), fs_responses[1].pack()) diff --git a/tests/cfdp/pdus/test_keep_alive_pdu.py b/tests/cfdp/pdus/test_keep_alive_pdu.py index 8f645e5..e278967 100644 --- a/tests/cfdp/pdus/test_keep_alive_pdu.py +++ b/tests/cfdp/pdus/test_keep_alive_pdu.py @@ -3,7 +3,7 @@ from spacepackets.cfdp import LargeFileFlag, PduFactory from spacepackets.cfdp.conf import PduConfig from spacepackets.cfdp.defs import Direction -from spacepackets.cfdp.pdu import KeepAlivePdu, DirectiveType +from spacepackets.cfdp.pdu import DirectiveType, KeepAlivePdu class TestKeepAlivePdu(TestCase): diff --git a/tests/cfdp/pdus/test_metadata.py b/tests/cfdp/pdus/test_metadata.py index 31108d5..a31e8aa 100644 --- a/tests/cfdp/pdus/test_metadata.py +++ b/tests/cfdp/pdus/test_metadata.py @@ -2,25 +2,26 @@ from spacepackets.cfdp import ( ChecksumType, - FileStoreRequestTlv, - FilestoreActionCode, ConditionCode, + FilestoreActionCode, + FileStoreRequestTlv, ) from spacepackets.cfdp.conf import PduConfig from spacepackets.cfdp.defs import ( + CrcFlag, Direction, FaultHandlerCode, LargeFileFlag, - CrcFlag, TransmissionMode, ) -from spacepackets.cfdp.pdu import MetadataPdu, MetadataParams -from spacepackets.cfdp.tlv import TlvHolder, FaultHandlerOverrideTlv +from spacepackets.cfdp.pdu import MetadataParams, MetadataPdu +from spacepackets.cfdp.tlv import FaultHandlerOverrideTlv, TlvHolder class TestMetadata(TestCase): def setUp(self) -> None: self.pdu_conf = PduConfig.default() + self.pdu_header_len = self.pdu_conf.header_len() self.metadata_params = MetadataParams( closure_requested=False, file_size=2, @@ -28,6 +29,16 @@ def setUp(self) -> None: dest_file_name="test2.txt", checksum_type=ChecksumType.MODULAR, ) + self.file_name = "hallo.txt" + self.option_0 = FileStoreRequestTlv( + action_code=FilestoreActionCode.CREATE_FILE_SNM, + first_file_name=self.file_name, + ) + self.option_1 = FaultHandlerOverrideTlv( + condition_code=ConditionCode.POSITIVE_ACK_LIMIT_REACHED, + handler_code=FaultHandlerCode.ABANDON_TRANSACTION, + ) + self.assertEqual(self.option_1.packet_len, 3) def test_metadata_simple(self): metadata_pdu = MetadataPdu(pdu_conf=self.pdu_conf, params=self.metadata_params) @@ -58,25 +69,20 @@ def test_metadata_with_crc(self): self.assertEqual(len(metadata_raw), expected_len) def test_metadata_pdu(self): - file_name = "hallo.txt" - option_0 = FileStoreRequestTlv( - action_code=FilestoreActionCode.CREATE_FILE_SNM, first_file_name=file_name - ) - - self.assertEqual(option_0.packet_len, 13) + self.assertEqual(self.option_0.packet_len, 13) expected_bytes = bytearray() expected_bytes.extend(bytes([0x00, 0x0B, 0x00, 0x09])) - expected_bytes.extend(file_name.encode()) - self.assertEqual(option_0.pack(), expected_bytes) + expected_bytes.extend(self.file_name.encode()) + self.assertEqual(self.option_0.pack(), expected_bytes) # Create completey new packet pdu_with_option = MetadataPdu( pdu_conf=self.pdu_conf, params=self.metadata_params, - options=[option_0], + options=[self.option_0], ) header_len = pdu_with_option.pdu_file_directive.header_len - self.assertEqual(pdu_with_option.options, [option_0]) + self.assertEqual(pdu_with_option.options, [self.option_0]) expected_len = 10 + 9 + 8 + 5 + 13 self.assertEqual(pdu_with_option.packet_len, expected_len) pdu_with_option_raw = pdu_with_option.pack() @@ -86,7 +92,7 @@ def test_metadata_pdu(self): tlv_wrapper = TlvHolder(pdu_with_option_unpacked.options[0]) # type: ignore tlv_typed = tlv_wrapper.to_fs_request() self.assertIsNotNone(tlv_typed) - self.assertEqual(tlv_typed.pack(), option_0.pack()) + self.assertEqual(tlv_typed.pack(), self.option_0.pack()) pdu_with_option.source_file_name = None pdu_with_option.dest_file_name = None @@ -94,11 +100,7 @@ def test_metadata_pdu(self): self.assertEqual(pdu_with_option.directive_param_field_len, 1 + 1 + 5 + 13) self.assertEqual(pdu_with_option.packet_len, expected_len) - option_1 = FaultHandlerOverrideTlv( - condition_code=ConditionCode.POSITIVE_ACK_LIMIT_REACHED, - handler_code=FaultHandlerCode.ABANDON_TRANSACTION, - ) - self.assertEqual(option_1.packet_len, 3) + def test_metadata_pdu_two_options(self): metadata_params = MetadataParams( closure_requested=False, file_size=2, @@ -109,20 +111,24 @@ def test_metadata_pdu(self): pdu_with_two_options = MetadataPdu( pdu_conf=self.pdu_conf, params=metadata_params, - options=[option_0, option_1], + options=[self.option_0, self.option_1], ) + options_abstract = pdu_with_two_options.options + options_concrete = pdu_with_two_options.options_as_tlv() + for idx, option in enumerate(options_abstract): + self.assertEqual(option.tlv_type, options_concrete[idx].tlv_type) + self.assertEqual(option.value, options_concrete[idx].value) pdu_with_two_options_raw = pdu_with_two_options.pack() - expected_len = header_len + 5 + 2 + option_0.packet_len + option_1.packet_len + header_len = pdu_with_two_options.header_len + expected_len = header_len + 5 + 2 + self.option_0.packet_len + self.option_1.packet_len self.assertEqual(pdu_with_two_options.packet_len, expected_len) self.assertEqual(len(pdu_with_two_options_raw), expected_len) pdu_with_two_options.source_file_name = "hello.txt" - expected_len = ( - header_len + 5 + 1 + 10 + option_0.packet_len + option_1.packet_len - ) + expected_len = header_len + 5 + 1 + 10 + self.option_0.packet_len + self.option_1.packet_len self.assertEqual(pdu_with_two_options.packet_len, expected_len) pdu_with_two_options.dest_file_name = "hello2.txt" expected_len = ( - header_len + 5 + 11 + 10 + option_0.packet_len + option_1.packet_len + header_len + 5 + 11 + 10 + self.option_0.packet_len + self.option_1.packet_len ) self.assertEqual(pdu_with_two_options.packet_len, expected_len) pdu_with_no_options = pdu_with_two_options @@ -132,14 +138,23 @@ def test_metadata_pdu(self): pdu_with_no_options.pack() self.pdu_conf.file_flag = LargeFileFlag.LARGE + + def test_metadata_pdu_1(self): + metadata_params = MetadataParams( + closure_requested=False, + file_size=2, + source_file_name=None, + dest_file_name=None, + checksum_type=ChecksumType.MODULAR, + ) pdu_file_size_large = MetadataPdu( pdu_conf=self.pdu_conf, params=metadata_params, options=None, ) - self.assertEqual(pdu_file_size_large.pdu_file_directive.header_len, header_len) - self.assertEqual(pdu_file_size_large.packet_len, header_len + 2 + 9) - pdu_file_size_large.options = [option_0] + # 1 byte directive type, 7 bytes metadata content + self.assertEqual(pdu_file_size_large.packet_len, self.pdu_header_len + 1 + 7) + pdu_file_size_large.options = [self.option_0] pdu_file_size_large_raw = pdu_file_size_large.pack() pdu_file_size_large_raw = pdu_file_size_large_raw[:-2] with self.assertRaises(ValueError): diff --git a/tests/cfdp/pdus/test_nak_pdu.py b/tests/cfdp/pdus/test_nak_pdu.py index 4806601..97178b4 100644 --- a/tests/cfdp/pdus/test_nak_pdu.py +++ b/tests/cfdp/pdus/test_nak_pdu.py @@ -1,6 +1,6 @@ from unittest import TestCase -from spacepackets.cfdp import TransmissionMode, PduFactory, DirectiveType +from spacepackets.cfdp import DirectiveType, PduFactory, TransmissionMode from spacepackets.cfdp.conf import PduConfig from spacepackets.cfdp.defs import CrcFlag, Direction, LargeFileFlag from spacepackets.cfdp.pdu import NakPdu @@ -10,16 +10,13 @@ class TestNakPdu(TestCase): def setUp(self) -> None: - self.pdu_conf = PduConfig( trans_mode=TransmissionMode.ACKNOWLEDGED, transaction_seq_num=ByteFieldU16(1), source_entity_id=ByteFieldU16(0), dest_entity_id=ByteFieldU16(1), ) - self.nak_pdu = NakPdu( - start_of_scope=0, end_of_scope=200, pdu_conf=self.pdu_conf - ) + self.nak_pdu = NakPdu(start_of_scope=0, end_of_scope=200, pdu_conf=self.pdu_conf) def test_state(self): self.assertEqual(self.nak_pdu.segment_requests, []) @@ -75,30 +72,22 @@ def test_segment_req_for_packet_size_large_file(self): nak_pdu = NakPdu(pdu_conf, start_of_scope=0, end_of_scope=0) self.assertEqual( 3, - get_max_seg_reqs_for_max_packet_size_and_pdu_cfg( - max_packet_size=72, pdu_conf=pdu_conf - ), + get_max_seg_reqs_for_max_packet_size_and_pdu_cfg(max_packet_size=72, pdu_conf=pdu_conf), ) self.assertEqual(nak_pdu.get_max_seg_reqs_for_max_packet_size(72), 3) self.assertEqual( 3, - get_max_seg_reqs_for_max_packet_size_and_pdu_cfg( - max_packet_size=73, pdu_conf=pdu_conf - ), + get_max_seg_reqs_for_max_packet_size_and_pdu_cfg(max_packet_size=73, pdu_conf=pdu_conf), ) self.assertEqual(nak_pdu.get_max_seg_reqs_for_max_packet_size(73), 3) self.assertEqual( 2, - get_max_seg_reqs_for_max_packet_size_and_pdu_cfg( - max_packet_size=71, pdu_conf=pdu_conf - ), + get_max_seg_reqs_for_max_packet_size_and_pdu_cfg(max_packet_size=71, pdu_conf=pdu_conf), ) self.assertEqual(nak_pdu.get_max_seg_reqs_for_max_packet_size(71), 2) self.assertEqual( 4, - get_max_seg_reqs_for_max_packet_size_and_pdu_cfg( - max_packet_size=88, pdu_conf=pdu_conf - ), + get_max_seg_reqs_for_max_packet_size_and_pdu_cfg(max_packet_size=88, pdu_conf=pdu_conf), ) self.assertEqual(nak_pdu.get_max_seg_reqs_for_max_packet_size(88), 4) @@ -111,23 +100,17 @@ def test_segment_req_for_packet_size_large_file_with_crc(self): nak_pdu = NakPdu(pdu_conf, start_of_scope=0, end_of_scope=0) self.assertEqual( 3, - get_max_seg_reqs_for_max_packet_size_and_pdu_cfg( - max_packet_size=74, pdu_conf=pdu_conf - ), + get_max_seg_reqs_for_max_packet_size_and_pdu_cfg(max_packet_size=74, pdu_conf=pdu_conf), ) self.assertEqual(nak_pdu.get_max_seg_reqs_for_max_packet_size(74), 3) self.assertEqual( 2, - get_max_seg_reqs_for_max_packet_size_and_pdu_cfg( - max_packet_size=73, pdu_conf=pdu_conf - ), + get_max_seg_reqs_for_max_packet_size_and_pdu_cfg(max_packet_size=73, pdu_conf=pdu_conf), ) self.assertEqual(nak_pdu.get_max_seg_reqs_for_max_packet_size(73), 2) self.assertEqual( 4, - get_max_seg_reqs_for_max_packet_size_and_pdu_cfg( - max_packet_size=90, pdu_conf=pdu_conf - ), + get_max_seg_reqs_for_max_packet_size_and_pdu_cfg(max_packet_size=90, pdu_conf=pdu_conf), ) self.assertEqual(nak_pdu.get_max_seg_reqs_for_max_packet_size(90), 4) diff --git a/tests/cfdp/pdus/test_pdu_holder.py b/tests/cfdp/pdus/test_pdu_holder.py index c7d27ec..83be15e 100644 --- a/tests/cfdp/pdus/test_pdu_holder.py +++ b/tests/cfdp/pdus/test_pdu_holder.py @@ -3,25 +3,25 @@ from spacepackets.cfdp import ChecksumType, ConditionCode from spacepackets.cfdp.conf import PduConfig from spacepackets.cfdp.pdu import ( - MetadataPdu, AckPdu, DirectiveType, - TransactionStatus, - NakPdu, - PromptPdu, EofPdu, FinishedPdu, KeepAlivePdu, + MetadataPdu, + NakPdu, + PromptPdu, + TransactionStatus, ) -from spacepackets.cfdp.pdu.file_data import FileDataPdu, FileDataParams +from spacepackets.cfdp.pdu.file_data import FileDataParams, FileDataPdu from spacepackets.cfdp.pdu.finished import ( DeliveryCode, FileStatus, FinishedParams, ) +from spacepackets.cfdp.pdu.helper import PduHolder from spacepackets.cfdp.pdu.metadata import MetadataParams from spacepackets.cfdp.pdu.prompt import ResponseRequired -from spacepackets.cfdp.pdu.helper import PduHolder class TestPduHolder(TestCase): @@ -32,9 +32,7 @@ def setUp(self) -> None: self.pdu_wrapper = PduHolder(None) def test_file_data(self): - fd_params = FileDataParams( - file_data=self.file_data_bytes, offset=0, segment_metadata=None - ) + fd_params = FileDataParams(file_data=self.file_data_bytes, offset=0, segment_metadata=None) file_data_pdu = FileDataPdu(pdu_conf=self.pdu_conf, params=fd_params) self.pdu_wrapper.pdu = file_data_pdu pdu_casted_back = self.pdu_wrapper.to_file_data_pdu() @@ -75,9 +73,7 @@ def test_metadata(self): self.assertEqual(metadata_casted_back, metadata_pdu) def test_invalid_cast(self): - fd_params = FileDataParams( - file_data=self.file_data_bytes, offset=0, segment_metadata=None - ) + fd_params = FileDataParams(file_data=self.file_data_bytes, offset=0, segment_metadata=None) file_data_pdu = FileDataPdu(pdu_conf=self.pdu_conf, params=fd_params) self.pdu_wrapper.pdu = file_data_pdu with self.assertRaises(TypeError) as cm: @@ -112,9 +108,7 @@ def test_prompt_cast(self): def test_eof_cast(self): zero_checksum = bytes([0x00, 0x00, 0x00, 0x00]) - eof_pdu = EofPdu( - file_checksum=zero_checksum, file_size=0, pdu_conf=self.pdu_conf - ) + eof_pdu = EofPdu(file_checksum=zero_checksum, file_size=0, pdu_conf=self.pdu_conf) self.pdu_wrapper.pdu = eof_pdu eof_pdu_converted = self.pdu_wrapper.to_eof_pdu() self.assertEqual(eof_pdu_converted, eof_pdu) diff --git a/tests/cfdp/pdus/test_prompt_pdu.py b/tests/cfdp/pdus/test_prompt_pdu.py index 503e275..c8c24a6 100644 --- a/tests/cfdp/pdus/test_prompt_pdu.py +++ b/tests/cfdp/pdus/test_prompt_pdu.py @@ -2,7 +2,7 @@ from spacepackets.cfdp.conf import PduConfig from spacepackets.cfdp.defs import Direction -from spacepackets.cfdp.pdu import PromptPdu, PduFactory +from spacepackets.cfdp.pdu import PduFactory, PromptPdu from spacepackets.cfdp.pdu.prompt import ResponseRequired @@ -25,9 +25,7 @@ def test_prompt_pdu(self): self.assertEqual(self.prompt_pdu.direction, Direction.TOWARDS_RECEIVER) self.assertEqual(self.prompt_pdu.pdu_file_directive.pdu_data_field_len, 2) self.assertEqual(self.prompt_pdu.pdu_file_directive.header_len, 8) - self.assertEqual( - prompt_pdu_unpacked.response_required, ResponseRequired.KEEP_ALIVE - ) + self.assertEqual(prompt_pdu_unpacked.response_required, ResponseRequired.KEEP_ALIVE) self.assertEqual(self.prompt_pdu.pdu_file_directive.large_file_flag_set, False) prompt_pdu_raw = prompt_pdu_raw[:-1] with self.assertRaises(ValueError): diff --git a/tests/cfdp/test_cfdp.py b/tests/cfdp/test_cfdp.py index 3e87daf..54f8637 100644 --- a/tests/cfdp/test_cfdp.py +++ b/tests/cfdp/test_cfdp.py @@ -1,8 +1,8 @@ from unittest import TestCase from spacepackets.cfdp.conf import ( - set_entity_ids, get_entity_ids, + set_entity_ids, ) diff --git a/tests/cfdp/test_header.py b/tests/cfdp/test_header.py index 4b587ec..55ad048 100644 --- a/tests/cfdp/test_header.py +++ b/tests/cfdp/test_header.py @@ -2,22 +2,22 @@ from spacepackets.cfdp.conf import PduConfig, set_entity_ids from spacepackets.cfdp.defs import ( - LenInBytes, - TransmissionMode, - Direction, CrcFlag, - SegmentationControl, + Direction, + LargeFileFlag, + LenInBytes, PduType, + SegmentationControl, SegmentMetadataFlag, - LargeFileFlag, + TransmissionMode, ) from spacepackets.cfdp.pdu import PduHeader, PromptPdu from spacepackets.cfdp.pdu.prompt import ResponseRequired from spacepackets.util import ( - get_printable_data_string, - PrintFormats, ByteFieldU8, ByteFieldU16, + PrintFormats, + get_printable_data_string, ) @@ -51,13 +51,9 @@ def test_pdu_header(self): self.assertEqual(self.pdu_header.pdu_type, PduType.FILE_DIRECTIVE) self.assertEqual(self.pdu_header.source_entity_id, ByteFieldU8(0)) self.assertEqual(self.pdu_header.source_entity_id.byte_len, 1) - self.assertEqual( - self.pdu_header.transmission_mode, TransmissionMode.ACKNOWLEDGED - ) + self.assertEqual(self.pdu_header.transmission_mode, TransmissionMode.ACKNOWLEDGED) self.assertEqual(self.pdu_header.direction, Direction.TOWARDS_RECEIVER) - self.assertEqual( - self.pdu_header.segment_metadata_flag, SegmentMetadataFlag.NOT_PRESENT - ) + self.assertEqual(self.pdu_header.segment_metadata_flag, SegmentMetadataFlag.NOT_PRESENT) self.assertFalse(self.pdu_header.large_file_flag_set) self.assertEqual(self.pdu_header.transaction_seq_num, ByteFieldU8(0)) self.assertEqual(self.pdu_header.transaction_seq_num.byte_len, 1) @@ -68,9 +64,7 @@ def test_pdu_header(self): ) self.assertEqual(self.pdu_header.header_len, 7) pdu_header_packed = self.pdu_header.pack() - string = get_printable_data_string( - print_format=PrintFormats.HEX, data=pdu_header_packed - ) + string = get_printable_data_string(print_format=PrintFormats.HEX, data=pdu_header_packed) self.assertEqual(string, "hex [20,00,00,00,00,00,00]") self.check_fields_case_one(pdu_header_packed=pdu_header_packed) pdu_header_unpacked = PduHeader.unpack(data=pdu_header_packed) @@ -97,7 +91,7 @@ def test_pdu_header_2(self): self.assertTrue(self.pdu_header.large_file_flag_set) pdu_header_packed = self.pdu_header.pack() self.check_fields_case_two(pdu_header_packed=pdu_header_packed) - set_entity_ids(source_entity_id=bytes(), dest_entity_id=bytes()) + set_entity_ids(source_entity_id=b"", dest_entity_id=b"") with self.assertRaises(ValueError): self.pdu_header.pdu_data_field_len = 78292 invalid_pdu_header = bytearray([0, 1, 2]) @@ -115,9 +109,7 @@ def test_with_prompt_pdu(self): self._switch_cfg() self.pdu_conf.source_entity_id = ByteFieldU8(0) self.pdu_conf.dest_entity_id = ByteFieldU8(0) - self.pdu_conf.transaction_seq_num = ByteFieldU16.from_u16_bytes( - bytes([0x00, 0x2C]) - ) + self.pdu_conf.transaction_seq_num = ByteFieldU16.from_u16_bytes(bytes([0x00, 0x2C])) prompt_pdu = PromptPdu( response_required=ResponseRequired.KEEP_ALIVE, pdu_conf=self.pdu_conf ) @@ -133,9 +125,7 @@ def test_with_prompt_pdu(self): self.assertEqual(prompt_pdu.pdu_file_directive.file_flag, LargeFileFlag.NORMAL) prompt_pdu.crc_flag = CrcFlag.NO_CRC self.assertEqual(prompt_pdu.crc_flag, CrcFlag.NO_CRC) - self.assertEqual( - prompt_pdu.pdu_file_directive.pdu_header.crc_flag, CrcFlag.NO_CRC - ) + self.assertEqual(prompt_pdu.pdu_file_directive.pdu_header.crc_flag, CrcFlag.NO_CRC) def check_fields_case_one(self, pdu_header_packed: bytes): self.assertEqual(len(pdu_header_packed), 7) @@ -187,9 +177,7 @@ def check_fields_case_two(self, pdu_header_packed: bytes): # Segmentation Control self.assertEqual((pdu_header_packed[3] & 0x80) >> 7, 1) # Length of entity IDs - self.assertEqual( - ((pdu_header_packed[3] >> 4) & 0b111) + 1, LenInBytes.TWO_BYTES - ) + self.assertEqual(((pdu_header_packed[3] >> 4) & 0b111) + 1, LenInBytes.TWO_BYTES) # Segment metadata flag self.assertEqual((pdu_header_packed[3] & 0x08) >> 3, 1) # Length of transaction sequence number diff --git a/tests/cfdp/test_transaction_id.py b/tests/cfdp/test_transaction_id.py index 91f5b66..971bccd 100644 --- a/tests/cfdp/test_transaction_id.py +++ b/tests/cfdp/test_transaction_id.py @@ -1,4 +1,5 @@ from unittest import TestCase + from spacepackets.cfdp import TransactionId from spacepackets.util import ByteFieldU16 @@ -18,7 +19,7 @@ def test_eq(self): self.assertNotEqual(self.transaction_id_0, self.transaction_id_1) def test_repr(self): - repr = self.transaction_id_0.__repr__() - self.assertTrue("TransactionId" in repr) - self.assertTrue("source_entity_id=" in repr) - self.assertTrue("transaction_seq_num=" in repr) + repr_str = self.transaction_id_0.__repr__() + self.assertTrue("TransactionId" in repr_str) + self.assertTrue("source_entity_id=" in repr_str) + self.assertTrue("transaction_seq_num=" in repr_str) diff --git a/tests/cfdp/tlvslvs/test_dir_params.py b/tests/cfdp/tlvslvs/test_dir_params.py index 4efdb7e..559e473 100644 --- a/tests/cfdp/tlvslvs/test_dir_params.py +++ b/tests/cfdp/tlvslvs/test_dir_params.py @@ -1,5 +1,6 @@ -from unittest import TestCase from pathlib import Path +from unittest import TestCase + from spacepackets.cfdp import CfdpLv from spacepackets.cfdp.tlv import DirectoryParams @@ -10,12 +11,8 @@ def setUp(self): self.dir_path_from_str = CfdpLv.from_str(self.dir_path) self.dir_file_name = "~/dir-listing.txt" self.dir_file_name_from_str = CfdpLv.from_str(self.dir_file_name) - self.dir_param = DirectoryParams( - self.dir_path_from_str, self.dir_file_name_from_str - ) - self.dir_param_from_strs = DirectoryParams.from_strs( - self.dir_path, self.dir_file_name - ) + self.dir_param = DirectoryParams(self.dir_path_from_str, self.dir_file_name_from_str) + self.dir_param_from_strs = DirectoryParams.from_strs(self.dir_path, self.dir_file_name) # As POSIX to ensure this works on Windows as well. self.dir_param_from_paths = DirectoryParams.from_paths( Path(self.dir_path).as_posix(), Path(self.dir_file_name).as_posix() diff --git a/tests/cfdp/tlvslvs/test_entity_id.py b/tests/cfdp/tlvslvs/test_entity_id.py index 2a4405e..7448a84 100644 --- a/tests/cfdp/tlvslvs/test_entity_id.py +++ b/tests/cfdp/tlvslvs/test_entity_id.py @@ -1,11 +1,11 @@ from unittest import TestCase from spacepackets.cfdp import ( + CfdpTlv, EntityIdTlv, TlvHolder, TlvType, - TlvTypeMissmatch, - CfdpTlv, + TlvTypeMissmatchError, ) @@ -39,7 +39,7 @@ def test_from_cfdp_tlv(self): def test_invalid_type(self): entity_id_tlv_tlv = self.entity_id_tlv.tlv entity_id_tlv_tlv.tlv_type = TlvType.FILESTORE_REQUEST - with self.assertRaises(TlvTypeMissmatch): + with self.assertRaises(TlvTypeMissmatchError): EntityIdTlv.from_tlv(cfdp_tlv=entity_id_tlv_tlv) def test_custom_eq(self): @@ -49,6 +49,4 @@ def test_custom_eq(self): def test_repr(self): repr_str = repr(self.entity_id_tlv) - self.assertEqual( - repr_str, f"Tlv(tlv_type={TlvType.ENTITY_ID!r}, value=0x[00,01,02,03])" - ) + self.assertEqual(repr_str, f"Tlv(tlv_type={TlvType.ENTITY_ID!r}, value=0x[00,01,02,03])") diff --git a/tests/cfdp/tlvslvs/test_fault_handler_tlv.py b/tests/cfdp/tlvslvs/test_fault_handler_tlv.py index b4cea83..8f260de 100644 --- a/tests/cfdp/tlvslvs/test_fault_handler_tlv.py +++ b/tests/cfdp/tlvslvs/test_fault_handler_tlv.py @@ -1,13 +1,13 @@ from unittest import TestCase from spacepackets.cfdp import ( - FaultHandlerOverrideTlv, + CfdpTlv, ConditionCode, FaultHandlerCode, + FaultHandlerOverrideTlv, TlvHolder, TlvType, - TlvTypeMissmatch, - CfdpTlv, + TlvTypeMissmatchError, ) @@ -35,7 +35,7 @@ def test_from_cfdp_tlv(self): def test_type_missmatch(self): fault_handler_ovvrd_tlv_tlv = self.fault_handler_ovvrd_tlv.tlv fault_handler_ovvrd_tlv_tlv.tlv_type = TlvType.ENTITY_ID - with self.assertRaises(TlvTypeMissmatch): + with self.assertRaises(TlvTypeMissmatchError): FaultHandlerOverrideTlv.from_tlv(cfdp_tlv=fault_handler_ovvrd_tlv_tlv) def test_unpack(self): diff --git a/tests/cfdp/tlvslvs/test_flow_label_tlv.py b/tests/cfdp/tlvslvs/test_flow_label_tlv.py index fa48975..0c1bf51 100644 --- a/tests/cfdp/tlvslvs/test_flow_label_tlv.py +++ b/tests/cfdp/tlvslvs/test_flow_label_tlv.py @@ -1,13 +1,13 @@ from unittest import TestCase from spacepackets.cfdp import ( - TlvType, TlvHolder, - TlvTypeMissmatch, + TlvType, + TlvTypeMissmatchError, ) from spacepackets.cfdp.tlv import ( - FlowLabelTlv, CfdpTlv, + FlowLabelTlv, ) @@ -37,8 +37,8 @@ def test_flow_label_tlv(self): flow_label_tlv_unpacked = FlowLabelTlv.unpack(data=flow_label_tlv_raw) self.assertEqual(flow_label_tlv_unpacked.tlv.value, bytes([0x00])) flow_label_tlv_tlv.tlv_type = TlvType.FILESTORE_REQUEST - with self.assertRaises(TlvTypeMissmatch): + with self.assertRaises(TlvTypeMissmatchError): FlowLabelTlv.from_tlv(cfdp_tlv=flow_label_tlv_tlv) flow_label_tlv_raw[0] = TlvType.FILESTORE_REQUEST - with self.assertRaises(TlvTypeMissmatch): + with self.assertRaises(TlvTypeMissmatchError): FlowLabelTlv.unpack(data=flow_label_tlv_raw) diff --git a/tests/cfdp/tlvslvs/test_fs_req_tlv.py b/tests/cfdp/tlvslvs/test_fs_req_tlv.py index 6f541fa..9c0272a 100644 --- a/tests/cfdp/tlvslvs/test_fs_req_tlv.py +++ b/tests/cfdp/tlvslvs/test_fs_req_tlv.py @@ -1,12 +1,12 @@ from unittest import TestCase from spacepackets.cfdp import ( - FileStoreRequestTlv, + CfdpTlv, FilestoreActionCode, + FileStoreRequestTlv, TlvHolder, - TlvTypeMissmatch, TlvType, - CfdpTlv, + TlvTypeMissmatchError, ) @@ -15,15 +15,11 @@ def setUp(self) -> None: self.fs_reqeust_tlv = FileStoreRequestTlv( action_code=FilestoreActionCode.APPEND_FILE_SNP, first_file_name="test.txt" ) - self.cfdp_tlv = CfdpTlv( - tlv_type=TlvType.FILESTORE_REQUEST, value=self.fs_reqeust_tlv.value - ) + self.cfdp_tlv = CfdpTlv(tlv_type=TlvType.FILESTORE_REQUEST, value=self.fs_reqeust_tlv.value) def test_basic(self): self.assertEqual(self.fs_reqeust_tlv.tlv_type, TlvType.FILESTORE_REQUEST) - self.assertEqual( - self.fs_reqeust_tlv.action_code, FilestoreActionCode.APPEND_FILE_SNP - ) + self.assertEqual(self.fs_reqeust_tlv.action_code, FilestoreActionCode.APPEND_FILE_SNP) # 2 bytes header, action code byte, 9 bytes first file name, # 1 byte second file name empty TLV self.assertEqual(self.fs_reqeust_tlv.packet_len, 13) @@ -40,9 +36,7 @@ def test_holder_cfdp_tlv(self): self.assertEqual(fs_req_tlv, self.fs_reqeust_tlv) def test_from_cfdp_tlv(self): - self.assertEqual( - FileStoreRequestTlv.from_tlv(self.cfdp_tlv), self.fs_reqeust_tlv - ) + self.assertEqual(FileStoreRequestTlv.from_tlv(self.cfdp_tlv), self.fs_reqeust_tlv) def test_fs_req_tlv(self): self.fs_reqeust_tlv.generate_tlv() @@ -50,9 +44,7 @@ def test_fs_req_tlv(self): fs_reqeust_tlv_raw = self.fs_reqeust_tlv.pack() fs_reqeust_tlv_unpacked = FileStoreRequestTlv.unpack(data=fs_reqeust_tlv_raw) self.assertEqual(fs_reqeust_tlv_unpacked.first_file_name, "test.txt") - self.assertEqual( - fs_reqeust_tlv_unpacked.action_code, FilestoreActionCode.APPEND_FILE_SNP - ) + self.assertEqual(fs_reqeust_tlv_unpacked.action_code, FilestoreActionCode.APPEND_FILE_SNP) fs_reqeust_tlv_tlv.tlv_type = TlvType.ENTITY_ID - with self.assertRaises(TlvTypeMissmatch): + with self.assertRaises(TlvTypeMissmatchError): FileStoreRequestTlv.from_tlv(cfdp_tlv=fs_reqeust_tlv_tlv) diff --git a/tests/cfdp/tlvslvs/test_fs_response.py b/tests/cfdp/tlvslvs/test_fs_response.py index 98da6f2..95e2ad8 100644 --- a/tests/cfdp/tlvslvs/test_fs_response.py +++ b/tests/cfdp/tlvslvs/test_fs_response.py @@ -1,13 +1,13 @@ from unittest import TestCase from spacepackets.cfdp import ( - FileStoreResponseTlv, + CfdpTlv, FilestoreActionCode, FilestoreResponseStatusCode, + FileStoreResponseTlv, TlvHolder, TlvType, - TlvTypeMissmatch, - CfdpTlv, + TlvTypeMissmatchError, ) @@ -23,9 +23,7 @@ def setUp(self) -> None: ) def test_from_cfdp_tlv(self): - self.assertEqual( - TlvHolder(self.cfdp_tlv).to_fs_response(), self.fs_response_tlv - ) + self.assertEqual(TlvHolder(self.cfdp_tlv).to_fs_response(), self.fs_response_tlv) def test_invalid_cast(self): with self.assertRaises(TypeError): @@ -39,7 +37,7 @@ def test_fs_response_tlv(self): self.assertEqual(fs_reply_tlv_from_fac.pack(), self.fs_response_tlv.pack()) fs_response_tlv_tlv.tlv_type = TlvType.ENTITY_ID - with self.assertRaises(TlvTypeMissmatch): + with self.assertRaises(TlvTypeMissmatchError): FileStoreResponseTlv.from_tlv(cfdp_tlv=fs_response_tlv_tlv) fs_response_tlv_tlv.tlv_type = TlvType.FILESTORE_RESPONSE fs_response_tlv_raw = self.fs_response_tlv.pack() @@ -49,7 +47,7 @@ def test_fs_response_tlv(self): FileStoreResponseTlv.unpack(data=fs_response_tlv_raw) # Wrong ID fs_response_tlv_raw[0] = TlvType.ENTITY_ID - with self.assertRaises(TlvTypeMissmatch): + with self.assertRaises(TlvTypeMissmatchError): FileStoreResponseTlv.unpack(data=fs_response_tlv_raw) fs_response_tlv_raw[0] = TlvType.FILESTORE_RESPONSE fs_response_tlv_raw[2] = 0b11110000 diff --git a/tests/cfdp/tlvslvs/test_lvs.py b/tests/cfdp/tlvslvs/test_lvs.py index b0a00da..3ee6c9f 100644 --- a/tests/cfdp/tlvslvs/test_lvs.py +++ b/tests/cfdp/tlvslvs/test_lvs.py @@ -1,5 +1,5 @@ -from unittest import TestCase from pathlib import Path +from unittest import TestCase from spacepackets.cfdp.lv import CfdpLv from spacepackets.cfdp.tlv import CfdpTlv diff --git a/tests/cfdp/tlvslvs/test_msg_to_user.py b/tests/cfdp/tlvslvs/test_msg_to_user.py index 9052df4..415c218 100644 --- a/tests/cfdp/tlvslvs/test_msg_to_user.py +++ b/tests/cfdp/tlvslvs/test_msg_to_user.py @@ -1,10 +1,10 @@ from unittest import TestCase -from spacepackets.cfdp import MessageToUserTlv, TlvHolder, TlvType, TlvTypeMissmatch +from spacepackets.cfdp import MessageToUserTlv, TlvHolder, TlvType, TlvTypeMissmatchError from spacepackets.cfdp.tlv import ( - create_cfdp_proxy_and_dir_op_message_marker, CfdpTlv, ProxyMessageType, + create_cfdp_proxy_and_dir_op_message_marker, ) @@ -24,7 +24,7 @@ def test_from_cfdp_tlv(self): def test_msg_to_user_tlv(self): msg_to_usr_tlv_tlv = self.msg_to_usr_tlv.tlv msg_to_usr_tlv_tlv.tlv_type = TlvType.FILESTORE_REQUEST - with self.assertRaises(TlvTypeMissmatch): + with self.assertRaises(TlvTypeMissmatchError): MessageToUserTlv.from_tlv(cfdp_tlv=msg_to_usr_tlv_tlv) msg_to_usr_tlv_tlv.tlv_type = TlvType.MESSAGE_TO_USER msg_to_usr_tlv_raw = self.msg_to_usr_tlv.pack() diff --git a/tests/cfdp/tlvslvs/test_proxy.py b/tests/cfdp/tlvslvs/test_proxy.py index 4473bd0..0ebca35 100644 --- a/tests/cfdp/tlvslvs/test_proxy.py +++ b/tests/cfdp/tlvslvs/test_proxy.py @@ -2,10 +2,10 @@ from spacepackets.cfdp import CfdpLv from spacepackets.cfdp.tlv import ( - ProxyPutRequest, - TlvType, ProxyMessageType, + ProxyPutRequest, ProxyPutRequestParams, + TlvType, ) from spacepackets.util import ByteFieldU8 @@ -23,7 +23,7 @@ def setUp(self) -> None: self.proxy_put_req = ProxyPutRequest(proxy_put_req_params) self.expected_raw_len = ( 2 # TLV header - + len("cfdp".encode()) + + len(b"cfdp") + 1 # Message type + self.dest_entity_id.byte_len + 1 @@ -47,18 +47,14 @@ def test_pack(self): self.assertEqual(raw_proxy_put_req[9], len(self.src_string)) current_idx = 10 self.assertEqual( - raw_proxy_put_req[ - current_idx : current_idx + len(self.src_string) - ].decode(), + raw_proxy_put_req[current_idx : current_idx + len(self.src_string)].decode(), self.src_string, ) current_idx += len(self.src_string) self.assertEqual(raw_proxy_put_req[current_idx], len(self.dest_string)) current_idx += 1 self.assertEqual( - raw_proxy_put_req[ - current_idx : current_idx + len(self.dest_string) - ].decode(), + raw_proxy_put_req[current_idx : current_idx + len(self.dest_string)].decode(), self.dest_string, ) current_idx += len(self.dest_string) diff --git a/tests/cfdp/tlvslvs/test_reserved_cfdp_msg.py b/tests/cfdp/tlvslvs/test_reserved_cfdp_msg.py index 3afd244..ff2f75b 100644 --- a/tests/cfdp/tlvslvs/test_reserved_cfdp_msg.py +++ b/tests/cfdp/tlvslvs/test_reserved_cfdp_msg.py @@ -4,31 +4,31 @@ from spacepackets.cfdp import ( CfdpLv, - TransactionId, ConditionCode, - FileStatus, DeliveryCode, + FileStatus, FinishedParams, + TransactionId, TransmissionMode, ) from spacepackets.cfdp.tlv import ( - ProxyPutRequest, - ProxyPutRequestParams, - ProxyPutResponseParams, - ProxyPutResponse, - ProxyClosureRequest, - ProxyTransmissionMode, - DirectoryParams, - DirListingOptions, + ORIGINATING_TRANSACTION_ID_MSG_TYPE_ID, + DirectoryListingParameters, DirectoryListingRequest, DirectoryListingResponse, - DirectoryListingParameters, DirectoryOperationMessageType, - ProxyCancelRequest, - OriginatingTransactionId, + DirectoryParams, + DirListingOptions, MessageToUserTlv, - ORIGINATING_TRANSACTION_ID_MSG_TYPE_ID, + OriginatingTransactionId, + ProxyCancelRequest, + ProxyClosureRequest, ProxyMessageType, + ProxyPutRequest, + ProxyPutRequestParams, + ProxyPutResponse, + ProxyPutResponseParams, + ProxyTransmissionMode, TlvType, ) from spacepackets.util import ByteFieldU8, ByteFieldU16 @@ -60,9 +60,7 @@ def setUp(self) -> None: ) self.proxy_put_response = ProxyPutResponse(self.proxy_put_response_params) self.proxy_closure_requested = ProxyClosureRequest(True) - self.proxy_transmission_mode = ProxyTransmissionMode( - TransmissionMode.UNACKNOWLEDGED - ) + self.proxy_transmission_mode = ProxyTransmissionMode(TransmissionMode.UNACKNOWLEDGED) self.proxy_cancel_request = ProxyCancelRequest() @@ -76,9 +74,7 @@ def setUp(self) -> None: self.dir_listing_options = DirListingOptions( self.dir_lst_opt_recursive, self.dir_lst_opt_all ) - self.dir_listing_options_msg = DirectoryListingParameters( - self.dir_listing_options - ) + self.dir_listing_options_msg = DirectoryListingParameters(self.dir_listing_options) def _generic_raw_data_verification( self, data: bytes, expected_custom_len: int, expected_msg_type: int @@ -128,9 +124,7 @@ def test_to_generic_and_to_reserved_again(self): self.assertEqual(self.proxy_put_request.packet_len, reserved_msg.packet_len) def test_originating_transaction_id_state(self): - self.assertTrue( - self.originating_transaction_id_msg.is_originating_transaction_id() - ) + self.assertTrue(self.originating_transaction_id_msg.is_originating_transaction_id()) self.assertFalse(self.originating_transaction_id_msg.is_cfdp_proxy_operation()) self.assertFalse(self.originating_transaction_id_msg.is_directory_operation()) @@ -147,8 +141,8 @@ def test_originating_transaction_id_pack(self): self.assertEqual(seq_num, 5) def test_originating_transaction_id_unpack(self): - id = self.originating_transaction_id_msg.get_originating_transaction_id() - self.assertEqual(self.originating_transaction_id, id) + originating_id = self.originating_transaction_id_msg.get_originating_transaction_id() + self.assertEqual(self.originating_transaction_id, originating_id) id_raw = self.originating_transaction_id_msg.pack() generic_reserved_msg = MessageToUserTlv.unpack(id_raw).to_reserved_msg_tlv() self.assertIsNotNone(generic_reserved_msg) @@ -166,9 +160,7 @@ def test_put_reponse_state(self): def test_put_reponse_pack(self): put_response_raw = self.proxy_put_response.pack() - self._generic_raw_data_verification( - put_response_raw, 1, ProxyMessageType.PUT_RESPONSE - ) + self._generic_raw_data_verification(put_response_raw, 1, ProxyMessageType.PUT_RESPONSE) self.assertEqual((put_response_raw[7] >> 4) & 0b1111, ConditionCode.NO_ERROR) self.assertEqual((put_response_raw[7] >> 2) & 0b1, DeliveryCode.DATA_COMPLETE) self.assertEqual(put_response_raw[7] & 0b11, FileStatus.FILE_RETAINED) @@ -177,9 +169,7 @@ def test_put_reponse_unpack(self): put_reponse_params = self.proxy_put_response.get_proxy_put_response_params() self.assertEqual(put_reponse_params, self.proxy_put_response_params) put_response_raw = self.proxy_put_response.pack() - generic_reserved_msg = MessageToUserTlv.unpack( - put_response_raw - ).to_reserved_msg_tlv() + generic_reserved_msg = MessageToUserTlv.unpack(put_response_raw).to_reserved_msg_tlv() self.assertIsNotNone(generic_reserved_msg) put_reponse_params_2 = self.proxy_put_response.get_proxy_put_response_params() self.assertEqual(put_reponse_params_2, self.proxy_put_response_params) @@ -195,18 +185,14 @@ def test_proxy_closure_requested_state(self): def test_proxy_closure_requested_pack(self): proxy_closure_raw = self.proxy_closure_requested.pack() - self._generic_raw_data_verification( - proxy_closure_raw, 1, ProxyMessageType.CLOSURE_REQUEST - ) + self._generic_raw_data_verification(proxy_closure_raw, 1, ProxyMessageType.CLOSURE_REQUEST) self.assertTrue(proxy_closure_raw[7] & 0b1) def test_proxy_closure_requested_unpack(self): closure_requested = self.proxy_closure_requested.get_proxy_closure_requested() self.assertTrue(closure_requested) proxy_closure_raw = self.proxy_closure_requested.pack() - generic_reserved_msg = MessageToUserTlv.unpack( - proxy_closure_raw - ).to_reserved_msg_tlv() + generic_reserved_msg = MessageToUserTlv.unpack(proxy_closure_raw).to_reserved_msg_tlv() self.assertTrue(generic_reserved_msg.get_proxy_closure_requested()) def test_proxy_transmission_mode_state(self): @@ -223,17 +209,13 @@ def test_proxy_transmission_mode_pack(self): self._generic_raw_data_verification( proxy_transmission_mode_raw, 1, ProxyMessageType.TRANSMISSION_MODE ) - self.assertEqual( - proxy_transmission_mode_raw[7] & 0b1, TransmissionMode.UNACKNOWLEDGED - ) + self.assertEqual(proxy_transmission_mode_raw[7] & 0b1, TransmissionMode.UNACKNOWLEDGED) def test_proxy_transmission_mode_unpack(self): transmission_mode = self.proxy_transmission_mode.get_proxy_transmission_mode() self.assertEqual(transmission_mode, TransmissionMode.UNACKNOWLEDGED) transmission_mode_raw = self.proxy_transmission_mode.pack() - generic_reserved_msg = MessageToUserTlv.unpack( - transmission_mode_raw - ).to_reserved_msg_tlv() + generic_reserved_msg = MessageToUserTlv.unpack(transmission_mode_raw).to_reserved_msg_tlv() self.assertEqual( generic_reserved_msg.get_proxy_transmission_mode(), TransmissionMode.UNACKNOWLEDGED, @@ -256,9 +238,7 @@ def test_dir_listing_req_pack(self): DirectoryOperationMessageType.LISTING_REQUEST, ) dir_path_lv = CfdpLv.unpack(dir_listing_req_raw[7:]) - dir_listing_name_lv = CfdpLv.unpack( - dir_listing_req_raw[7 + dir_path_lv.packet_len :] - ) + dir_listing_name_lv = CfdpLv.unpack(dir_listing_req_raw[7 + dir_path_lv.packet_len :]) self.assertEqual(dir_path_lv, self.dir_path_lv) self.assertEqual(dir_listing_name_lv, self.dir_listing_name_lv) @@ -266,9 +246,7 @@ def test_dir_listing_req_unpack(self): dir_listing_req_params = self.dir_listing_req.get_dir_listing_request_params() self.assertEqual(dir_listing_req_params, self.dir_params) dir_listing_raw = self.dir_listing_req.pack() - generic_reserved_msg = MessageToUserTlv.unpack( - dir_listing_raw - ).to_reserved_msg_tlv() + generic_reserved_msg = MessageToUserTlv.unpack(dir_listing_raw).to_reserved_msg_tlv() self.assertEqual( generic_reserved_msg.get_dir_listing_request_params(), self.dir_params, @@ -292,22 +270,16 @@ def test_dir_listing_response_pack(self): ) success_response = (dir_listing_response_raw[7] >> 7) & 0b1 dir_path_lv = CfdpLv.unpack(dir_listing_response_raw[8:]) - dir_listing_name_lv = CfdpLv.unpack( - dir_listing_response_raw[8 + dir_path_lv.packet_len :] - ) + dir_listing_name_lv = CfdpLv.unpack(dir_listing_response_raw[8 + dir_path_lv.packet_len :]) self.assertTrue(success_response) self.assertEqual(self.dir_path_lv, dir_path_lv) self.assertEqual(self.dir_listing_name_lv, dir_listing_name_lv) def test_dir_listing_response_unpack(self): - dir_listing_response_params = ( - self.dir_listing_req.get_dir_listing_request_params() - ) + dir_listing_response_params = self.dir_listing_req.get_dir_listing_request_params() self.assertEqual(dir_listing_response_params, self.dir_params) dir_listing_raw = self.dir_listing_response.pack() - generic_reserved_msg = MessageToUserTlv.unpack( - dir_listing_raw - ).to_reserved_msg_tlv() + generic_reserved_msg = MessageToUserTlv.unpack(dir_listing_raw).to_reserved_msg_tlv() ( success_response, dir_listing_params, @@ -338,9 +310,7 @@ def test_dir_listing_options_unpack(self): dir_listing_options = self.dir_listing_options_msg.get_dir_listing_options() self.assertEqual(dir_listing_options, self.dir_listing_options) dir_listing_opt_raw = self.dir_listing_options_msg.pack() - generic_reserved_msg = MessageToUserTlv.unpack( - dir_listing_opt_raw - ).to_reserved_msg_tlv() + generic_reserved_msg = MessageToUserTlv.unpack(dir_listing_opt_raw).to_reserved_msg_tlv() listing_opts_from_raw = generic_reserved_msg.get_dir_listing_options() self.assertEqual(listing_opts_from_raw, self.dir_listing_options) @@ -355,15 +325,11 @@ def test_proxy_cancel_request_state(self): def test_proxy_cancel_request_pack(self): proxy_put_cancel_raw = self.proxy_cancel_request.pack() - self._generic_raw_data_verification( - proxy_put_cancel_raw, 0, ProxyMessageType.PUT_CANCEL - ) + self._generic_raw_data_verification(proxy_put_cancel_raw, 0, ProxyMessageType.PUT_CANCEL) def test_proxy_cancel_request_unpack(self): proxy_put_cancel_raw = self.proxy_cancel_request.pack() - generic_reserved_msg = MessageToUserTlv.unpack( - proxy_put_cancel_raw - ).to_reserved_msg_tlv() + generic_reserved_msg = MessageToUserTlv.unpack(proxy_put_cancel_raw).to_reserved_msg_tlv() self.assertEqual( generic_reserved_msg.get_cfdp_proxy_message_type(), ProxyMessageType.PUT_CANCEL, @@ -383,9 +349,7 @@ def test_proxy_put_response_params_from_finished_params(self): self.assertEqual( self.proxy_put_response_params.delivery_code, finished_params.delivery_code ) - self.assertEqual( - self.proxy_put_response_params.file_status, finished_params.file_status - ) + self.assertEqual(self.proxy_put_response_params.file_status, finished_params.file_status) def test_proxy_put_req_param_api(self): src_as_str = "/tmp/test.txt" diff --git a/tests/cfdp/tlvslvs/test_tlvs.py b/tests/cfdp/tlvslvs/test_tlvs.py index 29a5034..e0988cb 100644 --- a/tests/cfdp/tlvslvs/test_tlvs.py +++ b/tests/cfdp/tlvslvs/test_tlvs.py @@ -1,28 +1,25 @@ from unittest import TestCase -from spacepackets.cfdp import TlvType, CfdpTlv from spacepackets.cfdp.tlv import ( - map_enum_status_code_to_action_status_code, - FilestoreResponseStatusCode, + CfdpTlv, FilestoreActionCode, + FilestoreResponseStatusCode, + TlvType, + map_enum_status_code_to_action_status_code, map_int_status_code_to_enum, ) class TestTlvs(TestCase): def test_basic(self): - test_tlv = CfdpTlv( - tlv_type=TlvType.FILESTORE_REQUEST, value=bytes([0, 1, 2, 3, 4]) - ) + test_tlv = CfdpTlv(tlv_type=TlvType.FILESTORE_REQUEST, value=bytes([0, 1, 2, 3, 4])) self.assertEqual(test_tlv.tlv_type, TlvType.FILESTORE_REQUEST) self.assertEqual(test_tlv.value_len, 5) self.assertEqual(test_tlv.value, bytes([0, 1, 2, 3, 4])) self.assertEqual(test_tlv.packet_len, 7) def test_packing(self): - test_tlv = CfdpTlv( - tlv_type=TlvType.FILESTORE_REQUEST, value=bytes([0, 1, 2, 3, 4]) - ) + test_tlv = CfdpTlv(tlv_type=TlvType.FILESTORE_REQUEST, value=bytes([0, 1, 2, 3, 4])) test_tlv_package = test_tlv.pack() test_tlv_unpacked = CfdpTlv.unpack(data=test_tlv_package) self.assertEqual(test_tlv_unpacked.tlv_type, TlvType.FILESTORE_REQUEST) @@ -59,9 +56,7 @@ def test_status_code_converters(self): self.assertEqual(action_code, FilestoreActionCode.APPEND_FILE_SNP) self.assertEqual(status_code, 0b1111) with self.assertRaises(ValueError): - map_enum_status_code_to_action_status_code( - FilestoreResponseStatusCode.INVALID - ) + map_enum_status_code_to_action_status_code(FilestoreResponseStatusCode.INVALID) status_code = map_int_status_code_to_enum( action_code=FilestoreActionCode.APPEND_FILE_SNP, status_code=0b1111 ) @@ -72,8 +67,6 @@ def test_status_code_converters(self): self.assertEqual(invalid_code, FilestoreResponseStatusCode.INVALID) def test_tlv_print(self): - test_tlv = CfdpTlv( - tlv_type=TlvType.FILESTORE_REQUEST, value=bytes([0, 1, 2, 3, 4]) - ) + test_tlv = CfdpTlv(tlv_type=TlvType.FILESTORE_REQUEST, value=bytes([0, 1, 2, 3, 4])) print(test_tlv) print(f"{test_tlv!r}") diff --git a/tests/ecss/common.py b/tests/ecss/common.py index 861527f..6c2f934 100644 --- a/tests/ecss/common.py +++ b/tests/ecss/common.py @@ -1,6 +1,6 @@ from unittest.mock import MagicMock, PropertyMock -from spacepackets.ccsds import CdsShortTimestamp, CcsdsTimeCodeId +from spacepackets.ccsds import CcsdsTimeCodeId, CdsShortTimestamp TEST_STAMP = bytes([CcsdsTimeCodeId.CDS << 4, 1, 2, 3, 4, 5, 6]) diff --git a/tests/ecss/test_pus_tc.py b/tests/ecss/test_pus_tc.py index 944d243..b71f890 100644 --- a/tests/ecss/test_pus_tc.py +++ b/tests/ecss/test_pus_tc.py @@ -2,10 +2,10 @@ import crcmod -from spacepackets import SpacePacketHeader, PacketType +from spacepackets import PacketType, SpacePacketHeader from spacepackets.ccsds.spacepacket import SequenceFlags -from spacepackets.ecss import PusTc, PusTcDataFieldHeader, check_pus_crc, PusVersion -from spacepackets.ecss.tc import generate_crc, generate_packet_crc, InvalidTcCrc16 +from spacepackets.ecss import PusTc, PusTcDataFieldHeader, PusVersion, check_pus_crc +from spacepackets.ecss.tc import InvalidTcCrc16Error, generate_crc, generate_packet_crc class TestTelecommand(TestCase): @@ -66,9 +66,7 @@ def test_source_id(self): self.assertEqual(self.ping_tc.source_id, 12) def test_from_sph(self): - sp = SpacePacketHeader( - apid=0x02, packet_type=PacketType.TC, seq_count=0x34, data_len=0 - ) + sp = SpacePacketHeader(apid=0x02, packet_type=PacketType.TC, seq_count=0x34, data_len=0) ping_tc_from_sph = PusTc.from_sp_header(sp_header=sp, service=17, subservice=1) self.assertEqual(self.ping_tc, ping_tc_from_sph) @@ -126,7 +124,7 @@ def test_faulty_unpack(self): def test_invalid_crc(self): # Make CRC invalid self.ping_tc_raw[-1] = self.ping_tc_raw[-1] + 1 - with self.assertRaises(InvalidTcCrc16): + with self.assertRaises(InvalidTcCrc16Error): PusTc.unpack(data=self.ping_tc_raw) self.assertEqual(PusTcDataFieldHeader.get_header_size(), 5) diff --git a/tests/ecss/test_pus_tm.py b/tests/ecss/test_pus_tm.py index 7fa6a13..43d9d65 100755 --- a/tests/ecss/test_pus_tm.py +++ b/tests/ecss/test_pus_tm.py @@ -6,22 +6,23 @@ from spacepackets.ccsds.spacepacket import ( PacketId, - PacketType, PacketSeqCtrl, + PacketType, SequenceFlags, SpacePacketHeader, ) -from spacepackets.ecss import check_pus_crc, PusVersion -from spacepackets.util import PrintFormats, get_printable_data_string +from spacepackets.ecss import PusVersion, check_pus_crc +from spacepackets.ecss.pus_1_verification import ( + RequestId, +) from spacepackets.ecss.tm import ( - PusTm, CdsShortTimestamp, + InvalidTmCrc16Error, + PusTm, PusTmSecondaryHeader, - InvalidTmCrc16, -) -from spacepackets.ecss.pus_1_verification import ( - RequestId, ) +from spacepackets.util import PrintFormats, get_printable_data_string + from .common import TEST_STAMP @@ -40,15 +41,9 @@ def setUp(self) -> None: def test_state(self): self.assertEqual(self.ping_reply.sp_header, self.ping_reply.space_packet_header) src_data = self.ping_reply.source_data - self.assertEqual( - get_printable_data_string(PrintFormats.DEC, src_data), "dec []" - ) - self.assertEqual( - get_printable_data_string(PrintFormats.HEX, src_data), "hex []" - ) - self.assertEqual( - get_printable_data_string(PrintFormats.BIN, src_data), "bin []" - ) + self.assertEqual(get_printable_data_string(PrintFormats.DEC, src_data), "dec []") + self.assertEqual(get_printable_data_string(PrintFormats.HEX, src_data), "hex []") + self.assertEqual(get_printable_data_string(PrintFormats.BIN, src_data), "bin []") self.assertEqual(self.ping_reply.subservice, 2) self.assertEqual(self.ping_reply.service, 17) self.assertEqual(self.ping_reply.apid, 0x123) @@ -66,9 +61,9 @@ def test_no_timestamp(self): apid=0x123, seq_count=0x234, source_data=bytearray(), - timestamp=bytes(), + timestamp=b"", ) - self.assertEqual(self.ping_reply.pus_tm_sec_header.timestamp, bytes()) + self.assertEqual(self.ping_reply.pus_tm_sec_header.timestamp, b"") tm_raw = self.ping_reply.pack() self.assertEqual(self.ping_reply.packet_len, 15) self.assertEqual(len(tm_raw), 15) @@ -111,17 +106,13 @@ def test_state_setting(self): self.assertTrue(isinstance(self.ping_reply.crc16, bytes)) assert self.ping_reply.crc16 is not None self.assertEqual(len(self.ping_reply.crc16), 2) - self.assertEqual( - self.ping_reply.pus_tm_sec_header.pus_version, PusVersion.PUS_C - ) + self.assertEqual(self.ping_reply.pus_tm_sec_header.pus_version, PusVersion.PUS_C) self.assertEqual(self.ping_reply.tm_data, source_data) self.assertEqual(self.ping_reply.packet_id.raw(), 0x0822) self.assertEqual(self.ping_reply.packet_len, 24) def test_service_from_raw(self): - self.assertEqual( - PusTm.service_from_bytes(raw_bytearray=self.ping_reply_raw), 17 - ) + self.assertEqual(PusTm.service_from_bytes(raw_bytearray=self.ping_reply_raw), 17) def test_service_from_raw_invalid(self): self.assertRaises(ValueError, PusTm.service_from_bytes, bytearray()) @@ -129,9 +120,7 @@ def test_service_from_raw_invalid(self): def test_source_data_string_getters(self): source_data = bytearray([0x42, 0x38]) self.ping_reply.tm_data = source_data - self.assertEqual( - f"hex [{self.ping_reply.source_data.hex(sep=',')}]", "hex [42,38]" - ) + self.assertEqual(f"hex [{self.ping_reply.source_data.hex(sep=',')}]", "hex [42,38]") self.assertEqual( get_printable_data_string(PrintFormats.DEC, self.ping_reply.source_data), "dec [66,56]", @@ -157,9 +146,7 @@ def test_full_printout(self): raw_secondary_packet_header = self.ping_reply.pus_tm_sec_header.pack() second_header_as_str = raw_secondary_packet_header.hex(sep=",") assert crc16 is not None - expected_printout = ( - f"hex [{sp_header_as_str},{second_header_as_str},{crc16.hex(sep=',')}]" - ) + expected_printout = f"hex [{sp_header_as_str},{second_header_as_str},{crc16.hex(sep=',')}]" self.assertEqual( f"hex [{self.ping_reply.pack(recalc_crc=False).hex(sep=',')}]", expected_printout, @@ -179,16 +166,12 @@ def test_unpack(self): self.ping_reply.space_packet_header.apid = 0x22 self.ping_reply_raw = self.ping_reply.pack() # self.time_stamp_provider.read_from_raw = MagicMock() - pus_17_tm_unpacked = PusTm.unpack( - data=self.ping_reply_raw, timestamp_len=len(TEST_STAMP) - ) + pus_17_tm_unpacked = PusTm.unpack(data=self.ping_reply_raw, timestamp_len=len(TEST_STAMP)) self.assertEqual(self.ping_reply.crc16, pus_17_tm_unpacked.crc16) self.assertEqual(pus_17_tm_unpacked, self.ping_reply) self.assertEqual(pus_17_tm_unpacked.apid, 0x22) - self.assertEqual( - pus_17_tm_unpacked.pus_tm_sec_header.pus_version, PusVersion.PUS_C - ) + self.assertEqual(pus_17_tm_unpacked.pus_tm_sec_header.pus_version, PusVersion.PUS_C) self.assertEqual(pus_17_tm_unpacked.tm_data, source_data) self.assertEqual(pus_17_tm_unpacked.packet_id.raw(), 0x0822) @@ -219,7 +202,7 @@ def test_unpack(self): incorrect_size = correct_size + 1 self.ping_reply_raw[4] = (incorrect_size & 0xFF00) >> 8 self.ping_reply_raw[5] = incorrect_size & 0xFF - with self.assertRaises(InvalidTmCrc16): + with self.assertRaises(InvalidTmCrc16Error): PusTm.unpack(data=self.ping_reply_raw, timestamp_len=len(TEST_STAMP)) def test_calc_crc(self): @@ -245,9 +228,7 @@ def test_faulty_unpack(self): def test_invalid_sec_header_unpack(self): invalid_secondary_header = bytearray([0x20, 0x00, 0x01, 0x06]) - self.assertRaises( - ValueError, PusTmSecondaryHeader.unpack, invalid_secondary_header, None - ) + self.assertRaises(ValueError, PusTmSecondaryHeader.unpack, invalid_secondary_header, None) def test_sp_header_getter(self): sp_header = self.ping_reply.sp_header @@ -282,9 +263,7 @@ def test_invalid_raw_size(self): # Set length field invalid self.ping_reply_raw[4] = 0x00 self.ping_reply_raw[5] = 0x00 - self.assertRaises( - ValueError, PusTm.unpack, self.ping_reply_raw, len(TEST_STAMP) - ) + self.assertRaises(ValueError, PusTm.unpack, self.ping_reply_raw, len(TEST_STAMP)) def test_req_id(self): tc_packet_id = PacketId(ptype=PacketType.TC, sec_header_flag=True, apid=0x42) diff --git a/tests/ecss/test_srv1.py b/tests/ecss/test_srv1.py index 9e0e60f..4e2034a 100644 --- a/tests/ecss/test_srv1.py +++ b/tests/ecss/test_srv1.py @@ -1,25 +1,25 @@ from typing import Optional from unittest import TestCase -from spacepackets import SpacePacketHeader, PacketType +from spacepackets import PacketType, SpacePacketHeader from spacepackets.ccsds import CdsShortTimestamp -from spacepackets.ecss import PusTc, PacketFieldEnum, RequestId +from spacepackets.ecss import PacketFieldEnum, PusTc, RequestId from spacepackets.ecss.pus_1_verification import ( + ErrorCode, + FailureNotice, Service1Tm, - create_start_success_tm, - UnpackParams, + StepId, Subservice, - create_acceptance_success_tm, - create_step_success_tm, - create_completion_success_tm, + UnpackParams, VerificationParams, - FailureNotice, create_acceptance_failure_tm, + create_acceptance_success_tm, + create_completion_failure_tm, + create_completion_success_tm, create_start_failure_tm, + create_start_success_tm, create_step_failure_tm, - create_completion_failure_tm, - ErrorCode, - StepId, + create_step_success_tm, ) from tests.ecss.common import TEST_STAMP @@ -34,12 +34,10 @@ def setUp(self) -> None: def test_failure_notice_invalid_creation(self): with self.assertRaises(ValueError): - FailureNotice(ErrorCode(pfc=4, val=2), bytes()) + FailureNotice(ErrorCode(pfc=4, val=2), b"") def test_basic(self): - self.assertEqual( - self.srv1_tm.sp_header, self.srv1_tm.pus_tm.space_packet_header - ) + self.assertEqual(self.srv1_tm.sp_header, self.srv1_tm.pus_tm.space_packet_header) self.assertEqual(self.srv1_tm.timestamp, TEST_STAMP) self.assertEqual(self.srv1_tm.is_step_reply, False) self.assertEqual(self.srv1_tm.service, 1) @@ -106,9 +104,7 @@ def _generic_test_srv_1_success(self, subservice: Subservice): helper_created = create_start_success_tm(self.def_apid, pus_tc, TEST_STAMP) elif subservice == Subservice.TM_STEP_SUCCESS: step_id = PacketFieldEnum.with_byte_size(1, 4) - helper_created = create_step_success_tm( - self.def_apid, pus_tc, step_id, TEST_STAMP - ) + helper_created = create_step_success_tm(self.def_apid, pus_tc, step_id, TEST_STAMP) elif subservice == Subservice.TM_COMPLETION_SUCCESS: helper_created = create_completion_success_tm( self.def_apid, pus_tc, timestamp=TEST_STAMP @@ -152,15 +148,9 @@ def _test_srv_1_success_tm( self.assertEqual(srv_1_tm.tc_req_id.tc_packet_id, pus_tc.packet_id) self.assertEqual(srv_1_tm.tc_req_id.tc_psc, pus_tc.packet_seq_control) srv_1_tm_raw = srv_1_tm.pack() - srv_1_tm_unpacked = Service1Tm.unpack( - srv_1_tm_raw, UnpackParams(len(TEST_STAMP)) - ) - self.assertEqual( - srv_1_tm_unpacked.tc_req_id.tc_packet_id.raw(), pus_tc.packet_id.raw() - ) - self.assertEqual( - srv_1_tm_unpacked.tc_req_id.tc_psc.raw(), pus_tc.packet_seq_control.raw() - ) + srv_1_tm_unpacked = Service1Tm.unpack(srv_1_tm_raw, UnpackParams(len(TEST_STAMP))) + self.assertEqual(srv_1_tm_unpacked.tc_req_id.tc_packet_id.raw(), pus_tc.packet_id.raw()) + self.assertEqual(srv_1_tm_unpacked.tc_req_id.tc_psc.raw(), pus_tc.packet_seq_control.raw()) if step_id is not None and subservice == Subservice.TM_STEP_SUCCESS: self.assertEqual(srv_1_tm_unpacked.step_id, step_id) @@ -236,15 +226,9 @@ def _test_srv_1_failure_comparison_helper( unpack_params.bytes_step_id = step_id.len() srv_1_tm_unpacked = Service1Tm.unpack(srv_1_tm_raw, unpack_params) self.assertEqual(srv_1_tm_unpacked.error_code.val, failure_notice.code.val) - self.assertEqual( - srv_1_tm_unpacked.tc_req_id.tc_packet_id.raw(), pus_tc.packet_id.raw() - ) - self.assertEqual( - srv_1_tm_unpacked.tc_req_id.tc_psc.raw(), pus_tc.packet_seq_control.raw() - ) + self.assertEqual(srv_1_tm_unpacked.tc_req_id.tc_packet_id.raw(), pus_tc.packet_id.raw()) + self.assertEqual(srv_1_tm_unpacked.tc_req_id.tc_psc.raw(), pus_tc.packet_seq_control.raw()) if failure_notice is not None: - self.assertEqual( - srv_1_tm_unpacked.failure_notice.pack(), failure_notice.pack() - ) + self.assertEqual(srv_1_tm_unpacked.failure_notice.pack(), failure_notice.pack()) if step_id is not None: self.assertEqual(srv_1_tm_unpacked.step_id.pack(), step_id.pack()) diff --git a/tests/ecss/test_srv17.py b/tests/ecss/test_srv17.py index a6ca240..887ae2d 100644 --- a/tests/ecss/test_srv17.py +++ b/tests/ecss/test_srv17.py @@ -4,29 +4,28 @@ from spacepackets.ccsds.spacepacket import PacketType, SequenceFlags from spacepackets.ecss import PusService from spacepackets.ecss.pus_17_test import Service17Tm -from .common import generic_time_provider_mock, TEST_STAMP + +from .common import TEST_STAMP, generic_time_provider_mock class TestSrv17Tm(TestCase): def setUp(self) -> None: self.def_apid = 0x05 - self.srv17_tm = Service17Tm(apid=self.def_apid, subservice=1, timestamp=bytes()) + self.srv17_tm = Service17Tm(apid=self.def_apid, subservice=1, timestamp=b"") self.srv17_tm.pus_tm.apid = 0x72 self.time_stamp_provider = generic_time_provider_mock(TEST_STAMP) def test_state(self): - self.assertEqual( - self.srv17_tm.sp_header, self.srv17_tm.pus_tm.space_packet_header - ) + self.assertEqual(self.srv17_tm.sp_header, self.srv17_tm.pus_tm.space_packet_header) self.assertEqual(self.srv17_tm.service, PusService.S17_TEST) self.assertEqual(self.srv17_tm.subservice, 1) - self.assertEqual(self.srv17_tm.timestamp, bytes()) + self.assertEqual(self.srv17_tm.timestamp, b"") self.assertEqual(self.srv17_tm.apid, 0x72) self.assertEqual(self.srv17_tm.seq_count, 0) self.assertEqual(self.srv17_tm.seq_flags, SequenceFlags.UNSEGMENTED) self.assertEqual(self.srv17_tm.packet_type, PacketType.TM) self.assertTrue(self.srv17_tm.sec_header_flag) - self.assertEqual(self.srv17_tm.source_data, bytes()) + self.assertEqual(self.srv17_tm.source_data, b"") def test_other_state(self): srv17_with_data = Service17Tm( @@ -45,7 +44,5 @@ def test_service_17_tm(self): srv_17_tm = Service17Tm(apid=self.def_apid, subservice=2, timestamp=TEST_STAMP) self.assertEqual(srv_17_tm.pus_tm.subservice, 2) srv_17_tm_raw = srv_17_tm.pack() - srv_17_tm_unpacked = Service17Tm.unpack( - data=srv_17_tm_raw, timestamp_len=len(TEST_STAMP) - ) + srv_17_tm_unpacked = Service17Tm.unpack(data=srv_17_tm_raw, timestamp_len=len(TEST_STAMP)) self.assertEqual(srv_17_tm_unpacked.pus_tm.subservice, 2) diff --git a/tests/test_countdown.py b/tests/test_countdown.py index 983637c..cb58403 100644 --- a/tests/test_countdown.py +++ b/tests/test_countdown.py @@ -1,6 +1,7 @@ import time from datetime import timedelta from unittest import TestCase + from spacepackets.countdown import Countdown @@ -14,9 +15,7 @@ def test_basic(self): self.assertTrue(test_cd.timed_out()) self.assertTrue(test_cd.remaining_time() == timedelta()) test_cd.timeout = timedelta(seconds=0.1) - self.assertEqual( - test_cd.timeout.total_seconds(), timedelta(seconds=0.1).total_seconds() - ) + self.assertEqual(test_cd.timeout.total_seconds(), timedelta(seconds=0.1).total_seconds()) self.assertEqual(test_cd.timeout_ms, 100) self.assertTrue(test_cd.busy()) self.assertFalse(test_cd.timed_out()) diff --git a/tests/test_misc.py b/tests/test_misc.py index 0696403..07645c5 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1,4 +1,5 @@ from unittest import TestCase + from spacepackets import get_lib_logger diff --git a/tests/test_pus_verificator.py b/tests/test_pus_verificator.py index a868885..bbae660 100644 --- a/tests/test_pus_verificator.py +++ b/tests/test_pus_verificator.py @@ -1,21 +1,20 @@ -from typing import Optional, List from unittest import TestCase from spacepackets.ccsds import CdsShortTimestamp from spacepackets.ecss import PusTc from spacepackets.ecss.pus_1_verification import ( - create_acceptance_success_tm, + ErrorCode, + FailureNotice, RequestId, - create_start_success_tm, - create_step_success_tm, StepId, - create_completion_success_tm, - FailureNotice, create_acceptance_failure_tm, + create_acceptance_success_tm, + create_completion_failure_tm, + create_completion_success_tm, create_start_failure_tm, + create_start_success_tm, create_step_failure_tm, - create_completion_failure_tm, - ErrorCode, + create_step_success_tm, ) from spacepackets.ecss.pus_verificator import ( PusVerificator, @@ -29,9 +28,7 @@ def __init__(self, apid: int, pus_tc: PusTc): self.pus_tc = pus_tc self.req_id = RequestId.from_pus_tc(pus_tc) self.empty_stamp = CdsShortTimestamp.empty() - self.acc_suc_tm = create_acceptance_success_tm( - apid, pus_tc, self.empty_stamp.pack() - ) + self.acc_suc_tm = create_acceptance_success_tm(apid, pus_tc, self.empty_stamp.pack()) self.sta_suc_tm = create_start_success_tm(apid, pus_tc, self.empty_stamp.pack()) self.ste_suc_tm = create_step_success_tm( apid=apid, @@ -39,9 +36,7 @@ def __init__(self, apid: int, pus_tc: PusTc): step_id=StepId.with_byte_size(1, 1), timestamp=self.empty_stamp.pack(), ) - self.fin_suc_tm = create_completion_success_tm( - apid, pus_tc, self.empty_stamp.pack() - ) + self.fin_suc_tm = create_completion_success_tm(apid, pus_tc, self.empty_stamp.pack()) class FailureSet: @@ -83,9 +78,7 @@ def setUp(self) -> None: self.pus_verificator = PusVerificator() def test_basic(self): - suc_set = SuccessSet( - self.def_apid, PusTc(apid=self.def_apid, service=17, subservice=1) - ) + suc_set = SuccessSet(self.def_apid, PusTc(apid=self.def_apid, service=17, subservice=1)) self.pus_verificator.add_tc(suc_set.pus_tc) check_res = self.pus_verificator.add_tm(suc_set.acc_suc_tm) self.assertEqual(check_res.completed, False) @@ -115,9 +108,7 @@ def test_basic(self): def test_complete_verification_clear_completed(self): self._regular_success_seq( - SuccessSet( - self.def_apid, PusTc(apid=self.def_apid, service=17, subservice=1) - ), + SuccessSet(self.def_apid, PusTc(apid=self.def_apid, service=17, subservice=1)), ) self.pus_verificator.remove_completed_entries() self.assertEqual(len(self.pus_verificator.verif_dict), 0) @@ -139,9 +130,7 @@ def test_complete_verification_clear_completed_multi(self): self.assertEqual(len(self.pus_verificator.verif_dict), 0) def test_complete_verification_remove_manually(self): - suc_set = SuccessSet( - self.def_apid, PusTc(apid=self.def_apid, service=17, subservice=1) - ) + suc_set = SuccessSet(self.def_apid, PusTc(apid=self.def_apid, service=17, subservice=1)) self._regular_success_seq(suc_set) self.assertTrue(self.pus_verificator.remove_entry(suc_set.req_id)) self.assertEqual(len(self.pus_verificator.verif_dict), 0) @@ -281,12 +270,12 @@ def _regular_success_seq(self, suc_set: SuccessSet): def _check_status( self, - status: Optional[VerificationStatus], + status: VerificationStatus | None, all_verifs: bool, acc_st: StatusField, sta_st: StatusField, step_st: StatusField, - step_list: List[int], + step_list: list[int], fin_st: StatusField, ): self.assertIsNotNone(status) diff --git a/tests/test_seq_cnt_provider.py b/tests/test_seq_cnt_provider.py index 6f39bd8..d52554b 100644 --- a/tests/test_seq_cnt_provider.py +++ b/tests/test_seq_cnt_provider.py @@ -1,10 +1,10 @@ import os -from pathlib import Path import platform +from pathlib import Path +from tempfile import NamedTemporaryFile from unittest import TestCase from spacepackets.seqcount import CcsdsFileSeqCountProvider -from tempfile import NamedTemporaryFile class TestSeqCount(TestCase): @@ -34,7 +34,6 @@ def test_with_real_file(self): self.assertTrue(self.file_name.exists()) self.assertEqual(seq_cnt_provider.current(), 0) self.assertEqual(next(seq_cnt_provider), 0) - pass def test_file_deleted_runtime(self): seq_cnt_provider = CcsdsFileSeqCountProvider(self.file_name) diff --git a/tests/test_uslp.py b/tests/test_uslp.py index da3e521..34f2ff7 100644 --- a/tests/test_uslp.py +++ b/tests/test_uslp.py @@ -1,33 +1,32 @@ from unittest import TestCase from spacepackets.uslp.defs import ( - UslpFhpVhopFieldMissing, - UslpInvalidConstructionRules, - UslpInvalidFrameHeader, - UslpTruncatedFrameNotAllowed, + UslpFhpVhopFieldMissingError, + UslpInvalidConstructionRulesError, + UslpInvalidFrameHeaderError, + UslpTruncatedFrameNotAllowedError, ) -from spacepackets.uslp.header import ( - TruncatedPrimaryHeader, - PrimaryHeader, - SourceOrDestField, - ProtocolCommandFlag, - BypassSequenceControlFlag, - determine_header_type, - HeaderType, - UslpTypeMissmatch, - UslpInvalidRawPacketOrFrameLen, - UslpVersionMissmatch, -) - from spacepackets.uslp.frame import ( + FixedFrameProperties, + FrameType, + TfdzConstructionRules, TransferFrame, TransferFrameDataField, - TfdzConstructionRules, UslpProtocolIdentifier, - FrameType, - FixedFrameProperties, VarFrameProperties, ) +from spacepackets.uslp.header import ( + BypassSequenceControlFlag, + HeaderType, + PrimaryHeader, + ProtocolCommandFlag, + SourceOrDestField, + TruncatedPrimaryHeader, + UslpInvalidRawPacketOrFrameLenError, + UslpTypeMissmatchError, + UslpVersionMissmatchError, + determine_header_type, +) class TestUslp(TestCase): @@ -138,21 +137,19 @@ def test_header(self): unpacked_primary_header = PrimaryHeader.unpack(raw_packet=packed_header) # Check field validity by serializing unpacked header again self.assertEqual(packed_header, unpacked_primary_header.pack()) + self.assertRaises(UslpTypeMissmatchError, TruncatedPrimaryHeader.unpack, packed_header) self.assertRaises( - UslpTypeMissmatch, TruncatedPrimaryHeader.unpack, packed_header - ) - self.assertRaises( - UslpInvalidRawPacketOrFrameLen, TruncatedPrimaryHeader.unpack, bytearray() + UslpInvalidRawPacketOrFrameLenError, TruncatedPrimaryHeader.unpack, bytearray() ) self.assertRaises( - UslpInvalidRawPacketOrFrameLen, + UslpInvalidRawPacketOrFrameLenError, PrimaryHeader.unpack, header_with_vcf_count[0:7], ) crap_with_valid_parsing_fields = bytearray(5) crap_with_valid_parsing_fields[0] = 0b11000000 self.assertRaises( - UslpInvalidRawPacketOrFrameLen, + UslpInvalidRawPacketOrFrameLenError, PrimaryHeader.unpack, crap_with_valid_parsing_fields, ) @@ -160,7 +157,7 @@ def test_header(self): crap_with_valid_parsing_fields[0] = 0b0001000 crap_with_valid_parsing_fields.extend(bytearray(3)) self.assertRaises( - UslpVersionMissmatch, + UslpVersionMissmatchError, PrimaryHeader.unpack, crap_with_valid_parsing_fields, ) @@ -237,32 +234,24 @@ def test_frame(self): frame_packed = transfer_frame.pack(truncated=False, frame_type=FrameType.FIXED) # 7 byte primary header + TFDF with 3 bytes, TFDZ is empty self.assertEqual(len(frame_packed), 10) - self.assertEqual( - (frame_packed[4] << 8) | frame_packed[5], len(frame_packed) - 1 - ) + self.assertEqual((frame_packed[4] << 8) | frame_packed[5], len(frame_packed) - 1) # The primary header was already unit-tested, its fields won't be checked again self.assertEqual(frame_packed[7], 0x00) self.assertEqual(frame_packed[8], 0x00) self.assertEqual(frame_packed[9], 0x00) - transfer_frame.tfdf.tfdz_contr_rules = ( - TfdzConstructionRules.FpFixedStartOfMapaSDU - ) + transfer_frame.tfdf.tfdz_contr_rules = TfdzConstructionRules.FpFixedStartOfMapaSDU transfer_frame.tfdf.uslp_ident = UslpProtocolIdentifier.IDLE_DATA transfer_frame.tfdf.fhp_or_lvop = 0xAFFE frame_packed = transfer_frame.pack() self.assertEqual(len(frame_packed), 10) - self.assertEqual( - (frame_packed[4] << 8) | frame_packed[5], len(frame_packed) - 1 - ) + self.assertEqual((frame_packed[4] << 8) | frame_packed[5], len(frame_packed) - 1) # TFDZ construction rule is 0b001, USLP identifier is 0b11111, concatenation is 0x3f self.assertEqual(frame_packed[7], 0x3F) # This pointer does not really make sense for an empty TFDZ, but we just check that is was # still set correctly self.assertEqual(frame_packed[8], 0xAF) self.assertEqual(frame_packed[9], 0xFE) - frame_properties = FixedFrameProperties( - has_insert_zone=False, has_fecf=False, fixed_len=10 - ) + frame_properties = FixedFrameProperties(has_insert_zone=False, has_fecf=False, fixed_len=10) frame_unpacked = TransferFrame.unpack( raw_frame=frame_packed, frame_type=FrameType.FIXED, @@ -271,9 +260,7 @@ def test_frame(self): self.assertEqual(frame_unpacked.insert_zone, None) self.assertEqual(frame_unpacked.fecf, None) self.assertEqual(frame_unpacked.op_ctrl_field, None) - self.assertEqual( - frame_unpacked.tfdf.uslp_ident, UslpProtocolIdentifier.IDLE_DATA - ) + self.assertEqual(frame_unpacked.tfdf.uslp_ident, UslpProtocolIdentifier.IDLE_DATA) self.assertEqual( frame_unpacked.tfdf.tfdz_contr_rules, TfdzConstructionRules.FpFixedStartOfMapaSDU, @@ -294,9 +281,7 @@ def test_frame(self): fhp_or_lvop=0, ) self.assertEqual(fp_tfdf.verify_frame_type(frame_type=FrameType.FIXED), True) - self.assertEqual( - fp_tfdf.verify_frame_type(frame_type=FrameType.VARIABLE), False - ) + self.assertEqual(fp_tfdf.verify_frame_type(frame_type=FrameType.VARIABLE), False) vp_tfdf = TransferFrameDataField( tfdz_cnstr_rules=TfdzConstructionRules.VpNoSegmentation, uslp_ident=UslpProtocolIdentifier.SPACE_PACKETS_ENCAPSULATION_PACKETS, @@ -304,15 +289,11 @@ def test_frame(self): ) self.assertEqual(vp_tfdf.verify_frame_type(frame_type=FrameType.VARIABLE), True) self.assertEqual( - vp_tfdf.should_have_fhp_or_lvp_field( - truncated=False, frame_type=FrameType.VARIABLE - ), + vp_tfdf.should_have_fhp_or_lvp_field(truncated=False, frame_type=FrameType.VARIABLE), False, ) self.assertEqual( - fp_tfdf.should_have_fhp_or_lvp_field( - truncated=False, frame_type=FrameType.FIXED - ), + fp_tfdf.should_have_fhp_or_lvp_field(truncated=False, frame_type=FrameType.FIXED), True, ) empty_short_tfdf = TransferFrameDataField( @@ -321,9 +302,7 @@ def test_frame(self): fhp_or_lvop=0, tfdz=bytearray(), ) - packed_short_tfdf = empty_short_tfdf.pack( - truncated=False, frame_type=FrameType.FIXED - ) + packed_short_tfdf = empty_short_tfdf.pack(truncated=False, frame_type=FrameType.FIXED) self.assertEqual(len(packed_short_tfdf), 3) TransferFrameDataField.unpack( raw_tfdf=packed_short_tfdf, @@ -338,20 +317,20 @@ def test_frame(self): tfdz=bytearray(), ) tfdf_vp_packed = tfdf_vp.pack() - with self.assertRaises(UslpFhpVhopFieldMissing): + with self.assertRaises(UslpFhpVhopFieldMissingError): TransferFrameDataField( tfdz_cnstr_rules=TfdzConstructionRules.FpFixedStartOfMapaSDU, uslp_ident=UslpProtocolIdentifier.SPACE_PACKETS_ENCAPSULATION_PACKETS, tfdz=bytearray(), ).pack() - with self.assertRaises(UslpInvalidRawPacketOrFrameLen): + with self.assertRaises(UslpInvalidRawPacketOrFrameLenError): TransferFrameDataField.unpack( raw_tfdf=bytearray(), truncated=False, exact_len=0, frame_type=FrameType.FIXED, ) - with self.assertRaises(UslpInvalidConstructionRules): + with self.assertRaises(UslpInvalidConstructionRulesError): short_tfdf = empty_short_tfdf.pack() short_tfdf[0] &= ~0b11100000 short_tfdf[0] |= TfdzConstructionRules.VpNoSegmentation << 5 @@ -372,9 +351,7 @@ def test_frame(self): tfdf_vp_unpacked.uslp_ident, UslpProtocolIdentifier.SPACE_PACKETS_ENCAPSULATION_PACKETS, ) - self.assertEqual( - tfdf_vp_unpacked.tfdz_contr_rules, TfdzConstructionRules.VpLastSegment - ) + self.assertEqual(tfdf_vp_unpacked.tfdz_contr_rules, TfdzConstructionRules.VpLastSegment) primary_header = PrimaryHeader( scid=0x10, map_id=0b0011, @@ -411,7 +388,7 @@ def test_frame(self): self.assertEqual(larger_frame_packed[14 : 14 + 4], bytearray([1, 2, 3, 4])) self.assertEqual(larger_frame_packed[18 : 18 + 4], bytearray([1, 2, 3, 4])) self.assertEqual(larger_frame_packed[22:], bytearray([3, 4])) - with self.assertRaises(UslpInvalidRawPacketOrFrameLen): + with self.assertRaises(UslpInvalidRawPacketOrFrameLenError): TransferFrame.unpack( raw_frame=larger_frame_packed, frame_type=FrameType.FIXED, @@ -423,7 +400,7 @@ def test_frame(self): fecf_len=2, ), ) - with self.assertRaises(UslpInvalidRawPacketOrFrameLen): + with self.assertRaises(UslpInvalidRawPacketOrFrameLenError): TransferFrame.unpack( raw_frame=larger_frame_packed, frame_type=FrameType.FIXED, @@ -448,11 +425,11 @@ def test_frame(self): ), ) larger_frame.header.op_ctrl_flag = False - with self.assertRaises(UslpInvalidFrameHeader): + with self.assertRaises(UslpInvalidFrameHeaderError): larger_frame.pack() larger_frame.header.op_ctrl_flag = True larger_frame.op_ctrl_field = None - with self.assertRaises(UslpInvalidFrameHeader): + with self.assertRaises(UslpInvalidFrameHeaderError): larger_frame.pack() larger_frame.header.op_ctrl_flag = True # Invalid length @@ -473,7 +450,7 @@ def test_frame(self): self.assertEqual(larger_frame_unpacked.fecf, bytearray([3, 4])) self.assertEqual(larger_frame_unpacked.insert_zone, bytearray(4)) self.assertEqual(larger_frame_unpacked.op_ctrl_field, bytearray([1, 2, 3, 4])) - with self.assertRaises(UslpInvalidRawPacketOrFrameLen): + with self.assertRaises(UslpInvalidRawPacketOrFrameLenError): TransferFrame.unpack( raw_frame=bytearray(3), frame_type=FrameType.FIXED, @@ -502,7 +479,7 @@ def test_frame(self): ) truncated_frame_packed = truncated_frame.pack(truncated=True) self.assertEqual(len(truncated_frame_packed), 9) - with self.assertRaises(UslpTruncatedFrameNotAllowed): + with self.assertRaises(UslpTruncatedFrameNotAllowedError): TransferFrame.unpack( raw_frame=truncated_frame_packed, frame_type=FrameType.FIXED, diff --git a/tests/test_util.py b/tests/test_util.py index 0c5740f..b919d93 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -7,8 +7,8 @@ ByteFieldU16, ByteFieldU32, ByteFieldU64, - UnsignedByteField, IntByteConversion, + UnsignedByteField, ) @@ -65,13 +65,11 @@ def test_one_byte_invalid_gen(self): ) with self.assertRaises(ValueError) as cm: ByteFieldGenerator.from_int(byte_len=1, val=-1) - self.assertEqual( - str(cm.exception), "Passed value -1 larger than allowed 255 or negative" - ) + self.assertEqual(str(cm.exception), "Passed value -1 larger than allowed 255 or negative") def test_byte_field_u8_invalid_unpack(self): with self.assertRaises(ValueError): - ByteFieldU8.from_u8_bytes(bytes()) + ByteFieldU8.from_u8_bytes(b"") def test_byte_field_u16_invalid_unpack(self): with self.assertRaises(ValueError): @@ -117,7 +115,7 @@ def test_setting_from_raw(self): self.assertEqual(int(one_byte_test), 0x22) self.assertEqual(one_byte_test.as_bytes, bytes([0x22])) with self.assertRaises(ValueError): - one_byte_test.value = bytes() + one_byte_test.value = b"" def invalid_byte_field_len(self): with self.assertRaises(ValueError):