threecommon 0.1.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.
- threecommon-0.1.0/.gitignore +32 -0
- threecommon-0.1.0/CHANGELOG.md +16 -0
- threecommon-0.1.0/LICENSE +21 -0
- threecommon-0.1.0/PKG-INFO +399 -0
- threecommon-0.1.0/README.md +360 -0
- threecommon-0.1.0/pyproject.toml +194 -0
- threecommon-0.1.0/src/threecommon/__init__.py +79 -0
- threecommon-0.1.0/src/threecommon/_core/__init__.py +6 -0
- threecommon-0.1.0/src/threecommon/_core/headers.py +41 -0
- threecommon-0.1.0/src/threecommon/_core/http_client.py +424 -0
- threecommon-0.1.0/src/threecommon/_core/parse.py +77 -0
- threecommon-0.1.0/src/threecommon/_core/retry.py +80 -0
- threecommon-0.1.0/src/threecommon/_core/telemetry.py +77 -0
- threecommon-0.1.0/src/threecommon/_core/url.py +31 -0
- threecommon-0.1.0/src/threecommon/_generated/__init__.py +8 -0
- threecommon-0.1.0/src/threecommon/_generated/models.py +614 -0
- threecommon-0.1.0/src/threecommon/api_version.py +15 -0
- threecommon-0.1.0/src/threecommon/client.py +184 -0
- threecommon-0.1.0/src/threecommon/config.py +140 -0
- threecommon-0.1.0/src/threecommon/errors/__init__.py +35 -0
- threecommon-0.1.0/src/threecommon/errors/base.py +81 -0
- threecommon-0.1.0/src/threecommon/errors/classes.py +75 -0
- threecommon-0.1.0/src/threecommon/events/__init__.py +28 -0
- threecommon-0.1.0/src/threecommon/events/service.py +170 -0
- threecommon-0.1.0/src/threecommon/events/types.py +124 -0
- threecommon-0.1.0/src/threecommon/filters/__init__.py +51 -0
- threecommon-0.1.0/src/threecommon/filters/builder.py +188 -0
- threecommon-0.1.0/src/threecommon/filters/types.py +69 -0
- threecommon-0.1.0/src/threecommon/helpers.py +19 -0
- threecommon-0.1.0/src/threecommon/invoices/__init__.py +40 -0
- threecommon-0.1.0/src/threecommon/invoices/service.py +266 -0
- threecommon-0.1.0/src/threecommon/invoices/types.py +195 -0
- threecommon-0.1.0/src/threecommon/pagination/__init__.py +12 -0
- threecommon-0.1.0/src/threecommon/pagination/auto_paginator.py +98 -0
- threecommon-0.1.0/src/threecommon/py.typed +0 -0
- threecommon-0.1.0/src/threecommon/version.py +10 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Build / dist
|
|
2
|
+
build/
|
|
3
|
+
dist/
|
|
4
|
+
*.egg-info/
|
|
5
|
+
src/threecommon/_version.py
|
|
6
|
+
|
|
7
|
+
# Test / coverage
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.coverage
|
|
10
|
+
.coverage.*
|
|
11
|
+
coverage.xml
|
|
12
|
+
htmlcov/
|
|
13
|
+
|
|
14
|
+
# Type checkers
|
|
15
|
+
.mypy_cache/
|
|
16
|
+
.pyright/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
|
|
19
|
+
# Virtualenvs
|
|
20
|
+
.venv/
|
|
21
|
+
venv/
|
|
22
|
+
env/
|
|
23
|
+
|
|
24
|
+
# Editor / OS
|
|
25
|
+
.vscode/
|
|
26
|
+
.idea/
|
|
27
|
+
*.swp
|
|
28
|
+
.DS_Store
|
|
29
|
+
|
|
30
|
+
# Python bytecode
|
|
31
|
+
__pycache__/
|
|
32
|
+
*.py[cod]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
|
|
4
|
+
versions follow [SemVer](https://semver.org/spec/v2.0.0.html).
|
|
5
|
+
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- Initial scaffolding.
|
|
11
|
+
- `ThreeCommon` (sync) and `AsyncThreeCommon` (async) clients.
|
|
12
|
+
- Events resource: `list`, `retrieve`, `update`, `list_auto_paginate`.
|
|
13
|
+
- Invoices resource: `list`, `retrieve`, `create`, `update`, `finalize`, `void`,
|
|
14
|
+
`record_payment`, `list_auto_paginate`. Both sync and async surfaces.
|
|
15
|
+
- Typed exception tree (`AuthError`, `NotFoundError`, `RateLimitError`, …).
|
|
16
|
+
- Conformance harness running shared YAML scenarios against both clients.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 3Common
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: threecommon
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python client for the 3Common Public API.
|
|
5
|
+
Project-URL: Homepage, https://github.com/3-Common/sdk/tree/main/sdk-python
|
|
6
|
+
Project-URL: Issues, https://github.com/3-Common/sdk/issues
|
|
7
|
+
Project-URL: Repository, https://github.com/3-Common/sdk
|
|
8
|
+
Author-email: 3Common <support@3common.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: 3common,api-client,events,invoices,sdk
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Requires-Dist: httpx<1.0,>=0.27
|
|
26
|
+
Requires-Dist: pydantic<3.0,>=2.7
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: datamodel-code-generator>=0.26; extra == 'dev'
|
|
29
|
+
Requires-Dist: mypy>=1.13; extra == 'dev'
|
|
30
|
+
Requires-Dist: pyright>=1.1.390; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest-cov>=6.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-httpx>=0.34; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest>=8.3; extra == 'dev'
|
|
35
|
+
Requires-Dist: pyyaml>=6.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
37
|
+
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
# `threecommon`
|
|
41
|
+
|
|
42
|
+
[](https://pypi.org/project/threecommon/)
|
|
43
|
+
[](https://pypi.org/project/threecommon/)
|
|
44
|
+
[](https://opensource.org/licenses/MIT)
|
|
45
|
+
|
|
46
|
+
Official Python client for the 3Common Public API. Sync **and** async, fully type-checked, Pydantic v2 models.
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install threecommon
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Requires **Python ≥ 3.10**.
|
|
55
|
+
|
|
56
|
+
## Quick start (sync)
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from threecommon import ThreeCommon
|
|
60
|
+
from threecommon.events import ListParams, UpdateBody
|
|
61
|
+
|
|
62
|
+
with ThreeCommon(api_key="3co_...") as client:
|
|
63
|
+
# List
|
|
64
|
+
result = client.events.list(ListParams(status="open", page_size=50))
|
|
65
|
+
|
|
66
|
+
# Retrieve
|
|
67
|
+
ev = client.events.retrieve("evt_123")
|
|
68
|
+
|
|
69
|
+
# Update
|
|
70
|
+
updated = client.events.update("evt_123", UpdateBody(name="New name"))
|
|
71
|
+
|
|
72
|
+
# Auto-paginate
|
|
73
|
+
for ev in client.events.list_auto_paginate(ListParams(status="open")):
|
|
74
|
+
print(ev.name)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Quick start (async)
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
import asyncio
|
|
81
|
+
from threecommon import AsyncThreeCommon
|
|
82
|
+
from threecommon.events import ListParams
|
|
83
|
+
|
|
84
|
+
async def main() -> None:
|
|
85
|
+
async with AsyncThreeCommon(api_key="3co_...") as client:
|
|
86
|
+
result = await client.events.list(ListParams(status="open"))
|
|
87
|
+
async for ev in client.events.list_auto_paginate(ListParams(status="open")):
|
|
88
|
+
print(ev.name)
|
|
89
|
+
|
|
90
|
+
asyncio.run(main())
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The API key may also be supplied via the `THREECOMMON_API_KEY` environment variable.
|
|
94
|
+
|
|
95
|
+
## Configuration
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from threecommon import ThreeCommon, RetryDelay
|
|
99
|
+
|
|
100
|
+
client = ThreeCommon(
|
|
101
|
+
api_key="3co_...", # required (or via env var)
|
|
102
|
+
base_url="https://api.3common.com", # default
|
|
103
|
+
api_version="2026-04-29", # pinned API version
|
|
104
|
+
timeout_seconds=30.0, # per-request deadline
|
|
105
|
+
max_retries=3, # automatic retries on 408/425/429/5xx
|
|
106
|
+
retry_delay=RetryDelay(
|
|
107
|
+
initial_seconds=0.5,
|
|
108
|
+
max_seconds=8.0,
|
|
109
|
+
jitter=True,
|
|
110
|
+
),
|
|
111
|
+
telemetry=True, # opt-out of anonymous telemetry
|
|
112
|
+
)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Error handling
|
|
116
|
+
|
|
117
|
+
Every error raised by the SDK inherits from `threecommon.APIError`. Catch the typed subclass you care about:
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from threecommon import (
|
|
121
|
+
NotFoundError,
|
|
122
|
+
AuthError,
|
|
123
|
+
RateLimitError,
|
|
124
|
+
ConnectionError,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
client.events.retrieve("evt_missing")
|
|
129
|
+
except NotFoundError as e:
|
|
130
|
+
# 404 — e.request_id, e.code, e.details
|
|
131
|
+
...
|
|
132
|
+
except AuthError as e:
|
|
133
|
+
# 401 — bad or expired API key
|
|
134
|
+
...
|
|
135
|
+
except RateLimitError as e:
|
|
136
|
+
# 429 — e.retry_after_seconds tells you when to retry
|
|
137
|
+
...
|
|
138
|
+
except ConnectionError as e:
|
|
139
|
+
# network error; original cause via e.__cause__
|
|
140
|
+
...
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Every error carries `code`, `message`, `http_status`, `request_id`, `details`, and `raw_response`. The default `str(e)` format includes the request ID for log correlation:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
[not_found] Event evt_missing not found (request_id=req-dfx-abc)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Pagination
|
|
150
|
+
|
|
151
|
+
Two flavors:
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
# One page at a time
|
|
155
|
+
result = client.events.list(ListParams(page_size=50))
|
|
156
|
+
|
|
157
|
+
# All pages, lazy
|
|
158
|
+
for ev in client.events.list_auto_paginate(ListParams(status="open")):
|
|
159
|
+
print(ev.name)
|
|
160
|
+
|
|
161
|
+
# Async
|
|
162
|
+
async for ev in async_client.events.list_auto_paginate(ListParams(status="open")):
|
|
163
|
+
print(ev.name)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Filters
|
|
167
|
+
|
|
168
|
+
The `filters` subpackage provides a typed builder for the API's `filters` query parameter — never write the JSON by hand:
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from threecommon import filters
|
|
172
|
+
from threecommon.events import ListParams
|
|
173
|
+
|
|
174
|
+
f = filters.and_(
|
|
175
|
+
filters.field("status").is_any_of(["open"]),
|
|
176
|
+
filters.field("ticket_sum").is_greater_than(10),
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
result = client.events.list(ListParams(filters=f.serialize()))
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The full operator set is enumerated in `threecommon.filters.types`.
|
|
183
|
+
|
|
184
|
+
## Retries
|
|
185
|
+
|
|
186
|
+
Idempotent methods (`GET`, `PATCH`, `PUT`) retry automatically on `408`, `425`, `429`, `500`, `502`, `503`, `504` and on network errors. Backoff is exponential with full jitter, capped at `RetryDelay.max_seconds`. The SDK honors a server-provided `Retry-After` header on `429`.
|
|
187
|
+
|
|
188
|
+
`POST` and `DELETE` do not retry by default; pass an `idempotency_key` via per-request options to opt in (forward-compat — no v1 endpoints currently use this).
|
|
189
|
+
|
|
190
|
+
## Telemetry
|
|
191
|
+
|
|
192
|
+
The SDK sends a small, anonymized `Threecommon-Client-Telemetry` header on every request (SDK version, language, last-request latency). This helps debug performance reports from real customers without instrumenting their code. Disable globally:
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
client = ThreeCommon(api_key="...", telemetry=False)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Or at runtime:
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
client.disable_telemetry()
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The header never contains your API key, request bodies, or response bodies.
|
|
205
|
+
|
|
206
|
+
## Repository layout
|
|
207
|
+
|
|
208
|
+
The package layout mirrors the Node and Go SDKs so behavior changes can be paired across languages:
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
sdk-python/
|
|
212
|
+
├── pyproject.toml
|
|
213
|
+
├── src/threecommon/
|
|
214
|
+
│ ├── __init__.py # public surface re-exports
|
|
215
|
+
│ ├── py.typed # PEP 561 marker
|
|
216
|
+
│ ├── client.py # ThreeCommon + AsyncThreeCommon
|
|
217
|
+
│ ├── config.py # ClientConfig, RetryDelay, defaults
|
|
218
|
+
│ ├── api_version.py # pinned API version + path
|
|
219
|
+
│ ├── version.py # SDK package version
|
|
220
|
+
│ ├── helpers.py # small utility helpers
|
|
221
|
+
│ ├── errors/ # exception tree
|
|
222
|
+
│ │ ├── base.py # APIError
|
|
223
|
+
│ │ └── classes.py # AuthError, NotFoundError, RateLimitError, ...
|
|
224
|
+
│ ├── pagination/ # auto-paginating iterators
|
|
225
|
+
│ │ └── auto_paginator.py # Iter[T] + AsyncIter[T]
|
|
226
|
+
│ ├── filters/ # typed filter builder (shared across resources)
|
|
227
|
+
│ ├── events/ # events resource (sync + async + Pydantic types)
|
|
228
|
+
│ ├── invoices/ # invoices resource (sync + async + Pydantic types)
|
|
229
|
+
│ ├── _core/ # private HTTP machinery (decomposed)
|
|
230
|
+
│ └── _generated/ # datamodel-code-generator output (re-run via `make gen`)
|
|
231
|
+
├── examples/
|
|
232
|
+
│ ├── events/
|
|
233
|
+
│ └── invoices/
|
|
234
|
+
└── tests/
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Development
|
|
238
|
+
|
|
239
|
+
The project uses [`uv`](https://github.com/astral-sh/uv) for venv + dependency management, [`ruff`](https://docs.astral.sh/ruff/) for lint and format, [`mypy`](https://mypy-lang.org/) and [`pyright`](https://github.com/microsoft/pyright) for type checking, and [`pytest`](https://docs.pytest.org/) for testing.
|
|
240
|
+
|
|
241
|
+
### Set up the dev environment
|
|
242
|
+
|
|
243
|
+
macOS and Linux:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
# One-time: create a venv, activate, install runtime deps + dev tools
|
|
247
|
+
uv venv --python 3.10 .venv
|
|
248
|
+
source .venv/bin/activate
|
|
249
|
+
uv pip install -e ".[dev]"
|
|
250
|
+
|
|
251
|
+
# Verify:
|
|
252
|
+
uv pip list | grep threecommon # should print: threecommon 0.0.0.dev0 /path/to/sdk-python
|
|
253
|
+
pytest -q # all tests pass
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Windows:
|
|
257
|
+
|
|
258
|
+
```powershell
|
|
259
|
+
# One-time: create a venv, activate, install runtime deps + dev tools
|
|
260
|
+
uv venv --python 3.10 .venv
|
|
261
|
+
.\.venv\Scripts\activate.ps1
|
|
262
|
+
uv pip install -e ".[dev]"
|
|
263
|
+
|
|
264
|
+
# Verify:
|
|
265
|
+
uv pip list | Select-String threecommon # should print: threecommon 0.0.0.dev0 \path\to\sdk-python
|
|
266
|
+
pytest -q # all tests pass
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
If activation fails with an execution-policy error, run `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` once and retry.
|
|
270
|
+
|
|
271
|
+
Note: with the virtual environment active, all further bash snippets should work as-is in PowerShell on Windows, except where a separate PowerShell snippet is provided.
|
|
272
|
+
|
|
273
|
+
### Run tests
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
pytest # all tests
|
|
277
|
+
pytest tests/test_events.py # one file
|
|
278
|
+
pytest tests/test_events.py::test_list_decodes_response # one test
|
|
279
|
+
pytest -k "conformance" # match by name
|
|
280
|
+
pytest -q # quiet output
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
The conformance harness (`tests/test_conformance.py`) parametrizes over the shared YAML scenarios at `../conformance/scenarios/*.yaml` and runs each one against both the sync and async clients.
|
|
284
|
+
|
|
285
|
+
### Coverage
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
pytest --cov=src/threecommon --cov-report=term # term summary
|
|
289
|
+
pytest --cov=src/threecommon --cov-report=html # HTML report at htmlcov/
|
|
290
|
+
pytest --cov=src/threecommon --cov-fail-under=90 # CI gate (≥ 90% line + branch)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Lint and format
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
ruff check . # lint
|
|
297
|
+
ruff check --fix . # auto-fix
|
|
298
|
+
ruff format . # format
|
|
299
|
+
ruff format --check . # CI-style check (no changes)
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Type check
|
|
303
|
+
|
|
304
|
+
Both run in CI; either failing blocks the PR.
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
mypy src/threecommon tests scripts # mypy --strict via pyproject
|
|
308
|
+
pyright src/threecommon scripts # pyright with project config
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Regenerate OpenAPI models
|
|
312
|
+
|
|
313
|
+
`src/threecommon/_generated/models.py` is produced from `../openapi/spec.yaml`. Re-run after every spec update:
|
|
314
|
+
|
|
315
|
+
macOS and Linux:
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
datamodel-codegen \
|
|
319
|
+
--input ../openapi/spec.yaml \
|
|
320
|
+
--input-file-type openapi \
|
|
321
|
+
--output src/threecommon/_generated/models.py \
|
|
322
|
+
--output-model-type pydantic_v2.BaseModel \
|
|
323
|
+
--target-python-version 3.10 \
|
|
324
|
+
--use-standard-collections --use-union-operator --use-double-quotes \
|
|
325
|
+
--field-constraints --use-schema-description --capitalise-enum-members \
|
|
326
|
+
--reuse-model --openapi-scopes paths schemas parameters
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Windows:
|
|
330
|
+
|
|
331
|
+
```powershell
|
|
332
|
+
datamodel-codegen `
|
|
333
|
+
--input ..\openapi\spec.yaml `
|
|
334
|
+
--input-file-type openapi `
|
|
335
|
+
--output .\src\threecommon\_generated\models.py `
|
|
336
|
+
--output-model-type pydantic_v2.BaseModel `
|
|
337
|
+
--target-python-version 3.10 `
|
|
338
|
+
--use-standard-collections --use-union-operator --use-double-quotes `
|
|
339
|
+
--field-constraints --use-schema-description --capitalise-enum-members `
|
|
340
|
+
--reuse-model --openapi-scopes paths schemas parameters
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
The generated package is treated as a contract reference; customer-facing types are hand-curated under `src/threecommon/<resource>/types.py`.
|
|
344
|
+
|
|
345
|
+
### Live smoke (maintainer-only)
|
|
346
|
+
|
|
347
|
+
macOS and Linux:
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
THREECOMMON_API_KEY=3co_real_key \
|
|
351
|
+
SMOKE_EVENT_ID=evt_known \
|
|
352
|
+
python scripts/livesmoke.py
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Windows:
|
|
356
|
+
|
|
357
|
+
```powershell
|
|
358
|
+
$env:THREECOMMON_API_KEY = "3co_real_key"
|
|
359
|
+
$env:SMOKE_EVENT_ID = "evt_known"
|
|
360
|
+
python .\scripts\livesmoke.py
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Runs ≤ 10 real API calls and verifies the happy path + 401/404 error paths. Set `THREECOMMON_BASE_URL` to override the default `https://api.3common.com`.
|
|
364
|
+
|
|
365
|
+
### Build a wheel locally
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
uv build # produces sdist + wheel under dist/
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## Versioning
|
|
372
|
+
|
|
373
|
+
The SDK follows SemVer. The pinned **API version** (sent as `Threecommon-Version`) is independent — the API can evolve without breaking already-deployed SDKs. Bump `api_version` to opt into newer server behavior.
|
|
374
|
+
|
|
375
|
+
PyPI distribution: `threecommon`. Tags use the path-prefixed form `sdk-python/vX.Y.Z` to share the monorepo with the Node and Go SDKs.
|
|
376
|
+
|
|
377
|
+
## Examples
|
|
378
|
+
|
|
379
|
+
End-to-end runnable examples live under [`examples/events/`](./examples/events/):
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
python examples/events/list_sync.py
|
|
383
|
+
python examples/events/list_async.py
|
|
384
|
+
python examples/events/retrieve.py
|
|
385
|
+
python examples/events/update.py
|
|
386
|
+
python examples/events/auto_paginate.py
|
|
387
|
+
python examples/events/error_handling.py
|
|
388
|
+
python examples/events/filters_demo.py
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Replace `3co_your_api_key_here` and `evt_replace_with_real_id` with real values before running.
|
|
392
|
+
|
|
393
|
+
## Contributing
|
|
394
|
+
|
|
395
|
+
See the [repository CONTRIBUTING guide](https://github.com/3-Common/sdk/blob/main/CONTRIBUTING.md). Issues and PRs welcome.
|
|
396
|
+
|
|
397
|
+
## License
|
|
398
|
+
|
|
399
|
+
[MIT](./LICENSE)
|