pangea-sdk 6.3.0__py3-none-any.whl → 6.5.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.
pangea/__init__.py CHANGED
@@ -1,15 +1,7 @@
1
- __version__ = "6.3.0"
1
+ __version__ = "6.5.0"
2
2
 
3
- from pangea.asyncio.request import PangeaRequestAsync
4
3
  from pangea.config import PangeaConfig
5
4
  from pangea.file_uploader import FileUploader
6
- from pangea.request import PangeaRequest
7
- from pangea.response import PangeaResponse
5
+ from pangea.response import PangeaResponse, PangeaResponseResult, TransferMethod
8
6
 
9
- __all__ = (
10
- "FileUploader",
11
- "PangeaConfig",
12
- "PangeaRequest",
13
- "PangeaRequestAsync",
14
- "PangeaResponse",
15
- )
7
+ __all__ = ("FileUploader", "PangeaConfig", "PangeaResponse", "PangeaResponseResult", "TransferMethod")
pangea/_constants.py ADDED
@@ -0,0 +1,4 @@
1
+ from __future__ import annotations
2
+
3
+ MAX_RETRY_DELAY = 8.0
4
+ RETRYABLE_HTTP_CODES = frozenset({500, 502, 503, 504})
pangea/_typing.py ADDED
@@ -0,0 +1,5 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TypeVar
4
+
5
+ T = TypeVar("T")
@@ -1,2 +1,3 @@
1
- # ruff: noqa: F401
2
1
  from .file_uploader import FileUploaderAsync
2
+
3
+ __all__ = ("FileUploaderAsync",)
@@ -6,9 +6,10 @@ from __future__ import annotations
6
6
  import io
7
7
  import logging
8
8
 
9
+ from pangea import PangeaConfig, TransferMethod
9
10
  from pangea.asyncio.request import PangeaRequestAsync
10
- from pangea.request import PangeaConfig
11
- from pangea.response import TransferMethod
11
+
12
+ __all__ = ("FileUploaderAsync",)
12
13
 
13
14
 
14
15
  class FileUploaderAsync:
pangea/asyncio/request.py CHANGED
@@ -10,6 +10,7 @@ import asyncio
10
10
  import json
11
11
  import time
12
12
  from collections.abc import Iterable, Mapping
13
+ from random import random
13
14
  from typing import Dict, List, Optional, Sequence, Tuple, Type, Union, cast
14
15
 
15
16
  import aiohttp
@@ -19,10 +20,13 @@ from pydantic_core import to_jsonable_python
19
20
  from typing_extensions import Any, TypeAlias, TypeVar, override
20
21
 
21
22
  import pangea.exceptions as pe
23
+ from pangea._constants import MAX_RETRY_DELAY, RETRYABLE_HTTP_CODES
22
24
  from pangea.request import MultipartResponse, PangeaRequestBase
23
25
  from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult, ResponseStatus, TransferMethod
24
26
  from pangea.utils import default_encoder
25
27
 
28
+ __all__ = ("PangeaRequestAsync",)
29
+
26
30
  _FileName: TypeAlias = Union[str, None]
27
31
  _FileContent: TypeAlias = Union[str, bytes]
28
32
  _FileContentType: TypeAlias = str
@@ -462,13 +466,46 @@ class PangeaRequestAsync(PangeaRequestBase):
462
466
 
463
467
  @override
464
468
  def _init_session(self) -> aiohttp.ClientSession:
465
- # retry_config = Retry(
466
- # total=self.config.request_retries,
467
- # backoff_factor=self.config.request_backoff,
468
- # status_forcelist=[500, 502, 503, 504],
469
- # )
470
- # adapter = HTTPAdapter(max_retries=retry_config)
471
- # TODO: Add retry config
472
-
473
- session = aiohttp.ClientSession()
474
- return session
469
+ return aiohttp.ClientSession(middlewares=[self._retry_middleware])
470
+
471
+ def _calculate_retry_timeout(self, remaining_retries: int) -> float:
472
+ max_retries = self.config.request_retries
473
+ nb_retries = min(max_retries - remaining_retries, 1000)
474
+ sleep_seconds = min(self.config.request_backoff * pow(2.0, nb_retries), MAX_RETRY_DELAY)
475
+ jitter = 1 - 0.25 * random()
476
+ timeout = sleep_seconds * jitter
477
+ return max(timeout, 0)
478
+
479
+ async def _retry_middleware(
480
+ self, request: aiohttp.ClientRequest, handler: aiohttp.ClientHandlerType
481
+ ) -> aiohttp.ClientResponse:
482
+ max_retries = self.config.request_retries
483
+ request_ids = set[str]()
484
+ retries_taken = 0
485
+ for retries_taken in range(max_retries + 1):
486
+ remaining_retries = max_retries - retries_taken
487
+
488
+ if len(request_ids) > 0:
489
+ request.headers["X-Pangea-Retried-Request-Ids"] = ",".join(request_ids)
490
+
491
+ response = await handler(request)
492
+
493
+ request_id = response.headers.get("x-request-id")
494
+ if request_id:
495
+ request_ids.add(request_id)
496
+
497
+ if not response.ok and remaining_retries > 0 and self._should_retry(response):
498
+ await self._sleep_for_retry(retries_taken=retries_taken, max_retries=max_retries)
499
+ continue
500
+
501
+ break
502
+
503
+ return response
504
+
505
+ def _should_retry(self, response: aiohttp.ClientResponse) -> bool:
506
+ return response.status in RETRYABLE_HTTP_CODES
507
+
508
+ async def _sleep_for_retry(self, *, retries_taken: int, max_retries: int) -> None:
509
+ remaining_retries = max_retries - retries_taken
510
+ timeout = self._calculate_retry_timeout(remaining_retries)
511
+ await asyncio.sleep(timeout)
@@ -1,5 +1,3 @@
1
- # ruff: noqa: F401
2
-
3
1
  from .ai_guard import AIGuardAsync
4
2
  from .audit import AuditAsync
5
3
  from .authn import AuthNAsync
@@ -12,3 +10,22 @@ from .redact import RedactAsync
12
10
  from .sanitize import SanitizeAsync
13
11
  from .share import ShareAsync
14
12
  from .vault import VaultAsync
13
+
14
+ __all__ = (
15
+ "AIGuardAsync",
16
+ "AuditAsync",
17
+ "AuthNAsync",
18
+ "AuthZAsync",
19
+ "DomainIntelAsync",
20
+ "EmbargoAsync",
21
+ "FileIntelAsync",
22
+ "FileScanAsync",
23
+ "IpIntelAsync",
24
+ "PromptGuardAsync",
25
+ "RedactAsync",
26
+ "SanitizeAsync",
27
+ "ShareAsync",
28
+ "UrlIntelAsync",
29
+ "UserIntelAsync",
30
+ "VaultAsync",
31
+ )
@@ -15,11 +15,9 @@ class AIGuardAsync(ServiceBaseAsync):
15
15
  Provides methods to interact with Pangea's AI Guard service.
16
16
 
17
17
  Examples:
18
- from pangea import PangeaConfig
19
18
  from pangea.asyncio.services import AIGuardAsync
20
19
 
21
- config = PangeaConfig(domain="aws.us.pangea.cloud")
22
- ai_guard = AIGuardAsync(token="pangea_token", config=config)
20
+ ai_guard = AIGuardAsync(token="pangea_token")
23
21
  """
24
22
 
25
23
  service_name = "ai-guard"
@@ -39,11 +37,9 @@ class AIGuardAsync(ServiceBaseAsync):
39
37
  config_id: Configuration ID.
40
38
 
41
39
  Examples:
42
- from pangea import PangeaConfig
43
40
  from pangea.asyncio.services import AIGuardAsync
44
41
 
45
- config = PangeaConfig(domain="aws.us.pangea.cloud")
46
- ai_guard = AIGuardAsync(token="pangea_token", config=config)
42
+ ai_guard = AIGuardAsync(token="pangea_token")
47
43
  """
48
44
 
49
45
  super().__init__(token, config, logger_name, config_id)
@@ -53,29 +49,31 @@ class AIGuardAsync(ServiceBaseAsync):
53
49
  self,
54
50
  text: str,
55
51
  *,
56
- recipe: str | None = None,
57
52
  debug: bool | None = None,
58
- overrides: Overrides | None = None,
59
53
  log_fields: LogFields | None = None,
54
+ overrides: Overrides | None = None,
55
+ recipe: str | None = None,
60
56
  ) -> PangeaResponse[TextGuardResult]:
61
57
  """
62
- Text Guard for scanning LLM inputs and outputs
58
+ Guard LLM input and output text
63
59
 
64
- Analyze and redact text to avoid manipulation of the model, addition of
65
- malicious content, and other undesirable data transfers.
60
+ Detect, remove, or block malicious content and intent in LLM inputs and
61
+ outputs to prevent model manipulation and data leakage.
66
62
 
67
63
  OperationId: ai_guard_post_v1_text_guard
68
64
 
69
65
  Args:
70
66
  text: Text to be scanned by AI Guard for PII, sensitive data,
71
67
  malicious content, and other data types defined by the
72
- configuration. Supports processing up to 10KB of text.
73
- recipe: Recipe key of a configuration of data types and settings
74
- defined in the Pangea User Console. It specifies the rules that
75
- are to be applied to the text, such as defang malicious URLs.
68
+ configuration. Supports processing up to 20 KiB of text.
76
69
  debug: Setting this value to true will provide a detailed analysis
77
70
  of the text data
78
71
  log_field: Additional fields to include in activity log
72
+ overrides: Overrides flags. Note: This parameter has no effect when
73
+ the request is made by AIDR
74
+ recipe: Recipe key of a configuration of data types and settings
75
+ defined in the Pangea User Console. It specifies the rules that
76
+ are to be applied to the text, such as defang malicious URLs.
79
77
 
80
78
  Examples:
81
79
  response = await ai_guard.guard_text("text")
@@ -92,24 +90,26 @@ class AIGuardAsync(ServiceBaseAsync):
92
90
  log_fields: LogFields | None = None,
93
91
  ) -> PangeaResponse[TextGuardResult]:
94
92
  """
95
- Text Guard for scanning LLM inputs and outputs
93
+ Guard LLM input and output text
96
94
 
97
- Analyze and redact text to avoid manipulation of the model, addition of
98
- malicious content, and other undesirable data transfers.
95
+ Detect, remove, or block malicious content and intent in LLM inputs and
96
+ outputs to prevent model manipulation and data leakage.
99
97
 
100
98
  OperationId: ai_guard_post_v1_text_guard
101
99
 
102
100
  Args:
103
101
  messages: Structured messages data to be scanned by AI Guard for
104
102
  PII, sensitive data, malicious content, and other data types
105
- defined by the configuration. Supports processing up to 10KB of
106
- JSON text
107
- recipe: Recipe key of a configuration of data types and settings
108
- defined in the Pangea User Console. It specifies the rules that
109
- are to be applied to the text, such as defang malicious URLs.
103
+ defined by the configuration. Supports processing up to 20 KiB
104
+ of JSON text using Pangea message format.
110
105
  debug: Setting this value to true will provide a detailed analysis
111
106
  of the text data
112
107
  log_field: Additional fields to include in activity log
108
+ overrides: Overrides flags. Note: This parameter has no effect when
109
+ the request is made by AIDR
110
+ recipe: Recipe key of a configuration of data types and settings
111
+ defined in the Pangea User Console. It specifies the rules that
112
+ are to be applied to the text, such as defang malicious URLs.
113
113
 
114
114
  Examples:
115
115
  response = await ai_guard.guard_text(messages=[Message(role="user", content="hello world")])
@@ -126,10 +126,10 @@ class AIGuardAsync(ServiceBaseAsync):
126
126
  log_fields: LogFields | None = None,
127
127
  ) -> PangeaResponse[TextGuardResult]:
128
128
  """
129
- Text Guard for scanning LLM inputs and outputs
129
+ Guard LLM input and output text
130
130
 
131
- Analyze and redact text to avoid manipulation of the model, addition of
132
- malicious content, and other undesirable data transfers.
131
+ Detect, remove, or block malicious content and intent in LLM inputs and
132
+ outputs to prevent model manipulation and data leakage.
133
133
 
134
134
  OperationId: ai_guard_post_v1_text_guard
135
135
 
@@ -141,12 +141,14 @@ class AIGuardAsync(ServiceBaseAsync):
141
141
  PII, sensitive data, malicious content, and other data types
142
142
  defined by the configuration. Supports processing up to 10KB of
143
143
  JSON text
144
- recipe: Recipe key of a configuration of data types and settings
145
- defined in the Pangea User Console. It specifies the rules that
146
- are to be applied to the text, such as defang malicious URLs.
147
144
  debug: Setting this value to true will provide a detailed analysis
148
145
  of the text data
149
146
  log_field: Additional fields to include in activity log
147
+ overrides: Overrides flags. Note: This parameter has no effect when
148
+ the request is made by AIDR
149
+ recipe: Recipe key of a configuration of data types and settings
150
+ defined in the Pangea User Console. It specifies the rules that
151
+ are to be applied to the text, such as defang malicious URLs.
150
152
 
151
153
  Examples:
152
154
  response = await ai_guard.guard_text("text")
@@ -10,9 +10,9 @@ from collections.abc import Mapping
10
10
  from typing import Dict, List, Literal, Optional, Union
11
11
 
12
12
  import pangea.services.authn.models as m
13
+ from pangea import PangeaResponse, PangeaResponseResult
13
14
  from pangea.asyncio.services.base import ServiceBaseAsync
14
15
  from pangea.config import PangeaConfig
15
- from pangea.response import PangeaResponse, PangeaResponseResult
16
16
 
17
17
  __all__ = ["AuthNAsync"]
18
18
 
@@ -66,11 +66,18 @@ class AuthNAsync(ServiceBaseAsync):
66
66
  authn = AuthNAsync(token="pangea_token", config=config)
67
67
  """
68
68
  super().__init__(token, config, logger_name=logger_name)
69
- self.user = AuthNAsync.UserAsync(token, config, logger_name=logger_name)
70
- self.flow = AuthNAsync.FlowAsync(token, config, logger_name=logger_name)
69
+ self.agreements = AuthNAsync.AgreementsAsync(token, config, logger_name=logger_name)
71
70
  self.client = AuthNAsync.ClientAsync(token, config, logger_name=logger_name)
71
+ self.flow = AuthNAsync.FlowAsync(token, config, logger_name=logger_name)
72
72
  self.session = AuthNAsync.SessionAsync(token, config, logger_name=logger_name)
73
- self.agreements = AuthNAsync.AgreementsAsync(token, config, logger_name=logger_name)
73
+ self.user = AuthNAsync.UserAsync(token, config, logger_name=logger_name)
74
+
75
+ async def close(self) -> None:
76
+ await self.agreements.close()
77
+ await self.client.close()
78
+ await self.flow.close()
79
+ await self.session.close()
80
+ await self.user.close()
74
81
 
75
82
  class SessionAsync(ServiceBaseAsync):
76
83
  service_name = _SERVICE_NAME
@@ -179,10 +186,15 @@ class AuthNAsync(ServiceBaseAsync):
179
186
  logger_name: str = "pangea",
180
187
  ) -> None:
181
188
  super().__init__(token, config, logger_name=logger_name)
182
- self.session = AuthNAsync.ClientAsync.SessionAsync(token, config, logger_name=logger_name)
183
189
  self.password = AuthNAsync.ClientAsync.PasswordAsync(token, config, logger_name=logger_name)
190
+ self.session = AuthNAsync.ClientAsync.SessionAsync(token, config, logger_name=logger_name)
184
191
  self.token_endpoints = AuthNAsync.ClientAsync.TokenAsync(token, config, logger_name=logger_name)
185
192
 
193
+ async def close(self) -> None:
194
+ await self.password.close()
195
+ await self.session.close()
196
+ await self.token_endpoints.close()
197
+
186
198
  async def userinfo(self, code: str) -> PangeaResponse[m.ClientUserinfoResult]:
187
199
  """
188
200
  Get User (client token)
@@ -470,9 +482,14 @@ class AuthNAsync(ServiceBaseAsync):
470
482
  logger_name: str = "pangea",
471
483
  ) -> None:
472
484
  super().__init__(token, config, logger_name=logger_name)
473
- self.profile = AuthNAsync.UserAsync.ProfileAsync(token, config, logger_name=logger_name)
474
485
  self.authenticators = AuthNAsync.UserAsync.AuthenticatorsAsync(token, config, logger_name=logger_name)
475
486
  self.invites = AuthNAsync.UserAsync.InvitesAsync(token, config, logger_name=logger_name)
487
+ self.profile = AuthNAsync.UserAsync.ProfileAsync(token, config, logger_name=logger_name)
488
+
489
+ async def close(self) -> None:
490
+ await self.authenticators.close()
491
+ await self.invites.close()
492
+ await self.profile.close()
476
493
 
477
494
  async def create(
478
495
  self,
@@ -932,7 +949,7 @@ class AuthNAsync(ServiceBaseAsync):
932
949
  return await self.request.post(
933
950
  "v2/user/group/assign",
934
951
  data={"id": user_id, "group_ids": group_ids},
935
- result_class=m.PangeaResponseResult,
952
+ result_class=PangeaResponseResult,
936
953
  )
937
954
 
938
955
  async def remove(self, user_id: str, group_id: str) -> PangeaResponse[PangeaResponseResult]:
@@ -946,7 +963,7 @@ class AuthNAsync(ServiceBaseAsync):
946
963
  return await self.request.post(
947
964
  "v2/user/group/remove",
948
965
  data={"id": user_id, "group_id": group_id},
949
- result_class=m.PangeaResponseResult,
966
+ result_class=PangeaResponseResult,
950
967
  )
951
968
 
952
969
  async def list(self, user_id: str) -> PangeaResponse[m.GroupList]:
@@ -6,14 +6,20 @@
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
+ from types import TracebackType
9
10
  from typing import Dict, Optional, Type, Union
10
11
 
11
12
  from typing_extensions import override
12
13
 
14
+ from pangea import PangeaResponse, PangeaResponseResult
15
+ from pangea._typing import T
13
16
  from pangea.asyncio.request import PangeaRequestAsync
14
17
  from pangea.exceptions import AcceptedRequestException
15
- from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult
16
- from pangea.services.base import PangeaRequest, ServiceBase
18
+ from pangea.request import PangeaRequest
19
+ from pangea.response import AttachedFile
20
+ from pangea.services.base import ServiceBase
21
+
22
+ __all__ = ("ServiceBaseAsync",)
17
23
 
18
24
 
19
25
  class ServiceBaseAsync(ServiceBase):
@@ -85,8 +91,17 @@ class ServiceBaseAsync(ServiceBase):
85
91
  return await self.request.download_file(url=url, filename=filename)
86
92
 
87
93
  async def close(self):
94
+ """Close the underlying aiohttp client."""
95
+
88
96
  await self.request.session.close()
89
- # Loop over all attributes to check if they are derived from ServiceBaseAsync and close them
90
- for _, value in self.__dict__.items():
91
- if issubclass(type(value), ServiceBaseAsync):
92
- await value.close()
97
+
98
+ async def __aenter__(self: T) -> T:
99
+ return self
100
+
101
+ async def __aexit__(
102
+ self,
103
+ exc_type: type[BaseException] | None,
104
+ exc: BaseException | None,
105
+ exc_tb: TracebackType | None,
106
+ ) -> None:
107
+ await self.close()
@@ -11,9 +11,9 @@ import logging
11
11
  from typing import Dict, List, Optional, Tuple
12
12
 
13
13
  import pangea.services.file_scan as m
14
+ from pangea import PangeaConfig
14
15
  from pangea.asyncio.request import PangeaRequestAsync
15
16
  from pangea.asyncio.services.base import ServiceBaseAsync
16
- from pangea.request import PangeaConfig
17
17
  from pangea.response import PangeaResponse, TransferMethod
18
18
  from pangea.utils import FileUploadParams, get_file_upload_params
19
19
 
@@ -12,6 +12,9 @@ if TYPE_CHECKING:
12
12
  from pangea.response import PangeaResponse
13
13
 
14
14
 
15
+ __all__ = ("Message", "PromptGuardAsync")
16
+
17
+
15
18
  class PromptGuardAsync(ServiceBaseAsync):
16
19
  """Prompt Guard service client.
17
20
 
pangea/config.py CHANGED
@@ -6,6 +6,8 @@ from typing import Any, Optional
6
6
 
7
7
  from pydantic import BaseModel, model_validator
8
8
 
9
+ __all__ = ("PangeaConfig",)
10
+
9
11
 
10
12
  class PangeaConfig(BaseModel):
11
13
  """Holds run time configuration information used by SDK components."""
@@ -34,12 +36,12 @@ class PangeaConfig(BaseModel):
34
36
 
35
37
  request_backoff: float = 0.5
36
38
  """
37
- Backoff strategy passed to 'requests'
39
+ A backoff factor to apply between request attempts.
38
40
  """
39
41
 
40
42
  request_timeout: int = 5
41
43
  """
42
- Timeout used on initial request attempts
44
+ Unused.
43
45
  """
44
46
 
45
47
  poll_result_timeout: int = 30
pangea/file_uploader.py CHANGED
@@ -8,9 +8,12 @@ import io
8
8
  import logging
9
9
  from typing import Dict, Optional
10
10
 
11
- from pangea.request import PangeaConfig, PangeaRequest
11
+ from pangea.config import PangeaConfig
12
+ from pangea.request import PangeaRequest
12
13
  from pangea.response import TransferMethod
13
14
 
15
+ __all__ = ("FileUploader",)
16
+
14
17
 
15
18
  class FileUploader:
16
19
  def __init__(self):
pangea/request.py CHANGED
@@ -11,18 +11,20 @@ import json
11
11
  import logging
12
12
  import time
13
13
  from collections.abc import Iterable, Mapping
14
+ from random import random
14
15
  from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Type, Union, cast
15
16
 
16
17
  import requests
17
18
  from pydantic import BaseModel
18
19
  from pydantic_core import to_jsonable_python
19
- from requests.adapters import HTTPAdapter, Retry
20
+ from requests.adapters import HTTPAdapter
20
21
  from requests_toolbelt import MultipartDecoder # type: ignore[import-untyped]
21
22
  from typing_extensions import TypeAlias, TypeVar, override
22
23
  from yarl import URL
23
24
 
24
25
  import pangea
25
26
  import pangea.exceptions as pe
27
+ from pangea._constants import MAX_RETRY_DELAY, RETRYABLE_HTTP_CODES
26
28
  from pangea.config import PangeaConfig
27
29
  from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult, ResponseStatus, TransferMethod
28
30
  from pangea.utils import default_encoder
@@ -46,6 +48,70 @@ _Files: TypeAlias = Union[Mapping[str, _FileSpec], Iterable[tuple[str, _FileSpec
46
48
  _HeadersUpdateMapping: TypeAlias = Mapping[str, str]
47
49
 
48
50
 
51
+ class PangeaHTTPAdapter(HTTPAdapter):
52
+ """Custom HTTP adapter that keeps track of retried request IDs."""
53
+
54
+ @override
55
+ def __init__(self, config: PangeaConfig, *args, **kwargs):
56
+ super().__init__(*args, **kwargs)
57
+ self.config = config
58
+
59
+ @override
60
+ def send(
61
+ self,
62
+ request: requests.PreparedRequest,
63
+ stream: bool = False,
64
+ timeout: None | float | tuple[float, float] | tuple[float, None] = None,
65
+ verify: bool | str = True,
66
+ cert: None | bytes | str | tuple[bytes | str, bytes | str] = None,
67
+ proxies: Mapping[str, str] | None = None,
68
+ ) -> requests.Response:
69
+ max_retries = self.config.request_retries
70
+ request_ids = set[str]()
71
+ retries_taken = 0
72
+ for retries_taken in range(max_retries + 1):
73
+ remaining_retries = max_retries - retries_taken
74
+
75
+ if len(request_ids) > 0:
76
+ request.headers["X-Pangea-Retried-Request-Ids"] = ",".join(request_ids)
77
+
78
+ response = super().send(request, stream, timeout, verify, cert, proxies)
79
+
80
+ request_id = response.headers.get("x-request-id")
81
+ if request_id:
82
+ request_ids.add(request_id)
83
+
84
+ try:
85
+ response.raise_for_status()
86
+ except requests.HTTPError as error:
87
+ if remaining_retries > 0 and self._should_retry(error.response):
88
+ error.response.close()
89
+ self._sleep_for_retry(retries_taken=retries_taken, max_retries=max_retries, config=self.config)
90
+ continue
91
+
92
+ break
93
+
94
+ break
95
+
96
+ return response
97
+
98
+ def _calculate_retry_timeout(self, remaining_retries: int, config: PangeaConfig) -> float:
99
+ max_retries = config.request_retries
100
+ nb_retries = min(max_retries - remaining_retries, 1000)
101
+ sleep_seconds = min(config.request_backoff * pow(2.0, nb_retries), MAX_RETRY_DELAY)
102
+ jitter = 1 - 0.25 * random()
103
+ timeout = sleep_seconds * jitter
104
+ return max(timeout, 0)
105
+
106
+ def _sleep_for_retry(self, *, retries_taken: int, max_retries: int, config: PangeaConfig) -> None:
107
+ remaining_retries = max_retries - retries_taken
108
+ timeout = self._calculate_retry_timeout(remaining_retries, config)
109
+ time.sleep(timeout)
110
+
111
+ def _should_retry(self, response: requests.Response) -> bool:
112
+ return response.status_code in RETRYABLE_HTTP_CODES
113
+
114
+
49
115
  class MultipartResponse:
50
116
  pangea_json: Dict[str, str]
51
117
  attached_files: List = []
@@ -111,8 +177,8 @@ class PangeaRequestBase:
111
177
 
112
178
  return self._queued_retry_enabled
113
179
 
114
- def _get_delay(self, retry_count, start):
115
- delay = retry_count * retry_count
180
+ def _get_delay(self, retry_count: int, start: float) -> float:
181
+ delay: float = retry_count * retry_count
116
182
  now = time.time()
117
183
  # if with this delay exceed timeout, reduce delay
118
184
  if now - start + delay >= self.config.poll_result_timeout:
@@ -120,10 +186,10 @@ class PangeaRequestBase:
120
186
 
121
187
  return delay
122
188
 
123
- def _reach_timeout(self, start):
189
+ def _reach_timeout(self, start: float) -> bool:
124
190
  return time.time() - start >= self.config.poll_result_timeout
125
191
 
126
- def _get_poll_path(self, request_id: str):
192
+ def _get_poll_path(self, request_id: str) -> str:
127
193
  return f"request/{request_id}"
128
194
 
129
195
  def _url(self, path: str) -> str:
@@ -628,13 +694,7 @@ class PangeaRequest(PangeaRequestBase):
628
694
 
629
695
  @override
630
696
  def _init_session(self) -> requests.Session:
631
- retry_config = Retry(
632
- total=self.config.request_retries,
633
- backoff_factor=self.config.request_backoff,
634
- status_forcelist=[500, 502, 503, 504],
635
- )
636
-
637
- adapter = HTTPAdapter(max_retries=retry_config)
697
+ adapter = PangeaHTTPAdapter(config=self.config)
638
698
  session = requests.Session()
639
699
 
640
700
  session.mount("http://", adapter)
pangea/response.py CHANGED
@@ -18,6 +18,8 @@ from typing_extensions import TypeVar
18
18
 
19
19
  from pangea.utils import format_datetime
20
20
 
21
+ __all__ = ("PangeaResponse", "PangeaResponseResult", "TransferMethod")
22
+
21
23
 
22
24
  class AttachedFile:
23
25
  filename: str
@@ -243,7 +245,9 @@ class PangeaResponse(ResponseHeader, Generic[T]):
243
245
 
244
246
  @property
245
247
  def http_status(self) -> int: # type: ignore[return]
246
- if self.raw_response:
248
+ # Must be an explicit None check because Response's boolean
249
+ # representation is equal to whether or not the response is OK.
250
+ if self.raw_response is not None:
247
251
  if isinstance(self.raw_response, aiohttp.ClientResponse):
248
252
  return self.raw_response.status
249
253
  else:
@@ -1,5 +1,3 @@
1
- # ruff: noqa: F401
2
-
3
1
  from .ai_guard import AIGuard
4
2
  from .audit.audit import Audit
5
3
  from .authn.authn import AuthN
@@ -12,3 +10,22 @@ from .redact import Redact
12
10
  from .sanitize import Sanitize
13
11
  from .share.share import Share
14
12
  from .vault.vault import Vault
13
+
14
+ __all__ = (
15
+ "AIGuard",
16
+ "Audit",
17
+ "AuthN",
18
+ "AuthZ",
19
+ "DomainIntel",
20
+ "Embargo",
21
+ "FileIntel",
22
+ "FileScan",
23
+ "IpIntel",
24
+ "PromptGuard",
25
+ "Redact",
26
+ "Sanitize",
27
+ "Share",
28
+ "UrlIntel",
29
+ "UserIntel",
30
+ "Vault",
31
+ )
@@ -3,7 +3,6 @@ from __future__ import annotations
3
3
  from collections.abc import Sequence
4
4
  from typing import Generic, Literal, Optional, overload
5
5
 
6
- from pydantic import BaseModel, ConfigDict
7
6
  from typing_extensions import TypeVar
8
7
 
9
8
  from pangea.config import PangeaConfig
@@ -21,9 +20,7 @@ MaliciousEntityAction = Literal["report", "defang", "disabled", "block"]
21
20
  PiiEntityAction = Literal["disabled", "report", "block", "mask", "partial_masking", "replacement", "hash", "fpe"]
22
21
 
23
22
 
24
- class Message(BaseModel):
25
- model_config = ConfigDict(extra="forbid")
26
-
23
+ class Message(APIRequestModel):
27
24
  role: str
28
25
  content: str
29
26
 
@@ -31,18 +28,21 @@ class Message(BaseModel):
31
28
  class CodeDetectionOverride(APIRequestModel):
32
29
  disabled: Optional[bool] = None
33
30
  action: Optional[Literal["report", "block"]] = None
31
+ threshold: Optional[float] = None
34
32
 
35
33
 
36
34
  class LanguageDetectionOverride(APIRequestModel):
37
35
  disabled: Optional[bool] = None
38
- allow: Optional[list[str]] = None
39
- block: Optional[list[str]] = None
40
- report: Optional[list[str]] = None
36
+ action: Optional[Literal["", "report", "allow", "block"]] = ""
37
+ languages: Optional[list[str]] = None
38
+ threshold: Optional[float] = None
41
39
 
42
40
 
43
41
  class TopicDetectionOverride(APIRequestModel):
44
42
  disabled: Optional[bool] = None
45
- block: Optional[list[str]] = None
43
+ action: Optional[Literal["", "report", "block"]] = ""
44
+ topics: Optional[list[str]] = None
45
+ threshold: Optional[float] = None
46
46
 
47
47
 
48
48
  class PromptInjectionOverride(APIRequestModel):
@@ -145,6 +145,8 @@ class SecretsDetectionOverride(APIRequestModel):
145
145
 
146
146
 
147
147
  class Overrides(APIRequestModel):
148
+ """Overrides flags."""
149
+
148
150
  ignore_recipe: Optional[bool] = None
149
151
  """Bypass existing Recipe content and create an on-the-fly Recipe."""
150
152
 
@@ -159,7 +161,7 @@ class Overrides(APIRequestModel):
159
161
  secrets_detection: Optional[SecretsDetectionOverride] = None
160
162
  selfharm: Optional[SelfHarmOverride] = None
161
163
  sentiment: Optional[SentimentOverride] = None
162
- topic_detection: Optional[TopicDetectionOverride] = None
164
+ topic: Optional[TopicDetectionOverride] = None
163
165
 
164
166
 
165
167
  class LogFields(APIRequestModel):
@@ -249,15 +251,24 @@ class SecretsEntityResult(APIResponseModel):
249
251
 
250
252
 
251
253
  class LanguageDetectionResult(APIResponseModel):
252
- language: str
253
- action: str
254
+ action: Optional[str] = None
254
255
  """The action taken by this Detector"""
255
256
 
257
+ language: Optional[str] = None
258
+
259
+
260
+ class Topic(APIResponseModel):
261
+ topic: str
262
+ confidence: float
263
+
256
264
 
257
265
  class TopicDetectionResult(APIResponseModel):
258
- action: str
266
+ action: Optional[str] = None
259
267
  """The action taken by this Detector"""
260
268
 
269
+ topics: Optional[list[Topic]] = None
270
+ """List of topics detected"""
271
+
261
272
 
262
273
  class CodeDetectionResult(APIResponseModel):
263
274
  language: str
@@ -274,38 +285,49 @@ class TextGuardDetector(APIResponseModel, Generic[_T]):
274
285
 
275
286
 
276
287
  class TextGuardDetectors(APIResponseModel):
277
- prompt_injection: Optional[TextGuardDetector[PromptInjectionResult]] = None
278
- pii_entity: Optional[TextGuardDetector[PiiEntityResult]] = None
279
- malicious_entity: Optional[TextGuardDetector[MaliciousEntityResult]] = None
288
+ code_detection: Optional[TextGuardDetector[CodeDetectionResult]] = None
289
+ competitors: Optional[TextGuardDetector[object]] = None
280
290
  custom_entity: Optional[TextGuardDetector[object]] = None
281
- secrets_detection: Optional[TextGuardDetector[SecretsEntityResult]] = None
282
- profanity_and_toxicity: Optional[TextGuardDetector[object]] = None
291
+ gibberish: Optional[TextGuardDetector[object]] = None
292
+ hardening: Optional[TextGuardDetector[object]] = None
283
293
  language_detection: Optional[TextGuardDetector[LanguageDetectionResult]] = None
284
- topic_detection: Optional[TextGuardDetector[TopicDetectionResult]] = None
285
- code_detection: Optional[TextGuardDetector[CodeDetectionResult]] = None
294
+ malicious_entity: Optional[TextGuardDetector[MaliciousEntityResult]] = None
295
+ pii_entity: Optional[TextGuardDetector[PiiEntityResult]] = None
296
+ profanity_and_toxicity: Optional[TextGuardDetector[object]] = None
297
+ prompt_injection: Optional[TextGuardDetector[PromptInjectionResult]] = None
298
+ secrets_detection: Optional[TextGuardDetector[SecretsEntityResult]] = None
299
+ selfharm: Optional[TextGuardDetector[object]] = None
300
+ sentiment: Optional[TextGuardDetector[object]] = None
301
+ topic: Optional[TextGuardDetector[TopicDetectionResult]] = None
286
302
 
287
303
 
288
304
  class TextGuardResult(PangeaResponseResult):
289
305
  detectors: TextGuardDetectors
290
306
  """Result of the recipe analyzing and input prompt."""
291
307
 
292
- prompt_text: Optional[str] = None
293
- """Updated prompt text, if applicable."""
308
+ access_rules: Optional[object] = None
309
+ """Result of the recipe evaluating configured rules"""
310
+
311
+ blocked: Optional[bool] = None
312
+ """Whether or not the prompt triggered a block detection."""
313
+
314
+ fpe_context: Optional[str] = None
315
+ """
316
+ If an FPE redaction method returned results, this will be the context passed to
317
+ unredact.
318
+ """
294
319
 
295
320
  prompt_messages: Optional[object] = None
296
321
  """Updated structured prompt, if applicable."""
297
322
 
298
- blocked: bool
299
- """Whether or not the prompt triggered a block detection."""
323
+ prompt_text: Optional[str] = None
324
+ """Updated prompt text, if applicable."""
300
325
 
301
- recipe: str
326
+ recipe: Optional[str] = None
302
327
  """The Recipe that was used."""
303
328
 
304
- fpe_context: Optional[str] = None
305
- """
306
- If an FPE redaction method returned results, this will be the context passed
307
- to unredact.
308
- """
329
+ transformed: Optional[bool] = None
330
+ """Whether or not the original input was transformed."""
309
331
 
310
332
 
311
333
  class AIGuard(ServiceBase):
@@ -314,11 +336,9 @@ class AIGuard(ServiceBase):
314
336
  Provides methods to interact with Pangea's AI Guard service.
315
337
 
316
338
  Examples:
317
- from pangea import PangeaConfig
318
339
  from pangea.services import AIGuard
319
340
 
320
- config = PangeaConfig(domain="aws.us.pangea.cloud")
321
- ai_guard = AIGuard(token="pangea_token", config=config)
341
+ ai_guard = AIGuard(token="pangea_token")
322
342
  """
323
343
 
324
344
  service_name = "ai-guard"
@@ -338,11 +358,9 @@ class AIGuard(ServiceBase):
338
358
  config_id: Configuration ID.
339
359
 
340
360
  Examples:
341
- from pangea import PangeaConfig
342
361
  from pangea.services import AIGuard
343
362
 
344
- config = PangeaConfig(domain="aws.us.pangea.cloud")
345
- ai_guard = AIGuard(token="pangea_token", config=config)
363
+ ai_guard = AIGuard(token="pangea_token")
346
364
  """
347
365
 
348
366
  super().__init__(token, config, logger_name, config_id)
@@ -352,29 +370,31 @@ class AIGuard(ServiceBase):
352
370
  self,
353
371
  text: str,
354
372
  *,
355
- recipe: str | None = None,
356
373
  debug: bool | None = None,
357
- overrides: Overrides | None = None,
358
374
  log_fields: LogFields | None = None,
375
+ overrides: Overrides | None = None,
376
+ recipe: str | None = None,
359
377
  ) -> PangeaResponse[TextGuardResult]:
360
378
  """
361
- Text Guard for scanning LLM inputs and outputs
379
+ Guard LLM input and output text
362
380
 
363
- Analyze and redact text to avoid manipulation of the model, addition of
364
- malicious content, and other undesirable data transfers.
381
+ Detect, remove, or block malicious content and intent in LLM inputs and
382
+ outputs to prevent model manipulation and data leakage.
365
383
 
366
384
  OperationId: ai_guard_post_v1_text_guard
367
385
 
368
386
  Args:
369
387
  text: Text to be scanned by AI Guard for PII, sensitive data,
370
388
  malicious content, and other data types defined by the
371
- configuration. Supports processing up to 10KB of text.
372
- recipe: Recipe key of a configuration of data types and settings
373
- defined in the Pangea User Console. It specifies the rules that
374
- are to be applied to the text, such as defang malicious URLs.
389
+ configuration. Supports processing up to 20 KiB of text.
375
390
  debug: Setting this value to true will provide a detailed analysis
376
391
  of the text data
377
392
  log_field: Additional fields to include in activity log
393
+ overrides: Overrides flags. Note: This parameter has no effect when
394
+ the request is made by AIDR
395
+ recipe: Recipe key of a configuration of data types and settings
396
+ defined in the Pangea User Console. It specifies the rules that
397
+ are to be applied to the text, such as defang malicious URLs.
378
398
 
379
399
  Examples:
380
400
  response = ai_guard.guard_text("text")
@@ -391,24 +411,26 @@ class AIGuard(ServiceBase):
391
411
  log_fields: LogFields | None = None,
392
412
  ) -> PangeaResponse[TextGuardResult]:
393
413
  """
394
- Text Guard for scanning LLM inputs and outputs
414
+ Guard LLM input and output text
395
415
 
396
- Analyze and redact text to avoid manipulation of the model, addition of
397
- malicious content, and other undesirable data transfers.
416
+ Detect, remove, or block malicious content and intent in LLM inputs and
417
+ outputs to prevent model manipulation and data leakage.
398
418
 
399
419
  OperationId: ai_guard_post_v1_text_guard
400
420
 
401
421
  Args:
402
422
  messages: Structured messages data to be scanned by AI Guard for
403
423
  PII, sensitive data, malicious content, and other data types
404
- defined by the configuration. Supports processing up to 10KB of
405
- JSON text
406
- recipe: Recipe key of a configuration of data types and settings
407
- defined in the Pangea User Console. It specifies the rules that
408
- are to be applied to the text, such as defang malicious URLs.
424
+ defined by the configuration. Supports processing up to 20 KiB
425
+ of JSON text using Pangea message format.
409
426
  debug: Setting this value to true will provide a detailed analysis
410
427
  of the text data
411
428
  log_field: Additional fields to include in activity log
429
+ overrides: Overrides flags. Note: This parameter has no effect when
430
+ the request is made by AIDR
431
+ recipe: Recipe key of a configuration of data types and settings
432
+ defined in the Pangea User Console. It specifies the rules that
433
+ are to be applied to the text, such as defang malicious URLs.
412
434
 
413
435
  Examples:
414
436
  response = ai_guard.guard_text(messages=[Message(role="user", content="hello world")])
@@ -419,16 +441,16 @@ class AIGuard(ServiceBase):
419
441
  text: str | None = None,
420
442
  *,
421
443
  messages: Sequence[Message] | None = None,
422
- recipe: str | None = None,
423
444
  debug: bool | None = None,
424
- overrides: Overrides | None = None,
425
445
  log_fields: LogFields | None = None,
446
+ overrides: Overrides | None = None,
447
+ recipe: str | None = None,
426
448
  ) -> PangeaResponse[TextGuardResult]:
427
449
  """
428
- Text Guard for scanning LLM inputs and outputs
450
+ Guard LLM input and output text
429
451
 
430
- Analyze and redact text to avoid manipulation of the model, addition of
431
- malicious content, and other undesirable data transfers.
452
+ Detect, remove, or block malicious content and intent in LLM inputs and
453
+ outputs to prevent model manipulation and data leakage.
432
454
 
433
455
  OperationId: ai_guard_post_v1_text_guard
434
456
 
@@ -440,12 +462,14 @@ class AIGuard(ServiceBase):
440
462
  PII, sensitive data, malicious content, and other data types
441
463
  defined by the configuration. Supports processing up to 10KB of
442
464
  JSON text
443
- recipe: Recipe key of a configuration of data types and settings
444
- defined in the Pangea User Console. It specifies the rules that
445
- are to be applied to the text, such as defang malicious URLs.
446
465
  debug: Setting this value to true will provide a detailed analysis
447
466
  of the text data
448
467
  log_field: Additional fields to include in activity log
468
+ overrides: Overrides flags. Note: This parameter has no effect when
469
+ the request is made by AIDR
470
+ recipe: Recipe key of a configuration of data types and settings
471
+ defined in the Pangea User Console. It specifies the rules that
472
+ are to be applied to the text, such as defang malicious URLs.
449
473
 
450
474
  Examples:
451
475
  response = ai_guard.guard_text("text")
@@ -57,6 +57,8 @@ from pangea.services.audit.util import (
57
57
  from pangea.services.base import ServiceBase
58
58
  from pangea.utils import canonicalize_nested_json
59
59
 
60
+ __all__ = ("Audit", "SearchOutput", "SearchResultOutput")
61
+
60
62
 
61
63
  class AuditBase:
62
64
  def __init__(
@@ -20,6 +20,8 @@ import requests
20
20
  from pangea.services.audit.models import Event, EventEnvelope, PublishedRoot
21
21
  from pangea.utils import default_encoder, format_datetime
22
22
 
23
+ __all__ = ("format_datetime",)
24
+
23
25
  Hash = bytes
24
26
 
25
27
 
@@ -10,11 +10,10 @@ from collections.abc import Mapping
10
10
  from typing import Dict, List, Literal, Optional, Union
11
11
 
12
12
  import pangea.services.authn.models as m
13
- from pangea.config import PangeaConfig
14
- from pangea.response import PangeaResponse, PangeaResponseResult
13
+ from pangea import PangeaConfig, PangeaResponse, PangeaResponseResult
15
14
  from pangea.services.base import ServiceBase
16
15
 
17
- __all__ = ["AuthN"]
16
+ __all__ = ("AuthN",)
18
17
 
19
18
 
20
19
  _SERVICE_NAME = "authn"
@@ -930,7 +929,7 @@ class AuthN(ServiceBase):
930
929
  return self.request.post(
931
930
  "v2/user/group/assign",
932
931
  data={"id": user_id, "group_ids": group_ids},
933
- result_class=m.PangeaResponseResult,
932
+ result_class=PangeaResponseResult,
934
933
  )
935
934
 
936
935
  def remove(self, user_id: str, group_id: str) -> PangeaResponse[PangeaResponseResult]:
@@ -944,7 +943,7 @@ class AuthN(ServiceBase):
944
943
  return self.request.post(
945
944
  "v2/user/group/remove",
946
945
  data={"id": user_id, "group_id": group_id},
947
- result_class=m.PangeaResponseResult,
946
+ result_class=PangeaResponseResult,
948
947
  )
949
948
 
950
949
  def list(self, user_id: str) -> PangeaResponse[m.GroupList]:
pangea/services/base.py CHANGED
@@ -18,6 +18,9 @@ from pangea.exceptions import AcceptedRequestException
18
18
  from pangea.request import PangeaRequest
19
19
  from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult
20
20
 
21
+ __all__ = ("ServiceBase",)
22
+
23
+
21
24
  TResult = TypeVar("TResult", bound=PangeaResponseResult, default=PangeaResponseResult)
22
25
 
23
26
 
@@ -10,8 +10,9 @@ import io
10
10
  import logging
11
11
  from typing import Dict, List, Optional, Tuple
12
12
 
13
- from pangea.request import PangeaConfig, PangeaRequest
14
- from pangea.response import APIRequestModel, PangeaResponse, PangeaResponseResult, TransferMethod
13
+ from pangea import PangeaConfig, PangeaResponse, PangeaResponseResult, TransferMethod
14
+ from pangea.request import PangeaRequest
15
+ from pangea.response import APIRequestModel
15
16
  from pangea.services.base import ServiceBase
16
17
  from pangea.utils import FileUploadParams, get_file_upload_params
17
18
 
@@ -10,6 +10,9 @@ if TYPE_CHECKING:
10
10
  from collections.abc import Iterable
11
11
 
12
12
 
13
+ __all__ = ("Message", "PromptGuard")
14
+
15
+
13
16
  class Message(APIRequestModel):
14
17
  role: str
15
18
  content: str
@@ -88,6 +88,9 @@ if TYPE_CHECKING:
88
88
  from pangea.request import TResult
89
89
 
90
90
 
91
+ __all__ = ("ExportEncryptionAlgorithm", "ItemType", "ItemVersionState", "TransformAlphabet", "Vault")
92
+
93
+
91
94
  VaultItem = Annotated[
92
95
  Union[AsymmetricKey, SymmetricKey, Secret, ClientSecret, Folder, PangeaToken], Field(discriminator="type")
93
96
  ]
@@ -1,24 +1,25 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: pangea-sdk
3
- Version: 6.3.0
3
+ Version: 6.5.0
4
4
  Summary: Pangea API SDK
5
- License: MIT
6
5
  Keywords: Pangea,SDK,Audit
7
6
  Author: Glenn Gallien
8
- Author-email: glenn.gallien@pangea.cloud
9
- Requires-Python: >=3.9.2,<4.0.0
7
+ Author-email: Glenn Gallien <glenn.gallien@pangea.cloud>
8
+ License-Expression: MIT
10
9
  Classifier: Topic :: Software Development
11
10
  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)
11
+ Requires-Dist: aiohttp>=3.12.15,<4.0.0
12
+ Requires-Dist: cryptography>=45.0.6,<46.0.0
13
+ Requires-Dist: deprecated>=1.2.18,<2.0.0
14
+ Requires-Dist: google-crc32c>=1.7.1,<2.0.0
15
+ Requires-Dist: pydantic>=2.11.7,<3.0.0
16
+ Requires-Dist: python-dateutil>=2.9.0.post0,<3.0.0
17
+ Requires-Dist: requests>=2.32.4,<3.0.0
18
+ Requires-Dist: requests-toolbelt>=1.0.0,<2.0.0
19
+ Requires-Dist: typing-extensions>=4.14.1,<5.0.0
20
+ Requires-Dist: yarl>=1.20.1,<2.0.0
21
+ Requires-Python: >=3.9.2, <4.0.0
22
+ Project-URL: repository, https://github.com/pangeacyber/pangea-python
22
23
  Description-Content-Type: text/markdown
23
24
 
24
25
  <a href="https://pangea.cloud?utm_source=github&utm_medium=python-sdk" target="_blank" rel="noopener noreferrer">
@@ -116,8 +117,7 @@ The SDK supports the following configuration options via `PangeaConfig`:
116
117
  Use `base_url_template` for more control over the URL, such as setting
117
118
  service-specific paths. Defaults to `aws.us.pangea.cloud`.
118
119
  - `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.
120
+ - `request_backoff` — A backoff factor to apply between request attempts.
121
121
  - `poll_result_timeout` — Timeout used to poll results after 202 (in secs).
122
122
  - `queued_retry_enabled` — Enable queued request retry support.
123
123
  - `custom_user_agent` — Custom user agent to be used in the request headers.
@@ -243,4 +243,3 @@ It accepts multiple file formats:
243
243
  [Beta Examples]: https://github.com/pangeacyber/pangea-python/tree/beta/examples
244
244
  [Pangea Console]: https://console.pangea.cloud/
245
245
  [Secure Audit Log]: https://pangea.cloud/docs/audit
246
-
@@ -0,0 +1,62 @@
1
+ pangea/__init__.py,sha256=5742d82dc2d689975ba2a51445ea8d77a80526dca1b8be128b1cc08bf65a8c4e,293
2
+ pangea/_constants.py,sha256=8061a843aae14a2144c3530a486239f3c087bc5a241b509ff5292474f7518d56,113
3
+ pangea/_typing.py,sha256=f8beebc1fdfed94696cf215e09d06b6b5be360718d923df71c32fad4a13ff856,81
4
+ pangea/asyncio/__init__.py,sha256=f7acf2b406f0ef488a96a1b0175d850937f7e7cfe28e405536ea3ed6f04ec872,79
5
+ pangea/asyncio/file_uploader.py,sha256=2e7f85bec1ccf9fab8be902f7e86107af7ac42033ec9c2ea836313fb9f31a14d,1435
6
+ pangea/asyncio/request.py,sha256=acb314586c7a3d93bbc42640caf55c3904117c1a7b2340660517b71c4fd888b6,20943
7
+ pangea/asyncio/services/__init__.py,sha256=8f7f59d02a43014cdd9f90bad5bfa4642b6ff493d741f438c24252485a799173,803
8
+ pangea/asyncio/services/ai_guard.py,sha256=e2cdb2567f24f1def800e3e1e5532a0cea6603e0c4674fc0ec0af2593963d448,6393
9
+ pangea/asyncio/services/audit.py,sha256=b26670cc229adfb5b3a3bc8da9af91a7b58258d5d74027e3280db93efc4bf1fa,26127
10
+ pangea/asyncio/services/authn.py,sha256=8d634843649bfb4be7de11c6289e3b5e6fbf103b39f2f6e05fa37053f6bd13bd,52815
11
+ pangea/asyncio/services/authz.py,sha256=bed490de21185062fb6929f84be5238b0cd71e531e016d2fa757db53baf1e98f,10796
12
+ pangea/asyncio/services/base.py,sha256=e52604639395c696b9a741ed515d8eaa958d97c70ff2a6316d0be95607af64c4,3416
13
+ pangea/asyncio/services/embargo.py,sha256=72dce3de48a9eb1a2cf84bb726e3ac92b086602f13dc996c800a2964788f4973,3068
14
+ pangea/asyncio/services/file_scan.py,sha256=e4291bddc5caa5ca0eeca4d4bba7a3af5b82e37fba1096fdd56b86387ae84471,7202
15
+ pangea/asyncio/services/intel.py,sha256=48a0cec9ef9bef74929a7bdea6e450fde8f8a27ef5b8278286d21f33499cc133,40193
16
+ pangea/asyncio/services/prompt_guard.py,sha256=c7c419cd3fed27c792b720210c3674e13d045cb7f73dde770457b7f6db3a7e4d,2597
17
+ pangea/asyncio/services/redact.py,sha256=df9e8a779b30c3ac09b3103a0c5209bd510995ed349fb1e28dd20d6fad585fd1,8014
18
+ pangea/asyncio/services/sanitize.py,sha256=3b26d30147e1ffbbd84706fa0a3a78687668787848960f1c689fc156b75b0350,8691
19
+ pangea/asyncio/services/share.py,sha256=015f456c0f88314e53161701b541e85ca0d061f38858024964a5babc5a2105bb,30816
20
+ pangea/asyncio/services/vault.py,sha256=6d82146265981fc2eac9c7f20f23684bcdc145631de7ab7e44cb7407e4d4f1c4,78564
21
+ pangea/audit_logger.py,sha256=0ceccbe68c97c1a3e5b2e2ba5511d79ff94f74d73867b2c71a3efc440ad7b390,3861
22
+ pangea/config.py,sha256=29b484ab5fe1e2fa76ab66087cf09c26d69609101178a21f3639d7282fe38133,1973
23
+ pangea/crypto/rsa.py,sha256=9b04a2372e7bd4a006af717aa043340975a497d0f4db7721f2575b65978b8ffe,4747
24
+ pangea/deep_verify.py,sha256=67cbe7af1122c1ade171324ee9c919a5d49ead01e3b609d452595a59300c7702,8637
25
+ pangea/deprecated.py,sha256=df288ced69d2387ab9e513ad26f8638930d298e1086b407ce583dcb557e9f965,597
26
+ pangea/dump_audit.py,sha256=6fcf63295ddec32efb580fc0cd53084f4e3f135094c53a658fde0851124cee77,7081
27
+ pangea/exceptions.py,sha256=1221fb362343c8debd6589558a417c775b403b7fc3a346ca97c7455e0858f2dd,5585
28
+ pangea/file_uploader.py,sha256=291bb3db303ae9a3b22864bd3d7516d6abfdbcb1ce18c7754479006e11a4ddc6,1329
29
+ pangea/py.typed,sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,0
30
+ pangea/request.py,sha256=3c06dc471ef8ea14a1b76d0afc43963de40c8c5cf18f0b3b29f74ccf383f575d,27938
31
+ pangea/response.py,sha256=d4e1b96cf584d23de9efbb56622bc6fcefced920fc8744eeabd5a537aace292d,7821
32
+ pangea/services/__init__.py,sha256=28fd94d3e4dcbac5b91f71941714bb35cfcbc7127e5f4b816f178b42618eebea,667
33
+ pangea/services/ai_guard.py,sha256=a0775d7b8dd62ba9ff520fe54006e7f8aabf778b96c65e2f43ceb61f8c65ed4e,16922
34
+ pangea/services/audit/audit.py,sha256=e348eb0803ae6729bf42c11f8608488cf9b728a5b03f1f41dd9289f93ed1e16e,39231
35
+ pangea/services/audit/exceptions.py,sha256=6e156e61ee1a9a669c395c7083df020a1c6fc197f914a811d83720a882ce7307,471
36
+ pangea/services/audit/models.py,sha256=a44e23b58027fdce4974fad705fa4a1f0a5102a3bf0d34823b2f901e43cc6a3c,15471
37
+ pangea/services/audit/signing.py,sha256=56c424b2d40bd6fc4874dd86871a783fe14b06957f048bc3b010a4440650a64f,5593
38
+ pangea/services/audit/util.py,sha256=7435420fbd15e981c55469966e6dc0387a1fc48f8e7de25e4cc0d843ee564b1a,7683
39
+ pangea/services/authn/authn.py,sha256=d3d83ef3dca6852e6d51e41758431bd9e8ca9d3b9e6972a4f0c82b744036e90a,51169
40
+ pangea/services/authn/models.py,sha256=56b7b3e66fc8bc1bd2377ba3adcb09dfcf2eeeb0f241474c53ca77b27a8f65c9,27218
41
+ pangea/services/authz.py,sha256=0c9c78d41e56f14ac63f711af6dfaa0780d27488b5b6f8ed0cc58e355e607458,16191
42
+ pangea/services/base.py,sha256=727c70092a99b7e96f606f5eb5b2515d5c6d1c7ebbb8c5b4ee9b5f55b7d57eae,3864
43
+ pangea/services/embargo.py,sha256=deb1372268c18365545d096319920279db2bd78a6c59dca60b6a6699d245d9ca,4000
44
+ pangea/services/file_scan.py,sha256=81295add5526825de203b0dcac27f504aa29bee9cf1b979c22f5f80f0cd83af7,7952
45
+ pangea/services/intel.py,sha256=52ba27ce09f31b966c986f4a9b5d89c3f6ade5b6005e817e36a818907ed659f8,56958
46
+ pangea/services/prompt_guard.py,sha256=1729c7cd6977347f862b6afd203eb67775432e04395cf7aab88ac92358544b5b,3485
47
+ pangea/services/redact.py,sha256=2c93073caf210f13cb11535f46011201680be0604c8890bfa6bd705c66fbf56f,13225
48
+ pangea/services/sanitize.py,sha256=d19942ac483c8a626d472a2fcb8a9925bd59019f29a483904e3fe7a1c049d823,13019
49
+ pangea/services/share/file_format.py,sha256=d6cbced5e7bf69e9c0f73a0efc0694f91939525a7b91c3ce73f2b036896ec901,2797
50
+ pangea/services/share/share.py,sha256=2214e296a59c4361a5b09ee41c7b956d77cdbbc8ef16d3c19c478cdba48db18f,52403
51
+ pangea/services/vault/models/asymmetric.py,sha256=17a24c77d0656096528df84945abea71a76640901b71de5dadeccb2d0fd9244b,5058
52
+ pangea/services/vault/models/common.py,sha256=570d3208b10cca6883ac51242a598fad811e8d427f2689c578c12fcbbc30660d,18050
53
+ pangea/services/vault/models/keys.py,sha256=d808b0bfa5026d3785ca4bc6616e9e5ddec9de180898609df1fe5d6281c9d9c1,2805
54
+ pangea/services/vault/models/secret.py,sha256=473e9c293456a256d6f165b7dfe17b456076f4623f957883ef685e95ba65bc59,1152
55
+ pangea/services/vault/models/symmetric.py,sha256=56a27f0b7c63d9ee0eb671623f29e05fafec39c5ca15fd7285ab5217d3e607dd,2629
56
+ pangea/services/vault/vault.py,sha256=3c9b356254ee77570f9e1c940cc82e204ca13748be85a1b592ecc0ff88728049,77676
57
+ pangea/tools.py,sha256=264c15a65bf1ecc08f45274f8454cbbce97a87b6ed6946d712e1e0532d041c15,6452
58
+ pangea/utils.py,sha256=4304ce0c8fc3f1bcbceae5de0343297612480afcf96da294b5fbf5ae0b90b215,4943
59
+ pangea/verify_audit.py,sha256=f957a940a1ed4aa651aa120a894b4bb9f6bbcb0c1d30d2cdd92ba18a780ca285,17288
60
+ pangea_sdk-6.5.0.dist-info/WHEEL,sha256=0f7d664a881437bddec71c703c3c2f01fd13581519f95130abcc96e296ef0426,79
61
+ pangea_sdk-6.5.0.dist-info/METADATA,sha256=ea6b911a8867d4bc54ff4ce3843c3e632b9ce8f151e31e9304c7ee73efc1d1cf,8029
62
+ pangea_sdk-6.5.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.8.11
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -1,60 +0,0 @@
1
- pangea/__init__.py,sha256=sj1sB7F5uQpLZtaAqYFcpmFREs0nbe4XOBnRWOCA1uE,370
2
- pangea/asyncio/__init__.py,sha256=TIiYYY-DR4X6d3rGBqpCBQkPMFkogzYLXYvi_RvmCEM,64
3
- pangea/asyncio/file_uploader.py,sha256=FwR-p-Xgtmq3UDW6_ptRQLTL4_2AIzdaY358WjxwJBw,1436
4
- pangea/asyncio/request.py,sha256=VX5e7xIUmtP8TBan6efiAcc9cCdXGUJOAYZN-mhgRqQ,19395
5
- pangea/asyncio/services/__init__.py,sha256=m0nqw9_7mlachetzNxyJKZDOtEe2j2_UHFCELAE3Irg,484
6
- pangea/asyncio/services/ai_guard.py,sha256=QaeiKZSn8aDuBPfEsF_KgUbkAtaaauSd_RTGBAbBU3g,6274
7
- pangea/asyncio/services/audit.py,sha256=smZwzCKa37Wzo7yNqa-Rp7WCWNXXQCfjKA25PvxL8fo,26127
8
- pangea/asyncio/services/authn.py,sha256=z22Q0ym87Sf1_X9oQzj2kiQ5Lbb0KmK4iBNEdr3XfRo,52291
9
- pangea/asyncio/services/authz.py,sha256=vtSQ3iEYUGL7aSn4S-UjiwzXHlMeAW0vp1fbU7rx6Y8,10796
10
- pangea/asyncio/services/base.py,sha256=ntvuwfyAuhyfrptlBg1NFViGlFb3tf9uqxnC1PiBX6U,3206
11
- pangea/asyncio/services/embargo.py,sha256=ctzj3kip6xos-Eu3JuOskrCGYC8T3JlsgAopZHiPSXM,3068
12
- pangea/asyncio/services/file_scan.py,sha256=OCKvrTZgsTCKA6P261PSRl4anWcU-CvDPtXfrTqAxgE,7210
13
- pangea/asyncio/services/intel.py,sha256=SKDOye-b73SSmnvepuRQ_ej4on71uCeChtIfM0mcwTM,40193
14
- pangea/asyncio/services/prompt_guard.py,sha256=NbYt-0tRtO5VH7kLmC1lJ5JSV-ztlb9dNFaKKs_fZUM,2553
15
- pangea/asyncio/services/redact.py,sha256=356Kd5sww6wJsxA6DFIJvVEJle00n7HijdINb61YX9E,8014
16
- pangea/asyncio/services/sanitize.py,sha256=OybTAUfh_7vYRwb6Cjp4aHZoeHhIlg8caJ_BVrdbA1A,8691
17
- pangea/asyncio/services/share.py,sha256=AV9FbA-IMU5TFhcBtUHoXKDQYfOIWAJJZKW6vFohBbs,30816
18
- pangea/asyncio/services/vault.py,sha256=bYIUYmWYH8LqycfyDyNoS83BRWMd56t-RMt0B-TU8cQ,78564
19
- pangea/audit_logger.py,sha256=DOzL5oyXwaPlsuK6VRHXn_lPdNc4Z7LHGj78RArXs5A,3861
20
- pangea/config.py,sha256=Z2WT_UG0qBQzzVzBfloXYFxS21mSg1YXQ36cAVCqrJk,1963
21
- pangea/crypto/rsa.py,sha256=mwSiNy571KAGr3F6oEM0CXWkl9D023ch8ldbZZeLj_4,4747
22
- pangea/deep_verify.py,sha256=Z8vnrxEiwa3hcTJO6ckZpdSerQHjtgnUUllaWTAMdwI,8637
23
- pangea/deprecated.py,sha256=3yiM7WnSOHq55ROtJvhjiTDSmOEIa0B85YPctVfp-WU,597
24
- pangea/dump_audit.py,sha256=b89jKV3ewy77WA_AzVMIT04_E1CUxTplj94IURJM7nc,7081
25
- pangea/exceptions.py,sha256=EiH7NiNDyN69ZYlVikF8d1tAO3_Do0bKl8dFXghY8t0,5585
26
- pangea/file_uploader.py,sha256=bDX9jZTw4h_gwFf9AjtfJYxQchLM2lVMgH93WhgCXsY,1275
27
- pangea/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- pangea/request.py,sha256=g5kQiV_hB4A38FVQnPX5Y64Y-N9LePWnf7QiFbxleOw,25541
29
- pangea/response.py,sha256=gE5m82v8BruKwGTMZlT_Krv1YwYAmp6dhpKnVWGZpWg,7597
30
- pangea/services/__init__.py,sha256=CzgsgeO-wR4xTn7OUE2DhoIF4HoYQO-uA-yBhjNSF4g,428
31
- pangea/services/ai_guard.py,sha256=bXf4hFFeNYvmdeiSwcDgAwgveTNwLXe5-KirOea3Qt0,15986
32
- pangea/services/audit/audit.py,sha256=sBRghIhGscR46CxvWYN7FGHjZyqqtFOB4xH8CwxAsw4,39172
33
- pangea/services/audit/exceptions.py,sha256=bhVuYe4ammacOVxwg98CChxvwZf5FKgR2DcgqILOcwc,471
34
- pangea/services/audit/models.py,sha256=pE4jtYAn_c5JdPrXBfpKHwpRAqO_DTSCOy-QHkPMajw,15471
35
- pangea/services/audit/signing.py,sha256=VsQkstQL1vxIdN2Ghxp4P-FLBpV_BIvDsBCkRAZQpk8,5593
36
- pangea/services/audit/util.py,sha256=dna9AKodlJ-C_VAXFebMu2r57Fl1DdRWdb1SyG7VLpA,7651
37
- pangea/services/authn/authn.py,sha256=vQUwf9wKKF0o-bcsyiBHky0cZ1UTqfqRCGeWPqNXdck,51206
38
- pangea/services/authn/models.py,sha256=Vrez5m_IvBvSN3ujrcsJ388u7rDyQUdMU8p3snqPZck,27218
39
- pangea/services/authz.py,sha256=DJx41B5W8UrGP3Ea9t-qB4DSdIi1tvjtDMWONV5gdFg,16191
40
- pangea/services/base.py,sha256=ShkR0elPiYPln323x4L4F_hGhjQ5fB0zpGZ9J4SLk4g,3835
41
- pangea/services/embargo.py,sha256=3rE3ImjBg2VUXQljGZICedsr14psWdymC2pmmdJF2co,4000
42
- pangea/services/file_scan.py,sha256=DzFYJyBrByWZHUQN8ll8OvzsynT8qegMzaEMXJfiP2Q,7934
43
- pangea/services/intel.py,sha256=UronzgnzG5ZsmG9Km12Jw_at5bYAXoF-NqgYkH7WWfg,56958
44
- pangea/services/prompt_guard.py,sha256=Cq8ume2_YPfHre4iN6FYkyTV7NrdwLXlr_wnilfKotE,3446
45
- pangea/services/redact.py,sha256=LJMHPK8hDxPLEVNfRgESAWgL4GBMiJC_pr1wXGb79W8,13225
46
- pangea/services/sanitize.py,sha256=0ZlCrEg8imJtRyovy4qZJb1ZAZ8ppIOQTj_nocBJ2CM,13019
47
- pangea/services/share/file_format.py,sha256=1svO1ee_aenA9zoO_AaU-Rk5Ulp7kcPOc_KwNoluyQE,2797
48
- pangea/services/share/share.py,sha256=IhTilqWcQ2GlsJ7kHHuVbXfNu8jvFtPBnEeM26SNsY8,52403
49
- pangea/services/vault/models/asymmetric.py,sha256=F6JMd9BlYJZSjfhJRavqcadmQJAbcd5drezLLQ_ZJEs,5058
50
- pangea/services/vault/models/common.py,sha256=Vw0yCLEMymiDrFEkKlmPrYEejUJ_JonFeMEvy7wwZg0,18050
51
- pangea/services/vault/models/keys.py,sha256=2Aiwv6UCbTeFykvGYW6eXd7J3hgImGCd8f5dYoHJ2cE,2805
52
- pangea/services/vault/models/secret.py,sha256=Rz6cKTRWolbW8WW33-F7RWB29GI_lXiD72helbplvFk,1152
53
- pangea/services/vault/models/symmetric.py,sha256=VqJ_C3xj2e4OtnFiPyngX6_sOcXKFf1yhatSF9PmB90,2629
54
- pangea/services/vault/vault.py,sha256=dYkaDleCeJIiDVdwMeJXYnvKFICKI8U0uLdfX1BZYr4,77572
55
- pangea/tools.py,sha256=JkwVplvx7MCPRSdPhFTLvOl6h7btaUbXEuHgUy0EHBU,6452
56
- pangea/utils.py,sha256=QwTODI_D8by86uXeA0MpdhJICvz5baKUtfv1rguQshU,4943
57
- pangea/verify_audit.py,sha256=-VepQKHtSqZRqhIKiUtLufa7ywwdMNLN2SuhingMooU,17288
58
- pangea_sdk-6.3.0.dist-info/METADATA,sha256=pe3QGeeLCoriUi0Ty34u_vBGoGxHReAqxTeZcopf3GA,8015
59
- pangea_sdk-6.3.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
60
- pangea_sdk-6.3.0.dist-info/RECORD,,
@@ -1,4 +0,0 @@
1
- Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.3
3
- Root-Is-Purelib: true
4
- Tag: py3-none-any