From ef315a76920476fe6897528485fbb37617d199b1 Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Wed, 18 Feb 2026 12:03:57 +0530 Subject: [PATCH 01/26] Added get_semiconductor_module_context_with_sites and scan for tsm_context in kwargs Added get_semiconductor_module_context_with_sites to get context with specific sites. Modified codemoduleapi.py - __call__ to check for context in kwargs as a fallback --- src/nitsm/codemoduleapi.py | 19 +++++++++++++------ src/nitsm/tsmcontext.py | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/nitsm/codemoduleapi.py b/src/nitsm/codemoduleapi.py index dd5452e..c45564e 100644 --- a/src/nitsm/codemoduleapi.py +++ b/src/nitsm/codemoduleapi.py @@ -42,13 +42,20 @@ def __call__(self, *args, **kwargs): if inspect.isclass(argument[1]): # class method check argument = next(arguments_iter) # move to second argument except StopIteration: - raise TypeError( - ( - "The number of arguments to the code module is less than expected. It must " - "accept as it's first argument the Semiconductor Module context passed from " - "TestStand or another code module.", + # Fallback: look for tsm context in kwargs by name + for key in ("context", "tsm_context", "SemiConductorModuleContext"): + if key in bound_arguments.arguments: + argument = (key, bound_arguments.arguments[key]) + break + else: + raise TypeError( + ( + "The number of arguments to the code module is less than expected. It must " + "accept as it's first argument the Semiconductor Module context passed from " + "TestStand or another code module or it should be passed as a keyword argument," + " with keywords - 'context', 'tsm_context', or 'SemiConductorModuleContext'.", + ) ) - ) # attempt to wrap argument in a SemiconductorModuleContext object argument_name, argument_value = argument diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 2b04bf1..9c547e5 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -286,6 +286,21 @@ def global_data_exists(self, data_id: str) -> bool: """ return self._context.GlobalDataExists(data_id) + def get_semiconductor_module_context_with_sites( + self, + site_numbers: list[int] + ) -> "SemiconductorModuleContext": + """Returns a Semiconductor Module context object which holds information and resources + specific to the site_numbers mentioned. + + Args: + site_numbers: A sequence of site numbers for which the resources should be used. + Returns: + Returns SemicondutorModuleContext object with resources specific to the site_number. + """ + print("This is inside the function") + return SemiconductorModuleContext(self._context.GetSemiconductorModuleContextWithSites(site_numbers)) + # NI-Digital def get_all_nidigital_instrument_names(self) -> "_StringTuple": From 2fff250d9947e8c52ef2c1062b4845c6b27318f8 Mon Sep 17 00:00:00 2001 From: Prithieraj M R <142006822+prithierajmr@users.noreply.github.com> Date: Mon, 9 Mar 2026 12:13:22 +0530 Subject: [PATCH 02/26] Update src/nitsm/tsmcontext.py Changed the type to Sequence of integers for Py <3.7 compatibility Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/nitsm/tsmcontext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 9c547e5..210036e 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -288,7 +288,7 @@ def global_data_exists(self, data_id: str) -> bool: def get_semiconductor_module_context_with_sites( self, - site_numbers: list[int] + site_numbers: "_Sequence[int]" ) -> "SemiconductorModuleContext": """Returns a Semiconductor Module context object which holds information and resources specific to the site_numbers mentioned. From 48cba717de4c91ba008a5eb21d02e960dc4f2019 Mon Sep 17 00:00:00 2001 From: Prithieraj M R <142006822+prithierajmr@users.noreply.github.com> Date: Mon, 9 Mar 2026 12:13:48 +0530 Subject: [PATCH 03/26] Update src/nitsm/tsmcontext.py Remove the print statement added for debugging Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/nitsm/tsmcontext.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 210036e..98c8978 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -298,7 +298,6 @@ def get_semiconductor_module_context_with_sites( Returns: Returns SemicondutorModuleContext object with resources specific to the site_number. """ - print("This is inside the function") return SemiconductorModuleContext(self._context.GetSemiconductorModuleContextWithSites(site_numbers)) # NI-Digital From 51978c318f85a5751d726eb3c54f0c143bcb8fac Mon Sep 17 00:00:00 2001 From: Prithieraj M R <142006822+prithierajmr@users.noreply.github.com> Date: Mon, 9 Mar 2026 12:15:17 +0530 Subject: [PATCH 04/26] Update src/nitsm/tsmcontext.py Typo in the returns - actual return TSM Context is for the specified site_numbers Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/nitsm/tsmcontext.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 98c8978..2e93c22 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -290,13 +290,13 @@ def get_semiconductor_module_context_with_sites( self, site_numbers: "_Sequence[int]" ) -> "SemiconductorModuleContext": - """Returns a Semiconductor Module context object which holds information and resources - specific to the site_numbers mentioned. + """Returns a Semiconductor Module context object which holds information and resources + specific to the specified site_numbers. Args: site_numbers: A sequence of site numbers for which the resources should be used. Returns: - Returns SemicondutorModuleContext object with resources specific to the site_number. + SemiconductorModuleContext object with resources specific to the specified site_numbers. """ return SemiconductorModuleContext(self._context.GetSemiconductorModuleContextWithSites(site_numbers)) From ffa316abfdf72e3d41dd7a035c08f44c5bb46c7b Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Thu, 12 Mar 2026 20:20:43 +0530 Subject: [PATCH 05/26] Used dumb dispatch for TSM context with Sites and Test for checking tsm_context in kwargs tsmcontext - dumbdispatch for getting context with sites codemoduleapi - Typo Added codemoduleapi test for checking tsm_context position --- src/nitsm/codemoduleapi.py | 4 ++-- src/nitsm/tsmcontext.py | 36 ++++++++++++++++++++++++++++-------- tests/test_codemoduleapi.py | 23 ++++++++++++++++++++++- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/nitsm/codemoduleapi.py b/src/nitsm/codemoduleapi.py index c45564e..f6f75cd 100644 --- a/src/nitsm/codemoduleapi.py +++ b/src/nitsm/codemoduleapi.py @@ -43,7 +43,7 @@ def __call__(self, *args, **kwargs): argument = next(arguments_iter) # move to second argument except StopIteration: # Fallback: look for tsm context in kwargs by name - for key in ("context", "tsm_context", "SemiConductorModuleContext"): + for key in ("context", "tsm_context", "SemiconductorModuleContext"): if key in bound_arguments.arguments: argument = (key, bound_arguments.arguments[key]) break @@ -53,7 +53,7 @@ def __call__(self, *args, **kwargs): "The number of arguments to the code module is less than expected. It must " "accept as it's first argument the Semiconductor Module context passed from " "TestStand or another code module or it should be passed as a keyword argument," - " with keywords - 'context', 'tsm_context', or 'SemiConductorModuleContext'.", + " with keywords - 'context', 'tsm_context', or 'SemiconductorModuleContext'.", ) ) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 2e93c22..beb93db 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -286,19 +286,39 @@ def global_data_exists(self, data_id: str) -> bool: """ return self._context.GlobalDataExists(data_id) - def get_semiconductor_module_context_with_sites( - self, - site_numbers: "_Sequence[int]" - ) -> "SemiconductorModuleContext": + def get_semiconductor_module_context_with_sites(self,site_numbers: _Sequence[int]) -> "SemiconductorModuleContext": """Returns a Semiconductor Module context object which holds information and resources - specific to the specified site_numbers. + specific to the site_numbers mentioned. Args: site_numbers: A sequence of site numbers for which the resources should be used. + Returns: - SemiconductorModuleContext object with resources specific to the specified site_numbers. - """ - return SemiconductorModuleContext(self._context.GetSemiconductorModuleContextWithSites(site_numbers)) + SemiconductorModuleContext object with resources specific to the site_numbers. + """ + # Normalize and validate the site numbers before passing them to the underlying + # Semiconductor Module context. This ensures predictable behavior for invalid or + # empty site lists. + if not site_numbers: + raise ValueError("site_numbers must contain at least one site number.") + normalized_site_numbers = [] + + for site in site_numbers: + if not isinstance(site, int) or site < 0: + raise ValueError("Each site number must be a non-negative integer.") + normalized_site_numbers.append(site) + + # We have to use DumbDispatch here because pywin32 fails to recognize + # ISemiconductorModuleContext as deriving from IDispatch; most likely because it isn't + # natively supported. So, we fetch it as IUnknown instead. + dumb_context = win32com.client.dynamic.DumbDispatch(self._context) + + # Retrieve the SemiconductorModuleContext COM pointer for the selected sites + context_with_sites = dumb_context.GetSemiconductorModuleContextWithSites(normalized_site_numbers) + + # Wrap the cleaned IUnknown pointer in the Python SemiconductorModuleContext wrapper + return SemiconductorModuleContext(context_with_sites) + # NI-Digital diff --git a/tests/test_codemoduleapi.py b/tests/test_codemoduleapi.py index 5f6f38b..043935c 100644 --- a/tests/test_codemoduleapi.py +++ b/tests/test_codemoduleapi.py @@ -1,5 +1,6 @@ import re import pytest +from unittest.mock import MagicMock from nitsm.codemoduleapi import code_module, SemiconductorModuleContext @@ -56,7 +57,8 @@ def test_invalid_number_of_positional_arguments(self): assert e.value.args[0] == ( "The number of arguments to the code module is less than expected. It must " "accept as it's first argument the Semiconductor Module context passed from " - "TestStand or another code module.", + "TestStand or another code module or it should be passed as a keyword argument," + " with keywords - 'context', 'tsm_context', or 'SemiconductorModuleContext'.", ) # noinspection PyUnusedLocal @@ -84,6 +86,25 @@ def test_positional_arguments_after_tsm_context( ): assert isinstance(standalone_tsm_context_com_object, SemiconductorModuleContext) + + def test_tsm_context_via_kwargs(self): + raw_com_context = MagicMock(name="RawTSMContext") + + received_context = None + + @code_module + def my_module(tsm_context=None): + nonlocal received_context + received_context = tsm_context + return "converted" + + result = my_module(tsm_context=raw_com_context) + + # The function returned normally + assert result == "converted" + + # Check that the wrapper converted raw COM object → SemiconductorModuleContext + assert isinstance(received_context, SemiconductorModuleContext) @pytest.mark.pin_map("codemoduleapi.pinmap") @code_module From 78cc0ce2e3f734925bb016d59b0fc05fa8b67349 Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Mon, 30 Mar 2026 18:04:21 +0530 Subject: [PATCH 06/26] Revert "Used dumb dispatch for TSM context with Sites and Test for checking tsm_context in kwargs" This reverts commit ffa316abfdf72e3d41dd7a035c08f44c5bb46c7b. Rewriting the changes, since we do not want to use dumbdispatch and remove the changes for code_moduleapi --- src/nitsm/codemoduleapi.py | 4 ++-- src/nitsm/tsmcontext.py | 36 ++++++++---------------------------- tests/test_codemoduleapi.py | 23 +---------------------- 3 files changed, 11 insertions(+), 52 deletions(-) diff --git a/src/nitsm/codemoduleapi.py b/src/nitsm/codemoduleapi.py index f6f75cd..c45564e 100644 --- a/src/nitsm/codemoduleapi.py +++ b/src/nitsm/codemoduleapi.py @@ -43,7 +43,7 @@ def __call__(self, *args, **kwargs): argument = next(arguments_iter) # move to second argument except StopIteration: # Fallback: look for tsm context in kwargs by name - for key in ("context", "tsm_context", "SemiconductorModuleContext"): + for key in ("context", "tsm_context", "SemiConductorModuleContext"): if key in bound_arguments.arguments: argument = (key, bound_arguments.arguments[key]) break @@ -53,7 +53,7 @@ def __call__(self, *args, **kwargs): "The number of arguments to the code module is less than expected. It must " "accept as it's first argument the Semiconductor Module context passed from " "TestStand or another code module or it should be passed as a keyword argument," - " with keywords - 'context', 'tsm_context', or 'SemiconductorModuleContext'.", + " with keywords - 'context', 'tsm_context', or 'SemiConductorModuleContext'.", ) ) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index beb93db..2e93c22 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -286,39 +286,19 @@ def global_data_exists(self, data_id: str) -> bool: """ return self._context.GlobalDataExists(data_id) - def get_semiconductor_module_context_with_sites(self,site_numbers: _Sequence[int]) -> "SemiconductorModuleContext": + def get_semiconductor_module_context_with_sites( + self, + site_numbers: "_Sequence[int]" + ) -> "SemiconductorModuleContext": """Returns a Semiconductor Module context object which holds information and resources - specific to the site_numbers mentioned. + specific to the specified site_numbers. Args: site_numbers: A sequence of site numbers for which the resources should be used. - Returns: - SemiconductorModuleContext object with resources specific to the site_numbers. - """ - # Normalize and validate the site numbers before passing them to the underlying - # Semiconductor Module context. This ensures predictable behavior for invalid or - # empty site lists. - if not site_numbers: - raise ValueError("site_numbers must contain at least one site number.") - normalized_site_numbers = [] - - for site in site_numbers: - if not isinstance(site, int) or site < 0: - raise ValueError("Each site number must be a non-negative integer.") - normalized_site_numbers.append(site) - - # We have to use DumbDispatch here because pywin32 fails to recognize - # ISemiconductorModuleContext as deriving from IDispatch; most likely because it isn't - # natively supported. So, we fetch it as IUnknown instead. - dumb_context = win32com.client.dynamic.DumbDispatch(self._context) - - # Retrieve the SemiconductorModuleContext COM pointer for the selected sites - context_with_sites = dumb_context.GetSemiconductorModuleContextWithSites(normalized_site_numbers) - - # Wrap the cleaned IUnknown pointer in the Python SemiconductorModuleContext wrapper - return SemiconductorModuleContext(context_with_sites) - + SemiconductorModuleContext object with resources specific to the specified site_numbers. + """ + return SemiconductorModuleContext(self._context.GetSemiconductorModuleContextWithSites(site_numbers)) # NI-Digital diff --git a/tests/test_codemoduleapi.py b/tests/test_codemoduleapi.py index 043935c..5f6f38b 100644 --- a/tests/test_codemoduleapi.py +++ b/tests/test_codemoduleapi.py @@ -1,6 +1,5 @@ import re import pytest -from unittest.mock import MagicMock from nitsm.codemoduleapi import code_module, SemiconductorModuleContext @@ -57,8 +56,7 @@ def test_invalid_number_of_positional_arguments(self): assert e.value.args[0] == ( "The number of arguments to the code module is less than expected. It must " "accept as it's first argument the Semiconductor Module context passed from " - "TestStand or another code module or it should be passed as a keyword argument," - " with keywords - 'context', 'tsm_context', or 'SemiconductorModuleContext'.", + "TestStand or another code module.", ) # noinspection PyUnusedLocal @@ -86,25 +84,6 @@ def test_positional_arguments_after_tsm_context( ): assert isinstance(standalone_tsm_context_com_object, SemiconductorModuleContext) - - def test_tsm_context_via_kwargs(self): - raw_com_context = MagicMock(name="RawTSMContext") - - received_context = None - - @code_module - def my_module(tsm_context=None): - nonlocal received_context - received_context = tsm_context - return "converted" - - result = my_module(tsm_context=raw_com_context) - - # The function returned normally - assert result == "converted" - - # Check that the wrapper converted raw COM object → SemiconductorModuleContext - assert isinstance(received_context, SemiconductorModuleContext) @pytest.mark.pin_map("codemoduleapi.pinmap") @code_module From be9f63a8f8afed9bb011bdd122fe792f657451a2 Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Mon, 30 Mar 2026 18:05:30 +0530 Subject: [PATCH 07/26] Revert "Update src/nitsm/tsmcontext.py " This reverts commit 51978c318f85a5751d726eb3c54f0c143bcb8fac. --- src/nitsm/tsmcontext.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 2e93c22..98c8978 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -290,13 +290,13 @@ def get_semiconductor_module_context_with_sites( self, site_numbers: "_Sequence[int]" ) -> "SemiconductorModuleContext": - """Returns a Semiconductor Module context object which holds information and resources - specific to the specified site_numbers. + """Returns a Semiconductor Module context object which holds information and resources + specific to the site_numbers mentioned. Args: site_numbers: A sequence of site numbers for which the resources should be used. Returns: - SemiconductorModuleContext object with resources specific to the specified site_numbers. + Returns SemicondutorModuleContext object with resources specific to the site_number. """ return SemiconductorModuleContext(self._context.GetSemiconductorModuleContextWithSites(site_numbers)) From 3bec2bf15d4c091ad599c4eb08699481bdb43cc3 Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Mon, 30 Mar 2026 18:05:41 +0530 Subject: [PATCH 08/26] Revert "Update src/nitsm/tsmcontext.py " This reverts commit 48cba717de4c91ba008a5eb21d02e960dc4f2019. --- src/nitsm/tsmcontext.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 98c8978..210036e 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -298,6 +298,7 @@ def get_semiconductor_module_context_with_sites( Returns: Returns SemicondutorModuleContext object with resources specific to the site_number. """ + print("This is inside the function") return SemiconductorModuleContext(self._context.GetSemiconductorModuleContextWithSites(site_numbers)) # NI-Digital From b2e716b0a50866b677b67bef958d297203a7f3b1 Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Mon, 30 Mar 2026 18:05:56 +0530 Subject: [PATCH 09/26] Revert "Update src/nitsm/tsmcontext.py " This reverts commit 2fff250d9947e8c52ef2c1062b4845c6b27318f8. --- src/nitsm/tsmcontext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 210036e..9c547e5 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -288,7 +288,7 @@ def global_data_exists(self, data_id: str) -> bool: def get_semiconductor_module_context_with_sites( self, - site_numbers: "_Sequence[int]" + site_numbers: list[int] ) -> "SemiconductorModuleContext": """Returns a Semiconductor Module context object which holds information and resources specific to the site_numbers mentioned. From 22e4c4a3ebd9f02e01608b1da866bda64804c181 Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Mon, 30 Mar 2026 18:08:57 +0530 Subject: [PATCH 10/26] Reapply "Update src/nitsm/tsmcontext.py " This reverts commit b2e716b0a50866b677b67bef958d297203a7f3b1. --- src/nitsm/tsmcontext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 9c547e5..210036e 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -288,7 +288,7 @@ def global_data_exists(self, data_id: str) -> bool: def get_semiconductor_module_context_with_sites( self, - site_numbers: list[int] + site_numbers: "_Sequence[int]" ) -> "SemiconductorModuleContext": """Returns a Semiconductor Module context object which holds information and resources specific to the site_numbers mentioned. From 6e82487d14294e9f0a7f1e78b54205cb5f193f1b Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Mon, 30 Mar 2026 18:09:03 +0530 Subject: [PATCH 11/26] Reapply "Update src/nitsm/tsmcontext.py " This reverts commit 3bec2bf15d4c091ad599c4eb08699481bdb43cc3. --- src/nitsm/tsmcontext.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 210036e..98c8978 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -298,7 +298,6 @@ def get_semiconductor_module_context_with_sites( Returns: Returns SemicondutorModuleContext object with resources specific to the site_number. """ - print("This is inside the function") return SemiconductorModuleContext(self._context.GetSemiconductorModuleContextWithSites(site_numbers)) # NI-Digital From 0bb839d8949cd89e1739c509c9a95fe45fe03797 Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Mon, 30 Mar 2026 18:09:10 +0530 Subject: [PATCH 12/26] Reapply "Update src/nitsm/tsmcontext.py " This reverts commit be9f63a8f8afed9bb011bdd122fe792f657451a2. --- src/nitsm/tsmcontext.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 98c8978..2e93c22 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -290,13 +290,13 @@ def get_semiconductor_module_context_with_sites( self, site_numbers: "_Sequence[int]" ) -> "SemiconductorModuleContext": - """Returns a Semiconductor Module context object which holds information and resources - specific to the site_numbers mentioned. + """Returns a Semiconductor Module context object which holds information and resources + specific to the specified site_numbers. Args: site_numbers: A sequence of site numbers for which the resources should be used. Returns: - Returns SemicondutorModuleContext object with resources specific to the site_number. + SemiconductorModuleContext object with resources specific to the specified site_numbers. """ return SemiconductorModuleContext(self._context.GetSemiconductorModuleContextWithSites(site_numbers)) From cf24d6f9a351296feb83e9f3e82b2069f1ed62a3 Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Mon, 30 Mar 2026 18:09:15 +0530 Subject: [PATCH 13/26] Reapply "Used dumb dispatch for TSM context with Sites and Test for checking tsm_context in kwargs" This reverts commit 78cc0ce2e3f734925bb016d59b0fc05fa8b67349. --- src/nitsm/codemoduleapi.py | 4 ++-- src/nitsm/tsmcontext.py | 36 ++++++++++++++++++++++++++++-------- tests/test_codemoduleapi.py | 23 ++++++++++++++++++++++- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/nitsm/codemoduleapi.py b/src/nitsm/codemoduleapi.py index c45564e..f6f75cd 100644 --- a/src/nitsm/codemoduleapi.py +++ b/src/nitsm/codemoduleapi.py @@ -43,7 +43,7 @@ def __call__(self, *args, **kwargs): argument = next(arguments_iter) # move to second argument except StopIteration: # Fallback: look for tsm context in kwargs by name - for key in ("context", "tsm_context", "SemiConductorModuleContext"): + for key in ("context", "tsm_context", "SemiconductorModuleContext"): if key in bound_arguments.arguments: argument = (key, bound_arguments.arguments[key]) break @@ -53,7 +53,7 @@ def __call__(self, *args, **kwargs): "The number of arguments to the code module is less than expected. It must " "accept as it's first argument the Semiconductor Module context passed from " "TestStand or another code module or it should be passed as a keyword argument," - " with keywords - 'context', 'tsm_context', or 'SemiConductorModuleContext'.", + " with keywords - 'context', 'tsm_context', or 'SemiconductorModuleContext'.", ) ) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 2e93c22..beb93db 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -286,19 +286,39 @@ def global_data_exists(self, data_id: str) -> bool: """ return self._context.GlobalDataExists(data_id) - def get_semiconductor_module_context_with_sites( - self, - site_numbers: "_Sequence[int]" - ) -> "SemiconductorModuleContext": + def get_semiconductor_module_context_with_sites(self,site_numbers: _Sequence[int]) -> "SemiconductorModuleContext": """Returns a Semiconductor Module context object which holds information and resources - specific to the specified site_numbers. + specific to the site_numbers mentioned. Args: site_numbers: A sequence of site numbers for which the resources should be used. + Returns: - SemiconductorModuleContext object with resources specific to the specified site_numbers. - """ - return SemiconductorModuleContext(self._context.GetSemiconductorModuleContextWithSites(site_numbers)) + SemiconductorModuleContext object with resources specific to the site_numbers. + """ + # Normalize and validate the site numbers before passing them to the underlying + # Semiconductor Module context. This ensures predictable behavior for invalid or + # empty site lists. + if not site_numbers: + raise ValueError("site_numbers must contain at least one site number.") + normalized_site_numbers = [] + + for site in site_numbers: + if not isinstance(site, int) or site < 0: + raise ValueError("Each site number must be a non-negative integer.") + normalized_site_numbers.append(site) + + # We have to use DumbDispatch here because pywin32 fails to recognize + # ISemiconductorModuleContext as deriving from IDispatch; most likely because it isn't + # natively supported. So, we fetch it as IUnknown instead. + dumb_context = win32com.client.dynamic.DumbDispatch(self._context) + + # Retrieve the SemiconductorModuleContext COM pointer for the selected sites + context_with_sites = dumb_context.GetSemiconductorModuleContextWithSites(normalized_site_numbers) + + # Wrap the cleaned IUnknown pointer in the Python SemiconductorModuleContext wrapper + return SemiconductorModuleContext(context_with_sites) + # NI-Digital diff --git a/tests/test_codemoduleapi.py b/tests/test_codemoduleapi.py index 5f6f38b..043935c 100644 --- a/tests/test_codemoduleapi.py +++ b/tests/test_codemoduleapi.py @@ -1,5 +1,6 @@ import re import pytest +from unittest.mock import MagicMock from nitsm.codemoduleapi import code_module, SemiconductorModuleContext @@ -56,7 +57,8 @@ def test_invalid_number_of_positional_arguments(self): assert e.value.args[0] == ( "The number of arguments to the code module is less than expected. It must " "accept as it's first argument the Semiconductor Module context passed from " - "TestStand or another code module.", + "TestStand or another code module or it should be passed as a keyword argument," + " with keywords - 'context', 'tsm_context', or 'SemiconductorModuleContext'.", ) # noinspection PyUnusedLocal @@ -84,6 +86,25 @@ def test_positional_arguments_after_tsm_context( ): assert isinstance(standalone_tsm_context_com_object, SemiconductorModuleContext) + + def test_tsm_context_via_kwargs(self): + raw_com_context = MagicMock(name="RawTSMContext") + + received_context = None + + @code_module + def my_module(tsm_context=None): + nonlocal received_context + received_context = tsm_context + return "converted" + + result = my_module(tsm_context=raw_com_context) + + # The function returned normally + assert result == "converted" + + # Check that the wrapper converted raw COM object → SemiconductorModuleContext + assert isinstance(received_context, SemiconductorModuleContext) @pytest.mark.pin_map("codemoduleapi.pinmap") @code_module From 73a5205cb667bb8ecb5b9e7f1b6b817c9698de58 Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Mon, 30 Mar 2026 18:09:20 +0530 Subject: [PATCH 14/26] Revert "Used dumb dispatch for TSM context with Sites and Test for checking tsm_context in kwargs" This reverts commit ffa316abfdf72e3d41dd7a035c08f44c5bb46c7b. --- src/nitsm/codemoduleapi.py | 4 ++-- src/nitsm/tsmcontext.py | 36 ++++++++---------------------------- tests/test_codemoduleapi.py | 23 +---------------------- 3 files changed, 11 insertions(+), 52 deletions(-) diff --git a/src/nitsm/codemoduleapi.py b/src/nitsm/codemoduleapi.py index f6f75cd..c45564e 100644 --- a/src/nitsm/codemoduleapi.py +++ b/src/nitsm/codemoduleapi.py @@ -43,7 +43,7 @@ def __call__(self, *args, **kwargs): argument = next(arguments_iter) # move to second argument except StopIteration: # Fallback: look for tsm context in kwargs by name - for key in ("context", "tsm_context", "SemiconductorModuleContext"): + for key in ("context", "tsm_context", "SemiConductorModuleContext"): if key in bound_arguments.arguments: argument = (key, bound_arguments.arguments[key]) break @@ -53,7 +53,7 @@ def __call__(self, *args, **kwargs): "The number of arguments to the code module is less than expected. It must " "accept as it's first argument the Semiconductor Module context passed from " "TestStand or another code module or it should be passed as a keyword argument," - " with keywords - 'context', 'tsm_context', or 'SemiconductorModuleContext'.", + " with keywords - 'context', 'tsm_context', or 'SemiConductorModuleContext'.", ) ) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index beb93db..2e93c22 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -286,39 +286,19 @@ def global_data_exists(self, data_id: str) -> bool: """ return self._context.GlobalDataExists(data_id) - def get_semiconductor_module_context_with_sites(self,site_numbers: _Sequence[int]) -> "SemiconductorModuleContext": + def get_semiconductor_module_context_with_sites( + self, + site_numbers: "_Sequence[int]" + ) -> "SemiconductorModuleContext": """Returns a Semiconductor Module context object which holds information and resources - specific to the site_numbers mentioned. + specific to the specified site_numbers. Args: site_numbers: A sequence of site numbers for which the resources should be used. - Returns: - SemiconductorModuleContext object with resources specific to the site_numbers. - """ - # Normalize and validate the site numbers before passing them to the underlying - # Semiconductor Module context. This ensures predictable behavior for invalid or - # empty site lists. - if not site_numbers: - raise ValueError("site_numbers must contain at least one site number.") - normalized_site_numbers = [] - - for site in site_numbers: - if not isinstance(site, int) or site < 0: - raise ValueError("Each site number must be a non-negative integer.") - normalized_site_numbers.append(site) - - # We have to use DumbDispatch here because pywin32 fails to recognize - # ISemiconductorModuleContext as deriving from IDispatch; most likely because it isn't - # natively supported. So, we fetch it as IUnknown instead. - dumb_context = win32com.client.dynamic.DumbDispatch(self._context) - - # Retrieve the SemiconductorModuleContext COM pointer for the selected sites - context_with_sites = dumb_context.GetSemiconductorModuleContextWithSites(normalized_site_numbers) - - # Wrap the cleaned IUnknown pointer in the Python SemiconductorModuleContext wrapper - return SemiconductorModuleContext(context_with_sites) - + SemiconductorModuleContext object with resources specific to the specified site_numbers. + """ + return SemiconductorModuleContext(self._context.GetSemiconductorModuleContextWithSites(site_numbers)) # NI-Digital diff --git a/tests/test_codemoduleapi.py b/tests/test_codemoduleapi.py index 043935c..5f6f38b 100644 --- a/tests/test_codemoduleapi.py +++ b/tests/test_codemoduleapi.py @@ -1,6 +1,5 @@ import re import pytest -from unittest.mock import MagicMock from nitsm.codemoduleapi import code_module, SemiconductorModuleContext @@ -57,8 +56,7 @@ def test_invalid_number_of_positional_arguments(self): assert e.value.args[0] == ( "The number of arguments to the code module is less than expected. It must " "accept as it's first argument the Semiconductor Module context passed from " - "TestStand or another code module or it should be passed as a keyword argument," - " with keywords - 'context', 'tsm_context', or 'SemiconductorModuleContext'.", + "TestStand or another code module.", ) # noinspection PyUnusedLocal @@ -86,25 +84,6 @@ def test_positional_arguments_after_tsm_context( ): assert isinstance(standalone_tsm_context_com_object, SemiconductorModuleContext) - - def test_tsm_context_via_kwargs(self): - raw_com_context = MagicMock(name="RawTSMContext") - - received_context = None - - @code_module - def my_module(tsm_context=None): - nonlocal received_context - received_context = tsm_context - return "converted" - - result = my_module(tsm_context=raw_com_context) - - # The function returned normally - assert result == "converted" - - # Check that the wrapper converted raw COM object → SemiconductorModuleContext - assert isinstance(received_context, SemiconductorModuleContext) @pytest.mark.pin_map("codemoduleapi.pinmap") @code_module From e9ca5ada75964df3a64f6c837441e4b4537148fc Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Mon, 30 Mar 2026 18:09:26 +0530 Subject: [PATCH 15/26] Revert "Update src/nitsm/tsmcontext.py " This reverts commit 51978c318f85a5751d726eb3c54f0c143bcb8fac. --- src/nitsm/tsmcontext.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 2e93c22..98c8978 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -290,13 +290,13 @@ def get_semiconductor_module_context_with_sites( self, site_numbers: "_Sequence[int]" ) -> "SemiconductorModuleContext": - """Returns a Semiconductor Module context object which holds information and resources - specific to the specified site_numbers. + """Returns a Semiconductor Module context object which holds information and resources + specific to the site_numbers mentioned. Args: site_numbers: A sequence of site numbers for which the resources should be used. Returns: - SemiconductorModuleContext object with resources specific to the specified site_numbers. + Returns SemicondutorModuleContext object with resources specific to the site_number. """ return SemiconductorModuleContext(self._context.GetSemiconductorModuleContextWithSites(site_numbers)) From e371832bd665e8cad2130b163b670584e0281972 Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Mon, 30 Mar 2026 18:09:30 +0530 Subject: [PATCH 16/26] Revert "Update src/nitsm/tsmcontext.py " This reverts commit 48cba717de4c91ba008a5eb21d02e960dc4f2019. --- src/nitsm/tsmcontext.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 98c8978..210036e 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -298,6 +298,7 @@ def get_semiconductor_module_context_with_sites( Returns: Returns SemicondutorModuleContext object with resources specific to the site_number. """ + print("This is inside the function") return SemiconductorModuleContext(self._context.GetSemiconductorModuleContextWithSites(site_numbers)) # NI-Digital From cfee7d58bf1fb0b1eb6f4d67ac969c5ee8073c9f Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Mon, 30 Mar 2026 18:09:33 +0530 Subject: [PATCH 17/26] Revert "Update src/nitsm/tsmcontext.py " This reverts commit 2fff250d9947e8c52ef2c1062b4845c6b27318f8. --- src/nitsm/tsmcontext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 210036e..9c547e5 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -288,7 +288,7 @@ def global_data_exists(self, data_id: str) -> bool: def get_semiconductor_module_context_with_sites( self, - site_numbers: "_Sequence[int]" + site_numbers: list[int] ) -> "SemiconductorModuleContext": """Returns a Semiconductor Module context object which holds information and resources specific to the site_numbers mentioned. From 2193d92ca5db1062556c0d3bc7d37ff6fd1fc82f Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Mon, 30 Mar 2026 18:09:38 +0530 Subject: [PATCH 18/26] Revert "Added get_semiconductor_module_context_with_sites and scan for tsm_context in kwargs" This reverts commit ef315a76920476fe6897528485fbb37617d199b1. --- src/nitsm/codemoduleapi.py | 19 ++++++------------- src/nitsm/tsmcontext.py | 15 --------------- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/src/nitsm/codemoduleapi.py b/src/nitsm/codemoduleapi.py index c45564e..dd5452e 100644 --- a/src/nitsm/codemoduleapi.py +++ b/src/nitsm/codemoduleapi.py @@ -42,20 +42,13 @@ def __call__(self, *args, **kwargs): if inspect.isclass(argument[1]): # class method check argument = next(arguments_iter) # move to second argument except StopIteration: - # Fallback: look for tsm context in kwargs by name - for key in ("context", "tsm_context", "SemiConductorModuleContext"): - if key in bound_arguments.arguments: - argument = (key, bound_arguments.arguments[key]) - break - else: - raise TypeError( - ( - "The number of arguments to the code module is less than expected. It must " - "accept as it's first argument the Semiconductor Module context passed from " - "TestStand or another code module or it should be passed as a keyword argument," - " with keywords - 'context', 'tsm_context', or 'SemiConductorModuleContext'.", - ) + raise TypeError( + ( + "The number of arguments to the code module is less than expected. It must " + "accept as it's first argument the Semiconductor Module context passed from " + "TestStand or another code module.", ) + ) # attempt to wrap argument in a SemiconductorModuleContext object argument_name, argument_value = argument diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 9c547e5..2b04bf1 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -286,21 +286,6 @@ def global_data_exists(self, data_id: str) -> bool: """ return self._context.GlobalDataExists(data_id) - def get_semiconductor_module_context_with_sites( - self, - site_numbers: list[int] - ) -> "SemiconductorModuleContext": - """Returns a Semiconductor Module context object which holds information and resources - specific to the site_numbers mentioned. - - Args: - site_numbers: A sequence of site numbers for which the resources should be used. - Returns: - Returns SemicondutorModuleContext object with resources specific to the site_number. - """ - print("This is inside the function") - return SemiconductorModuleContext(self._context.GetSemiconductorModuleContextWithSites(site_numbers)) - # NI-Digital def get_all_nidigital_instrument_names(self) -> "_StringTuple": From e717d23ae86ae49756b0d9bc9e35f5c8ae82db94 Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Tue, 31 Mar 2026 19:29:32 +0530 Subject: [PATCH 19/26] Reverted all the changes done earlier. Updated tsmcontext.py file with the get-context-with-sites method and added a test under 'test_multi_site.py' file with the corresponding pinmap --- tests/multi_site.pinmap | 27 +++++++++++++++++++++++++++ tests/test_multi_site.py | 21 +++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/multi_site.pinmap create mode 100644 tests/test_multi_site.py diff --git a/tests/multi_site.pinmap b/tests/multi_site.pinmap new file mode 100644 index 0000000..0b12940 --- /dev/null +++ b/tests/multi_site.pinmap @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_multi_site.py b/tests/test_multi_site.py new file mode 100644 index 0000000..24c42b0 --- /dev/null +++ b/tests/test_multi_site.py @@ -0,0 +1,21 @@ +import pytest +from nitsm.codemoduleapi import Capability, InstrumentTypeIdConstants +from nitsm.codemoduleapi import SemiconductorModuleContext + +@pytest.mark.pin_map("multi_site.pinmap") +class TestMultiSite: + pin_map_dut_pins = ["DUTPin1"] + pin_map_system_pins = ["SystemPin1", "SystemPin2"] + + def test_get_semiconductor_module_with_sites(self, standalone_tsm_context): + all_sites = standalone_tsm_context.site_numbers + # Get context for sites 1 and 3 + site_numbers = [1, 3] + filtered_tsm_context = standalone_tsm_context.get_semiconductor_module_context_with_sites(site_numbers) + filtered_sites = list(filtered_tsm_context.site_numbers) + + # Validate the site numbers + assert len(site_numbers) == len(filtered_sites) + assert site_numbers == filtered_sites + for site in site_numbers: + assert site in filtered_sites \ No newline at end of file From cc513cd90a09319a165868077df7a10aa46e04db Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Tue, 31 Mar 2026 19:30:05 +0530 Subject: [PATCH 20/26] Reverted all the changes done earlier. Updated tsmcontext.py file with the get-context-with-sites method and added a test under 'test_multi_site.py' file with the corresponding pinmap --- src/nitsm/tsmcontext.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index 2b04bf1..d67564b 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -208,7 +208,21 @@ def site_numbers(self) -> "_Tuple[int, ...]": return self._context.SiteNumbers # Site and Global Data + def get_semiconductor_module_context_with_sites(self, site_numbers: "_Sequence[int]") -> "SemiconductorModuleContext": + """Returns a Semiconductor Module context object which holds information and resources + specific to the site_numbers mentioned. + Args: + site_numbers: A sequence of site numbers for which the resources should be used. + + Returns: + SemicondutorModuleContext object with resources specific to the site_numbers. + """ + tsm_dispatch = self._context.GetSemiconductorModuleContextWithSites(site_numbers) + semiconductor_module_context_with_sites = SemiconductorModuleContext.__new__(SemiconductorModuleContext) + semiconductor_module_context_with_sites._context = tsm_dispatch + return semiconductor_module_context_with_sites + def set_site_data(self, data_id: str, data: "_Sequence[_Any]") -> None: """Associates a data item with each site. You can associate data with all sites or with the sub-set of sites in the Semiconductor Module context. You can use this method to store From f8eada432a42f5e727b700e8071b1a5439576a84 Mon Sep 17 00:00:00 2001 From: Prithieraj M R <142006822+prithierajmr@users.noreply.github.com> Date: Wed, 1 Apr 2026 13:14:06 +0530 Subject: [PATCH 21/26] Update src/nitsm/tsmcontext.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/nitsm/tsmcontext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index d67564b..ad4acf3 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -216,7 +216,7 @@ def get_semiconductor_module_context_with_sites(self, site_numbers: "_Sequence[i site_numbers: A sequence of site numbers for which the resources should be used. Returns: - SemicondutorModuleContext object with resources specific to the site_numbers. + SemiconductorModuleContext object with resources specific to the site_numbers. """ tsm_dispatch = self._context.GetSemiconductorModuleContextWithSites(site_numbers) semiconductor_module_context_with_sites = SemiconductorModuleContext.__new__(SemiconductorModuleContext) From 46373f2a23d294de93857a47d5dbb0037d9a9404 Mon Sep 17 00:00:00 2001 From: Prithieraj M R <142006822+prithierajmr@users.noreply.github.com> Date: Wed, 1 Apr 2026 13:17:54 +0530 Subject: [PATCH 22/26] Update tests/test_multi_site.py Remove unused imports Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tests/test_multi_site.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_multi_site.py b/tests/test_multi_site.py index 24c42b0..e647c35 100644 --- a/tests/test_multi_site.py +++ b/tests/test_multi_site.py @@ -1,9 +1,9 @@ import pytest -from nitsm.codemoduleapi import Capability, InstrumentTypeIdConstants -from nitsm.codemoduleapi import SemiconductorModuleContext + @pytest.mark.pin_map("multi_site.pinmap") class TestMultiSite: + pin_map_dut_pins = ["DUTPin1"] pin_map_dut_pins = ["DUTPin1"] pin_map_system_pins = ["SystemPin1", "SystemPin2"] From 5eaf01e62b1af1dfd2306370b17f557f857e9ada Mon Sep 17 00:00:00 2001 From: Prithieraj M R <142006822+prithierajmr@users.noreply.github.com> Date: Wed, 1 Apr 2026 14:41:18 +0530 Subject: [PATCH 23/26] Update tests/test_multi_site.py Increase the coverage of tests by calling other methods on the context Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tests/test_multi_site.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/test_multi_site.py b/tests/test_multi_site.py index e647c35..25403f1 100644 --- a/tests/test_multi_site.py +++ b/tests/test_multi_site.py @@ -13,9 +13,15 @@ def test_get_semiconductor_module_with_sites(self, standalone_tsm_context): site_numbers = [1, 3] filtered_tsm_context = standalone_tsm_context.get_semiconductor_module_context_with_sites(site_numbers) filtered_sites = list(filtered_tsm_context.site_numbers) - + # Validate the site numbers assert len(site_numbers) == len(filtered_sites) assert site_numbers == filtered_sites for site in site_numbers: - assert site in filtered_sites \ No newline at end of file + assert site in filtered_sites + + # Validate that a fully initialized SemiconductorModuleContext wrapper is returned + assert isinstance(filtered_tsm_context, SemiconductorModuleContext) + # Exercise another wrapper method to catch initialization regressions + pin_names = list(filtered_tsm_context.get_pin_names()) + assert isinstance(pin_names, list) \ No newline at end of file From 0fec9a2f63e832018bd6a0c1771a780dfe0a470d Mon Sep 17 00:00:00 2001 From: Prithieraj M R <142006822+prithierajmr@users.noreply.github.com> Date: Wed, 1 Apr 2026 14:46:50 +0530 Subject: [PATCH 24/26] Update tests/test_multi_site.py Remove all_sites, since they are not used anyway Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tests/test_multi_site.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_multi_site.py b/tests/test_multi_site.py index 25403f1..5e8a88d 100644 --- a/tests/test_multi_site.py +++ b/tests/test_multi_site.py @@ -8,7 +8,6 @@ class TestMultiSite: pin_map_system_pins = ["SystemPin1", "SystemPin2"] def test_get_semiconductor_module_with_sites(self, standalone_tsm_context): - all_sites = standalone_tsm_context.site_numbers # Get context for sites 1 and 3 site_numbers = [1, 3] filtered_tsm_context = standalone_tsm_context.get_semiconductor_module_context_with_sites(site_numbers) From a0a1c324b818e3d8889cc0f3d691234902b12b5b Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Wed, 1 Apr 2026 15:09:58 +0530 Subject: [PATCH 25/26] Ran black formatter on tsmcontext.py and added few additional checks in test_multi_site.py for validating the functionality --- src/nitsm/tsmcontext.py | 17 +++++++++++------ tests/test_multi_site.py | 11 +++++++---- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/nitsm/tsmcontext.py b/src/nitsm/tsmcontext.py index ad4acf3..e2e98e9 100644 --- a/src/nitsm/tsmcontext.py +++ b/src/nitsm/tsmcontext.py @@ -1,4 +1,5 @@ """TSM Context Wrapper""" + import ctypes.wintypes import time import typing @@ -208,21 +209,25 @@ def site_numbers(self) -> "_Tuple[int, ...]": return self._context.SiteNumbers # Site and Global Data - def get_semiconductor_module_context_with_sites(self, site_numbers: "_Sequence[int]") -> "SemiconductorModuleContext": - """Returns a Semiconductor Module context object which holds information and resources - specific to the site_numbers mentioned. + def get_semiconductor_module_context_with_sites( + self, site_numbers: "_Sequence[int]" + ) -> "SemiconductorModuleContext": + """Returns a Semiconductor Module context object which holds information and resources + specific to the site_numbers mentioned. Args: site_numbers: A sequence of site numbers for which the resources should be used. - + Returns: SemiconductorModuleContext object with resources specific to the site_numbers. """ tsm_dispatch = self._context.GetSemiconductorModuleContextWithSites(site_numbers) - semiconductor_module_context_with_sites = SemiconductorModuleContext.__new__(SemiconductorModuleContext) + semiconductor_module_context_with_sites = SemiconductorModuleContext.__new__( + SemiconductorModuleContext + ) semiconductor_module_context_with_sites._context = tsm_dispatch return semiconductor_module_context_with_sites - + def set_site_data(self, data_id: str, data: "_Sequence[_Any]") -> None: """Associates a data item with each site. You can associate data with all sites or with the sub-set of sites in the Semiconductor Module context. You can use this method to store diff --git a/tests/test_multi_site.py b/tests/test_multi_site.py index 5e8a88d..362c85a 100644 --- a/tests/test_multi_site.py +++ b/tests/test_multi_site.py @@ -1,11 +1,11 @@ import pytest - +from nitsm.codemoduleapi import SemiconductorModuleContext @pytest.mark.pin_map("multi_site.pinmap") class TestMultiSite: - pin_map_dut_pins = ["DUTPin1"] pin_map_dut_pins = ["DUTPin1"] pin_map_system_pins = ["SystemPin1", "SystemPin2"] + sites = 4 # [0, 1, 2, 3] def test_get_semiconductor_module_with_sites(self, standalone_tsm_context): # Get context for sites 1 and 3 @@ -22,5 +22,8 @@ def test_get_semiconductor_module_with_sites(self, standalone_tsm_context): # Validate that a fully initialized SemiconductorModuleContext wrapper is returned assert isinstance(filtered_tsm_context, SemiconductorModuleContext) # Exercise another wrapper method to catch initialization regressions - pin_names = list(filtered_tsm_context.get_pin_names()) - assert isinstance(pin_names, list) \ No newline at end of file + pin_names = list(filtered_tsm_context.get_pin_names()) # Should contain DUTPins and SystemPins as a tuple + assert isinstance(pin_names, list) + # Each item is a tuple, change it to list and compare + assert list(pin_names[0]) == self.pin_map_dut_pins + assert list(pin_names[1]) == self.pin_map_system_pins \ No newline at end of file From 9c95a1c872f1e1648aae251c65a8980ca28e17c8 Mon Sep 17 00:00:00 2001 From: Prithieraj M R Date: Mon, 6 Apr 2026 17:40:34 +0530 Subject: [PATCH 26/26] Lint fix - ran black --- tests/test_multi_site.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/test_multi_site.py b/tests/test_multi_site.py index 362c85a..f9891ed 100644 --- a/tests/test_multi_site.py +++ b/tests/test_multi_site.py @@ -1,16 +1,19 @@ import pytest from nitsm.codemoduleapi import SemiconductorModuleContext + @pytest.mark.pin_map("multi_site.pinmap") class TestMultiSite: pin_map_dut_pins = ["DUTPin1"] pin_map_system_pins = ["SystemPin1", "SystemPin2"] - sites = 4 # [0, 1, 2, 3] + sites = 4 # [0, 1, 2, 3] def test_get_semiconductor_module_with_sites(self, standalone_tsm_context): # Get context for sites 1 and 3 site_numbers = [1, 3] - filtered_tsm_context = standalone_tsm_context.get_semiconductor_module_context_with_sites(site_numbers) + filtered_tsm_context = standalone_tsm_context.get_semiconductor_module_context_with_sites( + site_numbers + ) filtered_sites = list(filtered_tsm_context.site_numbers) # Validate the site numbers @@ -22,8 +25,10 @@ def test_get_semiconductor_module_with_sites(self, standalone_tsm_context): # Validate that a fully initialized SemiconductorModuleContext wrapper is returned assert isinstance(filtered_tsm_context, SemiconductorModuleContext) # Exercise another wrapper method to catch initialization regressions - pin_names = list(filtered_tsm_context.get_pin_names()) # Should contain DUTPins and SystemPins as a tuple + pin_names = list( + filtered_tsm_context.get_pin_names() + ) # Should contain DUTPins and SystemPins as a tuple assert isinstance(pin_names, list) # Each item is a tuple, change it to list and compare assert list(pin_names[0]) == self.pin_map_dut_pins - assert list(pin_names[1]) == self.pin_map_system_pins \ No newline at end of file + assert list(pin_names[1]) == self.pin_map_system_pins