python-sendparcel 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. python_sendparcel-0.3.0/CHANGELOG.md +71 -0
  2. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/PKG-INFO +41 -24
  3. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/README.md +24 -12
  4. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/docs/provider-authoring.md +38 -18
  5. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/pyproject.toml +15 -11
  6. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/src/sendparcel/__init__.py +6 -12
  7. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/src/sendparcel/batch.py +77 -75
  8. python_sendparcel-0.3.0/src/sendparcel/concurrent.py +71 -0
  9. python_sendparcel-0.3.0/src/sendparcel/factory.py +33 -0
  10. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/src/sendparcel/flow.py +18 -44
  11. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/src/sendparcel/fsm.py +8 -8
  12. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/src/sendparcel/logging.py +5 -23
  13. python_sendparcel-0.3.0/src/sendparcel/provider.py +242 -0
  14. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/src/sendparcel/providers/dummy.py +7 -20
  15. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/src/sendparcel/registry.py +9 -0
  16. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/src/sendparcel/types.py +31 -4
  17. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/tests/test_batch.py +32 -14
  18. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/tests/test_builtin_dummy_provider.py +32 -14
  19. python_sendparcel-0.3.0/tests/test_concurrent.py +167 -0
  20. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/tests/test_enums.py +6 -8
  21. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/tests/test_flow.py +38 -50
  22. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/tests/test_fsm.py +5 -3
  23. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/tests/test_integration.py +20 -23
  24. python_sendparcel-0.3.0/tests/test_provider_enhancements.py +376 -0
  25. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/tests/test_public_api.py +2 -4
  26. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/tests/test_registry.py +11 -0
  27. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/tests/test_types.py +10 -0
  28. python_sendparcel-0.2.0/CHANGELOG.md +0 -20
  29. python_sendparcel-0.2.0/src/sendparcel/provider.py +0 -92
  30. python_sendparcel-0.2.0/src/sendparcel/validators.py +0 -21
  31. python_sendparcel-0.2.0/tests/test_validators.py +0 -66
  32. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/.github/workflows/ci.yml +0 -0
  33. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/.github/workflows/ecosystem-smoke.yml +0 -0
  34. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/.github/workflows/release.yml +0 -0
  35. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/.gitignore +0 -0
  36. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/.pre-commit-config.yaml +0 -0
  37. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/CONTRIBUTING.md +0 -0
  38. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/LICENSE +0 -0
  39. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/docs/Makefile +0 -0
  40. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/docs/compatibility-matrix.md +0 -0
  41. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/docs/conf.py +0 -0
  42. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/docs/getting-started.md +0 -0
  43. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/docs/index.md +0 -0
  44. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/docs/installation-matrix.md +0 -0
  45. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/docs/plans/2026-02-17-order-optional.md +0 -0
  46. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/docs/release-policy.md +0 -0
  47. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/docs/requirements.txt +0 -0
  48. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/src/sendparcel/enums.py +0 -0
  49. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/src/sendparcel/exceptions.py +0 -0
  50. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/src/sendparcel/protocols.py +0 -0
  51. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/src/sendparcel/providers/__init__.py +0 -0
  52. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/src/sendparcel/py.typed +0 -0
  53. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/tests/conftest.py +0 -0
  54. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/tests/test_exceptions.py +0 -0
  55. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/tests/test_protocols.py +0 -0
  56. {python_sendparcel-0.2.0 → python_sendparcel-0.3.0}/tests/test_provider.py +0 -0
@@ -0,0 +1,71 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/).
7
+
8
+ ## [0.3.0] - 2026-07-04
9
+
10
+ ### Changed (breaking)
11
+
12
+ - Unified the five capability trait ABCs (`LabelProvider`,
13
+ `PushCallbackProvider`, `PullStatusProvider`, `CancellableProvider`)
14
+ into a single `BaseProvider`; unsupported capabilities raise
15
+ `ProviderCapabilityError` by default
16
+ - Removed the validator framework; required config fields declared in
17
+ `config_schema` are now validated automatically at provider
18
+ construction
19
+ - Callbacks are handled through `CallbackContext`
20
+ (`verify_callback(ctx)` / `handle_callback(ctx)`)
21
+ - Providers receive their HTTP transport via `transport_factory`
22
+ injection (`create_provider` wires it)
23
+
24
+ ### Fixed
25
+
26
+ - Missing `Any` import in `sendparcel.types` made
27
+ `CallbackContext` annotations unresolvable at runtime
28
+ (`typing.get_type_hints` raised `NameError`)
29
+ - `ShipmentBatch` created without an explicit registry now uses the
30
+ global registry singleton, consistent with `ShipmentFlow`
31
+ - `ConcurrentExecutor` now uses anyio primitives and works under the
32
+ trio backend (previously hardcoded asyncio)
33
+ - Lint and type-check regressions; `ruff check`, `ruff format --check`,
34
+ `ty check`, and `mypy --strict src` all pass again
35
+ - README quick-start example was missing the `update_fields` repository
36
+ method required by `create_label`
37
+ - Provider-authoring guide rewritten for the unified `BaseProvider`
38
+ API (previous examples raised `ImportError`)
39
+
40
+ ### Added
41
+
42
+ - `PluginRegistry.slugs()` — public, thread-safe accessor for all
43
+ registered provider slugs
44
+
45
+ ### Removed
46
+
47
+ - `fastapi` and `litestar` extras from the README (not published)
48
+ - Dead code: `ShipmentStatusResponse` alias, logging compat aliases
49
+
50
+ ## [0.2.0] - 2025-06-05
51
+
52
+ ### Added
53
+
54
+ - `CallbackContext` for webhook callback handling
55
+ - Transport injection via factory pattern
56
+ - `ConcurrentExecutor` generic concurrency primitive
57
+ - Structured JSON logging helpers
58
+
59
+ ## [0.1.0] - 2025-02-16
60
+
61
+ ### Added
62
+
63
+ - Provider protocol and plugin registry with entry-point discovery
64
+ - Shipment domain types (`AddressInfo`, `ParcelInfo`, `ShipmentCreateResult`, `LabelInfo`)
65
+ - Finite state machine for shipment lifecycle (`ShipmentStatus` enum with 9 states)
66
+ - Framework-agnostic `ShipmentFlow` orchestrator
67
+ - `BaseProvider` abstract class for provider plugins
68
+ - Built-in `DummyProvider` for testing and development
69
+ - Global and per-provider validator support
70
+ - Async-first runtime powered by `anyio`
71
+ - Full test suite (157 tests)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-sendparcel
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Framework-agnostic parcel shipping core for Python.
5
5
  Project-URL: Homepage, https://github.com/python-sendparcel/python-sendparcel
6
6
  Project-URL: Repository, https://github.com/python-sendparcel/python-sendparcel
@@ -23,12 +23,13 @@ Requires-Python: >=3.12
23
23
  Requires-Dist: anyio>=4.0
24
24
  Requires-Dist: httpx>=0.27.0
25
25
  Provides-Extra: all
26
- Requires-Dist: django-sendparcel>=0.1.0; extra == 'all'
27
- Requires-Dist: python-sendparcel-cli>=0.1.0; extra == 'all'
28
- Requires-Dist: python-sendparcel-dpdpl>=0.1.0; extra == 'all'
29
- Requires-Dist: python-sendparcel-inpost>=0.1.0; extra == 'all'
26
+ Requires-Dist: django-sendparcel>=0.3.0; extra == 'all'
27
+ Requires-Dist: python-sendparcel-cli>=0.2.0; extra == 'all'
28
+ Requires-Dist: python-sendparcel-dpdpl>=0.1.1; extra == 'all'
29
+ Requires-Dist: python-sendparcel-inpost>=0.3.0; extra == 'all'
30
+ Requires-Dist: python-sendparcel-orlenpaczka>=0.0.1; extra == 'all'
30
31
  Provides-Extra: cli
31
- Requires-Dist: python-sendparcel-cli>=0.1.0; extra == 'cli'
32
+ Requires-Dist: python-sendparcel-cli>=0.2.0; extra == 'cli'
32
33
  Provides-Extra: dev
33
34
  Requires-Dist: pre-commit-hooks>=6.0.0; extra == 'dev'
34
35
  Requires-Dist: pre-commit>=4.0; extra == 'dev'
@@ -36,26 +37,30 @@ Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
36
37
  Requires-Dist: pytest-cov>=5.0; extra == 'dev'
37
38
  Requires-Dist: pytest>=8.0; extra == 'dev'
38
39
  Requires-Dist: ruff>=0.9.0; extra == 'dev'
40
+ Requires-Dist: trio>=0.27; extra == 'dev'
39
41
  Requires-Dist: ty>=0.0.16; extra == 'dev'
40
42
  Provides-Extra: django
41
- Requires-Dist: django-sendparcel>=0.1.0; extra == 'django'
43
+ Requires-Dist: django-sendparcel>=0.3.0; extra == 'django'
42
44
  Provides-Extra: dpdpl
43
- Requires-Dist: python-sendparcel-dpdpl>=0.1.0; extra == 'dpdpl'
45
+ Requires-Dist: python-sendparcel-dpdpl>=0.1.1; extra == 'dpdpl'
44
46
  Provides-Extra: dummy
45
47
  Provides-Extra: frameworks
46
- Requires-Dist: django-sendparcel>=0.1.0; extra == 'frameworks'
48
+ Requires-Dist: django-sendparcel>=0.3.0; extra == 'frameworks'
47
49
  Provides-Extra: inpost
48
- Requires-Dist: python-sendparcel-inpost>=0.1.0; extra == 'inpost'
50
+ Requires-Dist: python-sendparcel-inpost>=0.3.0; extra == 'inpost'
51
+ Provides-Extra: orlenpaczka
52
+ Requires-Dist: python-sendparcel-orlenpaczka>=0.0.1; extra == 'orlenpaczka'
49
53
  Provides-Extra: providers
50
- Requires-Dist: python-sendparcel-dpdpl>=0.1.0; extra == 'providers'
51
- Requires-Dist: python-sendparcel-inpost>=0.1.0; extra == 'providers'
54
+ Requires-Dist: python-sendparcel-dpdpl>=0.1.1; extra == 'providers'
55
+ Requires-Dist: python-sendparcel-inpost>=0.3.0; extra == 'providers'
56
+ Requires-Dist: python-sendparcel-orlenpaczka>=0.0.1; extra == 'providers'
52
57
  Description-Content-Type: text/markdown
53
58
 
54
59
  # python-sendparcel
55
60
 
56
61
  Framework-agnostic parcel shipping core for Python.
57
62
 
58
- > Alpha notice: `0.1.1` is still unstable. The API can change fast because the
63
+ > Alpha notice: `0.3.0` is still unstable. The API can change fast because the
59
64
  > ecosystem is still being cleaned up.
60
65
 
61
66
  ## What it is
@@ -120,6 +125,12 @@ class InMemoryRepository:
120
125
  self._store[shipment.id] = shipment
121
126
  return shipment
122
127
 
128
+ async def update_fields(self, shipment_id: str, **fields) -> MyShipment:
129
+ shipment = self._store[shipment_id]
130
+ for key, value in fields.items():
131
+ setattr(shipment, key, value)
132
+ return shipment
133
+
123
134
 
124
135
  async def main() -> None:
125
136
  flow = ShipmentFlow(repository=InMemoryRepository())
@@ -156,15 +167,20 @@ anyio.run(main)
156
167
 
157
168
  ## Provider model
158
169
 
159
- - `BaseProvider.create_shipment(...)` returns `ShipmentCreateResult`.
170
+ All providers subclass `BaseProvider`; capability methods raise
171
+ `ProviderCapabilityError` unless overridden:
172
+
173
+ - `BaseProvider.create_shipment(...)` returns `ShipmentCreateResult` (required).
160
174
  - `BaseProvider.confirmation_method` defaults to `ConfirmationMethod.NONE`.
161
- - `LabelProvider.create_label(...)` returns `LabelInfo`.
162
- - `PushCallbackProvider.handle_callback(...)` returns `ShipmentUpdateResult`.
163
- - `PullStatusProvider.fetch_shipment_status(...)` returns `ShipmentUpdateResult`.
164
- - `CancellableProvider.cancel_shipment(...)` returns `bool`.
175
+ - `BaseProvider.create_label(...)` returns `LabelInfo`.
176
+ - `BaseProvider.verify_callback(ctx)` / `handle_callback(ctx)` return
177
+ `None` / `ShipmentUpdateResult`.
178
+ - `BaseProvider.fetch_shipment_status(...)` returns `ShipmentUpdateResult`.
179
+ - `BaseProvider.cancel_shipment(...)` returns `bool`.
165
180
 
166
- Use `ConfirmationMethod.PUSH` only with `PushCallbackProvider` and
167
- `ConfirmationMethod.PULL` only with `PullStatusProvider`.
181
+ Use `ConfirmationMethod.PUSH` only when the callback methods are overridden
182
+ and `ConfirmationMethod.PULL` only when `fetch_shipment_status` is. See
183
+ `docs/provider-authoring.md` for the full guide.
168
184
 
169
185
  The core owns shipment state transitions. Providers translate carrier responses
170
186
  into normalized results.
@@ -184,10 +200,9 @@ uv add python-sendparcel
184
200
  ## Extras
185
201
 
186
202
  - `django`
187
- - `fastapi`
188
- - `litestar`
189
203
  - `inpost`
190
204
  - `dpdpl`
205
+ - `orlenpaczka`
191
206
  - `cli`
192
207
  - `frameworks`
193
208
  - `providers`
@@ -198,6 +213,8 @@ uv add python-sendparcel
198
213
  ```bash
199
214
  uv sync --extra dev
200
215
  uv run pytest
201
- uv run ruff check src tests
202
- uv run mypy src tests
216
+ uv run ruff check .
217
+ uv run ruff format --check .
218
+ uv run ty check
219
+ uv run mypy src
203
220
  ```
@@ -2,7 +2,7 @@
2
2
 
3
3
  Framework-agnostic parcel shipping core for Python.
4
4
 
5
- > Alpha notice: `0.1.1` is still unstable. The API can change fast because the
5
+ > Alpha notice: `0.3.0` is still unstable. The API can change fast because the
6
6
  > ecosystem is still being cleaned up.
7
7
 
8
8
  ## What it is
@@ -67,6 +67,12 @@ class InMemoryRepository:
67
67
  self._store[shipment.id] = shipment
68
68
  return shipment
69
69
 
70
+ async def update_fields(self, shipment_id: str, **fields) -> MyShipment:
71
+ shipment = self._store[shipment_id]
72
+ for key, value in fields.items():
73
+ setattr(shipment, key, value)
74
+ return shipment
75
+
70
76
 
71
77
  async def main() -> None:
72
78
  flow = ShipmentFlow(repository=InMemoryRepository())
@@ -103,15 +109,20 @@ anyio.run(main)
103
109
 
104
110
  ## Provider model
105
111
 
106
- - `BaseProvider.create_shipment(...)` returns `ShipmentCreateResult`.
112
+ All providers subclass `BaseProvider`; capability methods raise
113
+ `ProviderCapabilityError` unless overridden:
114
+
115
+ - `BaseProvider.create_shipment(...)` returns `ShipmentCreateResult` (required).
107
116
  - `BaseProvider.confirmation_method` defaults to `ConfirmationMethod.NONE`.
108
- - `LabelProvider.create_label(...)` returns `LabelInfo`.
109
- - `PushCallbackProvider.handle_callback(...)` returns `ShipmentUpdateResult`.
110
- - `PullStatusProvider.fetch_shipment_status(...)` returns `ShipmentUpdateResult`.
111
- - `CancellableProvider.cancel_shipment(...)` returns `bool`.
117
+ - `BaseProvider.create_label(...)` returns `LabelInfo`.
118
+ - `BaseProvider.verify_callback(ctx)` / `handle_callback(ctx)` return
119
+ `None` / `ShipmentUpdateResult`.
120
+ - `BaseProvider.fetch_shipment_status(...)` returns `ShipmentUpdateResult`.
121
+ - `BaseProvider.cancel_shipment(...)` returns `bool`.
112
122
 
113
- Use `ConfirmationMethod.PUSH` only with `PushCallbackProvider` and
114
- `ConfirmationMethod.PULL` only with `PullStatusProvider`.
123
+ Use `ConfirmationMethod.PUSH` only when the callback methods are overridden
124
+ and `ConfirmationMethod.PULL` only when `fetch_shipment_status` is. See
125
+ `docs/provider-authoring.md` for the full guide.
115
126
 
116
127
  The core owns shipment state transitions. Providers translate carrier responses
117
128
  into normalized results.
@@ -131,10 +142,9 @@ uv add python-sendparcel
131
142
  ## Extras
132
143
 
133
144
  - `django`
134
- - `fastapi`
135
- - `litestar`
136
145
  - `inpost`
137
146
  - `dpdpl`
147
+ - `orlenpaczka`
138
148
  - `cli`
139
149
  - `frameworks`
140
150
  - `providers`
@@ -145,6 +155,8 @@ uv add python-sendparcel
145
155
  ```bash
146
156
  uv sync --extra dev
147
157
  uv run pytest
148
- uv run ruff check src tests
149
- uv run mypy src tests
158
+ uv run ruff check .
159
+ uv run ruff format --check .
160
+ uv run ty check
161
+ uv run mypy src
150
162
  ```
@@ -17,19 +17,35 @@ mycarrier = "sendparcel_mycarrier.provider:MyCarrierProvider"
17
17
  ## Provider contract
18
18
 
19
19
  Every provider must subclass `sendparcel.provider.BaseProvider`.
20
+ There are no capability trait classes — `BaseProvider` declares every
21
+ capability method, and the unsupported ones raise
22
+ `ProviderCapabilityError` by default. Override only what the carrier
23
+ actually supports.
20
24
 
21
25
  ### Required
22
26
 
23
27
  - `create_shipment(sender_address, receiver_address, parcels, **kwargs) -> ShipmentCreateResult`
24
28
 
25
- ### Optional traits
29
+ ### Optional capability overrides
26
30
 
27
- | Capability | Trait | Return value |
31
+ | Capability | Method to override | Return value |
28
32
  |---|---|---|
29
- | Labels | `LabelProvider` | `LabelInfo` |
30
- | Webhooks | `PushCallbackProvider` | `ShipmentUpdateResult` |
31
- | Polling | `PullStatusProvider` | `ShipmentUpdateResult` |
32
- | Cancellation | `CancellableProvider` | `bool` |
33
+ | Labels | `create_label(**kwargs)` | `LabelInfo` |
34
+ | Webhooks | `verify_callback(ctx)` + `handle_callback(ctx)` | `None` / `ShipmentUpdateResult` |
35
+ | Polling | `fetch_shipment_status(**kwargs)` | `ShipmentUpdateResult` |
36
+ | Cancellation | `cancel_shipment(**kwargs)` | `bool` |
37
+
38
+ Webhook methods receive a `sendparcel.types.CallbackContext` carrying
39
+ `shipment_id`, `payload`, `headers`, `source_ip`, and `raw_body`.
40
+
41
+ ### Transport
42
+
43
+ Providers that talk HTTP declare a `transport_factory` classvar
44
+ (`transport_factory(**config) -> transport`). The factory is called by
45
+ `sendparcel.factory.create_provider`, and the built transport is
46
+ available inside the provider via `self._get_client()`. Configuration
47
+ fields are declared in `config_schema`; required fields are validated
48
+ automatically at construction time.
33
49
 
34
50
  ## Important rule
35
51
 
@@ -48,18 +64,20 @@ That means callback and polling implementations should translate carrier payload
48
64
  `BaseProvider.confirmation_method` defaults to `ConfirmationMethod.NONE`.
49
65
 
50
66
  - `NONE` - the provider does not expose shipment updates.
51
- - `PUSH` - the provider must implement `PushCallbackProvider`.
52
- - `PULL` - the provider must implement `PullStatusProvider`.
67
+ - `PUSH` - the provider must override `verify_callback` and
68
+ `handle_callback`.
69
+ - `PULL` - the provider must override `fetch_shipment_status`.
53
70
 
54
- Do not declare `PUSH` or `PULL` unless the provider actually implements the
55
- matching capability trait.
71
+ Do not declare `PUSH` or `PULL` unless the provider actually overrides the
72
+ matching capability methods.
56
73
 
57
74
  ## Minimal example
58
75
 
59
76
  ```python
60
77
  from typing import Any, ClassVar
61
78
 
62
- from sendparcel.provider import BaseProvider, LabelProvider
79
+ from sendparcel.enums import LabelFormat
80
+ from sendparcel.provider import BaseProvider
63
81
  from sendparcel.types import (
64
82
  AddressInfo,
65
83
  LabelInfo,
@@ -68,7 +86,7 @@ from sendparcel.types import (
68
86
  )
69
87
 
70
88
 
71
- class MyCarrierProvider(BaseProvider, LabelProvider):
89
+ class MyCarrierProvider(BaseProvider):
72
90
  slug: ClassVar[str] = "mycarrier"
73
91
  display_name: ClassVar[str] = "My Carrier"
74
92
 
@@ -87,7 +105,7 @@ class MyCarrierProvider(BaseProvider, LabelProvider):
87
105
 
88
106
  async def create_label(self, **kwargs: Any) -> LabelInfo:
89
107
  return LabelInfo(
90
- format="PDF",
108
+ format=LabelFormat.PDF,
91
109
  url="https://carrier.example/labels/TRACK-123.pdf",
92
110
  )
93
111
  ```
@@ -95,16 +113,18 @@ class MyCarrierProvider(BaseProvider, LabelProvider):
95
113
  ## Callback and polling example
96
114
 
97
115
  ```python
98
- from sendparcel.provider import PullStatusProvider, PushCallbackProvider
99
- from sendparcel.types import ShipmentUpdateResult
116
+ from sendparcel.enums import ConfirmationMethod
117
+ from sendparcel.types import CallbackContext, ShipmentUpdateResult
118
+
100
119
 
120
+ class StatusProvider(MyCarrierProvider):
121
+ confirmation_method = ConfirmationMethod.PUSH
101
122
 
102
- class StatusProvider(BaseProvider, PushCallbackProvider, PullStatusProvider):
103
- async def verify_callback(self, data, headers, **kwargs) -> None:
123
+ async def verify_callback(self, ctx: CallbackContext) -> None:
104
124
  return None
105
125
 
106
126
  async def handle_callback(
107
- self, data, headers, **kwargs
127
+ self, ctx: CallbackContext
108
128
  ) -> ShipmentUpdateResult:
109
129
  return ShipmentUpdateResult(status="in_transit")
110
130
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-sendparcel"
3
- version = "0.2.0"
3
+ version = "0.3.0"
4
4
  description = "Framework-agnostic parcel shipping core for Python."
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -28,28 +28,31 @@ dev = [
28
28
  "pytest-asyncio>=0.24.0",
29
29
  "pytest-cov>=5.0",
30
30
  "ruff>=0.9.0",
31
+ "trio>=0.27",
31
32
  "ty>=0.0.16",
32
33
  ]
33
34
  dummy = []
34
- django = ["django-sendparcel>=0.1.0"]
35
+ django = ["django-sendparcel>=0.3.0"]
35
36
  # fastapi = ["fastapi-sendparcel>=0.1.0"]
36
37
  # litestar = ["litestar-sendparcel>=0.1.0"]
37
- inpost = ["python-sendparcel-inpost>=0.1.0"]
38
- dpdpl = ["python-sendparcel-dpdpl>=0.1.0"]
39
- cli = ["python-sendparcel-cli>=0.1.0"]
40
- providers = ["python-sendparcel-inpost>=0.1.0", "python-sendparcel-dpdpl>=0.1.0"]
38
+ inpost = ["python-sendparcel-inpost>=0.3.0"]
39
+ dpdpl = ["python-sendparcel-dpdpl>=0.1.1"]
40
+ orlenpaczka = ["python-sendparcel-orlenpaczka>=0.0.1"]
41
+ cli = ["python-sendparcel-cli>=0.2.0"]
42
+ providers = ["python-sendparcel-inpost>=0.3.0", "python-sendparcel-dpdpl>=0.1.1", "python-sendparcel-orlenpaczka>=0.0.1"]
41
43
  frameworks = [
42
- "django-sendparcel>=0.1.0",
44
+ "django-sendparcel>=0.3.0",
43
45
  # "fastapi-sendparcel>=0.1.0",
44
46
  # "litestar-sendparcel>=0.1.0",
45
47
  ]
46
48
  all = [
47
- "django-sendparcel>=0.1.0",
49
+ "django-sendparcel>=0.3.0",
48
50
  # "fastapi-sendparcel>=0.1.0",
49
51
  # "litestar-sendparcel>=0.1.0",
50
- "python-sendparcel-inpost>=0.1.0",
51
- "python-sendparcel-dpdpl>=0.1.0",
52
- "python-sendparcel-cli>=0.1.0",
52
+ "python-sendparcel-inpost>=0.3.0",
53
+ "python-sendparcel-dpdpl>=0.1.1",
54
+ "python-sendparcel-orlenpaczka>=0.0.1",
55
+ "python-sendparcel-cli>=0.2.0",
53
56
  ]
54
57
 
55
58
  [project.urls]
@@ -101,6 +104,7 @@ invalid-return-type = "ignore"
101
104
  django-sendparcel = { path = "../django-sendparcel", editable = true }
102
105
  python-sendparcel-inpost = { path = "../python-sendparcel-inpost", editable = true }
103
106
  python-sendparcel-dpdpl = { path = "../python-sendparcel-dpdpl", editable = true }
107
+ python-sendparcel-orlenpaczka = { path = "../python-sendparcel-orlenpaczka", editable = true }
104
108
  python-sendparcel-cli = { path = "../python-sendparcel-cli", editable = true }
105
109
 
106
110
  [tool.coverage.run]
@@ -1,6 +1,6 @@
1
1
  """sendparcel core package."""
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.3.0"
4
4
 
5
5
  from sendparcel.batch import BatchCreateResult, BatchResult, ShipmentBatch
6
6
  from sendparcel.enums import ConfirmationMethod, LabelFormat, ShipmentStatus
@@ -13,18 +13,14 @@ from sendparcel.exceptions import (
13
13
  SendParcelException,
14
14
  ShipmentNotFoundError,
15
15
  )
16
+ from sendparcel.factory import create_provider
16
17
  from sendparcel.flow import ShipmentFlow
17
18
  from sendparcel.logging import configure_logging, get_logger
18
- from sendparcel.provider import (
19
- BaseProvider,
20
- CancellableProvider,
21
- LabelProvider,
22
- PullStatusProvider,
23
- PushCallbackProvider,
24
- )
19
+ from sendparcel.provider import BaseProvider
25
20
  from sendparcel.providers.dummy import DummyProvider
26
21
  from sendparcel.registry import registry
27
22
  from sendparcel.types import (
23
+ CallbackContext,
28
24
  CreateLabelOutcome,
29
25
  CreateShipmentOutcome,
30
26
  ShipmentUpdateOutcome,
@@ -35,7 +31,7 @@ __all__ = [
35
31
  "BaseProvider",
36
32
  "BatchCreateResult",
37
33
  "BatchResult",
38
- "CancellableProvider",
34
+ "CallbackContext",
39
35
  "CommunicationError",
40
36
  "ConfirmationMethod",
41
37
  "CreateLabelOutcome",
@@ -44,11 +40,8 @@ __all__ = [
44
40
  "InvalidCallbackError",
45
41
  "InvalidTransitionError",
46
42
  "LabelFormat",
47
- "LabelProvider",
48
43
  "ProviderCapabilityError",
49
44
  "ProviderNotFoundError",
50
- "PullStatusProvider",
51
- "PushCallbackProvider",
52
45
  "SendParcelException",
53
46
  "ShipmentBatch",
54
47
  "ShipmentFlow",
@@ -58,6 +51,7 @@ __all__ = [
58
51
  "ShipmentUpdateResult",
59
52
  "__version__",
60
53
  "configure_logging",
54
+ "create_provider",
61
55
  "get_logger",
62
56
  "registry",
63
57
  ]