Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

extract matter testing utilities to separate module #37309

Merged
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
998c3cc
extract utilities to separate module and mark them in original module…
asirko-soft Jan 29, 2025
54bbb3c
update build file to include utilities
asirko-soft Jan 29, 2025
5e486da
Use UserWarning instead of DeprecationWarning; Add type hint decorato…
asirko-soft Jan 29, 2025
ffb910b
lint code
asirko-soft Jan 29, 2025
95ffa2b
Merge branch 'master' into osirko_api_cleanup_extract-utilities
asirko-soft Jan 30, 2025
7b9c6a6
Merge branch 'master' into osirko_api_cleanup_extract-utilities
asirko-soft Jan 30, 2025
bf7f0db
fix incorrect signatures and return values
asirko-soft Jan 30, 2025
5276e70
adding missing alias and docstrings to utility methods
asirko-soft Jan 30, 2025
39cf68e
fix alias issue
asirko-soft Jan 30, 2025
1bd9b00
just update all the places where moved functiones are used
asirko-soft Jan 31, 2025
12e836b
remove commented out code
asirko-soft Jan 31, 2025
5a1a4fe
using direct aliases as requested in review
asirko-soft Feb 3, 2025
a816491
solit utilities to less general modules
asirko-soft Feb 6, 2025
86a464a
isort
asirko-soft Feb 6, 2025
1480b6e
rename types.py to matchers.py
asirko-soft Feb 6, 2025
7505489
rename type_matches to is_type
asirko-soft Feb 6, 2025
e093a0b
added docstrings and copyright to packages
asirko-soft Feb 6, 2025
5fdbc21
style fix
asirko-soft Feb 6, 2025
bbb911a
isort
asirko-soft Feb 6, 2025
6384035
point test_testing imports to original module for now
asirko-soft Feb 7, 2025
025cc48
add doctest for new modules
asirko-soft Feb 7, 2025
d8fb318
Merge branch 'master' into osirko_api_cleanup_extract-utilities
asirko-soft Feb 7, 2025
e258cde
Merge branch 'master' into osirko_api_cleanup_extract-utilities
asirko-soft Feb 7, 2025
b29c46a
this should fix build error, doctests will run when the module is imp…
asirko-soft Feb 7, 2025
c4c38e5
Merge remote-tracking branch 'upstream/master' into osirko_api_cleanu…
asirko-soft Feb 10, 2025
3b9525d
import modules as modules only; add ToDo to remove aliases in future
asirko-soft Feb 12, 2025
957957a
fix imports
asirko-soft Feb 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/python_testing/matter_testing_infrastructure/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pw_python_package("chip-testing-module") {
"chip/testing/spec_parsing.py",
"chip/testing/taglist_and_topology_test.py",
"chip/testing/tasks.py",
"chip/testing/utilities.py",
]
tests = [
"chip/testing/test_metadata.py",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,27 @@
import time
import typing
import uuid
from binascii import hexlify, unhexlify
import warnings
from binascii import unhexlify
from dataclasses import asdict as dataclass_asdict
from dataclasses import dataclass, field
from datetime import datetime, timedelta, timezone
from enum import Enum, IntFlag
from functools import partial
from functools import partial, wraps
from itertools import chain
from typing import Any, Iterable, List, Optional, Tuple

from chip.tlv import float32, uint
from typing import Any, Callable, Iterable, List, Optional, Tuple

from chip.testing.utilities import bytes_from_hex as new_bytes_from_hex
from chip.testing.utilities import cluster_id_str as new_cluster_id_str
from chip.testing.utilities import compare_time as new_compare_time
from chip.testing.utilities import get_wait_seconds_from_set_time as new_get_wait_seconds_from_set_time
from chip.testing.utilities import hex_from_bytes as new_hex_from_bytes
from chip.testing.utilities import id_str as new_id_str
from chip.testing.utilities import type_matches as new_type_matches
from chip.testing.utilities import utc_datetime_from_matter_epoch_us as new_utc_datetime_from_matter_epoch_us
from chip.testing.utilities import utc_datetime_from_posix_time_ms as new_utc_datetime_from_posix_time_ms
from chip.testing.utilities import utc_time_in_matter_epoch as new_utc_time_in_matter_epoch
from chip.tlv import uint

# isort: off

Expand Down Expand Up @@ -94,6 +105,23 @@ class TestRunnerHooks:
_DEFAULT_DUT_NODE_ID = 0x12344321
_DEFAULT_TRUST_ROOT_INDEX = 1

# Deprecation wrappers


def _deprecated(module_name: str) -> Callable[[Callable], Callable]:
def decorator(func: Callable) -> Callable:
@wraps(func)
def wrapper(*args, **kwargs):
warnings.warn(
f"{func.__name__} is deprecated; import from {module_name} instead.",
UserWarning,
stacklevel=2
)
return func(*args, **kwargs)
return wrapper
return decorator


# Mobly cannot deal with user config passing of ctypes objects,
# so we use this dict of uuid -> object to recover items stashed
# by reference.
Expand Down Expand Up @@ -149,76 +177,46 @@ def get_default_paa_trust_store(root_path: pathlib.Path) -> pathlib.Path:
return pathlib.Path.cwd()


@_deprecated("utilities")
def type_matches(received_value, desired_type):
""" Checks if the value received matches the expected type.

Handles unpacking Nullable and Optional types and
compares list value types for non-empty lists.
"""
if typing.get_origin(desired_type) == typing.Union:
return any(type_matches(received_value, t) for t in typing.get_args(desired_type))
elif typing.get_origin(desired_type) == list:
if isinstance(received_value, list):
# Assume an empty list is of the correct type
return True if received_value == [] else any(type_matches(received_value[0], t) for t in typing.get_args(desired_type))
else:
return False
elif desired_type == uint:
return isinstance(received_value, int) and received_value >= 0
elif desired_type == float32:
return isinstance(received_value, float)
else:
return isinstance(received_value, desired_type)

# TODO(#31177): Need to add unit tests for all time conversion methods.
"""DEPRECATED: Use utilities.type_matches instead"""
return new_type_matches(received_value, desired_type)


@_deprecated("utilities")
def utc_time_in_matter_epoch(desired_datetime: Optional[datetime] = None):
""" Returns the time in matter epoch in us.
"""DEPRECATED: Use utilities.utc_time_in_matter_epoch instead"""
return new_utc_time_in_matter_epoch(desired_datetime)

If desired_datetime is None, it will return the current time.
"""
if desired_datetime is None:
utc_native = datetime.now(tz=timezone.utc)
else:
utc_native = desired_datetime
# Matter epoch is 0 hours, 0 minutes, 0 seconds on Jan 1, 2000 UTC
utc_th_delta = utc_native - datetime(2000, 1, 1, 0, 0, 0, 0, timezone.utc)
utc_th_us = int(utc_th_delta.total_seconds() * 1000000)
return utc_th_us


matter_epoch_us_from_utc_datetime = utc_time_in_matter_epoch
@_deprecated("utilities")
def matter_epoch_us_from_utc_datetime(desired_datetime: Optional[datetime] = None):
"""DEPRECATED: Use utilities.utc_datetime_from_matter_epoch_us instead"""
return new_utc_time_in_matter_epoch(desired_datetime)


@_deprecated("utilities")
def utc_datetime_from_matter_epoch_us(matter_epoch_us: int) -> datetime:
"""Returns the given Matter epoch time as a usable Python datetime in UTC."""
delta_from_epoch = timedelta(microseconds=matter_epoch_us)
matter_epoch = datetime(2000, 1, 1, 0, 0, 0, 0, timezone.utc)

return matter_epoch + delta_from_epoch
"""DEPRECATED: Use utilities.utc_datetime_from_matter_epoch_us instead"""
return new_utc_datetime_from_matter_epoch_us(matter_epoch_us)


@_deprecated("utilities")
def utc_datetime_from_posix_time_ms(posix_time_ms: int) -> datetime:
millis = posix_time_ms % 1000
seconds = posix_time_ms // 1000
return datetime.fromtimestamp(seconds, timezone.utc) + timedelta(milliseconds=millis)
"""DEPRECATED: Use utilities.utc_datetime_from_posix_time_ms instead"""
return new_utc_datetime_from_posix_time_ms(posix_time_ms)


@_deprecated("utilities")
def compare_time(received: int, offset: timedelta = timedelta(), utc: Optional[int] = None, tolerance: timedelta = timedelta(seconds=5)) -> None:
if utc is None:
utc = utc_time_in_matter_epoch()

# total seconds includes fractional for microseconds
expected = utc + offset.total_seconds() * 1000000
delta_us = abs(expected - received)
delta = timedelta(microseconds=delta_us)
asserts.assert_less_equal(delta, tolerance, "Received time is out of tolerance")
"""DEPRECATED: Use utilities.compare_time instead"""
return new_compare_time(received, offset, utc, tolerance)


@_deprecated("utilities")
def get_wait_seconds_from_set_time(set_time_matter_us: int, wait_seconds: int):
seconds_passed = (utc_time_in_matter_epoch() - set_time_matter_us) // 1000000
return wait_seconds - seconds_passed
"""DEPRECATED: Use utilities.get_wait_seconds_from_set_time instead"""
return new_get_wait_seconds_from_set_time(set_time_matter_us, wait_seconds)


class SimpleEventCallback:
Expand Down Expand Up @@ -708,19 +706,16 @@ def get_attribute_string(self, cluster_id: int, attribute_id) -> str:
return f"Attribute {attribute_name} ({attribute_id}, 0x{attribute_id:04X})"


@_deprecated("utilities")
def id_str(id):
return f'{id} (0x{id:02x})'
"""DEPRECATED: Use utilities.id_str instead"""
return new_id_str(id)


@_deprecated("utilities")
def cluster_id_str(id):
if id in Clusters.ClusterObjects.ALL_CLUSTERS.keys():
s = Clusters.ClusterObjects.ALL_CLUSTERS[id].__name__
else:
s = "Unknown cluster"
try:
return f'{id_str(id)} {s}'
except TypeError:
return 'HERE IS THE PROBLEM'
"""DEPRECATED: Use utilities.cluster_id_str instead"""
return new_cluster_id_str(id)


@dataclass
Expand Down Expand Up @@ -930,17 +925,16 @@ def stack(self) -> ChipStack:
return builtins.chipStack


@_deprecated("utilities")
def bytes_from_hex(hex: str) -> bytes:
"""Converts any `hex` string representation including `01:ab:cd` to bytes

Handles any whitespace including newlines, which are all stripped.
"""
return unhexlify("".join(hex.replace(":", "").replace(" ", "").split()))
"""DEPRECATED: Use utilities.bytes_from_hex instead"""
return new_bytes_from_hex(hex)


@_deprecated("utilities")
def hex_from_bytes(b: bytes) -> str:
"""Converts a bytes object `b` into a hex string (reverse of bytes_from_hex)"""
return hexlify(b).decode("utf-8")
"""DEPRECATED: Use utilities.hex_from_bytes instead"""
return new_hex_from_bytes(b)


@dataclass
Expand Down
Loading
Loading