pangea-sdk 6.1.1__tar.gz → 6.2.0__tar.gz

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.
Files changed (60) hide show
  1. pangea_sdk-6.1.1/README.md → pangea_sdk-6.2.0/PKG-INFO +52 -9
  2. pangea_sdk-6.1.1/PKG-INFO → pangea_sdk-6.2.0/README.md +29 -34
  3. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/__init__.py +9 -1
  4. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/__init__.py +1 -0
  5. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/file_uploader.py +4 -2
  6. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/request.py +52 -17
  7. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/services/__init__.py +2 -0
  8. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/services/ai_guard.py +9 -12
  9. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/services/audit.py +6 -1
  10. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/services/authn.py +15 -4
  11. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/services/base.py +4 -0
  12. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/services/file_scan.py +7 -1
  13. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/services/intel.py +26 -28
  14. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/services/redact.py +4 -0
  15. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/services/sanitize.py +5 -1
  16. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/services/share.py +5 -1
  17. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/services/vault.py +4 -0
  18. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/audit_logger.py +3 -1
  19. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/deep_verify.py +13 -13
  20. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/deprecated.py +1 -1
  21. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/dump_audit.py +2 -3
  22. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/exceptions.py +8 -5
  23. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/file_uploader.py +4 -0
  24. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/request.py +63 -47
  25. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/response.py +21 -18
  26. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/__init__.py +2 -0
  27. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/ai_guard.py +35 -24
  28. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/audit/audit.py +10 -7
  29. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/audit/models.py +71 -34
  30. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/audit/signing.py +1 -1
  31. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/audit/util.py +10 -10
  32. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/authn/authn.py +15 -4
  33. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/authn/models.py +10 -56
  34. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/authz.py +4 -0
  35. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/base.py +7 -4
  36. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/embargo.py +6 -0
  37. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/file_scan.py +7 -1
  38. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/intel.py +36 -19
  39. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/redact.py +4 -0
  40. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/sanitize.py +5 -1
  41. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/share/share.py +13 -7
  42. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/vault/models/asymmetric.py +4 -0
  43. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/vault/models/common.py +4 -0
  44. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/vault/models/symmetric.py +4 -0
  45. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/vault/vault.py +2 -4
  46. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/tools.py +13 -9
  47. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/utils.py +3 -5
  48. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/verify_audit.py +23 -27
  49. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pyproject.toml +19 -20
  50. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/services/authz.py +0 -0
  51. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/services/embargo.py +0 -0
  52. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/asyncio/services/prompt_guard.py +0 -0
  53. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/config.py +0 -0
  54. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/crypto/rsa.py +0 -0
  55. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/py.typed +0 -0
  56. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/audit/exceptions.py +0 -0
  57. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/prompt_guard.py +0 -0
  58. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/share/file_format.py +0 -0
  59. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/vault/models/keys.py +0 -0
  60. {pangea_sdk-6.1.1 → pangea_sdk-6.2.0}/pangea/services/vault/models/secret.py +0 -0
@@ -1,3 +1,26 @@
1
+ Metadata-Version: 2.3
2
+ Name: pangea-sdk
3
+ Version: 6.2.0
4
+ Summary: Pangea API SDK
5
+ License: MIT
6
+ Keywords: Pangea,SDK,Audit
7
+ Author: Glenn Gallien
8
+ Author-email: glenn.gallien@pangea.cloud
9
+ Requires-Python: >=3.9.2,<4.0.0
10
+ Classifier: Topic :: Software Development
11
+ Classifier: Topic :: Software Development :: Libraries
12
+ Requires-Dist: aiohttp (>=3.12.13,<4.0.0)
13
+ Requires-Dist: cryptography (>=45.0.4,<46.0.0)
14
+ Requires-Dist: deprecated (>=1.2.18,<2.0.0)
15
+ Requires-Dist: google-crc32c (>=1.7.1,<2.0.0)
16
+ Requires-Dist: pydantic (>=2.11.7,<3.0.0)
17
+ Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
18
+ Requires-Dist: requests (>=2.32.4,<3.0.0)
19
+ Requires-Dist: requests-toolbelt (>=1.0.0,<2.0.0)
20
+ Requires-Dist: typing-extensions (>=4.14.0,<5.0.0)
21
+ Requires-Dist: yarl (>=1.20.1,<2.0.0)
22
+ Description-Content-Type: text/markdown
23
+
1
24
  <a href="https://pangea.cloud?utm_source=github&utm_medium=python-sdk" target="_blank" rel="noopener noreferrer">
2
25
  <img src="https://pangea-marketing.s3.us-west-2.amazonaws.com/pangea-color.svg" alt="Pangea Logo" height="40" />
3
26
  </a>
@@ -40,13 +63,13 @@ the same compatibility guarantees as stable releases.
40
63
  Via pip:
41
64
 
42
65
  ```bash
43
- $ pip3 install pangea-sdk==5.5.0b2
66
+ $ pip3 install pangea-sdk==6.2.0b2
44
67
  ```
45
68
 
46
69
  Via poetry:
47
70
 
48
71
  ```bash
49
- $ poetry add pangea-sdk==5.5.0b2
72
+ $ poetry add pangea-sdk==6.2.0b2
50
73
  ```
51
74
 
52
75
  ## Usage
@@ -79,6 +102,26 @@ audit = Audit(token, config)
79
102
  response = audit.log(message="Hello, World!")
80
103
  ```
81
104
 
105
+ ## Configuration
106
+
107
+ The SDK supports the following configuration options via `PangeaConfig`:
108
+
109
+ - `base_url_template` — Template for constructing the base URL for API requests.
110
+ The placeholder `{SERVICE_NAME}` will be replaced with the service name slug.
111
+ This is a more powerful version of `domain` that allows for setting more than
112
+ just the host of the API server. Defaults to
113
+ `https://{SERVICE_NAME}.aws.us.pangea.cloud`.
114
+ - `domain` — Base domain for API requests. This is a weaker version of
115
+ `base_url_template` that only allows for setting the host of the API server.
116
+ Use `base_url_template` for more control over the URL, such as setting
117
+ service-specific paths. Defaults to `aws.us.pangea.cloud`.
118
+ - `request_retries` — Number of retries on the initial request.
119
+ - `request_backoff` — Backoff strategy passed to 'requests'.
120
+ - `request_timeout` — Timeout used on initial request attempts.
121
+ - `poll_result_timeout` — Timeout used to poll results after 202 (in secs).
122
+ - `queued_retry_enabled` — Enable queued request retry support.
123
+ - `custom_user_agent` — Custom user agent to be used in the request headers.
124
+
82
125
  ## asyncio support
83
126
 
84
127
  asyncio support is available through the `pangea.asyncio.services` module. The
@@ -133,6 +176,7 @@ options:
133
176
  ```
134
177
 
135
178
  It accepts multiple file formats:
179
+
136
180
  - a Verification Artifact from the Pangea User Console
137
181
  - a search response from the REST API:
138
182
 
@@ -140,7 +184,6 @@ It accepts multiple file formats:
140
184
  $ curl -H "Authorization: Bearer ${PANGEA_TOKEN}" -X POST -H 'Content-Type: application/json' --data '{"verbose": true}' https://audit.aws.us.pangea.cloud/v1/search
141
185
  ```
142
186
 
143
-
144
187
  ### Bulk Download Audit Data
145
188
 
146
189
  Download all audit logs for a given time range. Start and end date should be provided,
@@ -190,14 +233,14 @@ options:
190
233
  ```
191
234
 
192
235
  It accepts multiple file formats:
236
+
193
237
  - a Verification Artifact from the Pangea User Console
194
238
  - a file generated by the `dump_audit` command
195
239
  - a search response from the REST API (see `verify_audit`)
196
240
 
241
+ [Documentation]: https://pangea.cloud/docs/sdk/python/
242
+ [GA Examples]: https://github.com/pangeacyber/pangea-python/tree/main/examples
243
+ [Beta Examples]: https://github.com/pangeacyber/pangea-python/tree/beta/examples
244
+ [Pangea Console]: https://console.pangea.cloud/
245
+ [Secure Audit Log]: https://pangea.cloud/docs/audit
197
246
 
198
-
199
- [Documentation]: https://pangea.cloud/docs/sdk/python/
200
- [GA Examples]: https://github.com/pangeacyber/pangea-python/tree/main/examples
201
- [Beta Examples]: https://github.com/pangeacyber/pangea-python/tree/beta/examples
202
- [Pangea Console]: https://console.pangea.cloud/
203
- [Secure Audit Log]: https://pangea.cloud/docs/audit
@@ -1,26 +1,3 @@
1
- Metadata-Version: 2.3
2
- Name: pangea-sdk
3
- Version: 6.1.1
4
- Summary: Pangea API SDK
5
- License: MIT
6
- Keywords: Pangea,SDK,Audit
7
- Author: Glenn Gallien
8
- Author-email: glenn.gallien@pangea.cloud
9
- Requires-Python: >=3.9.2,<4.0.0
10
- Classifier: Topic :: Software Development
11
- Classifier: Topic :: Software Development :: Libraries
12
- Requires-Dist: aiohttp (>=3.11.18,<4.0.0)
13
- Requires-Dist: cryptography (>=44.0.3,<44.0.4)
14
- Requires-Dist: deprecated (>=1.2.18,<2.0.0)
15
- Requires-Dist: google-crc32c (>=1.7.1,<2.0.0)
16
- Requires-Dist: pydantic (>=2.11.4,<3.0.0)
17
- Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
18
- Requires-Dist: requests (>=2.32.3,<3.0.0)
19
- Requires-Dist: requests-toolbelt (>=1.0.0,<2.0.0)
20
- Requires-Dist: typing-extensions (>=4.13.2,<5.0.0)
21
- Requires-Dist: yarl (>=1.20.0,<2.0.0)
22
- Description-Content-Type: text/markdown
23
-
24
1
  <a href="https://pangea.cloud?utm_source=github&utm_medium=python-sdk" target="_blank" rel="noopener noreferrer">
25
2
  <img src="https://pangea-marketing.s3.us-west-2.amazonaws.com/pangea-color.svg" alt="Pangea Logo" height="40" />
26
3
  </a>
@@ -63,13 +40,13 @@ the same compatibility guarantees as stable releases.
63
40
  Via pip:
64
41
 
65
42
  ```bash
66
- $ pip3 install pangea-sdk==5.5.0b2
43
+ $ pip3 install pangea-sdk==6.2.0b2
67
44
  ```
68
45
 
69
46
  Via poetry:
70
47
 
71
48
  ```bash
72
- $ poetry add pangea-sdk==5.5.0b2
49
+ $ poetry add pangea-sdk==6.2.0b2
73
50
  ```
74
51
 
75
52
  ## Usage
@@ -102,6 +79,26 @@ audit = Audit(token, config)
102
79
  response = audit.log(message="Hello, World!")
103
80
  ```
104
81
 
82
+ ## Configuration
83
+
84
+ The SDK supports the following configuration options via `PangeaConfig`:
85
+
86
+ - `base_url_template` — Template for constructing the base URL for API requests.
87
+ The placeholder `{SERVICE_NAME}` will be replaced with the service name slug.
88
+ This is a more powerful version of `domain` that allows for setting more than
89
+ just the host of the API server. Defaults to
90
+ `https://{SERVICE_NAME}.aws.us.pangea.cloud`.
91
+ - `domain` — Base domain for API requests. This is a weaker version of
92
+ `base_url_template` that only allows for setting the host of the API server.
93
+ Use `base_url_template` for more control over the URL, such as setting
94
+ service-specific paths. Defaults to `aws.us.pangea.cloud`.
95
+ - `request_retries` — Number of retries on the initial request.
96
+ - `request_backoff` — Backoff strategy passed to 'requests'.
97
+ - `request_timeout` — Timeout used on initial request attempts.
98
+ - `poll_result_timeout` — Timeout used to poll results after 202 (in secs).
99
+ - `queued_retry_enabled` — Enable queued request retry support.
100
+ - `custom_user_agent` — Custom user agent to be used in the request headers.
101
+
105
102
  ## asyncio support
106
103
 
107
104
  asyncio support is available through the `pangea.asyncio.services` module. The
@@ -156,6 +153,7 @@ options:
156
153
  ```
157
154
 
158
155
  It accepts multiple file formats:
156
+
159
157
  - a Verification Artifact from the Pangea User Console
160
158
  - a search response from the REST API:
161
159
 
@@ -163,7 +161,6 @@ It accepts multiple file formats:
163
161
  $ curl -H "Authorization: Bearer ${PANGEA_TOKEN}" -X POST -H 'Content-Type: application/json' --data '{"verbose": true}' https://audit.aws.us.pangea.cloud/v1/search
164
162
  ```
165
163
 
166
-
167
164
  ### Bulk Download Audit Data
168
165
 
169
166
  Download all audit logs for a given time range. Start and end date should be provided,
@@ -213,15 +210,13 @@ options:
213
210
  ```
214
211
 
215
212
  It accepts multiple file formats:
213
+
216
214
  - a Verification Artifact from the Pangea User Console
217
215
  - a file generated by the `dump_audit` command
218
216
  - a search response from the REST API (see `verify_audit`)
219
217
 
220
-
221
-
222
- [Documentation]: https://pangea.cloud/docs/sdk/python/
223
- [GA Examples]: https://github.com/pangeacyber/pangea-python/tree/main/examples
224
- [Beta Examples]: https://github.com/pangeacyber/pangea-python/tree/beta/examples
225
- [Pangea Console]: https://console.pangea.cloud/
226
- [Secure Audit Log]: https://pangea.cloud/docs/audit
227
-
218
+ [Documentation]: https://pangea.cloud/docs/sdk/python/
219
+ [GA Examples]: https://github.com/pangeacyber/pangea-python/tree/main/examples
220
+ [Beta Examples]: https://github.com/pangeacyber/pangea-python/tree/beta/examples
221
+ [Pangea Console]: https://console.pangea.cloud/
222
+ [Secure Audit Log]: https://pangea.cloud/docs/audit
@@ -1,7 +1,15 @@
1
- __version__ = "6.1.1"
1
+ __version__ = "6.2.0"
2
2
 
3
3
  from pangea.asyncio.request import PangeaRequestAsync
4
4
  from pangea.config import PangeaConfig
5
5
  from pangea.file_uploader import FileUploader
6
6
  from pangea.request import PangeaRequest
7
7
  from pangea.response import PangeaResponse
8
+
9
+ __all__ = (
10
+ "FileUploader",
11
+ "PangeaConfig",
12
+ "PangeaRequest",
13
+ "PangeaRequestAsync",
14
+ "PangeaResponse",
15
+ )
@@ -1 +1,2 @@
1
+ # ruff: noqa: F401
1
2
  from .file_uploader import FileUploaderAsync
@@ -1,8 +1,10 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+
4
+ from __future__ import annotations
5
+
3
6
  import io
4
7
  import logging
5
- from typing import Dict, Optional
6
8
 
7
9
  from pangea.asyncio.request import PangeaRequestAsync
8
10
  from pangea.request import PangeaConfig
@@ -24,7 +26,7 @@ class FileUploaderAsync:
24
26
  url: str,
25
27
  file: io.BufferedReader,
26
28
  transfer_method: TransferMethod = TransferMethod.PUT_URL,
27
- file_details: Optional[Dict] = None,
29
+ file_details: dict | None = None,
28
30
  ) -> None:
29
31
  if transfer_method == TransferMethod.PUT_URL:
30
32
  files = [("file", ("filename", file, "application/octet-stream"))]
@@ -1,23 +1,43 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+
4
+ # TODO: Modernize.
5
+ # ruff: noqa: UP006, UP035
6
+
3
7
  from __future__ import annotations
4
8
 
5
9
  import asyncio
6
10
  import json
7
11
  import time
12
+ from collections.abc import Iterable, Mapping
8
13
  from typing import Dict, List, Optional, Sequence, Tuple, Type, Union, cast
9
14
 
10
15
  import aiohttp
11
16
  from aiohttp import FormData
12
17
  from pydantic import BaseModel
13
18
  from pydantic_core import to_jsonable_python
14
- from typing_extensions import Any, TypeVar
19
+ from typing_extensions import Any, TypeAlias, TypeVar, override
15
20
 
16
21
  import pangea.exceptions as pe
17
22
  from pangea.request import MultipartResponse, PangeaRequestBase
18
23
  from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult, ResponseStatus, TransferMethod
19
24
  from pangea.utils import default_encoder
20
25
 
26
+ _FileName: TypeAlias = Union[str, None]
27
+ _FileContent: TypeAlias = Union[str, bytes]
28
+ _FileContentType: TypeAlias = str
29
+ _FileCustomHeaders: TypeAlias = Mapping[str, str]
30
+ _FileSpecTuple2: TypeAlias = tuple[_FileName, _FileContent]
31
+ _FileSpecTuple3: TypeAlias = tuple[_FileName, _FileContent, _FileContentType]
32
+ _FileSpecTuple4: TypeAlias = tuple[_FileName, _FileContent, _FileContentType, _FileCustomHeaders]
33
+ _FileSpec: TypeAlias = Union[_FileContent, _FileSpecTuple2, _FileSpecTuple3, _FileSpecTuple4]
34
+ _Files: TypeAlias = Union[Mapping[str, _FileSpec], Iterable[tuple[str, _FileSpec]]]
35
+ _LooseHeaders = Union[
36
+ Mapping[str, str],
37
+ Iterable[tuple[str, str]],
38
+ ]
39
+
40
+
21
41
  TResult = TypeVar("TResult", bound=PangeaResponseResult)
22
42
 
23
43
 
@@ -34,7 +54,7 @@ class PangeaRequestAsync(PangeaRequestBase):
34
54
  self,
35
55
  endpoint: str,
36
56
  result_class: Type[TResult],
37
- data: str | BaseModel | dict[str, Any] | None = None,
57
+ data: str | BaseModel | Mapping[str, Any] | None = None,
38
58
  files: Optional[List[Tuple]] = None,
39
59
  poll_result: bool = True,
40
60
  url: Optional[str] = None,
@@ -80,8 +100,11 @@ class PangeaRequestAsync(PangeaRequestBase):
80
100
  endpoint, result_class=result_class, data=data, files=files
81
101
  )
82
102
  else:
103
+ headers = self._headers()
104
+ if transfer_method == TransferMethod.MULTIPART.value:
105
+ del headers["Content-Type"]
83
106
  requests_response = await self._http_post(
84
- url, headers=self._headers(), data=data, files=files, presigned_url_post=False
107
+ url, headers=headers, data=data, files=files, presigned_url_post=False
85
108
  )
86
109
 
87
110
  await self._check_http_errors(requests_response)
@@ -103,7 +126,9 @@ class PangeaRequestAsync(PangeaRequestBase):
103
126
 
104
127
  pangea_response = PangeaResponse(requests_response, result_class=result_class, json=json_resp)
105
128
  except aiohttp.ContentTypeError as e:
106
- raise pe.PangeaException(f"Failed to decode json response. {e}. Body: {await requests_response.text()}")
129
+ raise pe.PangeaException(
130
+ f"Failed to decode json response. {e}. Body: {await requests_response.text()}"
131
+ ) from e
107
132
 
108
133
  if poll_result:
109
134
  pangea_response = await self._handle_queued_result(pangea_response)
@@ -164,7 +189,7 @@ class PangeaRequestAsync(PangeaRequestBase):
164
189
 
165
190
  return await self.poll_result_by_id(request_id, response.result_class, check_response=check_response)
166
191
 
167
- async def post_presigned_url(self, url: str, data: Dict, files: List[Tuple]):
192
+ async def post_presigned_url(self, url: str, data: dict[Any, Any], files: Sequence[Tuple]):
168
193
  # Send form request with file and upload_details as body
169
194
  resp = await self._http_post(url=url, data=data, files=files, presigned_url_post=True)
170
195
  self.logger.debug(
@@ -278,35 +303,44 @@ class PangeaRequestAsync(PangeaRequestBase):
278
303
  async def _http_post(
279
304
  self,
280
305
  url: str,
281
- headers: Dict = {},
282
- data: Union[str, Dict] = {},
283
- files: Optional[List[Tuple]] = [],
306
+ headers: _LooseHeaders = {}, # noqa: B006
307
+ data: str | dict[str, Any] | None = None,
308
+ files: _Files | None = None,
284
309
  presigned_url_post: bool = False,
285
310
  ) -> aiohttp.ClientResponse:
311
+ if data is None:
312
+ data = {}
313
+
286
314
  if files:
287
315
  form = FormData()
288
316
  if presigned_url_post:
289
- for k, v in data.items(): # type: ignore[union-attr]
317
+ assert isinstance(data, dict)
318
+ assert isinstance(files, list)
319
+ for k, v in data.items():
290
320
  form.add_field(k, v)
291
- for name, value in files:
321
+ for _name, value in files:
292
322
  form.add_field("file", value[1], filename=value[0], content_type=value[2])
293
323
  else:
294
- data_send = json.dumps(data, default=default_encoder) if isinstance(data, dict) else data
324
+ assert isinstance(files, list)
325
+ data_send: str | FormData = (
326
+ json.dumps(data, default=default_encoder) if isinstance(data, dict) else data
327
+ )
295
328
  form.add_field("request", data_send, content_type="application/json")
296
329
  for name, value in files:
297
330
  form.add_field(name, value[1], filename=value[0], content_type=value[2])
298
331
 
299
- data_send = form # type: ignore[assignment]
332
+ data_send = form
300
333
  else:
301
334
  data_send = json.dumps(data, default=default_encoder) if isinstance(data, dict) else data
302
335
 
336
+ assert isinstance(self.session, aiohttp.ClientSession)
303
337
  return await self.session.post(url, headers=headers, data=data_send)
304
338
 
305
339
  async def _http_put(
306
340
  self,
307
341
  url: str,
308
342
  files: Sequence[Tuple],
309
- headers: Dict = {},
343
+ headers: _LooseHeaders = {}, # noqa: B006
310
344
  ) -> aiohttp.ClientResponse:
311
345
  self.logger.debug(
312
346
  json.dumps({"service": self.service, "action": "http_put", "url": url}, default=default_encoder)
@@ -318,8 +352,8 @@ class PangeaRequestAsync(PangeaRequestBase):
318
352
  self,
319
353
  endpoint: str,
320
354
  result_class: Type[PangeaResponseResult],
321
- data: Union[str, Dict] = {},
322
- files: List[Tuple] = [],
355
+ data: Union[str, Mapping[str, Any]] = {},
356
+ files: Sequence[Tuple] = [],
323
357
  ):
324
358
  if len(files) == 0:
325
359
  raise AttributeError("files attribute should have at least 1 file")
@@ -343,7 +377,7 @@ class PangeaRequestAsync(PangeaRequestBase):
343
377
  self,
344
378
  endpoint: str,
345
379
  result_class: Type[PangeaResponseResult],
346
- data: Union[str, Dict] = {},
380
+ data: Union[str, Mapping[str, Any]] = {},
347
381
  ) -> PangeaResponse:
348
382
  # Send request
349
383
  try:
@@ -394,7 +428,7 @@ class PangeaRequestAsync(PangeaRequestBase):
394
428
  {"service": self.service, "action": "poll_presigned_url", "step": "exit", "cause": {str(e)}}
395
429
  )
396
430
  )
397
- raise pe.PresignedURLException("Failed to pull Presigned URL", loop_exc.response, e)
431
+ raise pe.PresignedURLException("Failed to pull Presigned URL", loop_exc.response, e) from e
398
432
 
399
433
  self.logger.debug(json.dumps({"service": self.service, "action": "poll_presigned_url", "step": "exit"}))
400
434
 
@@ -426,6 +460,7 @@ class PangeaRequestAsync(PangeaRequestBase):
426
460
  self.logger.debug(json.dumps({"service": self.service, "action": "poll_result_retry", "step": "exit"}))
427
461
  return self._check_response(response)
428
462
 
463
+ @override
429
464
  def _init_session(self) -> aiohttp.ClientSession:
430
465
  # retry_config = Retry(
431
466
  # total=self.config.request_retries,
@@ -1,3 +1,5 @@
1
+ # ruff: noqa: F401
2
+
1
3
  from .ai_guard import AIGuardAsync
2
4
  from .audit import AuditAsync
3
5
  from .authn import AuthNAsync
@@ -1,15 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from collections.abc import Sequence
3
4
  from typing import overload
4
5
 
5
- from typing_extensions import TypeVar
6
-
7
6
  from pangea.asyncio.services.base import ServiceBaseAsync
8
7
  from pangea.config import PangeaConfig
9
8
  from pangea.response import PangeaResponse
10
- from pangea.services.ai_guard import LogFields, Overrides, TextGuardResult
11
-
12
- _T = TypeVar("_T")
9
+ from pangea.services.ai_guard import LogFields, Message, Overrides, TextGuardResult
13
10
 
14
11
 
15
12
  class AIGuardAsync(ServiceBaseAsync):
@@ -60,7 +57,7 @@ class AIGuardAsync(ServiceBaseAsync):
60
57
  debug: bool | None = None,
61
58
  overrides: Overrides | None = None,
62
59
  log_fields: LogFields | None = None,
63
- ) -> PangeaResponse[TextGuardResult[None]]:
60
+ ) -> PangeaResponse[TextGuardResult]:
64
61
  """
65
62
  Text Guard for scanning LLM inputs and outputs
66
63
 
@@ -88,12 +85,12 @@ class AIGuardAsync(ServiceBaseAsync):
88
85
  async def guard_text(
89
86
  self,
90
87
  *,
91
- messages: _T,
88
+ messages: Sequence[Message],
92
89
  recipe: str | None = None,
93
90
  debug: bool | None = None,
94
91
  overrides: Overrides | None = None,
95
92
  log_fields: LogFields | None = None,
96
- ) -> PangeaResponse[TextGuardResult[_T]]:
93
+ ) -> PangeaResponse[TextGuardResult]:
97
94
  """
98
95
  Text Guard for scanning LLM inputs and outputs
99
96
 
@@ -115,19 +112,19 @@ class AIGuardAsync(ServiceBaseAsync):
115
112
  log_field: Additional fields to include in activity log
116
113
 
117
114
  Examples:
118
- response = await ai_guard.guard_text(messages=[{"role": "user", "content": "hello world"}])
115
+ response = await ai_guard.guard_text(messages=[Message(role="user", content="hello world")])
119
116
  """
120
117
 
121
- async def guard_text( # type: ignore[misc]
118
+ async def guard_text(
122
119
  self,
123
120
  text: str | None = None,
124
121
  *,
125
- messages: _T | None = None,
122
+ messages: Sequence[Message] | None = None,
126
123
  recipe: str | None = None,
127
124
  debug: bool | None = None,
128
125
  overrides: Overrides | None = None,
129
126
  log_fields: LogFields | None = None,
130
- ) -> PangeaResponse[TextGuardResult[None]]:
127
+ ) -> PangeaResponse[TextGuardResult]:
131
128
  """
132
129
  Text Guard for scanning LLM inputs and outputs
133
130
 
@@ -1,8 +1,13 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+
4
+ # TODO: Modernize.
5
+ # ruff: noqa: UP006, UP035
6
+
3
7
  from __future__ import annotations
4
8
 
5
9
  import datetime
10
+ from collections.abc import Mapping
6
11
  from typing import Any, Dict, Iterable, List, Optional, Sequence, Union
7
12
 
8
13
  import pangea.exceptions as pexc
@@ -63,7 +68,7 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
63
68
  token: str,
64
69
  config: PangeaConfig | None = None,
65
70
  private_key_file: str = "",
66
- public_key_info: dict[str, str] = {},
71
+ public_key_info: Mapping[str, str] = {},
67
72
  tenant_id: str | None = None,
68
73
  logger_name: str = "pangea",
69
74
  config_id: str | None = None,
@@ -1,7 +1,12 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+
4
+ # TODO: Modernize.
5
+ # ruff: noqa: UP006, UP035
6
+
3
7
  from __future__ import annotations
4
8
 
9
+ from collections.abc import Mapping
5
10
  from typing import Dict, List, Literal, Optional, Union
6
11
 
7
12
  import pangea.services.authn.models as m
@@ -475,7 +480,7 @@ class AuthNAsync(ServiceBaseAsync):
475
480
  async def create(
476
481
  self,
477
482
  email: str,
478
- profile: m.Profile,
483
+ profile: Mapping[str, str],
479
484
  *,
480
485
  username: str | None = None,
481
486
  ) -> PangeaResponse[m.UserCreateResult]:
@@ -866,7 +871,7 @@ class AuthNAsync(ServiceBaseAsync):
866
871
 
867
872
  async def update(
868
873
  self,
869
- profile: m.Profile,
874
+ profile: Mapping[str, str],
870
875
  id: str | None = None,
871
876
  email: str | None = None,
872
877
  *,
@@ -995,7 +1000,10 @@ class AuthNAsync(ServiceBaseAsync):
995
1000
  )
996
1001
 
997
1002
  async def restart(
998
- self, flow_id: str, choice: m.FlowChoice, data: m.FlowRestartData = {}
1003
+ self,
1004
+ flow_id: str,
1005
+ choice: m.FlowChoice,
1006
+ data: m.FlowRestartData = {}, # noqa: B006
999
1007
  ) -> PangeaResponse[m.FlowRestartResult]:
1000
1008
  """
1001
1009
  Restart a sign-up/sign-in flow
@@ -1068,7 +1076,10 @@ class AuthNAsync(ServiceBaseAsync):
1068
1076
  return await self.request.post("v2/flow/start", m.FlowStartResult, data=input.model_dump(exclude_none=True))
1069
1077
 
1070
1078
  async def update(
1071
- self, flow_id: str, choice: m.FlowChoice, data: m.FlowUpdateData = {}
1079
+ self,
1080
+ flow_id: str,
1081
+ choice: m.FlowChoice,
1082
+ data: m.FlowUpdateData = {}, # noqa: B006
1072
1083
  ) -> PangeaResponse[m.FlowUpdateResult]:
1073
1084
  """
1074
1085
  Update a sign-up/sign-in flow
@@ -1,5 +1,9 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+
4
+ # TODO: Modernize.
5
+ # ruff: noqa: UP006, UP035
6
+
3
7
  from __future__ import annotations
4
8
 
5
9
  from typing import Dict, Optional, Type, Union
@@ -1,5 +1,11 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+
4
+ # TODO: Modernize.
5
+ # ruff: noqa: UP006, UP035
6
+
7
+ from __future__ import annotations
8
+
3
9
  import io
4
10
  import logging
5
11
  from typing import Dict, List, Optional, Tuple
@@ -98,7 +104,7 @@ class FileScanAsync(ServiceBaseAsync):
98
104
  files: Optional[List[Tuple]] = None
99
105
  if file or file_path:
100
106
  if file_path:
101
- file = open(file_path, "rb")
107
+ file = open(file_path, "rb") # noqa: SIM115
102
108
  if transfer_method == TransferMethod.POST_URL:
103
109
  params = get_file_upload_params(file) # type: ignore[arg-type]
104
110
  crc = params.crc_hex