Skip to content

Commit 0ada3d7

Browse files
authored
feat: Add client for Artifacts API (#70)
Signed-off-by: Vigneshwaran Selvaraj <vigneshwaran.selvaraj@ni.com>
1 parent b3fff6b commit 0ada3d7

File tree

7 files changed

+172
-0
lines changed

7 files changed

+172
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import io
2+
3+
from nisystemlink.clients.artifact import ArtifactClient
4+
from nisystemlink.clients.core import HttpConfiguration
5+
6+
7+
# Setup the server configuration to point to your instance of SystemLink Enterprise
8+
server_configuration = HttpConfiguration(
9+
server_uri="https://yourserver.yourcompany.com",
10+
api_key="YourAPIKeyGeneratedFromSystemLink",
11+
)
12+
client = ArtifactClient(configuration=server_configuration)
13+
14+
# Define the workspace and artifact content
15+
workspace = "your workspace ID"
16+
artifact_stream = io.BytesIO(b"test content")
17+
18+
# Upload the artifact
19+
upload_response = client.upload_artifact(workspace=workspace, artifact=artifact_stream)
20+
if upload_response and upload_response.id:
21+
print(f"Uploaded artifact ID: {upload_response.id}")
22+
23+
# Download the artifact using the ID from the upload response
24+
artifact_id = upload_response.id
25+
download_response = client.download_artifact(artifact_id)
26+
if download_response:
27+
downloaded_content = download_response.read()
28+
print(f"Downloaded artifact content: {downloaded_content.decode('utf-8')}")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from ._artifact_client import ArtifactClient
2+
3+
# flake8: noqa
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"""Implementation of ArtifactClient"""
2+
3+
from typing import BinaryIO, Optional
4+
5+
from nisystemlink.clients import core
6+
from nisystemlink.clients.core._uplink._base_client import BaseClient
7+
from nisystemlink.clients.core._uplink._methods import get, post, response_handler
8+
from nisystemlink.clients.core.helpers._iterator_file_like import IteratorFileLike
9+
from requests.models import Response
10+
from uplink import Part, Path
11+
12+
from . import models
13+
14+
15+
class ArtifactClient(BaseClient):
16+
def __init__(self, configuration: Optional[core.HttpConfiguration] = None):
17+
"""Initialize an instance.
18+
19+
Args:
20+
configuration: Defines the web server to connect to and information about
21+
how to connect. If not provided, the
22+
:class:`HttpConfigurationManager <nisystemlink.clients.core.HttpConfigurationManager>`
23+
is used to obtain the configuration.
24+
25+
Raises:
26+
ApiException: if unable to communicate with the Notebook execution Service.
27+
"""
28+
if configuration is None:
29+
configuration = core.HttpConfigurationManager.get_configuration()
30+
31+
super().__init__(configuration, base_path="/ninbartifact/v1/")
32+
33+
@post("artifacts")
34+
def __upload_artifact(
35+
self, workspace: Part, artifact: Part
36+
) -> models.UploadArtifactResponse:
37+
"""Uploads an artifact using multipart/form-data headers to send the file payload in the HTTP body.
38+
39+
Args:
40+
workspace: The workspace containing the artifact.
41+
artifact: The artifact to upload.
42+
43+
Returns:
44+
UploadArtifactResponse: The response containing the artifact ID.
45+
46+
"""
47+
48+
def upload_artifact(
49+
self, workspace: str, artifact: BinaryIO
50+
) -> models.UploadArtifactResponse:
51+
"""Uploads an artifact.
52+
53+
Args:
54+
workspace: The workspace containing the artifact.
55+
artifact: The artifact to upload.
56+
57+
Returns:
58+
UploadArtifactResponse: The response containing the artifact ID.
59+
60+
"""
61+
response = self.__upload_artifact(
62+
workspace=workspace,
63+
artifact=artifact,
64+
)
65+
66+
return response
67+
68+
def _iter_content_filelike_wrapper(response: Response) -> IteratorFileLike:
69+
return IteratorFileLike(response.iter_content(chunk_size=4096))
70+
71+
@response_handler(_iter_content_filelike_wrapper)
72+
@get("artifacts/{id}")
73+
def download_artifact(self, id: Path) -> IteratorFileLike:
74+
"""Downloads an artifact.
75+
76+
Args:
77+
id: The ID of the artifact to download.
78+
79+
Returns:
80+
A file-like object for reading the artifact content.
81+
82+
"""
83+
...
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from ._upload_artifact_response import UploadArtifactResponse
2+
3+
# flake8: noqa
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from nisystemlink.clients.core._uplink._json_model import JsonModel
2+
3+
4+
class UploadArtifactResponse(JsonModel):
5+
"""Response for an artifact upload request."""
6+
7+
id: str
8+
"""Information about the uploaded artifact."""
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# flake8: noqa
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import io
2+
import os
3+
4+
import pytest
5+
from nisystemlink.clients.artifact import ArtifactClient
6+
from nisystemlink.clients.core._http_configuration import HttpConfiguration
7+
8+
9+
@pytest.fixture(scope="class")
10+
def client(enterprise_config: HttpConfiguration) -> ArtifactClient:
11+
"""Fixture to create an ArtifactClient instance."""
12+
return ArtifactClient(enterprise_config)
13+
14+
15+
@pytest.mark.integration
16+
@pytest.mark.enterprise
17+
class TestArtifact:
18+
19+
def test__upload_artifact__artifact_uploaded(self, client: ArtifactClient):
20+
workspace = os.getenv("SYSTEMLINK_WORKSPACE_ID")
21+
22+
if workspace is not None:
23+
artifact_stream = io.BytesIO(b"test content")
24+
25+
response = client.upload_artifact(
26+
workspace=workspace, artifact=artifact_stream
27+
)
28+
29+
assert response is not None
30+
assert response.id is not None
31+
32+
def test__download_artifact__artifact_downloaded(self, client: ArtifactClient):
33+
workspace = os.getenv("SYSTEMLINK_WORKSPACE_ID")
34+
35+
if workspace is not None:
36+
artifact_content = b"test content"
37+
artifact_stream = io.BytesIO(artifact_content)
38+
39+
upload_response = client.upload_artifact(
40+
workspace=workspace, artifact=artifact_stream
41+
)
42+
artifact_id = upload_response.id
43+
download_response = client.download_artifact(artifact_id)
44+
45+
assert download_response is not None
46+
assert download_response.read() == artifact_content

0 commit comments

Comments
 (0)