Skip to content

Commit 18b4996

Browse files
committed
Merge branch 'master' of https://github.com/ni/nisystemlink-clients-python into users/santosh/tm-steps-client
2 parents 1181821 + 53f1188 commit 18b4996

37 files changed

+1590
-143
lines changed

CHANGELOG.md

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

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

5+
## v2.0.0 (2025-03-05)
6+
7+
### Feature
8+
9+
* Add and resolve query projection for products and specs respectively ([#97](https://github.com/ni/nisystemlink-clients-python/issues/97)) ([`e9feff6`](https://github.com/ni/nisystemlink-clients-python/commit/e9feff6dc3e473dd34cbb53739f1c96eb7a8db0e))
10+
11+
### Breaking
12+
13+
* Product and Specification models have been updated to support projections. - Product client changes-- - `models.Product` now defines all fields as Optional. - `ProductClient.create_product`'s `products` parameter is now typed as `models.CreateProductRequest` - `ProductClient.update_product`'s `products` parameter is now typed as `models.UpdateProductRequest` - Specifications client changes-- - `models.Specification` and `models.SpecificationDefinition` now define all fields as Optional. - `models.QuerySpecifications` has been renamed `models.PagedSpecifications` to better align to other clients. - `models.CreateSpecificationeRequest.specs` is now typed as `models.CreateSpecificationsRequestObject` instead of `models.SpecificationDefinition` - `models.UpdateSpecificationeRequest.specs` is now typed as `models.UpdateSpecificationsRequestObject` instead of `models.Specification` ([`e9feff6`](https://github.com/ni/nisystemlink-clients-python/commit/e9feff6dc3e473dd34cbb53739f1c96eb7a8db0e))
14+
515
## v1.10.0 (2025-02-13)
616

717
### Feature

docs/api_reference/testmonitor.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ nisystemlink.clients.testmonitor
77
:exclude-members: __init__
88

99
.. automethod:: __init__
10+
.. automethod:: create_results
11+
.. automethod:: get_results
12+
.. automethod:: query_results
13+
.. automethod:: query_result_values
14+
.. automethod:: update_results
15+
.. automethod:: delete_result
16+
.. automethod:: delete_results
1017

1118
.. automodule:: nisystemlink.clients.testmonitor.models
1219
:members:

docs/getting_started.rst

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,30 @@ Delete a feed.
253253
.. literalinclude:: ../examples/feeds/delete_feed.py
254254
:language: python
255255
:linenos:
256+
257+
TestMonitor API (Results)
258+
-------
259+
260+
Overview
261+
~~~~~~~~
262+
263+
The :class:`.TestMonitorClient` class is the primary entry point of the Test Monitor API
264+
used to interact with test results (Results).
265+
266+
When constructing a :class:`.TestMonitorClient`, you can pass an
267+
:class:`.HttpConfiguration` (like one retrieved from the
268+
:class:`.HttpConfigurationManager`), or let :class:`.TestMonitorClient` use the
269+
default connection. The default connection depends on your environment.
270+
271+
With a :class:`.TestMonitorClient` object, you can:
272+
273+
* Create, update, query, and delete results
274+
275+
Examples
276+
~~~~~~~~
277+
278+
Create, query, update, and delete some results
279+
280+
.. literalinclude:: ../examples/result/results.py
281+
:language: python
282+
:linenos:

examples/product/products.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from nisystemlink.clients.core import HttpConfiguration
22
from nisystemlink.clients.product import ProductClient
33
from nisystemlink.clients.product.models import (
4-
Product,
4+
CreateProductRequest,
55
ProductField,
6+
ProductOrderBy,
67
QueryProductsRequest,
78
QueryProductValuesRequest,
89
)
@@ -14,14 +15,14 @@
1415
def create_some_products():
1516
"""Create two example products on your server."""
1617
new_products = [
17-
Product(
18+
CreateProductRequest(
1819
part_number="Example 123 AA",
1920
name=name,
2021
family=family,
2122
keywords=["original keyword"],
2223
properties={"original property key": "yes"},
2324
),
24-
Product(
25+
CreateProductRequest(
2526
part_number="Example 123 AA1",
2627
name=name,
2728
family=family,
@@ -58,9 +59,9 @@ def create_some_products():
5859
query_request = QueryProductsRequest(
5960
filter=f'family="{family}" && name="{name}"',
6061
return_count=True,
61-
order_by=ProductField.FAMILY,
62+
order_by=ProductOrderBy.FAMILY,
6263
)
63-
response = client.query_products_paged(query_request)
64+
query_response = client.query_products_paged(query_request)
6465

6566
# Update the first product that you just created and replace the keywords
6667
updated_product = create_response.products[0]

examples/spec/update_and_delete_specs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,4 @@
5656
# query all specs
5757
response = client.query_specs(QuerySpecificationsRequest(product_ids=[product]))
5858
if response.specs:
59-
client.delete_specs(ids=[spec.id for spec in response.specs])
59+
client.delete_specs(ids=[spec.id for spec in response.specs if spec.id])

examples/testmonitor/results.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
from nisystemlink.clients.testmonitor import TestMonitorClient
2+
from nisystemlink.clients.testmonitor.models import (
3+
CreateResultRequest,
4+
QueryResultsRequest,
5+
QueryResultValuesRequest,
6+
ResultField,
7+
Status,
8+
StatusType,
9+
)
10+
11+
program_name = "Example Name"
12+
host_name = "Example Host"
13+
status_type = StatusType.PASSED
14+
15+
16+
def create_some_results():
17+
"""Create two example results on your server."""
18+
new_results = [
19+
CreateResultRequest(
20+
part_number="Example 123 AA",
21+
program_name=program_name,
22+
host_name=host_name,
23+
status=Status.PASSED(),
24+
keywords=["original keyword"],
25+
properties={"original property key": "yes"},
26+
),
27+
CreateResultRequest(
28+
part_number="Example 123 AA1",
29+
program_name=program_name,
30+
host_name=host_name,
31+
status=Status(status_type=StatusType.CUSTOM, status_name="Custom"),
32+
keywords=["original keyword"],
33+
properties={"original property key": "original"},
34+
),
35+
]
36+
create_response = client.create_results(new_results)
37+
return create_response
38+
39+
40+
# Server configuration is not required when used with Systemlink Client or run throught Jupyter on SLE
41+
server_configuration = None
42+
43+
# # Example of setting up the server configuration to point to your instance of SystemLink Enterprise
44+
# server_configuration = HttpConfiguration(
45+
# server_uri="https://yourserver.yourcompany.com",
46+
# api_key="YourAPIKeyGeneratedFromSystemLink",
47+
# )
48+
49+
client = TestMonitorClient(configuration=server_configuration)
50+
51+
create_response = create_some_results()
52+
53+
# Get all the results using the continuation token in batches of 100 at a time.
54+
response = client.get_results(take=100, return_count=True)
55+
all_results = response.results
56+
while response.continuation_token:
57+
response = client.get_results(
58+
take=100, continuation_token=response.continuation_token, return_count=True
59+
)
60+
all_results.extend(response.results)
61+
62+
# use get for first result created
63+
created_result = client.get_result(create_response.results[0].id)
64+
65+
# Query results without continuation
66+
query_request = QueryResultsRequest(
67+
filter=f'status.statusType="{status_type.value}"', return_count=True
68+
)
69+
response = client.query_results(query_request)
70+
71+
# Update the first result that you just created and replace the keywords
72+
updated_result = create_response.results[0]
73+
updated_result.keywords = ["new keyword"]
74+
updated_result.properties = {"new property key": "new value"}
75+
update_response = client.update_results([create_response.results[0]], replace=True)
76+
77+
# Query for just the ids of results that match the family
78+
values_query = QueryResultValuesRequest(
79+
filter=f'programName="{program_name}"', field=ResultField.ID
80+
)
81+
values_response = client.query_result_values(query=values_query)
82+
83+
# delete each created result individually by id
84+
for result in create_response.results:
85+
client.delete_result(result.id)
86+
87+
# Create some more and delete them with a single call to delete.
88+
create_response = create_some_results()
89+
client.delete_results([result.id for result in create_response.results])

nisystemlink/clients/feeds/_feeds_client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
from nisystemlink.clients import core
66
from nisystemlink.clients.core._uplink._base_client import BaseClient
77
from nisystemlink.clients.core._uplink._methods import delete, get, post
8-
from uplink import Part, Path, Query
8+
from uplink import Part, Path, Query, retry
99

1010
from . import models
1111

1212

13+
@retry(when=retry.when.status(429), stop=retry.stop.after_attempt(5))
1314
class FeedsClient(BaseClient):
1415
def __init__(self, configuration: Optional[core.HttpConfiguration] = None):
1516
"""Initialize an instance.

nisystemlink/clients/product/_product_client.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
from nisystemlink.clients import core
66
from nisystemlink.clients.core._uplink._base_client import BaseClient
77
from nisystemlink.clients.core._uplink._methods import delete, get, post
8-
from nisystemlink.clients.product.models import Product
9-
from uplink import Field, Query, returns
8+
from uplink import Field, Query, retry, returns
109

1110
from . import models
1211

1312

13+
@retry(
14+
when=retry.when.status([408, 429, 502, 503, 504]), stop=retry.stop.after_attempt(5)
15+
)
1416
class ProductClient(BaseClient):
1517
def __init__(self, configuration: Optional[core.HttpConfiguration] = None):
1618
"""Initialize an instance.
@@ -30,7 +32,7 @@ def __init__(self, configuration: Optional[core.HttpConfiguration] = None):
3032

3133
@post("products", args=[Field("products")])
3234
def create_products(
33-
self, products: List[Product]
35+
self, products: List[models.CreateProductRequest]
3436
) -> models.CreateProductsPartialSuccess:
3537
"""Creates one or more products and returns errors for failed creations.
3638
@@ -128,7 +130,7 @@ def query_product_values(
128130

129131
@post("update-products", args=[Field("products"), Field("replace")])
130132
def update_products(
131-
self, products: List[Product], replace: bool = False
133+
self, products: List[models.UpdateProductRequest], replace: bool = False
132134
) -> models.CreateProductsPartialSuccess:
133135
"""Updates a list of products with optional field replacement.
134136
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
from ._product import Product
21
from ._create_products_partial_success import CreateProductsPartialSuccess
32
from ._delete_products_partial_success import DeleteProductsPartialSuccess
43
from ._paged_products import PagedProducts
54
from ._query_products_request import (
6-
QueryProductsRequest,
75
ProductField,
6+
ProductOrderBy,
7+
ProductProjection,
8+
QueryProductsRequest,
89
QueryProductValuesRequest,
910
)
11+
from ._product import Product
12+
from ._product_request import CreateProductRequest, UpdateProductRequest
1013

1114
# flake8: noqa

nisystemlink/clients/product/models/_create_products_partial_success.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,21 @@
22

33
from nisystemlink.clients.core import ApiError
44
from nisystemlink.clients.core._uplink._json_model import JsonModel
5-
from nisystemlink.clients.product.models import Product
5+
from nisystemlink.clients.product.models._product import Product
6+
from nisystemlink.clients.product.models._product_request import CreateProductRequest
67

78

89
class CreateProductsPartialSuccess(JsonModel):
910
products: List[Product]
1011
"""The list of products that were successfully created."""
1112

12-
failed: Optional[List[Product]] = None
13+
failed: Optional[List[CreateProductRequest]]
1314
"""The list of products that were not created.
1415
1516
If this is `None`, then all products were successfully created.
1617
"""
1718

18-
error: Optional[ApiError] = None
19+
error: Optional[ApiError]
1920
"""Error messages for products that were not created.
2021
2122
If this is `None`, then all products were successfully created.

0 commit comments

Comments
 (0)