Skip to content

Commit 88b801f

Browse files
authored
mypy compliance for basic_composition.py (project-chip#38564)
* mypy compliance for basic composition * review comments
1 parent f4efee0 commit 88b801f

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

.github/workflows/mypy-validation.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ jobs:
5757
src/python_testing/matter_testing_infrastructure/chip/testing/apps.py \
5858
src/python_testing/matter_testing_infrastructure/chip/testing/tasks.py \
5959
src/python_testing/matter_testing_infrastructure/chip/testing/taglist_and_topology_test.py \
60-
src/python_testing/matter_testing_infrastructure/chip/testing/pics.py"
60+
src/python_testing/matter_testing_infrastructure/chip/testing/pics.py \
61+
src/python_testing/matter_testing_infrastructure/chip/testing/basic_composition.py"
6162
6263
# Print a reminder about expanding coverage
6364
echo "⚠️ NOTE: Currently only checking a subset of files. Remember to expand coverage!"

src/python_testing/matter_testing_infrastructure/chip/testing/basic_composition.py

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@
3030
import chip.clusters as Clusters
3131
import chip.clusters.ClusterObjects
3232
import chip.tlv
33+
from chip.ChipDeviceCtrl import ChipDeviceController
3334
from chip.clusters.Attribute import ValueDecodeFailure
3435
from chip.testing.conformance import ConformanceException
36+
from chip.testing.matter_testing import MatterTestConfig, ProblemNotice
3537
from chip.testing.spec_parsing import PrebuiltDataModelDirectory, build_xml_clusters, build_xml_device_types, dm_from_spec_version
3638
from mobly import asserts
3739

@@ -125,6 +127,18 @@ def ConvertValue(value) -> Any:
125127

126128

127129
class BasicCompositionTests:
130+
# These attributes are initialized/provided by the inheriting test class (MatterBaseTest)
131+
# or its setup process. Providing type hints here for mypy.
132+
default_controller: ChipDeviceController
133+
matter_test_config: MatterTestConfig
134+
user_params: dict[str, Any]
135+
dut_node_id: int
136+
problems: list[ProblemNotice]
137+
endpoints: dict[int, Any] # Wildcard read result
138+
endpoints_tlv: dict[int, Any] # Wildcard read result (raw TLV)
139+
xml_clusters: dict[int, Any]
140+
xml_device_types: dict[int, Any]
141+
128142
def get_code(self, dev_ctrl):
129143
created_codes = []
130144
for idx, discriminator in enumerate(self.matter_test_config.discriminators):
@@ -154,7 +168,7 @@ def dump_wildcard(self, dump_device_composition_path: typing.Optional[str]) -> t
154168

155169
async def setup_class_helper(self, allow_pase: bool = True):
156170
dev_ctrl = self.default_controller
157-
self.problems = []
171+
self.problems: list[ProblemNotice] = []
158172

159173
dump_device_composition_path: Optional[str] = self.user_params.get("dump_device_composition_path", None)
160174

@@ -181,7 +195,7 @@ async def setup_class_helper(self, allow_pase: bool = True):
181195
except asyncio.CancelledError:
182196
pass
183197

184-
wildcard_read = (await dev_ctrl.Read(node_id, [()]))
198+
wildcard_read = (await dev_ctrl.Read(node_id, [()])) # type: ignore[list-item]
185199

186200
# ======= State kept for use by all tests =======
187201
# All endpoints in "full object" indexing format
@@ -204,23 +218,33 @@ async def setup_class_helper(self, allow_pase: bool = True):
204218

205219
def get_test_name(self) -> str:
206220
"""Return the function name of the caller. Used to create logging entries."""
207-
return sys._getframe().f_back.f_code.co_name
208-
209-
def fail_current_test(self, msg: Optional[str] = None):
221+
# Handle potential None from sys._getframe().f_back
222+
frame = sys._getframe().f_back
223+
if frame is None:
224+
# This case is highly unlikely in normal execution but satisfies mypy
225+
return "<unknown_test>"
226+
return frame.f_code.co_name
227+
228+
def fail_current_test(self, msg: Optional[str] = None) -> typing.NoReturn: # type: ignore[misc]
210229
if not msg:
211230
# Without a message, just log the last problem seen
212231
asserts.fail(msg=self.problems[-1].problem)
213232
else:
214233
asserts.fail(msg)
215234

216-
def _get_dm(self) -> PrebuiltDataModelDirectory:
235+
def _get_dm(self) -> PrebuiltDataModelDirectory: # type: ignore[return]
236+
# mypy doesn't understand that asserts.fail always raises a TestFailure
217237
try:
218238
spec_version = self.endpoints[0][Clusters.BasicInformation][Clusters.BasicInformation.Attributes.SpecificationVersion]
219239
except KeyError:
220240
asserts.fail(
221241
"Specification Version not found on device - ensure device bas a basic information cluster on EP0 supporting Specification Version")
222242
try:
223-
return dm_from_spec_version(spec_version)
243+
dm = dm_from_spec_version(spec_version)
244+
if dm is None:
245+
# Handle case where dm_from_spec_version returns None, although the current implementation raises an exception.
246+
asserts.fail("Could not determine data model from specification version.")
247+
return dm
224248
except ConformanceException as e:
225249
asserts.fail(f"Unable to identify specification version: {e}")
226250

0 commit comments

Comments
 (0)