pangea-sdk 6.2.0b1__tar.gz → 6.3.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 (64) hide show
  1. pangea_sdk-6.2.0b1/README.md → pangea_sdk-6.3.0/PKG-INFO +52 -9
  2. pangea_sdk-6.2.0b1/PKG-INFO → pangea_sdk-6.3.0/README.md +29 -34
  3. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/__init__.py +9 -1
  4. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/__init__.py +1 -0
  5. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/file_uploader.py +4 -2
  6. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/request.py +70 -169
  7. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/services/__init__.py +2 -1
  8. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/services/ai_guard.py +9 -12
  9. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/services/audit.py +13 -307
  10. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/services/authn.py +40 -32
  11. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/services/authz.py +51 -17
  12. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/services/base.py +4 -0
  13. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/services/file_scan.py +8 -2
  14. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/services/intel.py +26 -28
  15. pangea_sdk-6.3.0/pangea/asyncio/services/redact.py +206 -0
  16. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/services/sanitize.py +5 -1
  17. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/services/share.py +5 -1
  18. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/services/vault.py +71 -55
  19. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/audit_logger.py +3 -1
  20. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/deep_verify.py +13 -13
  21. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/deprecated.py +1 -1
  22. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/dump_audit.py +2 -3
  23. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/exceptions.py +8 -5
  24. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/file_uploader.py +4 -0
  25. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/request.py +80 -200
  26. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/response.py +21 -18
  27. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/__init__.py +2 -1
  28. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/ai_guard.py +35 -24
  29. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/audit/audit.py +17 -314
  30. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/audit/models.py +69 -307
  31. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/audit/signing.py +1 -1
  32. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/audit/util.py +10 -10
  33. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/authn/authn.py +39 -31
  34. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/authn/models.py +183 -148
  35. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/authz.py +108 -60
  36. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/base.py +7 -4
  37. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/embargo.py +6 -0
  38. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/file_scan.py +8 -2
  39. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/intel.py +36 -19
  40. pangea_sdk-6.3.0/pangea/services/redact.py +388 -0
  41. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/sanitize.py +5 -1
  42. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/share/share.py +13 -7
  43. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/vault/models/asymmetric.py +4 -0
  44. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/vault/models/common.py +15 -12
  45. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/vault/models/keys.py +4 -9
  46. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/vault/models/secret.py +3 -8
  47. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/vault/models/symmetric.py +4 -0
  48. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/vault/vault.py +69 -59
  49. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/tools.py +13 -9
  50. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/utils.py +3 -5
  51. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/verify_audit.py +23 -27
  52. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pyproject.toml +20 -21
  53. pangea_sdk-6.2.0b1/pangea/asyncio/services/management.py +0 -576
  54. pangea_sdk-6.2.0b1/pangea/asyncio/services/redact.py +0 -463
  55. pangea_sdk-6.2.0b1/pangea/services/management.py +0 -720
  56. pangea_sdk-6.2.0b1/pangea/services/redact.py +0 -850
  57. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/services/embargo.py +0 -0
  58. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/asyncio/services/prompt_guard.py +0 -0
  59. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/config.py +0 -0
  60. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/crypto/rsa.py +0 -0
  61. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/py.typed +0 -0
  62. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/audit/exceptions.py +0 -0
  63. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/prompt_guard.py +0 -0
  64. {pangea_sdk-6.2.0b1 → pangea_sdk-6.3.0}/pangea/services/share/file_format.py +0 -0
@@ -1,3 +1,26 @@
1
+ Metadata-Version: 2.3
2
+ Name: pangea-sdk
3
+ Version: 6.3.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.14,<4.0.0)
13
+ Requires-Dist: cryptography (>=45.0.5,<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.1,<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==6.2.0b1
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==6.2.0b1
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.2.0b1
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.16,<4.0.0)
13
- Requires-Dist: cryptography (>=44.0.2,<44.0.3)
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.3,<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==6.2.0b1
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==6.2.0b1
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.2.0beta1"
1
+ __version__ = "6.3.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,24 +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
8
12
  from collections.abc import Iterable, Mapping
9
- from typing import Dict, List, Literal, Optional, Sequence, Tuple, Type, Union, cast, overload
13
+ from typing import Dict, List, Optional, Sequence, Tuple, Type, Union, cast
10
14
 
11
15
  import aiohttp
12
16
  from aiohttp import FormData
13
- from pydantic import BaseModel, TypeAdapter
17
+ from pydantic import BaseModel
14
18
  from pydantic_core import to_jsonable_python
15
- from typing_extensions import Any, TypeVar
19
+ from typing_extensions import Any, TypeAlias, TypeVar, override
16
20
 
17
21
  import pangea.exceptions as pe
18
22
  from pangea.request import MultipartResponse, PangeaRequestBase
19
23
  from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult, ResponseStatus, TransferMethod
20
24
  from pangea.utils import default_encoder
21
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
+
22
41
  TResult = TypeVar("TResult", bound=PangeaResponseResult)
23
42
 
24
43
 
@@ -31,86 +50,26 @@ class PangeaRequestAsync(PangeaRequestBase):
31
50
  be set in PangeaConfig.
32
51
  """
33
52
 
34
- async def delete(self, endpoint: str) -> None:
35
- """
36
- Makes a DELETE call to a Pangea endpoint.
37
-
38
- Args:
39
- endpoint: The Pangea API endpoint.
40
- """
41
-
42
- url = self._url(endpoint)
43
-
44
- self.logger.debug(
45
- json.dumps({"service": self.service, "action": "delete", "url": url}, default=default_encoder)
46
- )
47
-
48
- requests_response = await self._http_delete(url, headers=self._headers())
49
- await self._check_http_errors(requests_response)
50
-
51
- @overload
52
53
  async def post(
53
54
  self,
54
55
  endpoint: str,
55
56
  result_class: Type[TResult],
56
- data: str | BaseModel | dict[str, Any] | None = None,
57
+ data: str | BaseModel | Mapping[str, Any] | None = None,
57
58
  files: Optional[List[Tuple]] = None,
58
59
  poll_result: bool = True,
59
60
  url: Optional[str] = None,
60
- *,
61
- pangea_response: Literal[True] = True,
62
61
  ) -> PangeaResponse[TResult]:
63
- """
64
- Makes a POST call to a Pangea Service endpoint.
62
+ """Makes the POST call to a Pangea Service endpoint.
65
63
 
66
64
  Args:
67
- endpoint: The Pangea Service API endpoint.
68
- data: The POST body payload object
65
+ endpoint(str): The Pangea Service API endpoint.
66
+ data(dict): The POST body payload object
69
67
 
70
68
  Returns:
71
69
  PangeaResponse which contains the response in its entirety and
72
70
  various properties to retrieve individual fields
73
71
  """
74
72
 
75
- @overload
76
- async def post(
77
- self,
78
- endpoint: str,
79
- result_class: Type[TResult],
80
- data: str | BaseModel | dict[str, Any] | None = None,
81
- files: Optional[List[Tuple]] = None,
82
- poll_result: bool = True,
83
- url: Optional[str] = None,
84
- *,
85
- pangea_response: Literal[False],
86
- ) -> TResult:
87
- """
88
- Makes a POST call to a Pangea Service endpoint.
89
-
90
- Args:
91
- endpoint: The Pangea Service API endpoint.
92
- data: The POST body payload object
93
- """
94
-
95
- async def post(
96
- self,
97
- endpoint: str,
98
- result_class: Type[TResult],
99
- data: str | BaseModel | dict[str, Any] | None = None,
100
- files: Optional[List[Tuple]] = None,
101
- poll_result: bool = True,
102
- url: Optional[str] = None,
103
- *,
104
- pangea_response: bool = True,
105
- ) -> PangeaResponse[TResult] | TResult:
106
- """
107
- Makes a POST call to a Pangea Service endpoint.
108
-
109
- Args:
110
- endpoint: The Pangea Service API endpoint.
111
- data: The POST body payload object
112
- """
113
-
114
73
  if isinstance(data, BaseModel):
115
74
  data = data.model_dump(exclude_none=True)
116
75
 
@@ -122,7 +81,7 @@ class PangeaRequestAsync(PangeaRequestBase):
122
81
  data = {}
123
82
 
124
83
  # Normalize.
125
- data = cast(dict[str, Any], to_jsonable_python(data))
84
+ data = cast(dict[str, Any], to_jsonable_python(data, exclude_none=True))
126
85
 
127
86
  if url is None:
128
87
  url = self._url(endpoint)
@@ -141,19 +100,18 @@ class PangeaRequestAsync(PangeaRequestBase):
141
100
  endpoint, result_class=result_class, data=data, files=files
142
101
  )
143
102
  else:
103
+ headers = self._headers()
104
+ if transfer_method == TransferMethod.MULTIPART.value:
105
+ del headers["Content-Type"]
144
106
  requests_response = await self._http_post(
145
- url, headers=self._headers(), data=data, files=files, presigned_url_post=False
107
+ url, headers=headers, data=data, files=files, presigned_url_post=False
146
108
  )
147
109
 
148
110
  await self._check_http_errors(requests_response)
149
111
 
150
- if not pangea_response:
151
- type_adapter = TypeAdapter(result_class)
152
- return type_adapter.validate_python(await requests_response.json())
153
-
154
112
  if "multipart/form-data" in requests_response.headers.get("content-type", ""):
155
113
  multipart_response = await self._process_multipart_response(requests_response)
156
- pangea_response_obj: PangeaResponse = PangeaResponse(
114
+ pangea_response: PangeaResponse = PangeaResponse(
157
115
  requests_response,
158
116
  result_class=result_class,
159
117
  json=multipart_response.pangea_json,
@@ -166,108 +124,49 @@ class PangeaRequestAsync(PangeaRequestBase):
166
124
  json.dumps({"service": self.service, "action": "post", "url": url, "response": json_resp})
167
125
  )
168
126
 
169
- pangea_response_obj = PangeaResponse(requests_response, result_class=result_class, json=json_resp)
127
+ pangea_response = PangeaResponse(requests_response, result_class=result_class, json=json_resp)
170
128
  except aiohttp.ContentTypeError as e:
171
- 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
172
132
 
173
133
  if poll_result:
174
- pangea_response_obj = await self._handle_queued_result(pangea_response_obj)
134
+ pangea_response = await self._handle_queued_result(pangea_response)
175
135
 
176
- return self._check_response(pangea_response_obj)
136
+ return self._check_response(pangea_response)
177
137
 
178
- @overload
179
- async def get(
180
- self,
181
- path: str,
182
- result_class: Type[TResult],
183
- check_response: bool = True,
184
- *,
185
- params: (
186
- Mapping[str | bytes | int | float, str | bytes | int | float | Iterable[str | bytes | int | float] | None]
187
- | None
188
- ) = None,
189
- pangea_response: Literal[True] = True,
190
- ) -> PangeaResponse[TResult]:
191
- """
192
- Makes the GET call to a Pangea Service endpoint.
138
+ async def get(self, path: str, result_class: Type[TResult], check_response: bool = True) -> PangeaResponse[TResult]:
139
+ """Makes the GET call to a Pangea Service endpoint.
193
140
 
194
141
  Args:
195
- path: Additional URL path
196
- params: Dictionary of querystring data to attach to the request
142
+ endpoint(str): The Pangea Service API endpoint.
143
+ path(str): Additional URL path
197
144
 
198
145
  Returns:
199
146
  PangeaResponse which contains the response in its entirety and
200
147
  various properties to retrieve individual fields
201
148
  """
202
149
 
203
- @overload
204
- async def get(
205
- self,
206
- path: str,
207
- result_class: Type[TResult],
208
- check_response: bool = True,
209
- *,
210
- params: (
211
- Mapping[str | bytes | int | float, str | bytes | int | float | Iterable[str | bytes | int | float] | None]
212
- | None
213
- ) = None,
214
- pangea_response: Literal[False] = False,
215
- ) -> TResult:
216
- """
217
- Makes the GET call to a Pangea Service endpoint.
218
-
219
- Args:
220
- path: Additional URL path
221
- params: Dictionary of querystring data to attach to the request
222
- """
223
-
224
- async def get(
225
- self,
226
- path: str,
227
- result_class: Type[TResult],
228
- check_response: bool = True,
229
- *,
230
- params: (
231
- Mapping[str | bytes | int | float, str | bytes | int | float | Iterable[str | bytes | int | float] | None]
232
- | None
233
- ) = None,
234
- pangea_response: bool = True,
235
- ) -> PangeaResponse[TResult] | TResult:
236
- """
237
- Makes the GET call to a Pangea Service endpoint.
238
-
239
- Args:
240
- path: Additional URL path
241
- params: Dictionary of querystring data to attach to the request
242
- pangea_response: Whether or not the response body follows Pangea's
243
- standard response schema
244
- """
245
-
246
150
  url = self._url(path)
247
151
  self.logger.debug(json.dumps({"service": self.service, "action": "get", "url": url}))
248
152
 
249
- async with self.session.get(url, params=params, headers=self._headers()) as requests_response:
153
+ async with self.session.get(url, headers=self._headers()) as requests_response:
250
154
  await self._check_http_errors(requests_response)
251
-
252
- if not pangea_response:
253
- type_adapter = TypeAdapter(result_class)
254
- return type_adapter.validate_python(await requests_response.json())
255
-
256
- pangea_response_obj = PangeaResponse(
155
+ pangea_response = PangeaResponse(
257
156
  requests_response, result_class=result_class, json=await requests_response.json()
258
157
  )
259
158
 
260
159
  self.logger.debug(
261
160
  json.dumps(
262
- {"service": self.service, "action": "get", "url": url, "response": pangea_response_obj.json},
161
+ {"service": self.service, "action": "get", "url": url, "response": pangea_response.json},
263
162
  default=default_encoder,
264
163
  )
265
164
  )
266
165
 
267
166
  if check_response is False:
268
- return pangea_response_obj
167
+ return pangea_response
269
168
 
270
- return self._check_response(pangea_response_obj)
169
+ return self._check_response(pangea_response)
271
170
 
272
171
  async def _check_http_errors(self, resp: aiohttp.ClientResponse):
273
172
  if resp.status == 503:
@@ -290,7 +189,7 @@ class PangeaRequestAsync(PangeaRequestBase):
290
189
 
291
190
  return await self.poll_result_by_id(request_id, response.result_class, check_response=check_response)
292
191
 
293
- 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]):
294
193
  # Send form request with file and upload_details as body
295
194
  resp = await self._http_post(url=url, data=data, files=files, presigned_url_post=True)
296
195
  self.logger.debug(
@@ -401,46 +300,47 @@ class PangeaRequestAsync(PangeaRequestBase):
401
300
  attached_files = await self._get_attached_files(multipart_reader)
402
301
  return MultipartResponse(pangea_json, attached_files) # type: ignore[arg-type]
403
302
 
404
- async def _http_delete(
405
- self,
406
- url: str,
407
- *,
408
- headers: Mapping[str, str | bytes | None] = {},
409
- ) -> aiohttp.ClientResponse:
410
- return await self.session.delete(url, headers=headers)
411
-
412
303
  async def _http_post(
413
304
  self,
414
305
  url: str,
415
- headers: Mapping[str, str | bytes | None] = {},
416
- data: Union[str, Dict] = {},
417
- files: Optional[List[Tuple]] = [],
306
+ headers: _LooseHeaders = {}, # noqa: B006
307
+ data: str | dict[str, Any] | None = None,
308
+ files: _Files | None = None,
418
309
  presigned_url_post: bool = False,
419
310
  ) -> aiohttp.ClientResponse:
311
+ if data is None:
312
+ data = {}
313
+
420
314
  if files:
421
315
  form = FormData()
422
316
  if presigned_url_post:
423
- 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():
424
320
  form.add_field(k, v)
425
- for name, value in files:
321
+ for _name, value in files:
426
322
  form.add_field("file", value[1], filename=value[0], content_type=value[2])
427
323
  else:
428
- 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
+ )
429
328
  form.add_field("request", data_send, content_type="application/json")
430
329
  for name, value in files:
431
330
  form.add_field(name, value[1], filename=value[0], content_type=value[2])
432
331
 
433
- data_send = form # type: ignore[assignment]
332
+ data_send = form
434
333
  else:
435
334
  data_send = json.dumps(data, default=default_encoder) if isinstance(data, dict) else data
436
335
 
336
+ assert isinstance(self.session, aiohttp.ClientSession)
437
337
  return await self.session.post(url, headers=headers, data=data_send)
438
338
 
439
339
  async def _http_put(
440
340
  self,
441
341
  url: str,
442
342
  files: Sequence[Tuple],
443
- headers: Dict = {},
343
+ headers: _LooseHeaders = {}, # noqa: B006
444
344
  ) -> aiohttp.ClientResponse:
445
345
  self.logger.debug(
446
346
  json.dumps({"service": self.service, "action": "http_put", "url": url}, default=default_encoder)
@@ -452,8 +352,8 @@ class PangeaRequestAsync(PangeaRequestBase):
452
352
  self,
453
353
  endpoint: str,
454
354
  result_class: Type[PangeaResponseResult],
455
- data: Union[str, Dict] = {},
456
- files: List[Tuple] = [],
355
+ data: Union[str, Mapping[str, Any]] = {},
356
+ files: Sequence[Tuple] = [],
457
357
  ):
458
358
  if len(files) == 0:
459
359
  raise AttributeError("files attribute should have at least 1 file")
@@ -477,7 +377,7 @@ class PangeaRequestAsync(PangeaRequestBase):
477
377
  self,
478
378
  endpoint: str,
479
379
  result_class: Type[PangeaResponseResult],
480
- data: Union[str, Dict] = {},
380
+ data: Union[str, Mapping[str, Any]] = {},
481
381
  ) -> PangeaResponse:
482
382
  # Send request
483
383
  try:
@@ -528,7 +428,7 @@ class PangeaRequestAsync(PangeaRequestBase):
528
428
  {"service": self.service, "action": "poll_presigned_url", "step": "exit", "cause": {str(e)}}
529
429
  )
530
430
  )
531
- 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
532
432
 
533
433
  self.logger.debug(json.dumps({"service": self.service, "action": "poll_presigned_url", "step": "exit"}))
534
434
 
@@ -560,6 +460,7 @@ class PangeaRequestAsync(PangeaRequestBase):
560
460
  self.logger.debug(json.dumps({"service": self.service, "action": "poll_result_retry", "step": "exit"}))
561
461
  return self._check_response(response)
562
462
 
463
+ @override
563
464
  def _init_session(self) -> aiohttp.ClientSession:
564
465
  # retry_config = Retry(
565
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
@@ -5,7 +7,6 @@ from .authz import AuthZAsync
5
7
  from .embargo import EmbargoAsync
6
8
  from .file_scan import FileScanAsync
7
9
  from .intel import DomainIntelAsync, FileIntelAsync, IpIntelAsync, UrlIntelAsync, UserIntelAsync
8
- from .management import ManagementAsync
9
10
  from .prompt_guard import PromptGuardAsync
10
11
  from .redact import RedactAsync
11
12
  from .sanitize import SanitizeAsync