Skip to content

Commit 138ecb7

Browse files
author
Priyadarshini Piramanayagam
committed
Merge remote-tracking branch 'upstream/master' into users/priya/results-dataframe-utility
2 parents 18bd82b + dc4c718 commit 138ecb7

22 files changed

+1473
-10
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
<!--next-version-placeholder-->
44

5+
## v2.3.0 (2025-03-07)
6+
7+
### Feature
8+
9+
* Add steps APIs to the testmonitor client ([#96](https://github.com/ni/nisystemlink-clients-python/issues/96)) ([`85a676d`](https://github.com/ni/nisystemlink-clients-python/commit/85a676d000b68233b03339a943834d1054fbf2ab))
10+
11+
## v2.2.0 (2025-03-07)
12+
13+
### Feature
14+
15+
* Export products as dataframe ([#102](https://github.com/ni/nisystemlink-clients-python/issues/102)) ([`e5a41c0`](https://github.com/ni/nisystemlink-clients-python/commit/e5a41c0839cbd2412d613e78ac698f7000c32e99))
16+
517
## v2.1.0 (2025-03-06)
618

719
### Feature

docs/api_reference/testmonitor.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ nisystemlink.clients.testmonitor
1414
.. automethod:: update_results
1515
.. automethod:: delete_result
1616
.. automethod:: delete_results
17+
.. automethod:: create_steps
18+
.. automethod:: query_steps
19+
.. automethod:: query_step_values
20+
.. automethod:: delete_steps
21+
.. automethod:: delete_step
22+
.. automethod:: update_steps
23+
.. automethod:: get_steps
24+
.. automethod:: get_step
1725

1826
.. automodule:: nisystemlink.clients.testmonitor.models
1927
:members:

docs/getting_started.rst

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ Overview
261261
~~~~~~~~
262262

263263
The :class:`.TestMonitorClient` class is the primary entry point of the Test Monitor API
264-
used to interact with test results (Results).
264+
used to interact with test results (Results) and test steps (Steps).
265265

266266
When constructing a :class:`.TestMonitorClient`, you can pass an
267267
:class:`.HttpConfiguration` (like one retrieved from the
@@ -271,12 +271,19 @@ default connection. The default connection depends on your environment.
271271
With a :class:`.TestMonitorClient` object, you can:
272272

273273
* Create, update, query, and delete results
274+
* Create, update, query, and delete steps
274275

275276
Examples
276277
~~~~~~~~
277278

278279
Create, query, update, and delete some results
279280

280-
.. literalinclude:: ../examples/result/results.py
281+
.. literalinclude:: ../examples/testmonitor/results.py
282+
:language: python
283+
:linenos:
284+
285+
Create, update, query, and delete steps
286+
287+
.. literalinclude:: ../examples/testmonitor/steps.py
281288
:language: python
282289
:linenos:

examples/testmonitor/steps.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
from nisystemlink.clients.testmonitor import TestMonitorClient
2+
from nisystemlink.clients.testmonitor.models import (
3+
CreateResultRequest,
4+
CreateStepRequest,
5+
NamedValue,
6+
QueryStepsRequest,
7+
QueryStepValuesRequest,
8+
StepField,
9+
StepIdResultIdPair,
10+
UpdateStepRequest,
11+
)
12+
from nisystemlink.clients.testmonitor.models._status import Status
13+
from nisystemlink.clients.testmonitor.models._step_data import Measurement, StepData
14+
15+
16+
def create_test_result():
17+
"""Create example result on your server."""
18+
new_results = [
19+
CreateResultRequest(
20+
part_number="Example 123 AA",
21+
program_name="Example Name",
22+
host_name="Example Host",
23+
status=Status.PASSED(),
24+
keywords=["original keyword"],
25+
properties={"original property key": "yes"},
26+
)
27+
]
28+
create_response = client.create_results(new_results)
29+
return create_response
30+
31+
32+
# Server configuration is not required when used with Systemlink Client or run throught Jupyter on SLE
33+
server_configuration = None
34+
35+
# # Example of setting up the server configuration to point to your instance of SystemLink Enterprise
36+
# server_configuration = HttpConfiguration(
37+
# server_uri="https://yourserver.yourcompany.com",
38+
# api_key="YourAPIKeyGeneratedFromSystemLink",
39+
# )
40+
41+
client = TestMonitorClient(configuration=server_configuration)
42+
43+
# create a result to attach the steps to
44+
create_response = create_test_result()
45+
46+
# Create the step requests
47+
result_id = create_response.results[0].result_id
48+
step_requests = [
49+
CreateStepRequest(
50+
step_id="step1",
51+
name="step1",
52+
result_id=result_id,
53+
inputs=[
54+
NamedValue(name="Temperature", value="35"),
55+
NamedValue(name="Voltage", value="5"),
56+
],
57+
),
58+
CreateStepRequest(
59+
step_id="step2",
60+
name="step2",
61+
result_id=result_id,
62+
),
63+
]
64+
65+
# Create the steps
66+
create_response = client.create_steps(steps=step_requests)
67+
created_steps = create_response.steps
68+
print(create_response)
69+
70+
# You can query steps based on any field using DynamicLinq syntax.
71+
# These are just some representative examples.
72+
# Query based on result id
73+
query_response = client.query_steps(
74+
QueryStepsRequest(filter=f'resultId == "{result_id}"')
75+
)
76+
queried_steps = query_response.steps
77+
78+
# query step name using query step values
79+
query_values_response = client.query_step_values(
80+
QueryStepValuesRequest(
81+
filter=f'resultId == "{result_id}"',
82+
field=StepField.NAME,
83+
)
84+
)
85+
86+
# update the data of the step
87+
# extra properties of the measurements will be converted to string if not already a string
88+
update_response = client.update_steps(
89+
steps=[
90+
UpdateStepRequest(
91+
step_id=step.step_id,
92+
result_id=step.result_id,
93+
data=StepData(
94+
text="My output string",
95+
parameters=[
96+
Measurement(
97+
name="Temperature",
98+
status="Passed",
99+
measurement="35",
100+
lowLimit="30",
101+
highLimit="40",
102+
units="C",
103+
comparisonType="Numeric",
104+
spec_id="spec1",
105+
spec_info={
106+
"specKey": 10
107+
}, # will be converted to string as '{"specKey": 10}'
108+
)
109+
],
110+
),
111+
)
112+
for step in created_steps
113+
]
114+
)
115+
116+
# delete all steps at once
117+
delete_response = client.delete_steps(
118+
steps=[
119+
StepIdResultIdPair(step_id=step.step_id, result_id=step.result_id)
120+
for step in queried_steps
121+
]
122+
)
123+
124+
create_response = client.create_steps(steps=step_requests)
125+
created_steps = create_response.steps
126+
127+
# delete steps one by one
128+
for step in created_steps:
129+
if step.step_id and step.result_id:
130+
client.delete_step(result_id=step.result_id, step_id=step.step_id)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from ._dataframe_utilities import convert_products_to_dataframe
12
from ._file_utilities import get_products_linked_to_file
23

34
# flake8: noqa
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from typing import List
2+
3+
import pandas as pd
4+
from nisystemlink.clients.product.models import Product
5+
from pandas import DataFrame
6+
7+
8+
def convert_products_to_dataframe(products: List[Product]) -> DataFrame:
9+
"""Converts a list of products into a normalized dataframe.
10+
11+
Args:
12+
products (List[Product]): A list of products
13+
14+
Returns:
15+
DataFrame:
16+
- A Pandas DataFrame containing the product data. The DataFrame would consist of all the
17+
fields in the input products.
18+
- A new column would be created for unique properties across all products. The property
19+
columns would be named in the format `properties.property_name`.
20+
"""
21+
products_dict_representation = [
22+
product.dict(exclude_none=True) for product in products
23+
]
24+
normalized_products_dataframe = pd.json_normalize(
25+
products_dict_representation, sep="."
26+
)
27+
28+
return normalized_products_dataframe

0 commit comments

Comments
 (0)