hiddenlayer-sdk 2.0.9__py3-none-any.whl → 3.0.0__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.
- hiddenlayer/__init__.py +109 -105
- hiddenlayer/_base_client.py +1995 -0
- hiddenlayer/_client.py +761 -0
- hiddenlayer/_compat.py +219 -0
- hiddenlayer/_constants.py +14 -0
- hiddenlayer/_exceptions.py +108 -0
- hiddenlayer/_files.py +123 -0
- hiddenlayer/_models.py +835 -0
- hiddenlayer/_oauth2.py +118 -0
- hiddenlayer/_qs.py +150 -0
- hiddenlayer/_resource.py +43 -0
- hiddenlayer/_response.py +832 -0
- hiddenlayer/_streaming.py +333 -0
- hiddenlayer/_types.py +260 -0
- hiddenlayer/_utils/__init__.py +64 -0
- hiddenlayer/_utils/_compat.py +45 -0
- hiddenlayer/_utils/_datetime_parse.py +136 -0
- hiddenlayer/_utils/_logs.py +25 -0
- hiddenlayer/_utils/_proxy.py +65 -0
- hiddenlayer/_utils/_reflection.py +42 -0
- hiddenlayer/_utils/_resources_proxy.py +24 -0
- hiddenlayer/_utils/_streams.py +12 -0
- hiddenlayer/_utils/_sync.py +86 -0
- hiddenlayer/_utils/_transform.py +457 -0
- hiddenlayer/_utils/_typing.py +156 -0
- hiddenlayer/_utils/_utils.py +421 -0
- hiddenlayer/_version.py +4 -0
- hiddenlayer/lib/.keep +4 -0
- hiddenlayer/lib/__init__.py +6 -0
- hiddenlayer/lib/community_scan.py +174 -0
- hiddenlayer/lib/model_scan.py +752 -0
- hiddenlayer/lib/scan_utils.py +142 -0
- hiddenlayer/pagination.py +127 -0
- hiddenlayer/resources/__init__.py +75 -0
- hiddenlayer/resources/interactions.py +205 -0
- hiddenlayer/resources/models/__init__.py +33 -0
- hiddenlayer/resources/models/cards.py +259 -0
- hiddenlayer/resources/models/models.py +284 -0
- hiddenlayer/resources/prompt_analyzer.py +207 -0
- hiddenlayer/resources/scans/__init__.py +61 -0
- hiddenlayer/resources/scans/jobs.py +499 -0
- hiddenlayer/resources/scans/results.py +169 -0
- hiddenlayer/resources/scans/scans.py +166 -0
- hiddenlayer/resources/scans/upload/__init__.py +33 -0
- hiddenlayer/resources/scans/upload/file.py +279 -0
- hiddenlayer/resources/scans/upload/upload.py +340 -0
- hiddenlayer/resources/sensors.py +575 -0
- hiddenlayer/types/__init__.py +16 -0
- hiddenlayer/types/interaction_analyze_params.py +62 -0
- hiddenlayer/types/interaction_analyze_response.py +199 -0
- hiddenlayer/types/model_retrieve_response.py +50 -0
- hiddenlayer/types/models/__init__.py +6 -0
- hiddenlayer/types/models/card_list_params.py +65 -0
- hiddenlayer/types/models/card_list_response.py +50 -0
- hiddenlayer/types/prompt_analyzer_create_params.py +23 -0
- hiddenlayer/types/prompt_analyzer_create_response.py +381 -0
- hiddenlayer/types/scans/__init__.py +14 -0
- hiddenlayer/types/scans/job_list_params.py +75 -0
- hiddenlayer/types/scans/job_list_response.py +22 -0
- hiddenlayer/types/scans/job_request_params.py +49 -0
- hiddenlayer/types/scans/job_retrieve_params.py +16 -0
- hiddenlayer/types/scans/result_sarif_response.py +7 -0
- hiddenlayer/types/scans/scan_job.py +46 -0
- hiddenlayer/types/scans/scan_report.py +367 -0
- hiddenlayer/types/scans/upload/__init__.py +6 -0
- hiddenlayer/types/scans/upload/file_add_response.py +24 -0
- hiddenlayer/types/scans/upload/file_complete_response.py +12 -0
- hiddenlayer/types/scans/upload_complete_all_response.py +12 -0
- hiddenlayer/types/scans/upload_start_params.py +34 -0
- hiddenlayer/types/scans/upload_start_response.py +12 -0
- hiddenlayer/types/sensor_create_params.py +24 -0
- hiddenlayer/types/sensor_create_response.py +33 -0
- hiddenlayer/types/sensor_query_params.py +39 -0
- hiddenlayer/types/sensor_query_response.py +43 -0
- hiddenlayer/types/sensor_retrieve_response.py +33 -0
- hiddenlayer/types/sensor_update_params.py +20 -0
- hiddenlayer/types/sensor_update_response.py +9 -0
- hiddenlayer_sdk-3.0.0.dist-info/METADATA +431 -0
- hiddenlayer_sdk-3.0.0.dist-info/RECORD +82 -0
- {hiddenlayer_sdk-2.0.9.dist-info → hiddenlayer_sdk-3.0.0.dist-info}/WHEEL +1 -2
- {hiddenlayer_sdk-2.0.9.dist-info → hiddenlayer_sdk-3.0.0.dist-info}/licenses/LICENSE +1 -1
- hiddenlayer/sdk/constants.py +0 -26
- hiddenlayer/sdk/exceptions.py +0 -12
- hiddenlayer/sdk/models.py +0 -58
- hiddenlayer/sdk/rest/__init__.py +0 -135
- hiddenlayer/sdk/rest/api/__init__.py +0 -10
- hiddenlayer/sdk/rest/api/aidr_predictive_api.py +0 -308
- hiddenlayer/sdk/rest/api/health_api.py +0 -272
- hiddenlayer/sdk/rest/api/model_api.py +0 -559
- hiddenlayer/sdk/rest/api/model_supply_chain_api.py +0 -4063
- hiddenlayer/sdk/rest/api/readiness_api.py +0 -272
- hiddenlayer/sdk/rest/api/sensor_api.py +0 -1432
- hiddenlayer/sdk/rest/api_client.py +0 -770
- hiddenlayer/sdk/rest/api_response.py +0 -21
- hiddenlayer/sdk/rest/configuration.py +0 -445
- hiddenlayer/sdk/rest/exceptions.py +0 -199
- hiddenlayer/sdk/rest/models/__init__.py +0 -113
- hiddenlayer/sdk/rest/models/address.py +0 -110
- hiddenlayer/sdk/rest/models/artifact.py +0 -155
- hiddenlayer/sdk/rest/models/artifact_change.py +0 -108
- hiddenlayer/sdk/rest/models/artifact_content.py +0 -101
- hiddenlayer/sdk/rest/models/artifact_location.py +0 -109
- hiddenlayer/sdk/rest/models/attachment.py +0 -129
- hiddenlayer/sdk/rest/models/begin_multi_file_upload200_response.py +0 -87
- hiddenlayer/sdk/rest/models/begin_multipart_file_upload200_response.py +0 -97
- hiddenlayer/sdk/rest/models/begin_multipart_file_upload200_response_parts_inner.py +0 -94
- hiddenlayer/sdk/rest/models/code_flow.py +0 -113
- hiddenlayer/sdk/rest/models/configuration_override.py +0 -108
- hiddenlayer/sdk/rest/models/conversion.py +0 -114
- hiddenlayer/sdk/rest/models/create_sensor_request.py +0 -95
- hiddenlayer/sdk/rest/models/edge.py +0 -108
- hiddenlayer/sdk/rest/models/edge_traversal.py +0 -122
- hiddenlayer/sdk/rest/models/errors_inner.py +0 -91
- hiddenlayer/sdk/rest/models/exception.py +0 -113
- hiddenlayer/sdk/rest/models/external_properties.py +0 -273
- hiddenlayer/sdk/rest/models/external_property_file_reference.py +0 -102
- hiddenlayer/sdk/rest/models/external_property_file_references.py +0 -240
- hiddenlayer/sdk/rest/models/file_details_v3.py +0 -139
- hiddenlayer/sdk/rest/models/file_result_v3.py +0 -117
- hiddenlayer/sdk/rest/models/file_scan_report_v3.py +0 -132
- hiddenlayer/sdk/rest/models/file_scan_reports_v3.py +0 -95
- hiddenlayer/sdk/rest/models/fix.py +0 -113
- hiddenlayer/sdk/rest/models/get_condensed_model_scan_reports200_response.py +0 -102
- hiddenlayer/sdk/rest/models/graph.py +0 -123
- hiddenlayer/sdk/rest/models/graph_traversal.py +0 -97
- hiddenlayer/sdk/rest/models/inventory_v3.py +0 -101
- hiddenlayer/sdk/rest/models/invocation.py +0 -199
- hiddenlayer/sdk/rest/models/location.py +0 -146
- hiddenlayer/sdk/rest/models/location_inner.py +0 -138
- hiddenlayer/sdk/rest/models/location_relationship.py +0 -107
- hiddenlayer/sdk/rest/models/logical_location.py +0 -104
- hiddenlayer/sdk/rest/models/message.py +0 -92
- hiddenlayer/sdk/rest/models/mitre_atlas_inner.py +0 -110
- hiddenlayer/sdk/rest/models/model.py +0 -103
- hiddenlayer/sdk/rest/models/model_inventory_info.py +0 -103
- hiddenlayer/sdk/rest/models/model_version.py +0 -97
- hiddenlayer/sdk/rest/models/multi_file_upload_request_v3.py +0 -97
- hiddenlayer/sdk/rest/models/multiformat_message_string.py +0 -95
- hiddenlayer/sdk/rest/models/node.py +0 -122
- hiddenlayer/sdk/rest/models/notification.py +0 -157
- hiddenlayer/sdk/rest/models/notify_model_scan_completed200_response.py +0 -87
- hiddenlayer/sdk/rest/models/paged_response_with_total.py +0 -94
- hiddenlayer/sdk/rest/models/pagination_v3.py +0 -95
- hiddenlayer/sdk/rest/models/physical_location.py +0 -94
- hiddenlayer/sdk/rest/models/problem_details.py +0 -103
- hiddenlayer/sdk/rest/models/property_bag.py +0 -101
- hiddenlayer/sdk/rest/models/rectangle.py +0 -110
- hiddenlayer/sdk/rest/models/region.py +0 -127
- hiddenlayer/sdk/rest/models/replacement.py +0 -103
- hiddenlayer/sdk/rest/models/reporting_configuration.py +0 -113
- hiddenlayer/sdk/rest/models/reporting_descriptor.py +0 -162
- hiddenlayer/sdk/rest/models/reporting_descriptor_reference.py +0 -103
- hiddenlayer/sdk/rest/models/reporting_descriptor_relationship.py +0 -115
- hiddenlayer/sdk/rest/models/result.py +0 -312
- hiddenlayer/sdk/rest/models/result_provenance.py +0 -133
- hiddenlayer/sdk/rest/models/rule_details_inner.py +0 -102
- hiddenlayer/sdk/rest/models/run.py +0 -318
- hiddenlayer/sdk/rest/models/run_automation_details.py +0 -129
- hiddenlayer/sdk/rest/models/sarif210.py +0 -123
- hiddenlayer/sdk/rest/models/scan_create_request.py +0 -87
- hiddenlayer/sdk/rest/models/scan_detection_v3.py +0 -159
- hiddenlayer/sdk/rest/models/scan_detection_v31.py +0 -158
- hiddenlayer/sdk/rest/models/scan_header_v3.py +0 -129
- hiddenlayer/sdk/rest/models/scan_job.py +0 -115
- hiddenlayer/sdk/rest/models/scan_job_access.py +0 -97
- hiddenlayer/sdk/rest/models/scan_model_details_v3.py +0 -99
- hiddenlayer/sdk/rest/models/scan_model_details_v31.py +0 -97
- hiddenlayer/sdk/rest/models/scan_model_ids_v3.py +0 -89
- hiddenlayer/sdk/rest/models/scan_report_v3.py +0 -139
- hiddenlayer/sdk/rest/models/scan_results_map_v3.py +0 -105
- hiddenlayer/sdk/rest/models/scan_results_v3.py +0 -120
- hiddenlayer/sdk/rest/models/security_posture.py +0 -89
- hiddenlayer/sdk/rest/models/sensor.py +0 -100
- hiddenlayer/sdk/rest/models/sensor_query_response.py +0 -101
- hiddenlayer/sdk/rest/models/sensor_sor_model_card_query_response.py +0 -101
- hiddenlayer/sdk/rest/models/sensor_sor_model_card_response.py +0 -127
- hiddenlayer/sdk/rest/models/sensor_sor_query_filter.py +0 -108
- hiddenlayer/sdk/rest/models/sensor_sor_query_request.py +0 -109
- hiddenlayer/sdk/rest/models/special_locations.py +0 -97
- hiddenlayer/sdk/rest/models/stack.py +0 -113
- hiddenlayer/sdk/rest/models/stack_frame.py +0 -104
- hiddenlayer/sdk/rest/models/submission_response.py +0 -95
- hiddenlayer/sdk/rest/models/submission_v2.py +0 -109
- hiddenlayer/sdk/rest/models/suppression.py +0 -133
- hiddenlayer/sdk/rest/models/thread_flow.py +0 -144
- hiddenlayer/sdk/rest/models/thread_flow_location.py +0 -166
- hiddenlayer/sdk/rest/models/tool.py +0 -107
- hiddenlayer/sdk/rest/models/tool_component.py +0 -251
- hiddenlayer/sdk/rest/models/tool_component_reference.py +0 -108
- hiddenlayer/sdk/rest/models/translation_metadata.py +0 -110
- hiddenlayer/sdk/rest/models/validation_error_model.py +0 -99
- hiddenlayer/sdk/rest/models/version_control_details.py +0 -108
- hiddenlayer/sdk/rest/models/web_request.py +0 -112
- hiddenlayer/sdk/rest/models/web_response.py +0 -112
- hiddenlayer/sdk/rest/rest.py +0 -257
- hiddenlayer/sdk/services/__init__.py +0 -0
- hiddenlayer/sdk/services/aidr_predictive.py +0 -130
- hiddenlayer/sdk/services/model_scan.py +0 -505
- hiddenlayer/sdk/utils.py +0 -92
- hiddenlayer/sdk/version.py +0 -1
- hiddenlayer_sdk-2.0.9.dist-info/METADATA +0 -368
- hiddenlayer_sdk-2.0.9.dist-info/RECORD +0 -126
- hiddenlayer_sdk-2.0.9.dist-info/top_level.txt +0 -1
- /hiddenlayer/{sdk/__init__.py → py.typed} +0 -0
@@ -0,0 +1,136 @@
|
|
1
|
+
"""
|
2
|
+
This file contains code from https://github.com/pydantic/pydantic/blob/main/pydantic/v1/datetime_parse.py
|
3
|
+
without the Pydantic v1 specific errors.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from __future__ import annotations
|
7
|
+
|
8
|
+
import re
|
9
|
+
from typing import Dict, Union, Optional
|
10
|
+
from datetime import date, datetime, timezone, timedelta
|
11
|
+
|
12
|
+
from .._types import StrBytesIntFloat
|
13
|
+
|
14
|
+
date_expr = r"(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})"
|
15
|
+
time_expr = (
|
16
|
+
r"(?P<hour>\d{1,2}):(?P<minute>\d{1,2})"
|
17
|
+
r"(?::(?P<second>\d{1,2})(?:\.(?P<microsecond>\d{1,6})\d{0,6})?)?"
|
18
|
+
r"(?P<tzinfo>Z|[+-]\d{2}(?::?\d{2})?)?$"
|
19
|
+
)
|
20
|
+
|
21
|
+
date_re = re.compile(f"{date_expr}$")
|
22
|
+
datetime_re = re.compile(f"{date_expr}[T ]{time_expr}")
|
23
|
+
|
24
|
+
|
25
|
+
EPOCH = datetime(1970, 1, 1)
|
26
|
+
# if greater than this, the number is in ms, if less than or equal it's in seconds
|
27
|
+
# (in seconds this is 11th October 2603, in ms it's 20th August 1970)
|
28
|
+
MS_WATERSHED = int(2e10)
|
29
|
+
# slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9
|
30
|
+
MAX_NUMBER = int(3e20)
|
31
|
+
|
32
|
+
|
33
|
+
def _get_numeric(value: StrBytesIntFloat, native_expected_type: str) -> Union[None, int, float]:
|
34
|
+
if isinstance(value, (int, float)):
|
35
|
+
return value
|
36
|
+
try:
|
37
|
+
return float(value)
|
38
|
+
except ValueError:
|
39
|
+
return None
|
40
|
+
except TypeError:
|
41
|
+
raise TypeError(f"invalid type; expected {native_expected_type}, string, bytes, int or float") from None
|
42
|
+
|
43
|
+
|
44
|
+
def _from_unix_seconds(seconds: Union[int, float]) -> datetime:
|
45
|
+
if seconds > MAX_NUMBER:
|
46
|
+
return datetime.max
|
47
|
+
elif seconds < -MAX_NUMBER:
|
48
|
+
return datetime.min
|
49
|
+
|
50
|
+
while abs(seconds) > MS_WATERSHED:
|
51
|
+
seconds /= 1000
|
52
|
+
dt = EPOCH + timedelta(seconds=seconds)
|
53
|
+
return dt.replace(tzinfo=timezone.utc)
|
54
|
+
|
55
|
+
|
56
|
+
def _parse_timezone(value: Optional[str]) -> Union[None, int, timezone]:
|
57
|
+
if value == "Z":
|
58
|
+
return timezone.utc
|
59
|
+
elif value is not None:
|
60
|
+
offset_mins = int(value[-2:]) if len(value) > 3 else 0
|
61
|
+
offset = 60 * int(value[1:3]) + offset_mins
|
62
|
+
if value[0] == "-":
|
63
|
+
offset = -offset
|
64
|
+
return timezone(timedelta(minutes=offset))
|
65
|
+
else:
|
66
|
+
return None
|
67
|
+
|
68
|
+
|
69
|
+
def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime:
|
70
|
+
"""
|
71
|
+
Parse a datetime/int/float/string and return a datetime.datetime.
|
72
|
+
|
73
|
+
This function supports time zone offsets. When the input contains one,
|
74
|
+
the output uses a timezone with a fixed offset from UTC.
|
75
|
+
|
76
|
+
Raise ValueError if the input is well formatted but not a valid datetime.
|
77
|
+
Raise ValueError if the input isn't well formatted.
|
78
|
+
"""
|
79
|
+
if isinstance(value, datetime):
|
80
|
+
return value
|
81
|
+
|
82
|
+
number = _get_numeric(value, "datetime")
|
83
|
+
if number is not None:
|
84
|
+
return _from_unix_seconds(number)
|
85
|
+
|
86
|
+
if isinstance(value, bytes):
|
87
|
+
value = value.decode()
|
88
|
+
|
89
|
+
assert not isinstance(value, (float, int))
|
90
|
+
|
91
|
+
match = datetime_re.match(value)
|
92
|
+
if match is None:
|
93
|
+
raise ValueError("invalid datetime format")
|
94
|
+
|
95
|
+
kw = match.groupdict()
|
96
|
+
if kw["microsecond"]:
|
97
|
+
kw["microsecond"] = kw["microsecond"].ljust(6, "0")
|
98
|
+
|
99
|
+
tzinfo = _parse_timezone(kw.pop("tzinfo"))
|
100
|
+
kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None}
|
101
|
+
kw_["tzinfo"] = tzinfo
|
102
|
+
|
103
|
+
return datetime(**kw_) # type: ignore
|
104
|
+
|
105
|
+
|
106
|
+
def parse_date(value: Union[date, StrBytesIntFloat]) -> date:
|
107
|
+
"""
|
108
|
+
Parse a date/int/float/string and return a datetime.date.
|
109
|
+
|
110
|
+
Raise ValueError if the input is well formatted but not a valid date.
|
111
|
+
Raise ValueError if the input isn't well formatted.
|
112
|
+
"""
|
113
|
+
if isinstance(value, date):
|
114
|
+
if isinstance(value, datetime):
|
115
|
+
return value.date()
|
116
|
+
else:
|
117
|
+
return value
|
118
|
+
|
119
|
+
number = _get_numeric(value, "date")
|
120
|
+
if number is not None:
|
121
|
+
return _from_unix_seconds(number).date()
|
122
|
+
|
123
|
+
if isinstance(value, bytes):
|
124
|
+
value = value.decode()
|
125
|
+
|
126
|
+
assert not isinstance(value, (float, int))
|
127
|
+
match = date_re.match(value)
|
128
|
+
if match is None:
|
129
|
+
raise ValueError("invalid date format")
|
130
|
+
|
131
|
+
kw = {k: int(v) for k, v in match.groupdict().items()}
|
132
|
+
|
133
|
+
try:
|
134
|
+
return date(**kw)
|
135
|
+
except ValueError:
|
136
|
+
raise ValueError("invalid date format") from None
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import os
|
2
|
+
import logging
|
3
|
+
|
4
|
+
logger: logging.Logger = logging.getLogger("hiddenlayer")
|
5
|
+
httpx_logger: logging.Logger = logging.getLogger("httpx")
|
6
|
+
|
7
|
+
|
8
|
+
def _basic_config() -> None:
|
9
|
+
# e.g. [2023-10-05 14:12:26 - hiddenlayer._base_client:818 - DEBUG] HTTP Request: POST http://127.0.0.1:4010/foo/bar "200 OK"
|
10
|
+
logging.basicConfig(
|
11
|
+
format="[%(asctime)s - %(name)s:%(lineno)d - %(levelname)s] %(message)s",
|
12
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
13
|
+
)
|
14
|
+
|
15
|
+
|
16
|
+
def setup_logging() -> None:
|
17
|
+
env = os.environ.get("HIDDENLAYER_LOG")
|
18
|
+
if env == "debug":
|
19
|
+
_basic_config()
|
20
|
+
logger.setLevel(logging.DEBUG)
|
21
|
+
httpx_logger.setLevel(logging.DEBUG)
|
22
|
+
elif env == "info":
|
23
|
+
_basic_config()
|
24
|
+
logger.setLevel(logging.INFO)
|
25
|
+
httpx_logger.setLevel(logging.INFO)
|
@@ -0,0 +1,65 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from abc import ABC, abstractmethod
|
4
|
+
from typing import Generic, TypeVar, Iterable, cast
|
5
|
+
from typing_extensions import override
|
6
|
+
|
7
|
+
T = TypeVar("T")
|
8
|
+
|
9
|
+
|
10
|
+
class LazyProxy(Generic[T], ABC):
|
11
|
+
"""Implements data methods to pretend that an instance is another instance.
|
12
|
+
|
13
|
+
This includes forwarding attribute access and other methods.
|
14
|
+
"""
|
15
|
+
|
16
|
+
# Note: we have to special case proxies that themselves return proxies
|
17
|
+
# to support using a proxy as a catch-all for any random access, e.g. `proxy.foo.bar.baz`
|
18
|
+
|
19
|
+
def __getattr__(self, attr: str) -> object:
|
20
|
+
proxied = self.__get_proxied__()
|
21
|
+
if isinstance(proxied, LazyProxy):
|
22
|
+
return proxied # pyright: ignore
|
23
|
+
return getattr(proxied, attr)
|
24
|
+
|
25
|
+
@override
|
26
|
+
def __repr__(self) -> str:
|
27
|
+
proxied = self.__get_proxied__()
|
28
|
+
if isinstance(proxied, LazyProxy):
|
29
|
+
return proxied.__class__.__name__
|
30
|
+
return repr(self.__get_proxied__())
|
31
|
+
|
32
|
+
@override
|
33
|
+
def __str__(self) -> str:
|
34
|
+
proxied = self.__get_proxied__()
|
35
|
+
if isinstance(proxied, LazyProxy):
|
36
|
+
return proxied.__class__.__name__
|
37
|
+
return str(proxied)
|
38
|
+
|
39
|
+
@override
|
40
|
+
def __dir__(self) -> Iterable[str]:
|
41
|
+
proxied = self.__get_proxied__()
|
42
|
+
if isinstance(proxied, LazyProxy):
|
43
|
+
return []
|
44
|
+
return proxied.__dir__()
|
45
|
+
|
46
|
+
@property # type: ignore
|
47
|
+
@override
|
48
|
+
def __class__(self) -> type: # pyright: ignore
|
49
|
+
try:
|
50
|
+
proxied = self.__get_proxied__()
|
51
|
+
except Exception:
|
52
|
+
return type(self)
|
53
|
+
if issubclass(type(proxied), LazyProxy):
|
54
|
+
return type(proxied)
|
55
|
+
return proxied.__class__
|
56
|
+
|
57
|
+
def __get_proxied__(self) -> T:
|
58
|
+
return self.__load__()
|
59
|
+
|
60
|
+
def __as_proxied__(self) -> T:
|
61
|
+
"""Helper method that returns the current proxy, typed as the loaded object"""
|
62
|
+
return cast(T, self)
|
63
|
+
|
64
|
+
@abstractmethod
|
65
|
+
def __load__(self) -> T: ...
|
@@ -0,0 +1,42 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import inspect
|
4
|
+
from typing import Any, Callable
|
5
|
+
|
6
|
+
|
7
|
+
def function_has_argument(func: Callable[..., Any], arg_name: str) -> bool:
|
8
|
+
"""Returns whether or not the given function has a specific parameter"""
|
9
|
+
sig = inspect.signature(func)
|
10
|
+
return arg_name in sig.parameters
|
11
|
+
|
12
|
+
|
13
|
+
def assert_signatures_in_sync(
|
14
|
+
source_func: Callable[..., Any],
|
15
|
+
check_func: Callable[..., Any],
|
16
|
+
*,
|
17
|
+
exclude_params: set[str] = set(),
|
18
|
+
) -> None:
|
19
|
+
"""Ensure that the signature of the second function matches the first."""
|
20
|
+
|
21
|
+
check_sig = inspect.signature(check_func)
|
22
|
+
source_sig = inspect.signature(source_func)
|
23
|
+
|
24
|
+
errors: list[str] = []
|
25
|
+
|
26
|
+
for name, source_param in source_sig.parameters.items():
|
27
|
+
if name in exclude_params:
|
28
|
+
continue
|
29
|
+
|
30
|
+
custom_param = check_sig.parameters.get(name)
|
31
|
+
if not custom_param:
|
32
|
+
errors.append(f"the `{name}` param is missing")
|
33
|
+
continue
|
34
|
+
|
35
|
+
if custom_param.annotation != source_param.annotation:
|
36
|
+
errors.append(
|
37
|
+
f"types for the `{name}` param are do not match; source={repr(source_param.annotation)} checking={repr(custom_param.annotation)}"
|
38
|
+
)
|
39
|
+
continue
|
40
|
+
|
41
|
+
if errors:
|
42
|
+
raise AssertionError(f"{len(errors)} errors encountered when comparing signatures:\n\n" + "\n\n".join(errors))
|
@@ -0,0 +1,24 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from typing import Any
|
4
|
+
from typing_extensions import override
|
5
|
+
|
6
|
+
from ._proxy import LazyProxy
|
7
|
+
|
8
|
+
|
9
|
+
class ResourcesProxy(LazyProxy[Any]):
|
10
|
+
"""A proxy for the `hiddenlayer.resources` module.
|
11
|
+
|
12
|
+
This is used so that we can lazily import `hiddenlayer.resources` only when
|
13
|
+
needed *and* so that users can just import `hiddenlayer` and reference `hiddenlayer.resources`
|
14
|
+
"""
|
15
|
+
|
16
|
+
@override
|
17
|
+
def __load__(self) -> Any:
|
18
|
+
import importlib
|
19
|
+
|
20
|
+
mod = importlib.import_module("hiddenlayer.resources")
|
21
|
+
return mod
|
22
|
+
|
23
|
+
|
24
|
+
resources = ResourcesProxy().__as_proxied__()
|
@@ -0,0 +1,12 @@
|
|
1
|
+
from typing import Any
|
2
|
+
from typing_extensions import Iterator, AsyncIterator
|
3
|
+
|
4
|
+
|
5
|
+
def consume_sync_iterator(iterator: Iterator[Any]) -> None:
|
6
|
+
for _ in iterator:
|
7
|
+
...
|
8
|
+
|
9
|
+
|
10
|
+
async def consume_async_iterator(iterator: AsyncIterator[Any]) -> None:
|
11
|
+
async for _ in iterator:
|
12
|
+
...
|
@@ -0,0 +1,86 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import sys
|
4
|
+
import asyncio
|
5
|
+
import functools
|
6
|
+
import contextvars
|
7
|
+
from typing import Any, TypeVar, Callable, Awaitable
|
8
|
+
from typing_extensions import ParamSpec
|
9
|
+
|
10
|
+
import anyio
|
11
|
+
import sniffio
|
12
|
+
import anyio.to_thread
|
13
|
+
|
14
|
+
T_Retval = TypeVar("T_Retval")
|
15
|
+
T_ParamSpec = ParamSpec("T_ParamSpec")
|
16
|
+
|
17
|
+
|
18
|
+
if sys.version_info >= (3, 9):
|
19
|
+
_asyncio_to_thread = asyncio.to_thread
|
20
|
+
else:
|
21
|
+
# backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread
|
22
|
+
# for Python 3.8 support
|
23
|
+
async def _asyncio_to_thread(
|
24
|
+
func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
|
25
|
+
) -> Any:
|
26
|
+
"""Asynchronously run function *func* in a separate thread.
|
27
|
+
|
28
|
+
Any *args and **kwargs supplied for this function are directly passed
|
29
|
+
to *func*. Also, the current :class:`contextvars.Context` is propagated,
|
30
|
+
allowing context variables from the main thread to be accessed in the
|
31
|
+
separate thread.
|
32
|
+
|
33
|
+
Returns a coroutine that can be awaited to get the eventual result of *func*.
|
34
|
+
"""
|
35
|
+
loop = asyncio.events.get_running_loop()
|
36
|
+
ctx = contextvars.copy_context()
|
37
|
+
func_call = functools.partial(ctx.run, func, *args, **kwargs)
|
38
|
+
return await loop.run_in_executor(None, func_call)
|
39
|
+
|
40
|
+
|
41
|
+
async def to_thread(
|
42
|
+
func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
|
43
|
+
) -> T_Retval:
|
44
|
+
if sniffio.current_async_library() == "asyncio":
|
45
|
+
return await _asyncio_to_thread(func, *args, **kwargs)
|
46
|
+
|
47
|
+
return await anyio.to_thread.run_sync(
|
48
|
+
functools.partial(func, *args, **kwargs),
|
49
|
+
)
|
50
|
+
|
51
|
+
|
52
|
+
# inspired by `asyncer`, https://github.com/tiangolo/asyncer
|
53
|
+
def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]:
|
54
|
+
"""
|
55
|
+
Take a blocking function and create an async one that receives the same
|
56
|
+
positional and keyword arguments. For python version 3.9 and above, it uses
|
57
|
+
asyncio.to_thread to run the function in a separate thread. For python version
|
58
|
+
3.8, it uses locally defined copy of the asyncio.to_thread function which was
|
59
|
+
introduced in python 3.9.
|
60
|
+
|
61
|
+
Usage:
|
62
|
+
|
63
|
+
```python
|
64
|
+
def blocking_func(arg1, arg2, kwarg1=None):
|
65
|
+
# blocking code
|
66
|
+
return result
|
67
|
+
|
68
|
+
|
69
|
+
result = asyncify(blocking_function)(arg1, arg2, kwarg1=value1)
|
70
|
+
```
|
71
|
+
|
72
|
+
## Arguments
|
73
|
+
|
74
|
+
`function`: a blocking regular callable (e.g. a function)
|
75
|
+
|
76
|
+
## Return
|
77
|
+
|
78
|
+
An async function that takes the same positional and keyword arguments as the
|
79
|
+
original one, that when called runs the same original function in a thread worker
|
80
|
+
and returns the result.
|
81
|
+
"""
|
82
|
+
|
83
|
+
async def wrapper(*args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs) -> T_Retval:
|
84
|
+
return await to_thread(function, *args, **kwargs)
|
85
|
+
|
86
|
+
return wrapper
|