From 91909164df50920c503e3af636065ac98e7cd7e8 Mon Sep 17 00:00:00 2001 From: Ian Later Date: Mon, 12 Jan 2026 16:39:56 -0800 Subject: [PATCH 1/7] python(feat): TestResults: Have pytest assertion errors be marked as step failures vs errors. --- .../_tests/util/test_test_results_utils.py | 18 +++++++-- python/lib/sift_client/sift_types/_base.py | 4 +- .../lib/sift_client/sift_types/test_report.py | 8 ++++ .../util/test_results/context_manager.py | 37 +++++++++++++------ .../util/test_results/pytest_util.py | 4 +- 5 files changed, 54 insertions(+), 17 deletions(-) diff --git a/python/lib/sift_client/_tests/util/test_test_results_utils.py b/python/lib/sift_client/_tests/util/test_test_results_utils.py index 82bea7c0c..a276a6c99 100644 --- a/python/lib/sift_client/_tests/util/test_test_results_utils.py +++ b/python/lib/sift_client/_tests/util/test_test_results_utils.py @@ -368,17 +368,27 @@ def test_bad_assert(self, report_context, step): parent_step = None substep = None nested_substep = None + nested_substep_2 = None sibling_substep = None with step.substep("Top Level Step", "Should fail") as parent_step_context: parent_step = parent_step_context.current_step with parent_step_context.substep("Parent Step", "Should fail") as substep_context: substep = substep_context.current_step with substep_context.substep( - "Nested Substep", "Has a bad assert" + "Nested Substep", + "Has a bad assert. Pytest util should nominally mark this as fail instead of error.", ) as nested_substep_context: nested_substep = nested_substep_context.current_step nested_substep_context.force_result = True assert False == True + with substep_context.substep( + "Nested Substep 2", + "Has a bad assert and shows assertion errors. Pytest util should mark this as error.", + ) as nested_substep_2_context: + nested_substep_2 = nested_substep_2_context.current_step + nested_substep_2_context.show_assertion_errors = True + nested_substep_2_context.force_result = True + assert False == True with substep_context.substep( "Sibling Substep", "Should pass" ) as sibling_substep_context: @@ -386,8 +396,10 @@ def test_bad_assert(self, report_context, step): assert parent_step.status == TestStatus.FAILED assert substep.status == TestStatus.FAILED - assert nested_substep.status == TestStatus.ERROR - assert "AssertionError" in nested_substep.error_info.error_message + assert nested_substep.status == TestStatus.FAILED + assert nested_substep.error_info is None + assert nested_substep_2.status == TestStatus.ERROR + assert "AssertionError" in nested_substep_2.error_info.error_message assert sibling_substep.status == TestStatus.PASSED # If this test was successful, mark that at a high level. diff --git a/python/lib/sift_client/sift_types/_base.py b/python/lib/sift_client/sift_types/_base.py index c8c0f8fae..3e9a214e9 100644 --- a/python/lib/sift_client/sift_types/_base.py +++ b/python/lib/sift_client/sift_types/_base.py @@ -57,7 +57,7 @@ def _update(self, other: BaseType[ProtoT, SelfT]) -> BaseType[ProtoT, SelfT]: """Update this instance with the values from another instance.""" # This bypasses the frozen status of the model for key in other.__class__.model_fields.keys(): - if key in self.model_fields: + if key in self.__class__.model_fields: self.__dict__.update({key: getattr(other, key)}) # Make sure we also update the proto since it is excluded @@ -68,7 +68,7 @@ def _update(self, other: BaseType[ProtoT, SelfT]) -> BaseType[ProtoT, SelfT]: @model_validator(mode="after") def _validate_timezones(self): """Validate datetime fiels have timezone information.""" - for field_name in self.model_fields.keys(): + for field_name in self.__class__.model_fields.keys(): val = getattr(self, field_name) if isinstance(val, datetime) and val.tzinfo is None: raise ValueError(f"{field_name} must have timezone information") diff --git a/python/lib/sift_client/sift_types/test_report.py b/python/lib/sift_client/sift_types/test_report.py index c03c94192..4ed8b31e0 100644 --- a/python/lib/sift_client/sift_types/test_report.py +++ b/python/lib/sift_client/sift_types/test_report.py @@ -43,6 +43,7 @@ class TestStatus(Enum): """TestStatus enum.""" + __test__ = False UNSPECIFIED = 0 DRAFT = 1 PASSED = 2 @@ -56,6 +57,7 @@ class TestStatus(Enum): class TestStepType(Enum): """TestStepType enum.""" + __test__ = False UNSPECIFIED = 0 SEQUENCE = 1 GROUP = 2 @@ -66,6 +68,7 @@ class TestStepType(Enum): class TestMeasurementType(Enum): """TestMeasurementType enum.""" + __test__ = False UNSPECIFIED = 0 DOUBLE = 1 STRING = 3 @@ -76,6 +79,7 @@ class TestMeasurementType(Enum): class TestStepBase(ModelCreateUpdateBase): """Base model for TestStepUpdate and TestStepCreate. Contains shared fields for all test steps. Update and create models differ mostly in what fields are required vs optional.""" + __test__ = False parent_step_id: str | None = None description: str | None = None error_info: ErrorInfo | None = None @@ -239,6 +243,7 @@ def __eq__(self, other: object) -> bool: class TestMeasurementBase(ModelCreateUpdateBase): """Base model for TestMeasurementUpdate and TestMeasurementCreate. Contains shared fields for all test measurements. Update and create models differ mostly in what fields are required vs optional.""" + __test__ = False numeric_value: float | None = None string_value: str | None = None boolean_value: bool | None = None @@ -325,6 +330,7 @@ def to_proto(self) -> TestMeasurementProto: class TestMeasurement(BaseType[TestMeasurementProto, "TestMeasurement"]): """TestMeasurement model representing a measurement in a test.""" + __test__ = False measurement_type: TestMeasurementType name: str test_step_id: str @@ -426,6 +432,7 @@ def update( class TestReportBase(ModelCreateUpdateBase): """Base model for TestReportUpdate and TestReportCreate. Contains shared fields for all test reports. Update and create models differ mostly in what fields are required vs optional.""" + __test__ = False status: TestStatus | None = None metadata: dict[str, str | float | bool] | None = None serial_number: str | None = None @@ -519,6 +526,7 @@ def _to_proto(self) -> ErrorInfoProto: class TestReport(BaseType[TestReportProto, "TestReport"], FileAttachmentsMixin): """TestReport model representing a test report.""" + __test__ = False status: TestStatus name: str test_system_name: str diff --git a/python/lib/sift_client/util/test_results/context_manager.py b/python/lib/sift_client/util/test_results/context_manager.py index da7de8c65..19871ae58 100644 --- a/python/lib/sift_client/util/test_results/context_manager.py +++ b/python/lib/sift_client/util/test_results/context_manager.py @@ -94,9 +94,13 @@ def __exit__(self, exc_type, exc_value, traceback): self.report.update(update) return True - def new_step(self, name: str, description: str | None = None) -> NewStep: + def new_step( + self, name: str, description: str | None = None, show_assertion_errors: bool = True + ) -> NewStep: """Alias to return a new step context manager from this report context. Use create_step for actually creating a TestStep in the current context.""" - return NewStep(self, name=name, description=description) + return NewStep( + self, name=name, description=description, show_assertion_errors=show_assertion_errors + ) def get_next_step_path(self) -> str: """Get the next step path for the current depth.""" @@ -191,6 +195,7 @@ class NewStep(AbstractContextManager): report_context: ReportContext client: SiftClient + show_assertion_errors: bool = True current_step: TestStep | None = None def __init__( @@ -198,6 +203,7 @@ def __init__( report_context: ReportContext, name: str, description: str | None = None, + show_assertion_errors: bool = True, ): """Initialize a new step context. @@ -205,10 +211,12 @@ def __init__( report_context: The report context to create the step in. name: The name of the step. description: The description of the step. + show_assertion_errors: Whether to show assertion errors in the step (exists because users don't want to see them when using pytest). """ self.report_context = report_context self.client = report_context.report.client self.current_step = self.report_context.create_step(name, description) + self.show_assertion_errors = show_assertion_errors def __enter__(self): """Enter the context manager to create a new step. @@ -233,15 +241,19 @@ def update_step_from_result( returns: The false if step failed or errored, true otherwise. """ error_info = None - if exc: - stack = traceback.format_exception(exc, exc_value, tb) # type: ignore - stack = [stack[0], *stack[-10:]] if len(stack) > 10 else stack - trace = "".join(stack) - error_info = ErrorInfo( - error_code=1, - error_message=trace, - ) assert self.current_step is not None + if exc: + if isinstance(exc_value, AssertionError) and not self.show_assertion_errors: + # If we're not showing assertion errors (i.e. pytest), mark step as failed but don't set error info. + self.report_context.record_step_outcome(False, self.current_step) + else: + stack = traceback.format_exception(exc, exc_value, tb) # type: ignore + stack = [stack[0], *stack[-10:]] if len(stack) > 10 else stack + trace = "".join(stack) + error_info = ErrorInfo( + error_code=1, + error_message=trace, + ) # Resolve the status of this step (i.e. fail if children failed) and propagate the result to the parent step. result = self.report_context.resolve_and_propagate_step_result( @@ -272,6 +284,7 @@ def __exit__(self, exc, exc_value, tb): self.report_context.exit_step(self.current_step) # Test only attribute (hence not public class variable) + # This changes the result after the status and error info are set. if hasattr(self, "force_result"): result = self.force_result @@ -421,4 +434,6 @@ def report_outcome(self, name: str, result: bool, reason: str | None = None) -> def substep(self, name: str, description: str | None = None) -> NewStep: """Alias to return a new step context manager from the current step. The ReportContext will manage nesting of steps.""" - return self.report_context.new_step(name=name, description=description) + return self.report_context.new_step( + name=name, description=description, show_assertion_errors=self.show_assertion_errors + ) diff --git a/python/lib/sift_client/util/test_results/pytest_util.py b/python/lib/sift_client/util/test_results/pytest_util.py index 90a30ced3..5a9a14c0e 100644 --- a/python/lib/sift_client/util/test_results/pytest_util.py +++ b/python/lib/sift_client/util/test_results/pytest_util.py @@ -63,7 +63,9 @@ def _step_impl( ) -> Generator[NewStep | None, None, None]: name = str(request.node.name) existing_docstring = request.node.obj.__doc__ or None - with report_context.new_step(name=name, description=existing_docstring) as new_step: + with report_context.new_step( + name=name, description=existing_docstring, show_assertion_errors=False + ) as new_step: yield new_step if hasattr(request.node, "rep_call") and request.node.rep_call.excinfo: new_step.update_step_from_result( From 7d68e73c8cdc54622f849855fc233940824c3bcf Mon Sep 17 00:00:00 2001 From: Ian Later Date: Tue, 13 Jan 2026 10:10:15 -0800 Subject: [PATCH 2/7] change flag name --- .../_tests/util/test_test_results_utils.py | 2 +- .../util/test_results/context_manager.py | 21 ++++++++++++------- .../util/test_results/pytest_util.py | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/python/lib/sift_client/_tests/util/test_test_results_utils.py b/python/lib/sift_client/_tests/util/test_test_results_utils.py index a276a6c99..79e0a690a 100644 --- a/python/lib/sift_client/_tests/util/test_test_results_utils.py +++ b/python/lib/sift_client/_tests/util/test_test_results_utils.py @@ -386,7 +386,7 @@ def test_bad_assert(self, report_context, step): "Has a bad assert and shows assertion errors. Pytest util should mark this as error.", ) as nested_substep_2_context: nested_substep_2 = nested_substep_2_context.current_step - nested_substep_2_context.show_assertion_errors = True + nested_substep_2_context.assertion_as_fail_not_error = True nested_substep_2_context.force_result = True assert False == True with substep_context.substep( diff --git a/python/lib/sift_client/util/test_results/context_manager.py b/python/lib/sift_client/util/test_results/context_manager.py index 19871ae58..937f21971 100644 --- a/python/lib/sift_client/util/test_results/context_manager.py +++ b/python/lib/sift_client/util/test_results/context_manager.py @@ -95,11 +95,14 @@ def __exit__(self, exc_type, exc_value, traceback): return True def new_step( - self, name: str, description: str | None = None, show_assertion_errors: bool = True + self, name: str, description: str | None = None, assertion_as_fail_not_error: bool = True ) -> NewStep: """Alias to return a new step context manager from this report context. Use create_step for actually creating a TestStep in the current context.""" return NewStep( - self, name=name, description=description, show_assertion_errors=show_assertion_errors + self, + name=name, + description=description, + assertion_as_fail_not_error=assertion_as_fail_not_error, ) def get_next_step_path(self) -> str: @@ -195,7 +198,7 @@ class NewStep(AbstractContextManager): report_context: ReportContext client: SiftClient - show_assertion_errors: bool = True + assertion_as_fail_not_error: bool = True current_step: TestStep | None = None def __init__( @@ -203,7 +206,7 @@ def __init__( report_context: ReportContext, name: str, description: str | None = None, - show_assertion_errors: bool = True, + assertion_as_fail_not_error: bool = True, ): """Initialize a new step context. @@ -211,12 +214,12 @@ def __init__( report_context: The report context to create the step in. name: The name of the step. description: The description of the step. - show_assertion_errors: Whether to show assertion errors in the step (exists because users don't want to see them when using pytest). + assertion_as_fail_not_error: Mark steps with assertion errors as failed instead of error+traceback (some users want assertions to work as simple failures especially when using pytest). """ self.report_context = report_context self.client = report_context.report.client self.current_step = self.report_context.create_step(name, description) - self.show_assertion_errors = show_assertion_errors + self.assertion_as_fail_not_error = assertion_as_fail_not_error def __enter__(self): """Enter the context manager to create a new step. @@ -243,7 +246,7 @@ def update_step_from_result( error_info = None assert self.current_step is not None if exc: - if isinstance(exc_value, AssertionError) and not self.show_assertion_errors: + if isinstance(exc_value, AssertionError) and not self.assertion_as_fail_not_error: # If we're not showing assertion errors (i.e. pytest), mark step as failed but don't set error info. self.report_context.record_step_outcome(False, self.current_step) else: @@ -435,5 +438,7 @@ def report_outcome(self, name: str, result: bool, reason: str | None = None) -> def substep(self, name: str, description: str | None = None) -> NewStep: """Alias to return a new step context manager from the current step. The ReportContext will manage nesting of steps.""" return self.report_context.new_step( - name=name, description=description, show_assertion_errors=self.show_assertion_errors + name=name, + description=description, + assertion_as_fail_not_error=self.assertion_as_fail_not_error, ) diff --git a/python/lib/sift_client/util/test_results/pytest_util.py b/python/lib/sift_client/util/test_results/pytest_util.py index 5a9a14c0e..c2bd3f9bc 100644 --- a/python/lib/sift_client/util/test_results/pytest_util.py +++ b/python/lib/sift_client/util/test_results/pytest_util.py @@ -64,7 +64,7 @@ def _step_impl( name = str(request.node.name) existing_docstring = request.node.obj.__doc__ or None with report_context.new_step( - name=name, description=existing_docstring, show_assertion_errors=False + name=name, description=existing_docstring, assertion_as_fail_not_error=False ) as new_step: yield new_step if hasattr(request.node, "rep_call") and request.node.rep_call.excinfo: From d55363599769141d3edbc88c75b698d4f07e2e12 Mon Sep 17 00:00:00 2001 From: Ian Later Date: Tue, 13 Jan 2026 10:40:05 -0800 Subject: [PATCH 3/7] Mark test results classes as non test classes in init --- python/lib/sift_client/resources/__init__.py | 5 +++++ python/lib/sift_client/sift_types/__init__.py | 15 +++++++++++++++ python/lib/sift_client/sift_types/test_report.py | 8 -------- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/python/lib/sift_client/resources/__init__.py b/python/lib/sift_client/resources/__init__.py index 5058ac366..6dec570f7 100644 --- a/python/lib/sift_client/resources/__init__.py +++ b/python/lib/sift_client/resources/__init__.py @@ -176,6 +176,11 @@ async def main(): FileAttachmentsAPI, ) +# These are not test classes, so we need to set __test__ to False to avoid pytest warnings. +# Do this here because for some reason our docs generation doesn't like it when done in the classes themselves. +TestResultsAPI.__test__ = False +TestResultsAPIAsync.__test__ = False + __all__ = [ "AssetsAPI", "AssetsAPIAsync", diff --git a/python/lib/sift_client/sift_types/__init__.py b/python/lib/sift_client/sift_types/__init__.py index b55717c60..585733550 100644 --- a/python/lib/sift_client/sift_types/__init__.py +++ b/python/lib/sift_client/sift_types/__init__.py @@ -163,6 +163,7 @@ from sift_client.sift_types.test_report import ( TestMeasurement, TestMeasurementCreate, + TestMeasurementUpdate, TestMeasurementType, TestReport, TestReportCreate, @@ -173,6 +174,20 @@ TestStepType, ) +# These are not test classes, so we need to set __test__ to False to avoid pytest warnings. +# Do this here because for some reason our docs generation doesn't like it when done in the classes themselves. +TestStepType.__test__ = False +TestMeasurementType.__test__ = False +TestMeasurement.__test__ = False +TestMeasurementCreate.__test__ = False +TestMeasurementUpdate.__test__ = False +TestStatus.__test__ = False +TestStep.__test__ = False +TestStepCreate.__test__ = False +TestReport.__test__ = False +TestReportCreate.__test__ = False +TestReportUpdate.__test__ = False + __all__ = [ "Asset", "AssetUpdate", diff --git a/python/lib/sift_client/sift_types/test_report.py b/python/lib/sift_client/sift_types/test_report.py index 4ed8b31e0..c03c94192 100644 --- a/python/lib/sift_client/sift_types/test_report.py +++ b/python/lib/sift_client/sift_types/test_report.py @@ -43,7 +43,6 @@ class TestStatus(Enum): """TestStatus enum.""" - __test__ = False UNSPECIFIED = 0 DRAFT = 1 PASSED = 2 @@ -57,7 +56,6 @@ class TestStatus(Enum): class TestStepType(Enum): """TestStepType enum.""" - __test__ = False UNSPECIFIED = 0 SEQUENCE = 1 GROUP = 2 @@ -68,7 +66,6 @@ class TestStepType(Enum): class TestMeasurementType(Enum): """TestMeasurementType enum.""" - __test__ = False UNSPECIFIED = 0 DOUBLE = 1 STRING = 3 @@ -79,7 +76,6 @@ class TestMeasurementType(Enum): class TestStepBase(ModelCreateUpdateBase): """Base model for TestStepUpdate and TestStepCreate. Contains shared fields for all test steps. Update and create models differ mostly in what fields are required vs optional.""" - __test__ = False parent_step_id: str | None = None description: str | None = None error_info: ErrorInfo | None = None @@ -243,7 +239,6 @@ def __eq__(self, other: object) -> bool: class TestMeasurementBase(ModelCreateUpdateBase): """Base model for TestMeasurementUpdate and TestMeasurementCreate. Contains shared fields for all test measurements. Update and create models differ mostly in what fields are required vs optional.""" - __test__ = False numeric_value: float | None = None string_value: str | None = None boolean_value: bool | None = None @@ -330,7 +325,6 @@ def to_proto(self) -> TestMeasurementProto: class TestMeasurement(BaseType[TestMeasurementProto, "TestMeasurement"]): """TestMeasurement model representing a measurement in a test.""" - __test__ = False measurement_type: TestMeasurementType name: str test_step_id: str @@ -432,7 +426,6 @@ def update( class TestReportBase(ModelCreateUpdateBase): """Base model for TestReportUpdate and TestReportCreate. Contains shared fields for all test reports. Update and create models differ mostly in what fields are required vs optional.""" - __test__ = False status: TestStatus | None = None metadata: dict[str, str | float | bool] | None = None serial_number: str | None = None @@ -526,7 +519,6 @@ def _to_proto(self) -> ErrorInfoProto: class TestReport(BaseType[TestReportProto, "TestReport"], FileAttachmentsMixin): """TestReport model representing a test report.""" - __test__ = False status: TestStatus name: str test_system_name: str From e0f433b0039e87f3ae4c9fb97cc3654912590bae Mon Sep 17 00:00:00 2001 From: Ian Later Date: Tue, 13 Jan 2026 10:43:35 -0800 Subject: [PATCH 4/7] lint --- python/lib/sift_client/sift_types/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/lib/sift_client/sift_types/__init__.py b/python/lib/sift_client/sift_types/__init__.py index 585733550..1a571e8f6 100644 --- a/python/lib/sift_client/sift_types/__init__.py +++ b/python/lib/sift_client/sift_types/__init__.py @@ -163,8 +163,8 @@ from sift_client.sift_types.test_report import ( TestMeasurement, TestMeasurementCreate, - TestMeasurementUpdate, TestMeasurementType, + TestMeasurementUpdate, TestReport, TestReportCreate, TestReportUpdate, From 852d928ed8ba1b72cd9474fdcf6cdf9a9f4700f1 Mon Sep 17 00:00:00 2001 From: Ian Later Date: Tue, 13 Jan 2026 10:47:10 -0800 Subject: [PATCH 5/7] mypy --- python/lib/sift_client/resources/__init__.py | 4 ++-- python/lib/sift_client/sift_types/__init__.py | 22 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/python/lib/sift_client/resources/__init__.py b/python/lib/sift_client/resources/__init__.py index 6dec570f7..f83e72c70 100644 --- a/python/lib/sift_client/resources/__init__.py +++ b/python/lib/sift_client/resources/__init__.py @@ -178,8 +178,8 @@ async def main(): # These are not test classes, so we need to set __test__ to False to avoid pytest warnings. # Do this here because for some reason our docs generation doesn't like it when done in the classes themselves. -TestResultsAPI.__test__ = False -TestResultsAPIAsync.__test__ = False +TestResultsAPI.__test__ = False # type: ignore +TestResultsAPIAsync.__test__ = False # type: ignore __all__ = [ "AssetsAPI", diff --git a/python/lib/sift_client/sift_types/__init__.py b/python/lib/sift_client/sift_types/__init__.py index 1a571e8f6..df3582438 100644 --- a/python/lib/sift_client/sift_types/__init__.py +++ b/python/lib/sift_client/sift_types/__init__.py @@ -176,17 +176,17 @@ # These are not test classes, so we need to set __test__ to False to avoid pytest warnings. # Do this here because for some reason our docs generation doesn't like it when done in the classes themselves. -TestStepType.__test__ = False -TestMeasurementType.__test__ = False -TestMeasurement.__test__ = False -TestMeasurementCreate.__test__ = False -TestMeasurementUpdate.__test__ = False -TestStatus.__test__ = False -TestStep.__test__ = False -TestStepCreate.__test__ = False -TestReport.__test__ = False -TestReportCreate.__test__ = False -TestReportUpdate.__test__ = False +TestStepType.__test__ = False # type: ignore +TestMeasurementType.__test__ = False # type: ignore +TestMeasurement.__test__ = False # type: ignore +TestMeasurementCreate.__test__ = False # type: ignore +TestMeasurementUpdate.__test__ = False # type: ignore +TestStatus.__test__ = False # type: ignore +TestStep.__test__ = False # type: ignore +TestStepCreate.__test__ = False # type: ignore +TestReport.__test__ = False # type: ignore +TestReportCreate.__test__ = False # type: ignore +TestReportUpdate.__test__ = False # type: ignore __all__ = [ "Asset", From 1049823ba573e78516e3dd81adff13ad3089a226 Mon Sep 17 00:00:00 2001 From: Ian Later Date: Tue, 13 Jan 2026 11:21:41 -0800 Subject: [PATCH 6/7] fmt --- python/lib/sift_client/resources/__init__.py | 4 ++-- python/lib/sift_client/sift_types/__init__.py | 22 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/python/lib/sift_client/resources/__init__.py b/python/lib/sift_client/resources/__init__.py index f83e72c70..23de44186 100644 --- a/python/lib/sift_client/resources/__init__.py +++ b/python/lib/sift_client/resources/__init__.py @@ -178,8 +178,8 @@ async def main(): # These are not test classes, so we need to set __test__ to False to avoid pytest warnings. # Do this here because for some reason our docs generation doesn't like it when done in the classes themselves. -TestResultsAPI.__test__ = False # type: ignore -TestResultsAPIAsync.__test__ = False # type: ignore +TestResultsAPI.__test__ = False # type: ignore +TestResultsAPIAsync.__test__ = False # type: ignore __all__ = [ "AssetsAPI", diff --git a/python/lib/sift_client/sift_types/__init__.py b/python/lib/sift_client/sift_types/__init__.py index df3582438..33e2f90ed 100644 --- a/python/lib/sift_client/sift_types/__init__.py +++ b/python/lib/sift_client/sift_types/__init__.py @@ -176,17 +176,17 @@ # These are not test classes, so we need to set __test__ to False to avoid pytest warnings. # Do this here because for some reason our docs generation doesn't like it when done in the classes themselves. -TestStepType.__test__ = False # type: ignore -TestMeasurementType.__test__ = False # type: ignore -TestMeasurement.__test__ = False # type: ignore -TestMeasurementCreate.__test__ = False # type: ignore -TestMeasurementUpdate.__test__ = False # type: ignore -TestStatus.__test__ = False # type: ignore -TestStep.__test__ = False # type: ignore -TestStepCreate.__test__ = False # type: ignore -TestReport.__test__ = False # type: ignore -TestReportCreate.__test__ = False # type: ignore -TestReportUpdate.__test__ = False # type: ignore +TestStepType.__test__ = False # type: ignore +TestMeasurementType.__test__ = False # type: ignore +TestMeasurement.__test__ = False # type: ignore +TestMeasurementCreate.__test__ = False # type: ignore +TestMeasurementUpdate.__test__ = False # type: ignore +TestStatus.__test__ = False # type: ignore +TestStep.__test__ = False # type: ignore +TestStepCreate.__test__ = False # type: ignore +TestReport.__test__ = False # type: ignore +TestReportCreate.__test__ = False # type: ignore +TestReportUpdate.__test__ = False # type: ignore __all__ = [ "Asset", From 93812f2379cdb24ee9e55533a81b4cbfd9b986ed Mon Sep 17 00:00:00 2001 From: Ian Later Date: Tue, 13 Jan 2026 12:01:54 -0800 Subject: [PATCH 7/7] add __test__=False only when running pytest --- python/lib/sift_client/resources/__init__.py | 11 ++++--- python/lib/sift_client/sift_types/__init__.py | 29 ++++++++++--------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/python/lib/sift_client/resources/__init__.py b/python/lib/sift_client/resources/__init__.py index 23de44186..cdc651485 100644 --- a/python/lib/sift_client/resources/__init__.py +++ b/python/lib/sift_client/resources/__init__.py @@ -176,10 +176,13 @@ async def main(): FileAttachmentsAPI, ) -# These are not test classes, so we need to set __test__ to False to avoid pytest warnings. -# Do this here because for some reason our docs generation doesn't like it when done in the classes themselves. -TestResultsAPI.__test__ = False # type: ignore -TestResultsAPIAsync.__test__ = False # type: ignore +import sys + +if "pytest" in sys.modules: + # These are not test classes, so we need to set __test__ to False to avoid pytest warnings. + # Do this here because for some reason our docs generation doesn't like it when done in the classes themselves. + TestResultsAPI.__test__ = False # type: ignore + TestResultsAPIAsync.__test__ = False # type: ignore __all__ = [ "AssetsAPI", diff --git a/python/lib/sift_client/sift_types/__init__.py b/python/lib/sift_client/sift_types/__init__.py index 33e2f90ed..73d219704 100644 --- a/python/lib/sift_client/sift_types/__init__.py +++ b/python/lib/sift_client/sift_types/__init__.py @@ -129,6 +129,8 @@ ``` """ +import sys + from sift_client.sift_types.asset import Asset, AssetUpdate from sift_client.sift_types.calculated_channel import ( CalculatedChannel, @@ -174,19 +176,20 @@ TestStepType, ) -# These are not test classes, so we need to set __test__ to False to avoid pytest warnings. -# Do this here because for some reason our docs generation doesn't like it when done in the classes themselves. -TestStepType.__test__ = False # type: ignore -TestMeasurementType.__test__ = False # type: ignore -TestMeasurement.__test__ = False # type: ignore -TestMeasurementCreate.__test__ = False # type: ignore -TestMeasurementUpdate.__test__ = False # type: ignore -TestStatus.__test__ = False # type: ignore -TestStep.__test__ = False # type: ignore -TestStepCreate.__test__ = False # type: ignore -TestReport.__test__ = False # type: ignore -TestReportCreate.__test__ = False # type: ignore -TestReportUpdate.__test__ = False # type: ignore +if "pytest" in sys.modules: + # These are not test classes, so we need to set __test__ to False to avoid pytest warnings. + # Do this here because for some reason our docs generation doesn't like it when done in the classes themselves. + TestStepType.__test__ = False # type: ignore + TestMeasurementType.__test__ = False # type: ignore + TestMeasurement.__test__ = False # type: ignore + TestMeasurementCreate.__test__ = False # type: ignore + TestMeasurementUpdate.__test__ = False # type: ignore + TestStatus.__test__ = False # type: ignore + TestStep.__test__ = False # type: ignore + TestStepCreate.__test__ = False # type: ignore + TestReport.__test__ = False # type: ignore + TestReportCreate.__test__ = False # type: ignore + TestReportUpdate.__test__ = False # type: ignore __all__ = [ "Asset",