hiddenlayer-sdk 1.0.0__py3-none-any.whl → 1.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,3 +12,4 @@ class ScanStatus(str, Enum):
12
12
 
13
13
  class ApiErrors(str, Enum):
14
14
  NON_ADHOC_SENSOR_DELETE = "only adhoc sensors may be deleted"
15
+ SENSOR_EXISTS = "already exists"
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.file_results_inner import FileResultsInner
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[FileResultsInner]] = []
53
+ file_results: Optional[List[FileScanReportV3]] = []
54
54
 
55
55
 
56
56
  class Sarif(Sarif210):
@@ -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
@@ -16,8 +16,8 @@ from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt
16
16
  from typing import Any, Dict, List, Optional, Tuple, Union
17
17
  from typing_extensions import Annotated
18
18
 
19
- from pydantic import Field, StrictFloat, StrictInt, StrictStr, field_validator
20
- from typing import Any, Dict, Optional, Union
19
+ from pydantic import Field, StrictInt, StrictStr, field_validator
20
+ from typing import Any, Optional
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
@@ -48,7 +48,7 @@ class SensorApi:
48
48
  def begin_multipart_upload(
49
49
  self,
50
50
  sensor_id: StrictStr,
51
- x_content_length: Annotated[Union[StrictFloat, StrictInt], Field(description="The total size of multipart upload.")],
51
+ x_content_length: Annotated[StrictInt, Field(description="The total size of multipart upload.")],
52
52
  _request_timeout: Union[
53
53
  None,
54
54
  Annotated[StrictFloat, Field(gt=0)],
@@ -68,7 +68,7 @@ class SensorApi:
68
68
  :param sensor_id: (required)
69
69
  :type sensor_id: str
70
70
  :param x_content_length: The total size of multipart upload. (required)
71
- :type x_content_length: float
71
+ :type x_content_length: int
72
72
  :param _request_timeout: timeout setting for this request. If one
73
73
  number provided, it will be total request
74
74
  timeout. It can also be a pair (tuple) of
@@ -119,7 +119,7 @@ class SensorApi:
119
119
  def begin_multipart_upload_with_http_info(
120
120
  self,
121
121
  sensor_id: StrictStr,
122
- x_content_length: Annotated[Union[StrictFloat, StrictInt], Field(description="The total size of multipart upload.")],
122
+ x_content_length: Annotated[StrictInt, Field(description="The total size of multipart upload.")],
123
123
  _request_timeout: Union[
124
124
  None,
125
125
  Annotated[StrictFloat, Field(gt=0)],
@@ -139,7 +139,7 @@ class SensorApi:
139
139
  :param sensor_id: (required)
140
140
  :type sensor_id: str
141
141
  :param x_content_length: The total size of multipart upload. (required)
142
- :type x_content_length: float
142
+ :type x_content_length: int
143
143
  :param _request_timeout: timeout setting for this request. If one
144
144
  number provided, it will be total request
145
145
  timeout. It can also be a pair (tuple) of
@@ -190,7 +190,7 @@ class SensorApi:
190
190
  def begin_multipart_upload_without_preload_content(
191
191
  self,
192
192
  sensor_id: StrictStr,
193
- x_content_length: Annotated[Union[StrictFloat, StrictInt], Field(description="The total size of multipart upload.")],
193
+ x_content_length: Annotated[StrictInt, Field(description="The total size of multipart upload.")],
194
194
  _request_timeout: Union[
195
195
  None,
196
196
  Annotated[StrictFloat, Field(gt=0)],
@@ -210,7 +210,7 @@ class SensorApi:
210
210
  :param sensor_id: (required)
211
211
  :type sensor_id: str
212
212
  :param x_content_length: The total size of multipart upload. (required)
213
- :type x_content_length: float
213
+ :type x_content_length: int
214
214
  :param _request_timeout: timeout setting for this request. If one
215
215
  number provided, it will be total request
216
216
  timeout. It can also be a pair (tuple) of
@@ -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
- ) -> object:
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': "object",
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[object]:
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': "object",
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': "object",
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
@@ -1984,7 +1978,7 @@ class SensorApi:
1984
1978
  self,
1985
1979
  sensor_id: StrictStr,
1986
1980
  upload_id: StrictStr,
1987
- part: Union[StrictFloat, StrictInt],
1981
+ part: StrictInt,
1988
1982
  body: Optional[Any],
1989
1983
  _request_timeout: Union[
1990
1984
  None,
@@ -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
- ) -> object:
1995
+ ) -> None:
2002
1996
  """Upload part
2003
1997
 
2004
1998
 
@@ -2007,7 +2001,7 @@ class SensorApi:
2007
2001
  :param upload_id: (required)
2008
2002
  :type upload_id: str
2009
2003
  :param part: (required)
2010
- :type part: float
2004
+ :type part: int
2011
2005
  :param body: (required)
2012
2006
  :type body: object
2013
2007
  :param _request_timeout: timeout setting for this request. If one
@@ -2044,7 +2038,7 @@ class SensorApi:
2044
2038
  )
2045
2039
 
2046
2040
  _response_types_map: Dict[str, Optional[str]] = {
2047
- '200': "object",
2041
+ '200': None,
2048
2042
  '400': None,
2049
2043
  }
2050
2044
  response_data = self.api_client.call_api(
@@ -2063,7 +2057,7 @@ class SensorApi:
2063
2057
  self,
2064
2058
  sensor_id: StrictStr,
2065
2059
  upload_id: StrictStr,
2066
- part: Union[StrictFloat, StrictInt],
2060
+ part: StrictInt,
2067
2061
  body: Optional[Any],
2068
2062
  _request_timeout: Union[
2069
2063
  None,
@@ -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[object]:
2074
+ ) -> ApiResponse[None]:
2081
2075
  """Upload part
2082
2076
 
2083
2077
 
@@ -2086,7 +2080,7 @@ class SensorApi:
2086
2080
  :param upload_id: (required)
2087
2081
  :type upload_id: str
2088
2082
  :param part: (required)
2089
- :type part: float
2083
+ :type part: int
2090
2084
  :param body: (required)
2091
2085
  :type body: object
2092
2086
  :param _request_timeout: timeout setting for this request. If one
@@ -2123,7 +2117,7 @@ class SensorApi:
2123
2117
  )
2124
2118
 
2125
2119
  _response_types_map: Dict[str, Optional[str]] = {
2126
- '200': "object",
2120
+ '200': None,
2127
2121
  '400': None,
2128
2122
  }
2129
2123
  response_data = self.api_client.call_api(
@@ -2142,7 +2136,7 @@ class SensorApi:
2142
2136
  self,
2143
2137
  sensor_id: StrictStr,
2144
2138
  upload_id: StrictStr,
2145
- part: Union[StrictFloat, StrictInt],
2139
+ part: StrictInt,
2146
2140
  body: Optional[Any],
2147
2141
  _request_timeout: Union[
2148
2142
  None,
@@ -2165,7 +2159,7 @@ class SensorApi:
2165
2159
  :param upload_id: (required)
2166
2160
  :type upload_id: str
2167
2161
  :param part: (required)
2168
- :type part: float
2162
+ :type part: int
2169
2163
  :param body: (required)
2170
2164
  :type body: object
2171
2165
  :param _request_timeout: timeout setting for this request. If one
@@ -2202,7 +2196,7 @@ class SensorApi:
2202
2196
  )
2203
2197
 
2204
2198
  _response_types_map: Dict[str, Optional[str]] = {
2205
- '200': "object",
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 pydantic import BaseModel, ConfigDict
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.file_results_inner import FileResultsInner
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
- file_results: Optional[List[FileResultsInner]] = None
31
- __properties: ClassVar[List[str]] = ["file_results"]
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
- "file_results": [FileResultsInner.from_dict(_item) for _item in obj["file_results"]] if obj.get("file_results") is not None else None
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
+
@@ -18,7 +18,7 @@ import re # noqa: F401
18
18
  import json
19
19
 
20
20
  from pydantic import BaseModel, ConfigDict, Field
21
- from typing import Any, ClassVar, Dict, List, Optional, Union
21
+ from typing import Any, ClassVar, Dict, List, Optional
22
22
  from typing_extensions import Annotated
23
23
  from hiddenlayer.sdk.rest.models.scan_report_v3 import ScanReportV3
24
24
  from typing import Optional, Set
@@ -29,7 +29,7 @@ class ModelScanApiV3ScanQuery200Response(BaseModel):
29
29
  ModelScanApiV3ScanQuery200Response
30
30
  """ # noqa: E501
31
31
  items: Optional[List[ScanReportV3]] = None
32
- total: Union[Annotated[float, Field(strict=True, ge=0)], Annotated[int, Field(strict=True, ge=0)]] = Field(description="Total number of items available based on the query criteria.")
32
+ total: Annotated[int, Field(strict=True, ge=0)] = Field(description="Total number of items available based on the query criteria.")
33
33
  limit: Annotated[int, Field(le=100, strict=True, ge=1)] = Field(description="Maximum number of items to return")
34
34
  offset: Annotated[int, Field(strict=True, ge=0)] = Field(description="Begin returning the results from this offset")
35
35
  __properties: ClassVar[List[str]] = ["items", "total", "limit", "offset"]
@@ -17,8 +17,8 @@ import pprint
17
17
  import re # noqa: F401
18
18
  import json
19
19
 
20
- from pydantic import BaseModel, ConfigDict, Field, StrictFloat, StrictInt, StrictStr
21
- from typing import Any, ClassVar, Dict, List, Optional, Union
20
+ from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr
21
+ from typing import Any, ClassVar, Dict, List, Optional
22
22
  from typing import Optional, Set
23
23
  from typing_extensions import Self
24
24
 
@@ -26,9 +26,9 @@ class MultipartUploadPart(BaseModel):
26
26
  """
27
27
  MultipartUploadPart
28
28
  """ # noqa: E501
29
- part_number: Union[StrictFloat, StrictInt]
30
- start_offset: Union[StrictFloat, StrictInt]
31
- end_offset: Union[StrictFloat, StrictInt]
29
+ part_number: StrictInt
30
+ start_offset: StrictInt
31
+ end_offset: StrictInt
32
32
  upload_url: Optional[StrictStr] = Field(default=None, description="only provided when part is to be directly uploaded to a cloud provider (adhoc)")
33
33
  __properties: ClassVar[List[str]] = ["part_number", "start_offset", "end_offset", "upload_url"]
34
34
 
@@ -18,7 +18,7 @@ import re # noqa: F401
18
18
  import json
19
19
 
20
20
  from pydantic import BaseModel, ConfigDict, Field, StrictStr
21
- from typing import Any, ClassVar, Dict, List, Optional, Union
21
+ from typing import Any, ClassVar, Dict, List, Optional
22
22
  from typing_extensions import Annotated
23
23
  from typing import Optional, Set
24
24
  from typing_extensions import Self
@@ -28,7 +28,7 @@ class PagedResponseWithTotal(BaseModel):
28
28
  PagedResponseWithTotal
29
29
  """ # noqa: E501
30
30
  items: Optional[List[StrictStr]] = Field(default=None, description="List of items. If no matching items are found, then `[]` will be returned.")
31
- total: Union[Annotated[float, Field(strict=True, ge=0)], Annotated[int, Field(strict=True, ge=0)]] = Field(description="Total number of items available based on the query criteria.")
31
+ total: Annotated[int, Field(strict=True, ge=0)] = Field(description="Total number of items available based on the query criteria.")
32
32
  limit: Annotated[int, Field(le=100, strict=True, ge=1)] = Field(description="Maximum number of items to return")
33
33
  offset: Annotated[int, Field(strict=True, ge=0)] = Field(description="Begin returning the results from this offset")
34
34
  __properties: ClassVar[List[str]] = ["items", "total", "limit", "offset"]
@@ -66,8 +66,8 @@ class ScanDetectionV3(BaseModel):
66
66
  if value is None:
67
67
  return value
68
68
 
69
- if not re.match(r"^CWE-\d{1,4}.*$", value):
70
- raise ValueError(r"must validate the regular expression /^CWE-\d{1,4}.*$/")
69
+ if not re.match(r"^CWE-\d{1,4}.*$|^$", value):
70
+ raise ValueError(r"must validate the regular expression /^CWE-\d{1,4}.*$|^$/")
71
71
  return value
72
72
 
73
73
  model_config = ConfigDict(
@@ -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.file_results_inner import FileResultsInner
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[FileResultsInner]] = None
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": [FileResultsInner.from_dict(_item) for _item in obj["file_results"]] if obj.get("file_results") is not None else None
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 timestamp")
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.create(
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)
@@ -1 +1 @@
1
- VERSION = "1.0.0"
1
+ VERSION = "1.1.1"
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: hiddenlayer-sdk
3
- Version: 1.0.0
3
+ Version: 1.1.1
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=517WH-MCaedeOK2yXDfJvjmuqWSpRFvuQzV6e22-3jg,283
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=FxNn_D9vHWjQW2t79UWWwwLLfkkVqMWsaEgmVLWS02I,1835
5
+ hiddenlayer/sdk/models.py,sha256=T6GJTFCfBQgBteR0pl0eyYzan-iIFOSpcnlmlCuuQwc,1836
6
6
  hiddenlayer/sdk/utils.py,sha256=Ntao8hfsYuB7obZOanayIlrgJ98IWcPhs3sRi39IDkg,2997
7
- hiddenlayer/sdk/version.py,sha256=lzGFsymf0DtA_1oAZcPbeQ557iY-1BRkekhfA2qaFh8,18
8
- hiddenlayer/sdk/rest/__init__.py,sha256=5zmzsJXKVVfk-V6En3_0R0XjNu5HNESfM3Mtj7lgi24,7806
7
+ hiddenlayer/sdk/version.py,sha256=mDldA753XXTzV03_TN3RwueHcj_1Dg00eIWo8LRZG5Y,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=TKmqa5kuqCb1Ax_kIDkhoNCP3zMEOxPUxpilutn_Evg,87935
21
- hiddenlayer/sdk/rest/models/__init__.py,sha256=w7xG3tRuBAZDFB77NMjS5EwuIDnUYDLuELl13OmY9u8,6808
20
+ hiddenlayer/sdk/rest/api/sensor_api.py,sha256=7pHFdPkeWTVkDx_Cr6e30TMSxGtK8q7h5d8Wiz52_CM,87375
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/file_results_inner.py,sha256=KpXwUU-7Gw4BLBTi7N9wLLwQk6F-MxZHuwcLMJhpvHk,4541
41
- hiddenlayer/sdk/rest/models/file_scan_report_v3.py,sha256=ppamPmZfb3KlugmYWQf8ukkFmQhutX54jyBzHVqaF1k,2991
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
@@ -54,12 +54,12 @@ hiddenlayer/sdk/rest/models/model.py,sha256=P9KhYtnXYB6I5HWbwn7N3JDRwN-2mOl9FS0y
54
54
  hiddenlayer/sdk/rest/models/model_inventory_info.py,sha256=mVqFy64_6E9RPZlKBbiWpcmW-VOpRgCGNg5roQIZYVY,3550
55
55
  hiddenlayer/sdk/rest/models/model_query_response.py,sha256=rnJIq1VULoan4ACIbDAFQKptfKvQch0lG1GubpHxSzM,3163
56
56
  hiddenlayer/sdk/rest/models/model_scan_api_v3_scan_model_version_id_patch200_response.py,sha256=Kte2VZW9Sxg6iuQcUejMKgwu2o93enamPkn8AkmocPc,2639
57
- hiddenlayer/sdk/rest/models/model_scan_api_v3_scan_query200_response.py,sha256=EWHIzVE9kL_BqhK1iHO6RR3CFcaPRofjCEz221Nfqv8,3690
57
+ hiddenlayer/sdk/rest/models/model_scan_api_v3_scan_query200_response.py,sha256=1ZwhiLPdUJ91wbXsZBReHStLPRy7MuypGA7TvuWUyCI,3632
58
58
  hiddenlayer/sdk/rest/models/multiformat_message_string.py,sha256=dCTBPDxsH82CsjG8Li1DQ3g7jVTElwK9Y40jsHfX6as,3188
59
- hiddenlayer/sdk/rest/models/multipart_upload_part.py,sha256=l-8F4iozfhxsRa3sZA2NnIXWV6eCRIDYQrDDjw6FGbU,2984
59
+ hiddenlayer/sdk/rest/models/multipart_upload_part.py,sha256=YlQzUpdFPdLOI1eUINf5awh_ZEbLPfJ14kMD2GVuTxE,2904
60
60
  hiddenlayer/sdk/rest/models/node.py,sha256=ncjJUVzG3lHmZy214R-Mq1hMeI-i1QyaZPUTlluopdM,4552
61
61
  hiddenlayer/sdk/rest/models/notification.py,sha256=pAuZat0q2eUI8psHfYzlymF-ESJRuX2SS1kFCGuT6M8,7077
62
- hiddenlayer/sdk/rest/models/paged_response_with_total.py,sha256=O8KD2Ipvi9Gwm6eUg21FeLgtlV8tdB7JhMMWl9ip3Fs,3307
62
+ hiddenlayer/sdk/rest/models/paged_response_with_total.py,sha256=6cg4f0n0sWm2KRuW_2N5jaRu60my84psVQwFD2PLCvA,3249
63
63
  hiddenlayer/sdk/rest/models/physical_location.py,sha256=5ZVAVRRcgPx0VtpPvAzE2zqivhOJeevxLbYiaDCx9Vs,3068
64
64
  hiddenlayer/sdk/rest/models/property_bag.py,sha256=AveUPrUpsS6ssiU3uq_gX0RBgte4bq7tyOhSV1XKRpo,3273
65
65
  hiddenlayer/sdk/rest/models/rectangle.py,sha256=EVfO4yTrzqLGg1w8NfTQ9MwS-hwUTntfCteQO7MK5wo,4295
@@ -76,19 +76,19 @@ hiddenlayer/sdk/rest/models/run.py,sha256=8BS3hXvOuIZybITl5epQUzlj4kOwoUjAQx0VCU
76
76
  hiddenlayer/sdk/rest/models/run_automation_details.py,sha256=r_v4HEGNv_WH7Rv2AW8jfh0nTAQd6lmnOvbL8To9WoY,5354
77
77
  hiddenlayer/sdk/rest/models/sarif210.py,sha256=c4yCBNKheoNkmLw7UOI5wMahO8fb9XDhq0KctcDnMGk,5019
78
78
  hiddenlayer/sdk/rest/models/scan_create_request.py,sha256=gxOl_N4_GjwwDT3VGg_d5uNKdxVxtQezcZcnkRg3N7o,2455
79
- hiddenlayer/sdk/rest/models/scan_detection_v3.py,sha256=_zLrBnMFMdh5So1V0cFqqL4t11ODsVbgNO8mxEhSlyQ,6386
79
+ hiddenlayer/sdk/rest/models/scan_detection_v3.py,sha256=UY7mLBUyopY1MF61PxjBDqs_p_wYzEyQV7nwlICbBBE,6392
80
80
  hiddenlayer/sdk/rest/models/scan_header_v3.py,sha256=3jaA-8UQMhpaoobk-TD2gdvQpU-XxJunvEKLd3pFiEs,5077
81
81
  hiddenlayer/sdk/rest/models/scan_job.py,sha256=ELKdaLTGRs9M5PuX4VD8DB_K1JgUg9NkzOKy90gW2wg,3610
82
82
  hiddenlayer/sdk/rest/models/scan_job_inventory.py,sha256=OV1KAy1czwndF7h-OZg4KYwVjHRh1ie4fGfgSOWQgO0,5370
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=3ArfJ_kOK-eYKKS_vgWnvTH0bQWg2ADTiYrbJ2eyeYE,5699
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=_O1QiTzF-d1FjwCHtv-mIme7rI-W8G4apji5CJ3I1ss,4693
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=Lgx1_4I2u1aV6Az0yw1nFgi1q9-SYuVV9GXH2SycU-w,3180
113
- hiddenlayer/sdk/services/model_scan.py,sha256=FMwRwqHQ_VrrWyhl3OuDHNlcGGZWan1HnLtkVaxZNGg,17116
114
- hiddenlayer_sdk-1.0.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
115
- hiddenlayer_sdk-1.0.0.dist-info/METADATA,sha256=9k9M9WvNBngYYo6KiJiTEshS3VlMpa0kdqhybXo5iwE,17342
116
- hiddenlayer_sdk-1.0.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
117
- hiddenlayer_sdk-1.0.0.dist-info/top_level.txt,sha256=8BxcmGvEN1RqsMvTWg9Q0vDmtBGcTmatnme6nzyPj2U,12
118
- hiddenlayer_sdk-1.0.0.dist-info/RECORD,,
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.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
115
+ hiddenlayer_sdk-1.1.1.dist-info/METADATA,sha256=quGYg7HvsPUKSD3yu9tTxfTzS692TkN0MP253DrighI,17342
116
+ hiddenlayer_sdk-1.1.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
117
+ hiddenlayer_sdk-1.1.1.dist-info/top_level.txt,sha256=8BxcmGvEN1RqsMvTWg9Q0vDmtBGcTmatnme6nzyPj2U,12
118
+ hiddenlayer_sdk-1.1.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -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
-