hiddenlayer-sdk 1.0.0__py3-none-any.whl → 1.1.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- hiddenlayer/sdk/constants.py +1 -0
- hiddenlayer/sdk/models.py +2 -2
- hiddenlayer/sdk/rest/__init__.py +1 -1
- hiddenlayer/sdk/rest/api/sensor_api.py +11 -23
- hiddenlayer/sdk/rest/models/__init__.py +1 -1
- hiddenlayer/sdk/rest/models/file_scan_report_v3.py +42 -5
- hiddenlayer/sdk/rest/models/file_scan_reports_v3.py +95 -0
- hiddenlayer/sdk/rest/models/scan_report_v3.py +3 -3
- hiddenlayer/sdk/rest/models/sensor_sor_model_card_response.py +1 -1
- hiddenlayer/sdk/services/model.py +46 -1
- hiddenlayer/sdk/services/model_scan.py +1 -1
- hiddenlayer/sdk/version.py +1 -1
- {hiddenlayer_sdk-1.0.0.dist-info → hiddenlayer_sdk-1.1.0.dist-info}/METADATA +2 -2
- {hiddenlayer_sdk-1.0.0.dist-info → hiddenlayer_sdk-1.1.0.dist-info}/RECORD +17 -17
- {hiddenlayer_sdk-1.0.0.dist-info → hiddenlayer_sdk-1.1.0.dist-info}/WHEEL +1 -1
- hiddenlayer/sdk/rest/models/file_results_inner.py +0 -121
- {hiddenlayer_sdk-1.0.0.dist-info → hiddenlayer_sdk-1.1.0.dist-info}/LICENSE +0 -0
- {hiddenlayer_sdk-1.0.0.dist-info → hiddenlayer_sdk-1.1.0.dist-info}/top_level.txt +0 -0
hiddenlayer/sdk/constants.py
CHANGED
hiddenlayer/sdk/models.py
CHANGED
@@ -9,7 +9,7 @@ from hiddenlayer.sdk.rest.models import (
|
|
9
9
|
ModelInventoryInfo,
|
10
10
|
ScanReportV3,
|
11
11
|
)
|
12
|
-
from hiddenlayer.sdk.rest.models.
|
12
|
+
from hiddenlayer.sdk.rest.models.file_scan_report_v3 import FileScanReportV3
|
13
13
|
from hiddenlayer.sdk.rest.models.sarif210 import Sarif210
|
14
14
|
|
15
15
|
|
@@ -50,7 +50,7 @@ class EmptyScanResults(ScanResults):
|
|
50
50
|
start_time: datetime = datetime.now()
|
51
51
|
end_time: Optional[datetime] = datetime.now()
|
52
52
|
severity: Optional[StrictStr] = ""
|
53
|
-
file_results: Optional[List[
|
53
|
+
file_results: Optional[List[FileScanReportV3]] = []
|
54
54
|
|
55
55
|
|
56
56
|
class Sarif(Sarif210):
|
hiddenlayer/sdk/rest/__init__.py
CHANGED
@@ -54,8 +54,8 @@ from hiddenlayer.sdk.rest.models.external_properties import ExternalProperties
|
|
54
54
|
from hiddenlayer.sdk.rest.models.external_property_file_reference import ExternalPropertyFileReference
|
55
55
|
from hiddenlayer.sdk.rest.models.external_property_file_references import ExternalPropertyFileReferences
|
56
56
|
from hiddenlayer.sdk.rest.models.file_details_v3 import FileDetailsV3
|
57
|
-
from hiddenlayer.sdk.rest.models.file_results_inner import FileResultsInner
|
58
57
|
from hiddenlayer.sdk.rest.models.file_scan_report_v3 import FileScanReportV3
|
58
|
+
from hiddenlayer.sdk.rest.models.file_scan_reports_v3 import FileScanReportsV3
|
59
59
|
from hiddenlayer.sdk.rest.models.fix import Fix
|
60
60
|
from hiddenlayer.sdk.rest.models.get_multipart_upload_response import GetMultipartUploadResponse
|
61
61
|
from hiddenlayer.sdk.rest.models.graph import Graph
|
@@ -17,7 +17,7 @@ from typing import Any, Dict, List, Optional, Tuple, Union
|
|
17
17
|
from typing_extensions import Annotated
|
18
18
|
|
19
19
|
from pydantic import Field, StrictFloat, StrictInt, StrictStr, field_validator
|
20
|
-
from typing import Any,
|
20
|
+
from typing import Any, Optional, Union
|
21
21
|
from typing_extensions import Annotated
|
22
22
|
from hiddenlayer.sdk.rest.models.create_sensor_request import CreateSensorRequest
|
23
23
|
from hiddenlayer.sdk.rest.models.get_multipart_upload_response import GetMultipartUploadResponse
|
@@ -334,7 +334,7 @@ class SensorApi:
|
|
334
334
|
_content_type: Optional[StrictStr] = None,
|
335
335
|
_headers: Optional[Dict[StrictStr, Any]] = None,
|
336
336
|
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
337
|
-
) ->
|
337
|
+
) -> None:
|
338
338
|
"""Complete Multipart Upload
|
339
339
|
|
340
340
|
|
@@ -374,7 +374,7 @@ class SensorApi:
|
|
374
374
|
)
|
375
375
|
|
376
376
|
_response_types_map: Dict[str, Optional[str]] = {
|
377
|
-
'200':
|
377
|
+
'200': None,
|
378
378
|
'400': None,
|
379
379
|
}
|
380
380
|
response_data = self.api_client.call_api(
|
@@ -405,7 +405,7 @@ class SensorApi:
|
|
405
405
|
_content_type: Optional[StrictStr] = None,
|
406
406
|
_headers: Optional[Dict[StrictStr, Any]] = None,
|
407
407
|
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
408
|
-
) -> ApiResponse[
|
408
|
+
) -> ApiResponse[None]:
|
409
409
|
"""Complete Multipart Upload
|
410
410
|
|
411
411
|
|
@@ -445,7 +445,7 @@ class SensorApi:
|
|
445
445
|
)
|
446
446
|
|
447
447
|
_response_types_map: Dict[str, Optional[str]] = {
|
448
|
-
'200':
|
448
|
+
'200': None,
|
449
449
|
'400': None,
|
450
450
|
}
|
451
451
|
response_data = self.api_client.call_api(
|
@@ -516,7 +516,7 @@ class SensorApi:
|
|
516
516
|
)
|
517
517
|
|
518
518
|
_response_types_map: Dict[str, Optional[str]] = {
|
519
|
-
'200':
|
519
|
+
'200': None,
|
520
520
|
'400': None,
|
521
521
|
}
|
522
522
|
response_data = self.api_client.call_api(
|
@@ -559,12 +559,6 @@ class SensorApi:
|
|
559
559
|
# process the body parameter
|
560
560
|
|
561
561
|
|
562
|
-
# set the HTTP header `Accept`
|
563
|
-
_header_params['Accept'] = self.api_client.select_header_accept(
|
564
|
-
[
|
565
|
-
'application/json'
|
566
|
-
]
|
567
|
-
)
|
568
562
|
|
569
563
|
|
570
564
|
# authentication setting
|
@@ -1998,7 +1992,7 @@ class SensorApi:
|
|
1998
1992
|
_content_type: Optional[StrictStr] = None,
|
1999
1993
|
_headers: Optional[Dict[StrictStr, Any]] = None,
|
2000
1994
|
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
2001
|
-
) ->
|
1995
|
+
) -> None:
|
2002
1996
|
"""Upload part
|
2003
1997
|
|
2004
1998
|
|
@@ -2044,7 +2038,7 @@ class SensorApi:
|
|
2044
2038
|
)
|
2045
2039
|
|
2046
2040
|
_response_types_map: Dict[str, Optional[str]] = {
|
2047
|
-
'200':
|
2041
|
+
'200': None,
|
2048
2042
|
'400': None,
|
2049
2043
|
}
|
2050
2044
|
response_data = self.api_client.call_api(
|
@@ -2077,7 +2071,7 @@ class SensorApi:
|
|
2077
2071
|
_content_type: Optional[StrictStr] = None,
|
2078
2072
|
_headers: Optional[Dict[StrictStr, Any]] = None,
|
2079
2073
|
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
2080
|
-
) -> ApiResponse[
|
2074
|
+
) -> ApiResponse[None]:
|
2081
2075
|
"""Upload part
|
2082
2076
|
|
2083
2077
|
|
@@ -2123,7 +2117,7 @@ class SensorApi:
|
|
2123
2117
|
)
|
2124
2118
|
|
2125
2119
|
_response_types_map: Dict[str, Optional[str]] = {
|
2126
|
-
'200':
|
2120
|
+
'200': None,
|
2127
2121
|
'400': None,
|
2128
2122
|
}
|
2129
2123
|
response_data = self.api_client.call_api(
|
@@ -2202,7 +2196,7 @@ class SensorApi:
|
|
2202
2196
|
)
|
2203
2197
|
|
2204
2198
|
_response_types_map: Dict[str, Optional[str]] = {
|
2205
|
-
'200':
|
2199
|
+
'200': None,
|
2206
2200
|
'400': None,
|
2207
2201
|
}
|
2208
2202
|
response_data = self.api_client.call_api(
|
@@ -2251,12 +2245,6 @@ class SensorApi:
|
|
2251
2245
|
_body_params = body
|
2252
2246
|
|
2253
2247
|
|
2254
|
-
# set the HTTP header `Accept`
|
2255
|
-
_header_params['Accept'] = self.api_client.select_header_accept(
|
2256
|
-
[
|
2257
|
-
'application/json'
|
2258
|
-
]
|
2259
|
-
)
|
2260
2248
|
|
2261
2249
|
# set the HTTP header `Content-Type`
|
2262
2250
|
if _content_type:
|
@@ -32,8 +32,8 @@ from hiddenlayer.sdk.rest.models.external_properties import ExternalProperties
|
|
32
32
|
from hiddenlayer.sdk.rest.models.external_property_file_reference import ExternalPropertyFileReference
|
33
33
|
from hiddenlayer.sdk.rest.models.external_property_file_references import ExternalPropertyFileReferences
|
34
34
|
from hiddenlayer.sdk.rest.models.file_details_v3 import FileDetailsV3
|
35
|
-
from hiddenlayer.sdk.rest.models.file_results_inner import FileResultsInner
|
36
35
|
from hiddenlayer.sdk.rest.models.file_scan_report_v3 import FileScanReportV3
|
36
|
+
from hiddenlayer.sdk.rest.models.file_scan_reports_v3 import FileScanReportsV3
|
37
37
|
from hiddenlayer.sdk.rest.models.fix import Fix
|
38
38
|
from hiddenlayer.sdk.rest.models.get_multipart_upload_response import GetMultipartUploadResponse
|
39
39
|
from hiddenlayer.sdk.rest.models.graph import Graph
|
@@ -17,9 +17,11 @@ import pprint
|
|
17
17
|
import re # noqa: F401
|
18
18
|
import json
|
19
19
|
|
20
|
-
from
|
20
|
+
from datetime import datetime
|
21
|
+
from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator
|
21
22
|
from typing import Any, ClassVar, Dict, List, Optional
|
22
|
-
from hiddenlayer.sdk.rest.models.
|
23
|
+
from hiddenlayer.sdk.rest.models.file_details_v3 import FileDetailsV3
|
24
|
+
from hiddenlayer.sdk.rest.models.scan_detection_v3 import ScanDetectionV3
|
23
25
|
from typing import Optional, Set
|
24
26
|
from typing_extensions import Self
|
25
27
|
|
@@ -27,8 +29,23 @@ class FileScanReportV3(BaseModel):
|
|
27
29
|
"""
|
28
30
|
FileScanReportV3
|
29
31
|
""" # noqa: E501
|
30
|
-
|
31
|
-
|
32
|
+
file_instance_id: StrictStr = Field(description="unique ID of the file")
|
33
|
+
file_location: StrictStr = Field(description="full file path")
|
34
|
+
start_time: datetime = Field(description="time the scan started")
|
35
|
+
end_time: datetime = Field(description="time the scan ended")
|
36
|
+
details: FileDetailsV3
|
37
|
+
status: StrictStr = Field(description="status of the scan")
|
38
|
+
seen: datetime = Field(description="time the scan was seen at")
|
39
|
+
detections: Optional[List[ScanDetectionV3]] = None
|
40
|
+
file_results: Optional[List[FileScanReportV3]] = None
|
41
|
+
__properties: ClassVar[List[str]] = ["file_instance_id", "file_location", "start_time", "end_time", "details", "status", "seen", "detections", "file_results"]
|
42
|
+
|
43
|
+
@field_validator('status')
|
44
|
+
def status_validate_enum(cls, value):
|
45
|
+
"""Validates the enum"""
|
46
|
+
if value not in set(['skipped', 'pending', 'running', 'done', 'failed', 'canceled']):
|
47
|
+
raise ValueError("must be one of enum values ('skipped', 'pending', 'running', 'done', 'failed', 'canceled')")
|
48
|
+
return value
|
32
49
|
|
33
50
|
model_config = ConfigDict(
|
34
51
|
populate_by_name=True,
|
@@ -69,6 +86,16 @@ class FileScanReportV3(BaseModel):
|
|
69
86
|
exclude=excluded_fields,
|
70
87
|
exclude_none=True,
|
71
88
|
)
|
89
|
+
# override the default output from pydantic by calling `to_dict()` of details
|
90
|
+
if self.details:
|
91
|
+
_dict['details'] = self.details.to_dict()
|
92
|
+
# override the default output from pydantic by calling `to_dict()` of each item in detections (list)
|
93
|
+
_items = []
|
94
|
+
if self.detections:
|
95
|
+
for _item in self.detections:
|
96
|
+
if _item:
|
97
|
+
_items.append(_item.to_dict())
|
98
|
+
_dict['detections'] = _items
|
72
99
|
# override the default output from pydantic by calling `to_dict()` of each item in file_results (list)
|
73
100
|
_items = []
|
74
101
|
if self.file_results:
|
@@ -88,8 +115,18 @@ class FileScanReportV3(BaseModel):
|
|
88
115
|
return cls.model_validate(obj)
|
89
116
|
|
90
117
|
_obj = cls.model_validate({
|
91
|
-
"
|
118
|
+
"file_instance_id": obj.get("file_instance_id"),
|
119
|
+
"file_location": obj.get("file_location"),
|
120
|
+
"start_time": obj.get("start_time"),
|
121
|
+
"end_time": obj.get("end_time"),
|
122
|
+
"details": FileDetailsV3.from_dict(obj["details"]) if obj.get("details") is not None else None,
|
123
|
+
"status": obj.get("status"),
|
124
|
+
"seen": obj.get("seen"),
|
125
|
+
"detections": [ScanDetectionV3.from_dict(_item) for _item in obj["detections"]] if obj.get("detections") is not None else None,
|
126
|
+
"file_results": [FileScanReportV3.from_dict(_item) for _item in obj["file_results"]] if obj.get("file_results") is not None else None
|
92
127
|
})
|
93
128
|
return _obj
|
94
129
|
|
130
|
+
# TODO: Rewrite to not use raise_errors
|
131
|
+
FileScanReportV3.model_rebuild(raise_errors=False)
|
95
132
|
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
"""
|
4
|
+
HiddenLayer ModelScan V2
|
5
|
+
|
6
|
+
HiddenLayer ModelScan API for scanning of models
|
7
|
+
|
8
|
+
The version of the OpenAPI document: 1
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
10
|
+
|
11
|
+
Do not edit the class manually.
|
12
|
+
""" # noqa: E501
|
13
|
+
|
14
|
+
|
15
|
+
from __future__ import annotations
|
16
|
+
import pprint
|
17
|
+
import re # noqa: F401
|
18
|
+
import json
|
19
|
+
|
20
|
+
from pydantic import BaseModel, ConfigDict
|
21
|
+
from typing import Any, ClassVar, Dict, List, Optional
|
22
|
+
from hiddenlayer.sdk.rest.models.file_scan_report_v3 import FileScanReportV3
|
23
|
+
from typing import Optional, Set
|
24
|
+
from typing_extensions import Self
|
25
|
+
|
26
|
+
class FileScanReportsV3(BaseModel):
|
27
|
+
"""
|
28
|
+
FileScanReportsV3
|
29
|
+
""" # noqa: E501
|
30
|
+
file_results: Optional[List[FileScanReportV3]] = None
|
31
|
+
__properties: ClassVar[List[str]] = ["file_results"]
|
32
|
+
|
33
|
+
model_config = ConfigDict(
|
34
|
+
populate_by_name=True,
|
35
|
+
validate_assignment=True,
|
36
|
+
protected_namespaces=(),
|
37
|
+
)
|
38
|
+
|
39
|
+
|
40
|
+
def to_str(self) -> str:
|
41
|
+
"""Returns the string representation of the model using alias"""
|
42
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
43
|
+
|
44
|
+
def to_json(self) -> str:
|
45
|
+
"""Returns the JSON representation of the model using alias"""
|
46
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
47
|
+
return json.dumps(self.to_dict())
|
48
|
+
|
49
|
+
@classmethod
|
50
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
51
|
+
"""Create an instance of FileScanReportsV3 from a JSON string"""
|
52
|
+
return cls.from_dict(json.loads(json_str))
|
53
|
+
|
54
|
+
def to_dict(self) -> Dict[str, Any]:
|
55
|
+
"""Return the dictionary representation of the model using alias.
|
56
|
+
|
57
|
+
This has the following differences from calling pydantic's
|
58
|
+
`self.model_dump(by_alias=True)`:
|
59
|
+
|
60
|
+
* `None` is only added to the output dict for nullable fields that
|
61
|
+
were set at model initialization. Other fields with value `None`
|
62
|
+
are ignored.
|
63
|
+
"""
|
64
|
+
excluded_fields: Set[str] = set([
|
65
|
+
])
|
66
|
+
|
67
|
+
_dict = self.model_dump(
|
68
|
+
by_alias=True,
|
69
|
+
exclude=excluded_fields,
|
70
|
+
exclude_none=True,
|
71
|
+
)
|
72
|
+
# override the default output from pydantic by calling `to_dict()` of each item in file_results (list)
|
73
|
+
_items = []
|
74
|
+
if self.file_results:
|
75
|
+
for _item in self.file_results:
|
76
|
+
if _item:
|
77
|
+
_items.append(_item.to_dict())
|
78
|
+
_dict['file_results'] = _items
|
79
|
+
return _dict
|
80
|
+
|
81
|
+
@classmethod
|
82
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
83
|
+
"""Create an instance of FileScanReportsV3 from a dict"""
|
84
|
+
if obj is None:
|
85
|
+
return None
|
86
|
+
|
87
|
+
if not isinstance(obj, dict):
|
88
|
+
return cls.model_validate(obj)
|
89
|
+
|
90
|
+
_obj = cls.model_validate({
|
91
|
+
"file_results": [FileScanReportV3.from_dict(_item) for _item in obj["file_results"]] if obj.get("file_results") is not None else None
|
92
|
+
})
|
93
|
+
return _obj
|
94
|
+
|
95
|
+
|
@@ -20,7 +20,7 @@ import json
|
|
20
20
|
from datetime import datetime
|
21
21
|
from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr, field_validator
|
22
22
|
from typing import Any, ClassVar, Dict, List, Optional
|
23
|
-
from hiddenlayer.sdk.rest.models.
|
23
|
+
from hiddenlayer.sdk.rest.models.file_scan_report_v3 import FileScanReportV3
|
24
24
|
from hiddenlayer.sdk.rest.models.model_inventory_info import ModelInventoryInfo
|
25
25
|
from typing import Optional, Set
|
26
26
|
from typing_extensions import Self
|
@@ -40,7 +40,7 @@ class ScanReportV3(BaseModel):
|
|
40
40
|
end_time: Optional[datetime] = Field(default=None, description="time the scan ended")
|
41
41
|
status: StrictStr = Field(description="status of the scan")
|
42
42
|
severity: Optional[StrictStr] = Field(default=None, description="detection severity")
|
43
|
-
file_results: Optional[List[
|
43
|
+
file_results: Optional[List[FileScanReportV3]] = None
|
44
44
|
__properties: ClassVar[List[str]] = ["file_count", "files_with_detections_count", "detection_count", "detection_categories", "inventory", "version", "scan_id", "start_time", "end_time", "status", "severity", "file_results"]
|
45
45
|
|
46
46
|
@field_validator('status')
|
@@ -132,7 +132,7 @@ class ScanReportV3(BaseModel):
|
|
132
132
|
"end_time": obj.get("end_time"),
|
133
133
|
"status": obj.get("status"),
|
134
134
|
"severity": obj.get("severity"),
|
135
|
-
"file_results": [
|
135
|
+
"file_results": [FileScanReportV3.from_dict(_item) for _item in obj["file_results"]] if obj.get("file_results") is not None else None
|
136
136
|
})
|
137
137
|
return _obj
|
138
138
|
|
@@ -28,7 +28,7 @@ class SensorSORModelCardResponse(BaseModel):
|
|
28
28
|
SensorSORModelCardResponse
|
29
29
|
""" # noqa: E501
|
30
30
|
model_id: StrictStr
|
31
|
-
created_at: StrictInt = Field(description="Unix
|
31
|
+
created_at: StrictInt = Field(description="Unix Nano Epoch")
|
32
32
|
plaintext_name: StrictStr
|
33
33
|
active_versions: List[StrictInt]
|
34
34
|
source: StrictStr
|
@@ -1,4 +1,6 @@
|
|
1
1
|
import json
|
2
|
+
import random
|
3
|
+
import time
|
2
4
|
from typing import Optional
|
3
5
|
|
4
6
|
from hiddenlayer.sdk.constants import ApiErrors
|
@@ -37,6 +39,49 @@ class ModelAPI:
|
|
37
39
|
)
|
38
40
|
)
|
39
41
|
|
42
|
+
def create_or_get(self, *, model_name: str, model_version: Optional[int]) -> Model:
|
43
|
+
"""
|
44
|
+
Creates a model in the HiddenLayer Platform if it does not exist.
|
45
|
+
If the model and version already exists, returns the existing model.
|
46
|
+
|
47
|
+
:params model_name: Name of the model
|
48
|
+
:params model_version: Version of the model
|
49
|
+
|
50
|
+
:returns: HiddenLayer ModelID
|
51
|
+
"""
|
52
|
+
try:
|
53
|
+
return self.create(model_name=model_name, model_version=model_version)
|
54
|
+
except ApiException as e:
|
55
|
+
if e.status == 400 and str(e.body).find(ApiErrors.SENSOR_EXISTS) != -1:
|
56
|
+
return self.get_with_retry(
|
57
|
+
model_name=model_name, version=model_version, retry=3
|
58
|
+
)
|
59
|
+
else:
|
60
|
+
raise e
|
61
|
+
|
62
|
+
def get_with_retry(
|
63
|
+
self, *, model_name: str, version: Optional[int], retry: int
|
64
|
+
) -> Model:
|
65
|
+
"""
|
66
|
+
Gets a HiddenLayer model object. If not version is supplied, the latest model is returned.
|
67
|
+
Retries if the model is not found.
|
68
|
+
|
69
|
+
:param model_name: Name of the model.
|
70
|
+
:param version: Version of the model to get.
|
71
|
+
:param retry: Number of retries
|
72
|
+
|
73
|
+
:returns: HiddenLayer Model object
|
74
|
+
"""
|
75
|
+
|
76
|
+
base_delay = 0.1 # seconds
|
77
|
+
for retryCount in range(retry):
|
78
|
+
try:
|
79
|
+
return self.get(model_name=model_name, version=version)
|
80
|
+
except ModelDoesNotExistError:
|
81
|
+
time.sleep(base_delay * 2**retryCount + random.uniform(0, 1))
|
82
|
+
pass
|
83
|
+
raise ModelDoesNotExistError(f"Model {model_name} does not exist")
|
84
|
+
|
40
85
|
def get(self, *, model_name: str, version: Optional[int] = None) -> Model:
|
41
86
|
"""
|
42
87
|
Gets a HiddenLayer model object. If not version is supplied, the latest model is returned.
|
@@ -90,7 +135,7 @@ class ModelAPI:
|
|
90
135
|
)
|
91
136
|
)
|
92
137
|
|
93
|
-
if not models.results:
|
138
|
+
if not models.results or len(models.results) == 0:
|
94
139
|
msg = f"Model {model_name} does not exist"
|
95
140
|
|
96
141
|
if version:
|
@@ -70,7 +70,7 @@ class ModelScanAPI:
|
|
70
70
|
file_path = Path(model_path)
|
71
71
|
|
72
72
|
filesize = file_path.stat().st_size
|
73
|
-
sensor = self._model_api.
|
73
|
+
sensor = self._model_api.create_or_get(
|
74
74
|
model_name=model_name, model_version=model_version
|
75
75
|
)
|
76
76
|
upload = self._sensor_api.begin_multipart_upload(sensor.sensor_id, filesize)
|
hiddenlayer/sdk/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
VERSION = "1.
|
1
|
+
VERSION = "1.1.0"
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: hiddenlayer-sdk
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.1.0
|
4
4
|
Summary: Official HiddenLayer Python SDK
|
5
5
|
Author-email: HiddenLayer Integrations Team <integrations@hiddenlayer.com>
|
6
6
|
Maintainer-email: HiddenLayer Integrations Team <integrations@hiddenlayer.com>
|
@@ -1,11 +1,11 @@
|
|
1
1
|
hiddenlayer/__init__.py,sha256=Uik1ha6cV_6MkpB0zpKn6f7Zsw7q6W_sh3MgGq2M3vU,3582
|
2
2
|
hiddenlayer/sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
hiddenlayer/sdk/constants.py,sha256=
|
3
|
+
hiddenlayer/sdk/constants.py,sha256=QwBZAQdF7FW9q4C-O8LyxrpqfJFBBlqRUDMjnJ-ouZQ,320
|
4
4
|
hiddenlayer/sdk/exceptions.py,sha256=LNkD6AvSwNwQjnTDrvY152DmvPKzSejrBsIu-qI44Ec,225
|
5
|
-
hiddenlayer/sdk/models.py,sha256=
|
5
|
+
hiddenlayer/sdk/models.py,sha256=T6GJTFCfBQgBteR0pl0eyYzan-iIFOSpcnlmlCuuQwc,1836
|
6
6
|
hiddenlayer/sdk/utils.py,sha256=Ntao8hfsYuB7obZOanayIlrgJ98IWcPhs3sRi39IDkg,2997
|
7
|
-
hiddenlayer/sdk/version.py,sha256=
|
8
|
-
hiddenlayer/sdk/rest/__init__.py,sha256=
|
7
|
+
hiddenlayer/sdk/version.py,sha256=DFGnvNkISEu0RDsAfc03O0dRz9PfmIb63Kyi-am-trE,18
|
8
|
+
hiddenlayer/sdk/rest/__init__.py,sha256=Egcd1PM10KlYQww3y-HkVz0IqF3jnycvn5lYcE6uXVw,7809
|
9
9
|
hiddenlayer/sdk/rest/api_client.py,sha256=Zd_yX0nQq06z0Ome2KcsNUcETnOxzhQK9js53qsN7aI,26333
|
10
10
|
hiddenlayer/sdk/rest/api_response.py,sha256=eMxw1mpmJcoGZ3gs9z6jM4oYoZ10Gjk333s9sKxGv7s,652
|
11
11
|
hiddenlayer/sdk/rest/configuration.py,sha256=0AzoYBOp3MzQvM9R3AkUWTycx1I3bcvNtn759JQ0fLo,14747
|
@@ -17,8 +17,8 @@ hiddenlayer/sdk/rest/api/health_api.py,sha256=oKHVksIqs_Vt_aQK-n9ZcQfbwW06pVeiYJ
|
|
17
17
|
hiddenlayer/sdk/rest/api/model_scan_api.py,sha256=G32t9LzeDTCUF4QOMYYs3Vjm8bo0a2kZa3FXBAqPo6s,22047
|
18
18
|
hiddenlayer/sdk/rest/api/model_supply_chain_api.py,sha256=kyay-8hob2E5HoGJPFQXYuffsZOKrg4yJ_S3wMuW030,116057
|
19
19
|
hiddenlayer/sdk/rest/api/readiness_api.py,sha256=5SddYxvRA3GuwZ43DoVTRfPBeTkLXyBGbQtIdUyc2FA,10102
|
20
|
-
hiddenlayer/sdk/rest/api/sensor_api.py,sha256=
|
21
|
-
hiddenlayer/sdk/rest/models/__init__.py,sha256
|
20
|
+
hiddenlayer/sdk/rest/api/sensor_api.py,sha256=yEvLUOVkpHAxsMZdoLQLWUW1TimlpKJ1bkRjJsGsAcU,87527
|
21
|
+
hiddenlayer/sdk/rest/models/__init__.py,sha256=-SO-mMt_gSxn-3hRXPeekUXEMe9hweu-ihepPrMNjXU,6811
|
22
22
|
hiddenlayer/sdk/rest/models/address.py,sha256=amsl9GIcBhHswzfA8eQ0jbRw9zVEd6DmtDFSKRyQB9s,5285
|
23
23
|
hiddenlayer/sdk/rest/models/artifact.py,sha256=FSV-aFgOpyZU3khHkbWXajenYLi_Zfn153cZTlz6TAI,8138
|
24
24
|
hiddenlayer/sdk/rest/models/artifact_change.py,sha256=714PhIumUnwj1bBAtaFEFl78zoKbsiJfEGFQtkhFzgI,4136
|
@@ -37,8 +37,8 @@ hiddenlayer/sdk/rest/models/external_properties.py,sha256=_kr2izVVqjDaKAZYM9YljI
|
|
37
37
|
hiddenlayer/sdk/rest/models/external_property_file_reference.py,sha256=CYWp1dkeTyONFxgyL1s9lgEIrL_WRLfCHu2uesTo0hM,3741
|
38
38
|
hiddenlayer/sdk/rest/models/external_property_file_references.py,sha256=exYjkAMMKsWnj5PYAM9JvdrfnvoooeM1_-JKK0HEWtI,14776
|
39
39
|
hiddenlayer/sdk/rest/models/file_details_v3.py,sha256=jnIDdpjngvEP29GTvVAbuAlonaDiIlsorpBKfsk8iH8,5419
|
40
|
-
hiddenlayer/sdk/rest/models/
|
41
|
-
hiddenlayer/sdk/rest/models/
|
40
|
+
hiddenlayer/sdk/rest/models/file_scan_report_v3.py,sha256=SiHmoz13npUwPGxsfWtPIFhuFSBJ__l7MqnOcuUjKX8,5178
|
41
|
+
hiddenlayer/sdk/rest/models/file_scan_reports_v3.py,sha256=eF39zwE-TQjbY0ChH28NyKlF285QqcTX5Hoiwk78FqE,2996
|
42
42
|
hiddenlayer/sdk/rest/models/fix.py,sha256=IMGNyz-obFVq4xTNHxpwnlJhiSLI2ILg1XnmjrbqyFY,4397
|
43
43
|
hiddenlayer/sdk/rest/models/get_multipart_upload_response.py,sha256=mSg6L4R_CoTNKtCNV2wDvCTk0dEkW8E6ChrRjBbdaDc,3049
|
44
44
|
hiddenlayer/sdk/rest/models/graph.py,sha256=iMO4X58bcyPhrtMnnsVlRb2gbYtvkOoW8kLA7uwdQvM,4806
|
@@ -83,12 +83,12 @@ hiddenlayer/sdk/rest/models/scan_job_inventory.py,sha256=OV1KAy1czwndF7h-OZg4KYw
|
|
83
83
|
hiddenlayer/sdk/rest/models/scan_model_details_v3.py,sha256=U63IEpPWJNnZfKoW4-G51m05iXjwoT8cXyP3Va-x3NI,3195
|
84
84
|
hiddenlayer/sdk/rest/models/scan_model_ids_v3.py,sha256=FSJn2oVqEKd0YOF3xsKs1xnSgpYuVT5WBIEwAm5DcKY,2681
|
85
85
|
hiddenlayer/sdk/rest/models/scan_model_request.py,sha256=vjIE1onx_OTS-wcpuFWcPpMe-wp9IU1fM7oWVJxBkEk,2451
|
86
|
-
hiddenlayer/sdk/rest/models/scan_report_v3.py,sha256=
|
86
|
+
hiddenlayer/sdk/rest/models/scan_report_v3.py,sha256=C3dMv1ndMLGerBB1bWgYnG7cjS2BhucljsU8-Ne2YAA,5700
|
87
87
|
hiddenlayer/sdk/rest/models/scan_results.py,sha256=02__33uy5wf_LMDoJfaSnNr2wMv4b59IcVq9F9suWUA,4031
|
88
88
|
hiddenlayer/sdk/rest/models/scan_results_v2.py,sha256=-JCwgKrbjpAhye0uAQGq9rg2M6L6cHL3dqkoM_tmDnc,4494
|
89
89
|
hiddenlayer/sdk/rest/models/security_posture.py,sha256=QJAJzaqrL1R69-jUkLX8Hpjz7-aCw99doUIAgPR6n7w,2619
|
90
90
|
hiddenlayer/sdk/rest/models/sensor_sor_model_card_query_response.py,sha256=axRm4bobSm-VfsBS9qRLo5IBT07OXfej24lEY-u6z2s,3303
|
91
|
-
hiddenlayer/sdk/rest/models/sensor_sor_model_card_response.py,sha256
|
91
|
+
hiddenlayer/sdk/rest/models/sensor_sor_model_card_response.py,sha256=-tV9VWuN-bqOkOCuGcXT-QmKTqmeVe01jvEFt2Mmo0A,4694
|
92
92
|
hiddenlayer/sdk/rest/models/sensor_sor_query_filter.py,sha256=t1ZdI4iwNk-mPjGX1j1oVCwrJ9qMAmEkMAxVkDE38yg,3406
|
93
93
|
hiddenlayer/sdk/rest/models/sensor_sor_query_request.py,sha256=QdCmGShcIpQUVbFgLtzxtk9ucrmrwNfTLLwe78chuuY,3740
|
94
94
|
hiddenlayer/sdk/rest/models/special_locations.py,sha256=FU5Y9nHrth5hixkeleSkxB3a9ZYALC4TI8BQXV4tWCw,3322
|
@@ -109,10 +109,10 @@ hiddenlayer/sdk/rest/models/web_request.py,sha256=0LKMRsAIg7oVOPso8DiaFgfsozpdKv
|
|
109
109
|
hiddenlayer/sdk/rest/models/web_response.py,sha256=iwGQ5WjqAB4qGwe9nzGOwtxB1OSUc024pXSOaZM3Cdc,4746
|
110
110
|
hiddenlayer/sdk/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
111
111
|
hiddenlayer/sdk/services/aidr_predictive.py,sha256=aD2anFzWQzfLsR13NwwdQjt_X_iAlOkmss_yHy-154U,2958
|
112
|
-
hiddenlayer/sdk/services/model.py,sha256=
|
113
|
-
hiddenlayer/sdk/services/model_scan.py,sha256=
|
114
|
-
hiddenlayer_sdk-1.
|
115
|
-
hiddenlayer_sdk-1.
|
116
|
-
hiddenlayer_sdk-1.
|
117
|
-
hiddenlayer_sdk-1.
|
118
|
-
hiddenlayer_sdk-1.
|
112
|
+
hiddenlayer/sdk/services/model.py,sha256=qoVrwgL7E0raCUI0bNyim4SrmDEGBmcU1UaoJ-JNoCg,4871
|
113
|
+
hiddenlayer/sdk/services/model_scan.py,sha256=xGHveChHA6pHArSNF8YKXFOi0FqaH9BnzfuKC_6VyBY,17123
|
114
|
+
hiddenlayer_sdk-1.1.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
115
|
+
hiddenlayer_sdk-1.1.0.dist-info/METADATA,sha256=8M5hvwdG5HDkwRvIAiKDQJf3vSGCoex7itoWrd8baUk,17342
|
116
|
+
hiddenlayer_sdk-1.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
117
|
+
hiddenlayer_sdk-1.1.0.dist-info/top_level.txt,sha256=8BxcmGvEN1RqsMvTWg9Q0vDmtBGcTmatnme6nzyPj2U,12
|
118
|
+
hiddenlayer_sdk-1.1.0.dist-info/RECORD,,
|
@@ -1,121 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
|
-
"""
|
4
|
-
HiddenLayer ModelScan V2
|
5
|
-
|
6
|
-
HiddenLayer ModelScan API for scanning of models
|
7
|
-
|
8
|
-
The version of the OpenAPI document: 1
|
9
|
-
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
10
|
-
|
11
|
-
Do not edit the class manually.
|
12
|
-
""" # noqa: E501
|
13
|
-
|
14
|
-
|
15
|
-
from __future__ import annotations
|
16
|
-
import pprint
|
17
|
-
import re # noqa: F401
|
18
|
-
import json
|
19
|
-
|
20
|
-
from datetime import datetime
|
21
|
-
from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator
|
22
|
-
from typing import Any, ClassVar, Dict, List, Optional
|
23
|
-
from hiddenlayer.sdk.rest.models.file_details_v3 import FileDetailsV3
|
24
|
-
from hiddenlayer.sdk.rest.models.scan_detection_v3 import ScanDetectionV3
|
25
|
-
from typing import Optional, Set
|
26
|
-
from typing_extensions import Self
|
27
|
-
|
28
|
-
class FileResultsInner(BaseModel):
|
29
|
-
"""
|
30
|
-
FileResultsInner
|
31
|
-
""" # noqa: E501
|
32
|
-
file_instance_id: StrictStr = Field(description="unique ID of the file")
|
33
|
-
file_location: StrictStr = Field(description="full file path")
|
34
|
-
start_time: datetime = Field(description="time the scan started")
|
35
|
-
end_time: datetime = Field(description="time the scan ended")
|
36
|
-
details: FileDetailsV3
|
37
|
-
status: StrictStr = Field(description="status of the scan")
|
38
|
-
seen: datetime = Field(description="time the scan was seen at")
|
39
|
-
detections: Optional[List[ScanDetectionV3]] = None
|
40
|
-
__properties: ClassVar[List[str]] = ["file_instance_id", "file_location", "start_time", "end_time", "details", "status", "seen", "detections"]
|
41
|
-
|
42
|
-
@field_validator('status')
|
43
|
-
def status_validate_enum(cls, value):
|
44
|
-
"""Validates the enum"""
|
45
|
-
if value not in set(['skipped', 'pending', 'running', 'done', 'failed', 'canceled']):
|
46
|
-
raise ValueError("must be one of enum values ('skipped', 'pending', 'running', 'done', 'failed', 'canceled')")
|
47
|
-
return value
|
48
|
-
|
49
|
-
model_config = ConfigDict(
|
50
|
-
populate_by_name=True,
|
51
|
-
validate_assignment=True,
|
52
|
-
protected_namespaces=(),
|
53
|
-
)
|
54
|
-
|
55
|
-
|
56
|
-
def to_str(self) -> str:
|
57
|
-
"""Returns the string representation of the model using alias"""
|
58
|
-
return pprint.pformat(self.model_dump(by_alias=True))
|
59
|
-
|
60
|
-
def to_json(self) -> str:
|
61
|
-
"""Returns the JSON representation of the model using alias"""
|
62
|
-
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
63
|
-
return json.dumps(self.to_dict())
|
64
|
-
|
65
|
-
@classmethod
|
66
|
-
def from_json(cls, json_str: str) -> Optional[Self]:
|
67
|
-
"""Create an instance of FileResultsInner from a JSON string"""
|
68
|
-
return cls.from_dict(json.loads(json_str))
|
69
|
-
|
70
|
-
def to_dict(self) -> Dict[str, Any]:
|
71
|
-
"""Return the dictionary representation of the model using alias.
|
72
|
-
|
73
|
-
This has the following differences from calling pydantic's
|
74
|
-
`self.model_dump(by_alias=True)`:
|
75
|
-
|
76
|
-
* `None` is only added to the output dict for nullable fields that
|
77
|
-
were set at model initialization. Other fields with value `None`
|
78
|
-
are ignored.
|
79
|
-
"""
|
80
|
-
excluded_fields: Set[str] = set([
|
81
|
-
])
|
82
|
-
|
83
|
-
_dict = self.model_dump(
|
84
|
-
by_alias=True,
|
85
|
-
exclude=excluded_fields,
|
86
|
-
exclude_none=True,
|
87
|
-
)
|
88
|
-
# override the default output from pydantic by calling `to_dict()` of details
|
89
|
-
if self.details:
|
90
|
-
_dict['details'] = self.details.to_dict()
|
91
|
-
# override the default output from pydantic by calling `to_dict()` of each item in detections (list)
|
92
|
-
_items = []
|
93
|
-
if self.detections:
|
94
|
-
for _item in self.detections:
|
95
|
-
if _item:
|
96
|
-
_items.append(_item.to_dict())
|
97
|
-
_dict['detections'] = _items
|
98
|
-
return _dict
|
99
|
-
|
100
|
-
@classmethod
|
101
|
-
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
102
|
-
"""Create an instance of FileResultsInner from a dict"""
|
103
|
-
if obj is None:
|
104
|
-
return None
|
105
|
-
|
106
|
-
if not isinstance(obj, dict):
|
107
|
-
return cls.model_validate(obj)
|
108
|
-
|
109
|
-
_obj = cls.model_validate({
|
110
|
-
"file_instance_id": obj.get("file_instance_id"),
|
111
|
-
"file_location": obj.get("file_location"),
|
112
|
-
"start_time": obj.get("start_time"),
|
113
|
-
"end_time": obj.get("end_time"),
|
114
|
-
"details": FileDetailsV3.from_dict(obj["details"]) if obj.get("details") is not None else None,
|
115
|
-
"status": obj.get("status"),
|
116
|
-
"seen": obj.get("seen"),
|
117
|
-
"detections": [ScanDetectionV3.from_dict(_item) for _item in obj["detections"]] if obj.get("detections") is not None else None
|
118
|
-
})
|
119
|
-
return _obj
|
120
|
-
|
121
|
-
|
File without changes
|
File without changes
|