epostix 1.0.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 (61) hide show
  1. epostix-1.0.0/.codegen.json +31 -0
  2. epostix-1.0.0/.github/workflows/ci.yml +105 -0
  3. epostix-1.0.0/.github/workflows/release.yml +85 -0
  4. epostix-1.0.0/.gitignore +7 -0
  5. epostix-1.0.0/PKG-INFO +6 -0
  6. epostix-1.0.0/conftest.py +131 -0
  7. epostix-1.0.0/epostix/__init__.py +223 -0
  8. epostix-1.0.0/epostix/_client.py +253 -0
  9. epostix-1.0.0/epostix/_codec.py +248 -0
  10. epostix-1.0.0/epostix/_errors.py +335 -0
  11. epostix-1.0.0/epostix/_generated/__init__.py +19 -0
  12. epostix-1.0.0/epostix/_generated/codecs.py +1027 -0
  13. epostix-1.0.0/epostix/_generated/models.py +1268 -0
  14. epostix-1.0.0/epostix/_generated/operations.py +879 -0
  15. epostix-1.0.0/epostix/_generated/resources/__init__.py +90 -0
  16. epostix-1.0.0/epostix/_generated/resources/analytics.py +83 -0
  17. epostix-1.0.0/epostix/_generated/resources/api_keys.py +231 -0
  18. epostix-1.0.0/epostix/_generated/resources/attachments.py +15 -0
  19. epostix-1.0.0/epostix/_generated/resources/broadcasts.py +239 -0
  20. epostix-1.0.0/epostix/_generated/resources/contacts.py +296 -0
  21. epostix-1.0.0/epostix/_generated/resources/domains.py +193 -0
  22. epostix-1.0.0/epostix/_generated/resources/emails.py +346 -0
  23. epostix-1.0.0/epostix/_generated/resources/events.py +136 -0
  24. epostix-1.0.0/epostix/_generated/resources/inbound.py +169 -0
  25. epostix-1.0.0/epostix/_generated/resources/suppressions.py +186 -0
  26. epostix-1.0.0/epostix/_generated/resources/tags.py +119 -0
  27. epostix-1.0.0/epostix/_generated/resources/templates.py +202 -0
  28. epostix-1.0.0/epostix/_generated/resources/templates_versions.py +157 -0
  29. epostix-1.0.0/epostix/_generated/resources/webhooks.py +236 -0
  30. epostix-1.0.0/epostix/_generated/resources/webhooks_logs.py +150 -0
  31. epostix-1.0.0/epostix/_mailbox.py +23 -0
  32. epostix-1.0.0/epostix/_model.py +24 -0
  33. epostix-1.0.0/epostix/_pagination.py +293 -0
  34. epostix-1.0.0/epostix/_response.py +109 -0
  35. epostix-1.0.0/epostix/_retry.py +193 -0
  36. epostix-1.0.0/epostix/_transport.py +716 -0
  37. epostix-1.0.0/epostix/_types.py +20 -0
  38. epostix-1.0.0/epostix/attachments.py +152 -0
  39. epostix-1.0.0/epostix/batch.py +119 -0
  40. epostix-1.0.0/epostix/models.py +291 -0
  41. epostix-1.0.0/epostix/overrides.py +216 -0
  42. epostix-1.0.0/epostix/py.typed +0 -0
  43. epostix-1.0.0/epostix/webhooks.py +322 -0
  44. epostix-1.0.0/openapi/developer-v1.yaml +5774 -0
  45. epostix-1.0.0/pyproject.toml +21 -0
  46. epostix-1.0.0/tests/fixtures/decoding.json +126 -0
  47. epostix-1.0.0/tests/fixtures/pagination.json +62 -0
  48. epostix-1.0.0/tests/fixtures/serialization.json +389 -0
  49. epostix-1.0.0/tests/fixtures/webhook.json +186 -0
  50. epostix-1.0.0/tests/test_attachments.py +118 -0
  51. epostix-1.0.0/tests/test_batch.py +138 -0
  52. epostix-1.0.0/tests/test_decoding.py +203 -0
  53. epostix-1.0.0/tests/test_exports.py +52 -0
  54. epostix-1.0.0/tests/test_operations.py +123 -0
  55. epostix-1.0.0/tests/test_overrides.py +213 -0
  56. epostix-1.0.0/tests/test_pagination.py +209 -0
  57. epostix-1.0.0/tests/test_parity.py +148 -0
  58. epostix-1.0.0/tests/test_retry.py +374 -0
  59. epostix-1.0.0/tests/test_serialization.py +168 -0
  60. epostix-1.0.0/tests/test_transport.py +285 -0
  61. epostix-1.0.0/tests/test_webhook.py +182 -0
@@ -0,0 +1,31 @@
1
+ {
2
+ "generator": "epostix-codegen",
3
+ "spec": {
4
+ "raw_sha256": "bb71a54ab7ec8025ecc7f833f8a9c260ee0a9040fcfb39608c5cde1ba952c6f2",
5
+ "contract_sha256": "8f5de3df7a3ac063c6f0110ffc007cea51db26cb9f2826b0d72e6e27d235b4f3"
6
+ },
7
+ "ir_sha256": "182bab5a6f40f8c424518090112332f014d04098e0969687b0f3321738d93b07",
8
+ "files": {
9
+ "epostix/_generated/models.py": "ad1cb5fed77e365c193fe31f9d17bb7b84dab9700a3824b6f5955251be01a0fe",
10
+ "epostix/models.py": "2f647a6f861262349357aa6bab61e9403af76c9fde9d6e68f5c5c9e25ae4fab2",
11
+ "epostix/_generated/codecs.py": "94d7e413d040b0592efe1cd3baf97698d0bec68ac5307dc135f0da4e09a19ad0",
12
+ "epostix/_generated/operations.py": "547b7896baea9dafd21f6ce4e7794f07e7e0cb8e93833a168f463245356ea963",
13
+ "epostix/_generated/resources/analytics.py": "3bb7c5464b1f8dbc83eaa408db8b2da660599545a9b0b88cc6e327ef44e910e1",
14
+ "epostix/_generated/resources/api_keys.py": "514a460940e59e8bc91af1554e08c9cc9c827b40630e5014c302969f3183dfba",
15
+ "epostix/_generated/resources/attachments.py": "e87758a7f2957a7093f173d6d701a692e7915117ed029fd2276a7bd7815f7ae8",
16
+ "epostix/_generated/resources/broadcasts.py": "e756cfb53034d502cc767f167ee5c872816231ba86a4901ac992a8bc408b4534",
17
+ "epostix/_generated/resources/contacts.py": "757ed6ca3e5140954b675d324c8d4f8c1ca9d592205cae2b62ab1ab5af22b9e2",
18
+ "epostix/_generated/resources/domains.py": "eb961f7a3c46c9ac6f0a2a81ec38163ddb24816344083aa1cb6697fed33011bf",
19
+ "epostix/_generated/resources/emails.py": "1a9dfe9c838d6eb31dc5f505b14c9a4f5fbdba128a4c476688cd597944dea330",
20
+ "epostix/_generated/resources/events.py": "0fc1e45b2c6ed11e846d9e6413cd4184e7852a2299b1460717e62536c9738a14",
21
+ "epostix/_generated/resources/inbound.py": "75e8a5b18195051d60cea5fd972c48a5580921c7b3511d2c90e25f048df09b83",
22
+ "epostix/_generated/resources/suppressions.py": "38d60c29befe9259ad5bb160f6959e2140ac696b31d6e58b1d132372c9672dc7",
23
+ "epostix/_generated/resources/tags.py": "9fd18587e35a1b09949808210bb91812c859b9e28e7f7cc5794adadcec29ca4d",
24
+ "epostix/_generated/resources/templates.py": "47d6e3be9377ae9f42dcacdcc414895588d9b2c502a99be2cf878fed5efa72d0",
25
+ "epostix/_generated/resources/templates_versions.py": "a9ccd5054204147eb35cb0fb107fd038cdc2658afc80ce725efe0ca3ed6dcca1",
26
+ "epostix/_generated/resources/webhooks.py": "4a44e89fceaf0e7687c214815b3939d532be835c955a92001945b259081b9d28",
27
+ "epostix/_generated/resources/webhooks_logs.py": "bd09bf857b311d080cdf09533a85b098512d09681c3401f96c89ff9b285f8d84",
28
+ "epostix/_generated/resources/__init__.py": "8242f142db2e5367c72f73f140e25b5c2eff97ac7af2c54c97d594c2232d68f4",
29
+ "epostix/_generated/__init__.py": "64747d64d6dc44e816b417cd4dd4f9d50643c3ef1f2931d6dc1fa2d6396e87ef"
30
+ }
31
+ }
@@ -0,0 +1,105 @@
1
+ name: ci
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: ["**"]
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ci-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ contract:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@v5
20
+ - name: the vendored spec must match the codegen manifest
21
+ run: |
22
+ expected=$(python3 -c "import json;print(json.load(open('.codegen.json'))['spec']['raw_sha256'])")
23
+ actual=$(sha256sum openapi/developer-v1.yaml | cut -d' ' -f1)
24
+ if [ "$expected" != "$actual" ]; then
25
+ echo "the vendored spec does not match .codegen.json"
26
+ exit 1
27
+ fi
28
+ - name: generated files must not be hand-edited
29
+ run: |
30
+ python3 - <<'PY'
31
+ import hashlib, json, sys
32
+ manifest = json.load(open('.codegen.json'))
33
+ failures = 0
34
+ for path, expected in manifest['files'].items():
35
+ try:
36
+ actual = hashlib.sha256(open(path, 'rb').read()).hexdigest()
37
+ except FileNotFoundError:
38
+ print(f'missing generated file: {path}')
39
+ failures += 1
40
+ continue
41
+ if actual != expected:
42
+ print(f'generated file was edited by hand: {path}')
43
+ failures += 1
44
+ if failures:
45
+ sys.exit(1)
46
+ print(f"contract ok: {len(manifest['files'])} generated files")
47
+ PY
48
+
49
+ test:
50
+ needs: contract
51
+ runs-on: ubuntu-latest
52
+ strategy:
53
+ fail-fast: false
54
+ matrix:
55
+ python: ["3.11", "3.12", "3.13", "3.14"]
56
+ steps:
57
+ - uses: actions/checkout@v5
58
+ - uses: actions/setup-python@v6
59
+ with:
60
+ python-version: ${{ matrix.python }}
61
+ - run: pip install httpx pytest pytest-asyncio mypy
62
+ - run: python -m pytest -q
63
+ - run: python -m mypy --strict epostix
64
+
65
+ prerelease:
66
+ needs: contract
67
+ runs-on: ubuntu-latest
68
+ continue-on-error: true
69
+ steps:
70
+ - uses: actions/checkout@v5
71
+ - uses: actions/setup-python@v6
72
+ with:
73
+ python-version: "3.15"
74
+ allow-prereleases: true
75
+ - run: pip install httpx pytest pytest-asyncio
76
+ - run: python -m pytest -q
77
+
78
+ package:
79
+ needs: test
80
+ runs-on: ubuntu-latest
81
+ steps:
82
+ - uses: actions/checkout@v5
83
+ - uses: actions/setup-python@v6
84
+ with:
85
+ python-version: "3.13"
86
+ - run: pip install build
87
+ - run: python -m build
88
+ - name: install the built wheel into a clean environment
89
+ run: |
90
+ python -m venv /tmp/smoke
91
+ /tmp/smoke/bin/pip install --quiet dist/*.whl
92
+ /tmp/smoke/bin/python -c "
93
+ import epostix
94
+ client = epostix.Epostix(api_key='tix_test_smoke')
95
+ assert callable(client.emails.send_email)
96
+ assert callable(client.templates.versions.list_template_versions)
97
+ assert callable(client.attachments.upload_attachment)
98
+ from epostix.webhooks import EpostixWebhookVerifier
99
+ assert EpostixWebhookVerifier is not None
100
+ print('install smoke ok')
101
+ "
102
+ - uses: actions/upload-artifact@v4
103
+ with:
104
+ name: distributions
105
+ path: dist/
@@ -0,0 +1,85 @@
1
+ name: release
2
+
3
+ on:
4
+ release:
5
+ types: [created]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ verify:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v5
15
+ with:
16
+ ref: ${{ github.event.release.tag_name }}
17
+ - uses: actions/setup-python@v6
18
+ with:
19
+ python-version: "3.13"
20
+ - run: pip install httpx pytest pytest-asyncio mypy
21
+ - run: python -m pytest -q
22
+ - run: python -m mypy --strict epostix
23
+ - name: the tag must match the project version
24
+ run: |
25
+ version=$(python3 -c "import tomllib;print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
26
+ tag="${{ github.event.release.tag_name }}"
27
+ if [ "v$version" != "$tag" ]; then
28
+ echo "pyproject.toml is $version but the tag is $tag"
29
+ exit 1
30
+ fi
31
+ - name: the tag must be a signed annotated tag
32
+ env:
33
+ GH_TOKEN: ${{ github.token }}
34
+ run: |
35
+ tag="${{ github.event.release.tag_name }}"
36
+ ref=$(gh api "repos/${{ github.repository }}/git/ref/tags/$tag")
37
+ kind=$(echo "$ref" | jq -r .object.type)
38
+ sha=$(echo "$ref" | jq -r .object.sha)
39
+
40
+ if [ "$kind" != "tag" ]; then
41
+ echo "$tag is a lightweight tag; a release must use a signed annotated tag"
42
+ exit 1
43
+ fi
44
+
45
+ object=$(gh api "repos/${{ github.repository }}/git/tags/$sha")
46
+ verified=$(echo "$object" | jq -r .verification.verified)
47
+ reason=$(echo "$object" | jq -r .verification.reason)
48
+
49
+ if [ "$verified" != "true" ]; then
50
+ echo "$tag is not a verified signed tag: $reason"
51
+ exit 1
52
+ fi
53
+
54
+ echo "$tag is signed and verified by GitHub ($reason)"
55
+
56
+ build:
57
+ needs: verify
58
+ runs-on: ubuntu-latest
59
+ steps:
60
+ - uses: actions/checkout@v5
61
+ with:
62
+ ref: ${{ github.event.release.tag_name }}
63
+ - uses: actions/setup-python@v6
64
+ with:
65
+ python-version: "3.13"
66
+ - run: pip install build
67
+ - run: python -m build
68
+ - uses: actions/upload-artifact@v4
69
+ with:
70
+ name: distributions
71
+ path: dist/
72
+
73
+ publish:
74
+ needs: build
75
+ runs-on: ubuntu-latest
76
+ environment: pypi
77
+ permissions:
78
+ contents: read
79
+ id-token: write
80
+ steps:
81
+ - uses: actions/download-artifact@v5
82
+ with:
83
+ name: distributions
84
+ path: dist/
85
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,7 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.egg-info/
4
+ .pytest_cache/
5
+ .mypy_cache/
6
+ dist/
7
+ build/
epostix-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.5
2
+ Name: epostix
3
+ Version: 1.0.0
4
+ Summary: Epostix Developer API client
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: httpx<1,>=0.27
@@ -0,0 +1,131 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import re
5
+ from dataclasses import dataclass, field
6
+ from pathlib import Path
7
+ from typing import Any, Callable, Iterator, Sequence, cast
8
+
9
+ import httpx
10
+ import pytest
11
+
12
+ from epostix import AsyncEpostix, Epostix
13
+ from epostix._codec import Codec
14
+ from epostix._generated import codecs
15
+ from epostix._retry import DISABLED_RETRY_POLICY, RetryPolicy
16
+
17
+ FIXTURES = Path(__file__).parent / "tests" / "fixtures"
18
+
19
+ BASE_URL = "https://api.epostix.test/v1"
20
+ API_KEY = "tix_test_abcdef"
21
+
22
+ def load_fixture(name: str) -> Any:
23
+ return json.loads((FIXTURES / f"{name}.json").read_text())
24
+
25
+
26
+ def screaming(name: str) -> str:
27
+ name = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", name)
28
+ name = re.sub(r"([A-Z]+)([A-Z][a-z])", r"\1_\2", name)
29
+
30
+ return name.upper()
31
+
32
+
33
+ def codec_for(type_name: str) -> Codec:
34
+ codec = getattr(codecs, "CODEC_" + screaming(type_name), None)
35
+
36
+ if codec is None:
37
+ raise AssertionError(f"no codec for fixture type {type_name}")
38
+
39
+ return cast(Codec, codec)
40
+
41
+
42
+ @dataclass
43
+ class Reply:
44
+ status: int = 200
45
+ body: Any = None
46
+ text: str | None = None
47
+ headers: dict[str, str] = field(default_factory=dict)
48
+
49
+
50
+ @dataclass
51
+ class Recorder:
52
+ replies: list[Reply]
53
+ requests: list[httpx.Request] = field(default_factory=list)
54
+
55
+ def __call__(self, request: httpx.Request) -> httpx.Response:
56
+ index = min(len(self.requests), len(self.replies) - 1)
57
+ self.requests.append(request)
58
+ reply = self.replies[index]
59
+
60
+ if reply.text is not None:
61
+ return httpx.Response(reply.status, text=reply.text, headers=reply.headers)
62
+
63
+ return httpx.Response(reply.status, json=reply.body, headers=reply.headers)
64
+
65
+ @property
66
+ def count(self) -> int:
67
+ return len(self.requests)
68
+
69
+ def query_of(self, index: int) -> dict[str, list[str]]:
70
+ params = self.requests[index].url.params
71
+
72
+ return {key: params.get_list(key) for key in params.keys()}
73
+
74
+
75
+ @dataclass
76
+ class Clients:
77
+ _closers: list[Callable[[], None]] = field(default_factory=list)
78
+
79
+ def sync(
80
+ self,
81
+ recorder: Recorder,
82
+ *,
83
+ retry_policy: RetryPolicy = DISABLED_RETRY_POLICY,
84
+ automatic_idempotency_keys: bool = True,
85
+ ) -> Epostix:
86
+ http = httpx.Client(transport=httpx.MockTransport(recorder))
87
+ self._closers.append(http.close)
88
+
89
+ return Epostix(
90
+ API_KEY,
91
+ base_url=BASE_URL,
92
+ http_client=http,
93
+ retry_policy=retry_policy,
94
+ automatic_idempotency_keys=automatic_idempotency_keys,
95
+ )
96
+
97
+ def asynchronous(
98
+ self,
99
+ recorder: Recorder,
100
+ *,
101
+ retry_policy: RetryPolicy = DISABLED_RETRY_POLICY,
102
+ automatic_idempotency_keys: bool = True,
103
+ ) -> AsyncEpostix:
104
+ http = httpx.AsyncClient(transport=httpx.MockTransport(recorder))
105
+
106
+ return AsyncEpostix(
107
+ API_KEY,
108
+ base_url=BASE_URL,
109
+ http_client=http,
110
+ retry_policy=retry_policy,
111
+ automatic_idempotency_keys=automatic_idempotency_keys,
112
+ )
113
+
114
+ def close(self) -> None:
115
+ for closer in self._closers:
116
+ closer()
117
+
118
+
119
+ @pytest.fixture
120
+ def clients() -> Iterator[Clients]:
121
+ built = Clients()
122
+ yield built
123
+ built.close()
124
+
125
+
126
+ def replies(*items: Reply) -> list[Reply]:
127
+ return list(items)
128
+
129
+
130
+ def pages(bodies: Sequence[Any]) -> list[Reply]:
131
+ return [Reply(status=200, body=body) for body in bodies]
@@ -0,0 +1,223 @@
1
+ from __future__ import annotations
2
+
3
+ from . import attachments as attachments
4
+ from . import batch as batch
5
+ from . import models as models
6
+ from . import overrides as overrides
7
+ from . import webhooks as webhooks
8
+ from ._client import (
9
+ DEDUPLICATION_SCOPE as DEDUPLICATION_SCOPE,
10
+ )
11
+ from ._client import (
12
+ PRODUCTION_BASE_URL as PRODUCTION_BASE_URL,
13
+ )
14
+ from ._client import (
15
+ SANDBOX_DOMAIN as SANDBOX_DOMAIN,
16
+ )
17
+ from ._client import (
18
+ STAGING_BASE_URL as STAGING_BASE_URL,
19
+ )
20
+ from ._client import (
21
+ AsyncEpostix as AsyncEpostix,
22
+ )
23
+ from ._client import (
24
+ Epostix as Epostix,
25
+ )
26
+ from ._client import (
27
+ KeyEnvironment as KeyEnvironment,
28
+ )
29
+ from ._client import (
30
+ key_environment_of as key_environment_of,
31
+ )
32
+ from ._codec import (
33
+ EpostixDecodeError as EpostixDecodeError,
34
+ )
35
+ from ._codec import (
36
+ is_known_enum_value as is_known_enum_value,
37
+ )
38
+ from ._errors import (
39
+ EpostixAccountSuspendedError as EpostixAccountSuspendedError,
40
+ )
41
+ from ._errors import (
42
+ EpostixAPIError as EpostixAPIError,
43
+ )
44
+ from ._errors import (
45
+ EpostixAuthenticationError as EpostixAuthenticationError,
46
+ )
47
+ from ._errors import (
48
+ EpostixConfigurationError as EpostixConfigurationError,
49
+ )
50
+ from ._errors import (
51
+ EpostixConflictError as EpostixConflictError,
52
+ )
53
+ from ._errors import (
54
+ EpostixContentError as EpostixContentError,
55
+ )
56
+ from ._errors import (
57
+ EpostixError as EpostixError,
58
+ )
59
+ from ._errors import (
60
+ EpostixErrorType as EpostixErrorType,
61
+ )
62
+ from ._errors import (
63
+ EpostixIdempotencyConflictError as EpostixIdempotencyConflictError,
64
+ )
65
+ from ._errors import (
66
+ EpostixIdempotencyInProgressError as EpostixIdempotencyInProgressError,
67
+ )
68
+ from ._errors import (
69
+ EpostixInvalidRequestError as EpostixInvalidRequestError,
70
+ )
71
+ from ._errors import (
72
+ EpostixNotFoundError as EpostixNotFoundError,
73
+ )
74
+ from ._errors import (
75
+ EpostixOutcomeUnknownError as EpostixOutcomeUnknownError,
76
+ )
77
+ from ._errors import (
78
+ EpostixPaginationError as EpostixPaginationError,
79
+ )
80
+ from ._errors import (
81
+ EpostixPermissionError as EpostixPermissionError,
82
+ )
83
+ from ._errors import (
84
+ EpostixQuotaExceededError as EpostixQuotaExceededError,
85
+ )
86
+ from ._errors import (
87
+ EpostixRateLimitError as EpostixRateLimitError,
88
+ )
89
+ from ._errors import (
90
+ EpostixServerError as EpostixServerError,
91
+ )
92
+ from ._errors import (
93
+ EpostixTimeoutError as EpostixTimeoutError,
94
+ )
95
+ from ._errors import (
96
+ EpostixTransportError as EpostixTransportError,
97
+ )
98
+ from ._errors import (
99
+ EpostixValidationError as EpostixValidationError,
100
+ )
101
+ from ._errors import (
102
+ EpostixWebhookVerificationError as EpostixWebhookVerificationError,
103
+ )
104
+ from ._errors import (
105
+ FieldError as FieldError,
106
+ )
107
+ from ._errors import (
108
+ PaginationFailureReason as PaginationFailureReason,
109
+ )
110
+ from ._errors import (
111
+ QuotaPeriod as QuotaPeriod,
112
+ )
113
+ from ._errors import (
114
+ TimeoutPhase as TimeoutPhase,
115
+ )
116
+ from ._errors import (
117
+ WebhookFailureReason as WebhookFailureReason,
118
+ )
119
+ from ._mailbox import (
120
+ Mailbox as Mailbox,
121
+ )
122
+ from ._mailbox import (
123
+ addr as addr,
124
+ )
125
+ from ._mailbox import (
126
+ named as named,
127
+ )
128
+ from ._model import (
129
+ Model as Model,
130
+ )
131
+ from ._model import (
132
+ response_metadata_of as response_metadata_of,
133
+ )
134
+ from ._model import (
135
+ unknown_fields_of as unknown_fields_of,
136
+ )
137
+ from ._pagination import (
138
+ AsyncPaginator as AsyncPaginator,
139
+ )
140
+ from ._pagination import (
141
+ Collection as Collection,
142
+ )
143
+ from ._pagination import (
144
+ Page as Page,
145
+ )
146
+ from ._pagination import (
147
+ Paginator as Paginator,
148
+ )
149
+ from ._response import (
150
+ AttemptRecord as AttemptRecord,
151
+ )
152
+ from ._response import (
153
+ RateLimitSnapshot as RateLimitSnapshot,
154
+ )
155
+ from ._response import (
156
+ ResponseMetadata as ResponseMetadata,
157
+ )
158
+ from ._response import (
159
+ RetriesExhaustedReason as RetriesExhaustedReason,
160
+ )
161
+ from ._retry import (
162
+ BATCH_RETRY_POLICY as BATCH_RETRY_POLICY,
163
+ )
164
+ from ._retry import (
165
+ DEFAULT_RETRY_POLICY as DEFAULT_RETRY_POLICY,
166
+ )
167
+ from ._retry import (
168
+ DISABLED_RETRY_POLICY as DISABLED_RETRY_POLICY,
169
+ )
170
+ from ._retry import (
171
+ UPLOAD_RETRY_POLICY as UPLOAD_RETRY_POLICY,
172
+ )
173
+ from ._retry import (
174
+ MutationRetryMode as MutationRetryMode,
175
+ )
176
+ from ._retry import (
177
+ RetryClass as RetryClass,
178
+ )
179
+ from ._retry import (
180
+ RetryPolicy as RetryPolicy,
181
+ )
182
+ from ._transport import (
183
+ IDEMPOTENCY_KEY_MAXIMUM_LENGTH as IDEMPOTENCY_KEY_MAXIMUM_LENGTH,
184
+ )
185
+ from ._transport import (
186
+ IDEMPOTENCY_RETENTION_HOURS as IDEMPOTENCY_RETENTION_HOURS,
187
+ )
188
+ from ._transport import (
189
+ OperationSpec as OperationSpec,
190
+ )
191
+ from ._transport import (
192
+ RequestOptions as RequestOptions,
193
+ )
194
+ from .attachments import (
195
+ ATTACHMENT_DECODED_LIMIT_BYTES as ATTACHMENT_DECODED_LIMIT_BYTES,
196
+ )
197
+ from .attachments import (
198
+ REQUEST_BODY_LIMIT_BYTES as REQUEST_BODY_LIMIT_BYTES,
199
+ )
200
+ from .attachments import (
201
+ EpostixAttachmentTooLargeError as EpostixAttachmentTooLargeError,
202
+ )
203
+ from .attachments import (
204
+ EpostixRequestTooLargeError as EpostixRequestTooLargeError,
205
+ )
206
+ from ._types import (
207
+ NOT_GIVEN as NOT_GIVEN,
208
+ )
209
+ from ._types import (
210
+ JsonValue as JsonValue,
211
+ )
212
+ from ._types import (
213
+ NotGiven as NotGiven,
214
+ )
215
+
216
+ from .overrides import (
217
+ AsyncRawContent as AsyncRawContent,
218
+ )
219
+ from .overrides import (
220
+ RawContent as RawContent,
221
+ )
222
+
223
+ __version__ = "1.0.0"