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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
-