Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ef315a7
Added get_semiconductor_module_context_with_sites and scan for tsm_co…
prithierajmr Feb 18, 2026
2fff250
Update src/nitsm/tsmcontext.py
prithierajmr Mar 9, 2026
48cba71
Update src/nitsm/tsmcontext.py
prithierajmr Mar 9, 2026
51978c3
Update src/nitsm/tsmcontext.py
prithierajmr Mar 9, 2026
ffa316a
Used dumb dispatch for TSM context with Sites and Test for checking t…
prithierajmr Mar 12, 2026
78cc0ce
Revert "Used dumb dispatch for TSM context with Sites and Test for ch…
prithierajmr Mar 30, 2026
be9f63a
Revert "Update src/nitsm/tsmcontext.py "
prithierajmr Mar 30, 2026
3bec2bf
Revert "Update src/nitsm/tsmcontext.py "
prithierajmr Mar 30, 2026
b2e716b
Revert "Update src/nitsm/tsmcontext.py "
prithierajmr Mar 30, 2026
22e4c4a
Reapply "Update src/nitsm/tsmcontext.py "
prithierajmr Mar 30, 2026
6e82487
Reapply "Update src/nitsm/tsmcontext.py "
prithierajmr Mar 30, 2026
0bb839d
Reapply "Update src/nitsm/tsmcontext.py "
prithierajmr Mar 30, 2026
cf24d6f
Reapply "Used dumb dispatch for TSM context with Sites and Test for c…
prithierajmr Mar 30, 2026
73a5205
Revert "Used dumb dispatch for TSM context with Sites and Test for ch…
prithierajmr Mar 30, 2026
e9ca5ad
Revert "Update src/nitsm/tsmcontext.py "
prithierajmr Mar 30, 2026
e371832
Revert "Update src/nitsm/tsmcontext.py "
prithierajmr Mar 30, 2026
cfee7d5
Revert "Update src/nitsm/tsmcontext.py "
prithierajmr Mar 30, 2026
2193d92
Revert "Added get_semiconductor_module_context_with_sites and scan fo…
prithierajmr Mar 30, 2026
e717d23
Reverted all the changes done earlier. Updated tsmcontext.py file wit…
prithierajmr Mar 31, 2026
cc513cd
Reverted all the changes done earlier. Updated tsmcontext.py file wit…
prithierajmr Mar 31, 2026
f8eada4
Update src/nitsm/tsmcontext.py
prithierajmr Apr 1, 2026
46373f2
Update tests/test_multi_site.py
prithierajmr Apr 1, 2026
5eaf01e
Update tests/test_multi_site.py
prithierajmr Apr 1, 2026
0fec9a2
Update tests/test_multi_site.py
prithierajmr Apr 1, 2026
a0a1c32
Ran black formatter on tsmcontext.py and added few additional checks …
prithierajmr Apr 1, 2026
9c95a1c
Lint fix - ran black
prithierajmr Apr 6, 2026
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
19 changes: 13 additions & 6 deletions src/nitsm/codemoduleapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"):
Comment thread
devin-roffman-emerson marked this conversation as resolved.
Outdated
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
Expand Down
34 changes: 34 additions & 0 deletions src/nitsm/tsmcontext.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,40 @@ 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":
"""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.
"""
# Normalize and validate the site numbers before passing them to the underlying
Comment thread
devin-roffman-emerson marked this conversation as resolved.
Outdated
# 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

def get_all_nidigital_instrument_names(self) -> "_StringTuple":
Expand Down
23 changes: 22 additions & 1 deletion tests/test_codemoduleapi.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import re
import pytest
from unittest.mock import MagicMock
from nitsm.codemoduleapi import code_module, SemiconductorModuleContext


Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down