novaposhta-python-client 0.1.10__tar.gz → 0.1.12__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 (19) hide show
  1. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/PKG-INFO +102 -8
  2. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/README.md +90 -4
  3. novaposhta_python_client-0.1.12/novaposhta/chains.py +104 -0
  4. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/novaposhta/client.py +1 -1
  5. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/novaposhta/models/internet_document.py +4 -0
  6. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/novaposhta/types.py +2 -0
  7. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/pyproject.toml +17 -4
  8. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/LICENSE.md +0 -0
  9. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/novaposhta/__init__.py +0 -0
  10. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/novaposhta/models/__init__.py +0 -0
  11. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/novaposhta/models/additional_service.py +0 -0
  12. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/novaposhta/models/address.py +0 -0
  13. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/novaposhta/models/base.py +0 -0
  14. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/novaposhta/models/common.py +0 -0
  15. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/novaposhta/models/contact_person.py +0 -0
  16. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/novaposhta/models/counterparty.py +0 -0
  17. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/novaposhta/models/scan_sheet.py +0 -0
  18. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/novaposhta/models/tracking_document.py +0 -0
  19. {novaposhta_python_client-0.1.10 → novaposhta_python_client-0.1.12}/novaposhta/mypi.ini +0 -0
@@ -1,25 +1,33 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: novaposhta-python-client
3
- Version: 0.1.10
3
+ Version: 0.1.12
4
4
  Summary: Python client for Nova Poshta API
5
- Home-page: https://github.com/semolex/novaposhta-python-client
6
5
  License: MIT
6
+ License-File: LICENSE.md
7
7
  Keywords: api,nova-poshta,novaposhta,nova-poshta-api,novaposhta-api
8
8
  Author: Oleksii
9
9
  Author-email: semolex@live.com
10
10
  Requires-Python: >=3.9,<4.0
11
- Classifier: Development Status :: 4 - Beta
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
12
13
  Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Natural Language :: English
13
15
  Classifier: Operating System :: OS Independent
14
16
  Classifier: Programming Language :: Python :: 3
15
17
  Classifier: Programming Language :: Python :: 3.9
16
18
  Classifier: Programming Language :: Python :: 3.10
17
19
  Classifier: Programming Language :: Python :: 3.11
18
20
  Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
19
23
  Classifier: Programming Language :: Python :: 3 :: Only
24
+ Classifier: Programming Language :: Python :: Implementation :: CPython
20
25
  Classifier: Topic :: Software Development :: Build Tools
21
26
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
+ Classifier: Typing :: Typed
28
+ Requires-Dist: h11 (>=0.16.0,<0.17.0)
22
29
  Requires-Dist: httpx (>=0.24.0)
30
+ Project-URL: Homepage, https://github.com/semolex/novaposhta-python-client
23
31
  Project-URL: Repository, https://github.com/semolex/novaposhta-python-client
24
32
  Description-Content-Type: text/markdown
25
33
 
@@ -28,8 +36,14 @@ Description-Content-Type: text/markdown
28
36
  A Python client for interfacing with the Nova Poshta API. Designed to provide easy access to all API functionalities
29
37
  with emphasis on consistency and usability.
30
38
 
31
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
32
-
39
+ [![Tests](https://github.com/semolex/novaposhta-python-client/actions/workflows/tests.yml/badge.svg)](https://github.com/semolex/novaposhta-python-client/actions/workflows/tests.yml)
40
+ [![License](https://img.shields.io/github/license/semolex/novaposhta-python-client)](https://github.com/semolex/novaposhta-python-client/blob/master/LICENSE.md)
41
+ [![PyPI](https://img.shields.io/pypi/v/novaposhta-python-client)](https://pypi.org/project/novaposhta-python-client/)
42
+ [![Downloads](https://pepy.tech/badge/novaposhta-python-client)](https://pepy.tech/project/novaposhta-python-client)
43
+ [![Downloads](https://pepy.tech/badge/novaposhta-python-client/month)](https://pepy.tech/project/novaposhta-python-client)
44
+ [![Python Versions](https://img.shields.io/pypi/pyversions/novaposhta-python-client.svg)](https://pypi.org/project/novaposhta-python-client/)
45
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
46
+ [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1)](https://pycqa.github.io/isort/)
33
47
 
34
48
  ## Description
35
49
 
@@ -161,13 +175,93 @@ To get your custom model instance, use the get method:
161
175
  my_custom_model = client.get(MyCustomModel.name)
162
176
  ```
163
177
 
164
- ## Testing and linting
178
+ ## Experimental: Chain Operations
179
+
180
+ The chain functionality allows you to sequence multiple API operations, where each operation's output can be transformed and passed to the next operation. This is particularly useful for scenarios that require multiple dependent API calls, like searching for addresses or creating shipments.
181
+ Each result of `prepare_next` is passed to the next operation as updated `kwargs`.
182
+ > ⚠️ **Note**: This feature is experimental and currently optimized for async usage.
183
+
184
+ ### Basic Usage
185
+
186
+ ```python
187
+ from novaposhta.client import NovaPoshtaApi
188
+ from novaposhta.chains import Chain
189
+
190
+ # Initialize client in async mode
191
+ client = NovaPoshtaApi("API_KEY", async_mode=True)
192
+
193
+ # Create a chain of operations
194
+ chain = (
195
+ Chain(
196
+ client.address.get_areas,
197
+ prepare_next=lambda x: {'ref': x['data'][0]['AreasCenter']}
198
+ ) |
199
+ Chain(
200
+ client.address.get_cities,
201
+ prepare_next=lambda x: {'city_ref': x['data'][0]['Ref']}
202
+ ) |
203
+ Chain(
204
+ client.address.get_street,
205
+ kwargs={'find_by_string': 'Street Name'}
206
+ )
207
+ )
208
+
209
+ # Execute chain
210
+ results = await chain.execute_async()
211
+ ```
212
+
213
+ ### Features
214
+
215
+ - Chain multiple API operations using the `|` operator
216
+ - Transform operation results for next operation using `prepare_next`
217
+ - Automatic error handling and chain interruption on failure
218
+ - Preserve both original API responses and transformed data
219
+ - Initial parameters via `kwargs`
220
+
221
+ ### Common Patterns
165
222
 
223
+ ```python
224
+ # Address search chain
225
+ from novaposhta.client import NovaPoshtaApi
226
+
227
+ client = NovaPoshtaApi("API_KEY", async_mode=True)
228
+ from novaposhta.chains import Chain
229
+ address = client.address
230
+ chain = (
231
+ Chain(
232
+ address.search_settlements,
233
+ kwargs={'city_name': 'Київ'},
234
+ prepare_next=lambda x: {'settlement_ref': x['data'][0]['Ref']}
235
+ ) |
236
+ Chain(
237
+ address.search_settlement_streets,
238
+ kwargs={'street_name': 'Main'}
239
+ )
240
+ )
241
+
242
+ # Execute and process results
243
+ results = await chain.execute_async()
244
+ for result in results:
245
+ print(f"Success: {result.success}")
246
+ print(f"Data: {result.data}")
247
+ print(f"Next kwargs: {result.next_kwargs}")
248
+ ```
249
+
250
+ ### Limitations
251
+
252
+ - Currently optimized for async usage
253
+ - Experimental API that may change
254
+ - Sequential execution only (no parallel operations)
255
+
256
+
257
+
258
+ ## Testing and linting
259
+ Note: install dev dependencies first
166
260
  ```bash
167
261
  poetry run black novaposhta/
168
262
  poetry run isort novaposhta/
169
263
  poetry run mypy novaposhta/
170
- poetry run pytest tests/
264
+ poetry run pytest --cov=novaposhta tests/
171
265
  ```
172
266
 
173
267
  ## Contributing
@@ -3,8 +3,14 @@
3
3
  A Python client for interfacing with the Nova Poshta API. Designed to provide easy access to all API functionalities
4
4
  with emphasis on consistency and usability.
5
5
 
6
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
-
6
+ [![Tests](https://github.com/semolex/novaposhta-python-client/actions/workflows/tests.yml/badge.svg)](https://github.com/semolex/novaposhta-python-client/actions/workflows/tests.yml)
7
+ [![License](https://img.shields.io/github/license/semolex/novaposhta-python-client)](https://github.com/semolex/novaposhta-python-client/blob/master/LICENSE.md)
8
+ [![PyPI](https://img.shields.io/pypi/v/novaposhta-python-client)](https://pypi.org/project/novaposhta-python-client/)
9
+ [![Downloads](https://pepy.tech/badge/novaposhta-python-client)](https://pepy.tech/project/novaposhta-python-client)
10
+ [![Downloads](https://pepy.tech/badge/novaposhta-python-client/month)](https://pepy.tech/project/novaposhta-python-client)
11
+ [![Python Versions](https://img.shields.io/pypi/pyversions/novaposhta-python-client.svg)](https://pypi.org/project/novaposhta-python-client/)
12
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
13
+ [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1)](https://pycqa.github.io/isort/)
8
14
 
9
15
  ## Description
10
16
 
@@ -136,13 +142,93 @@ To get your custom model instance, use the get method:
136
142
  my_custom_model = client.get(MyCustomModel.name)
137
143
  ```
138
144
 
139
- ## Testing and linting
145
+ ## Experimental: Chain Operations
146
+
147
+ The chain functionality allows you to sequence multiple API operations, where each operation's output can be transformed and passed to the next operation. This is particularly useful for scenarios that require multiple dependent API calls, like searching for addresses or creating shipments.
148
+ Each result of `prepare_next` is passed to the next operation as updated `kwargs`.
149
+ > ⚠️ **Note**: This feature is experimental and currently optimized for async usage.
150
+
151
+ ### Basic Usage
152
+
153
+ ```python
154
+ from novaposhta.client import NovaPoshtaApi
155
+ from novaposhta.chains import Chain
156
+
157
+ # Initialize client in async mode
158
+ client = NovaPoshtaApi("API_KEY", async_mode=True)
159
+
160
+ # Create a chain of operations
161
+ chain = (
162
+ Chain(
163
+ client.address.get_areas,
164
+ prepare_next=lambda x: {'ref': x['data'][0]['AreasCenter']}
165
+ ) |
166
+ Chain(
167
+ client.address.get_cities,
168
+ prepare_next=lambda x: {'city_ref': x['data'][0]['Ref']}
169
+ ) |
170
+ Chain(
171
+ client.address.get_street,
172
+ kwargs={'find_by_string': 'Street Name'}
173
+ )
174
+ )
175
+
176
+ # Execute chain
177
+ results = await chain.execute_async()
178
+ ```
179
+
180
+ ### Features
181
+
182
+ - Chain multiple API operations using the `|` operator
183
+ - Transform operation results for next operation using `prepare_next`
184
+ - Automatic error handling and chain interruption on failure
185
+ - Preserve both original API responses and transformed data
186
+ - Initial parameters via `kwargs`
187
+
188
+ ### Common Patterns
140
189
 
190
+ ```python
191
+ # Address search chain
192
+ from novaposhta.client import NovaPoshtaApi
193
+
194
+ client = NovaPoshtaApi("API_KEY", async_mode=True)
195
+ from novaposhta.chains import Chain
196
+ address = client.address
197
+ chain = (
198
+ Chain(
199
+ address.search_settlements,
200
+ kwargs={'city_name': 'Київ'},
201
+ prepare_next=lambda x: {'settlement_ref': x['data'][0]['Ref']}
202
+ ) |
203
+ Chain(
204
+ address.search_settlement_streets,
205
+ kwargs={'street_name': 'Main'}
206
+ )
207
+ )
208
+
209
+ # Execute and process results
210
+ results = await chain.execute_async()
211
+ for result in results:
212
+ print(f"Success: {result.success}")
213
+ print(f"Data: {result.data}")
214
+ print(f"Next kwargs: {result.next_kwargs}")
215
+ ```
216
+
217
+ ### Limitations
218
+
219
+ - Currently optimized for async usage
220
+ - Experimental API that may change
221
+ - Sequential execution only (no parallel operations)
222
+
223
+
224
+
225
+ ## Testing and linting
226
+ Note: install dev dependencies first
141
227
  ```bash
142
228
  poetry run black novaposhta/
143
229
  poetry run isort novaposhta/
144
230
  poetry run mypy novaposhta/
145
- poetry run pytest tests/
231
+ poetry run pytest --cov=novaposhta tests/
146
232
  ```
147
233
 
148
234
  ## Contributing
@@ -0,0 +1,104 @@
1
+ """Chain of calls with error handling and data passing between calls. """
2
+
3
+ import asyncio
4
+ from dataclasses import dataclass
5
+ from typing import Any, Callable, Dict, List, Optional, TypeVar, Union
6
+
7
+ T = TypeVar("T")
8
+
9
+
10
+ @dataclass
11
+ class ChainResult:
12
+ """
13
+ Result of a single chain execution.
14
+ """
15
+
16
+ success: bool
17
+ data: Optional[Any]
18
+ error: Optional[str]
19
+ next_kwargs: Optional[Dict[str, Any]] = None
20
+
21
+
22
+ @dataclass
23
+ class Chain:
24
+ """
25
+ Chain object that represents a single call in the chain.
26
+ """
27
+
28
+ method: Callable
29
+ kwargs: Optional[Dict[str, Any]] = None
30
+ prepare_next: Optional[Callable[[Any], Dict[str, Any]]] = None
31
+
32
+ async def execute(self, prev_result: Optional[ChainResult] = None) -> ChainResult:
33
+ """
34
+ Execute the chain.
35
+
36
+ :param prev_result: result of the previous chain.
37
+ :return: result of the current chain.
38
+ """
39
+ try:
40
+ execution_kwargs = {**(self.kwargs or {})}
41
+ if prev_result and prev_result.next_kwargs:
42
+ execution_kwargs.update(prev_result.next_kwargs)
43
+
44
+ result = self.method(**execution_kwargs)
45
+ if asyncio.iscoroutine(result):
46
+ result = await result
47
+
48
+ next_kwargs = self.prepare_next(result) if self.prepare_next else {}
49
+
50
+ return ChainResult(
51
+ success=result.get("success", False),
52
+ data=result.get("data"),
53
+ error=None,
54
+ next_kwargs=next_kwargs,
55
+ )
56
+ except Exception as e:
57
+ return ChainResult(success=False, data=None, error=str(e), next_kwargs=None)
58
+
59
+ def __or__(self, other: "Chain") -> "ChainExecutor":
60
+ """
61
+ Create a chain executor with the current chain and another chain.
62
+ Allows chaining multiple chains together via the `|` operator.
63
+
64
+ :param other: another chain.
65
+ :return ChainExecutor: chain executor with the current chain and another chain.
66
+ """
67
+ return ChainExecutor([self, other])
68
+
69
+
70
+ class ChainExecutor:
71
+ """
72
+ Chain executor that executes multiple chains in a sequence.
73
+ """
74
+
75
+ def __init__(self, chains: Optional[List[Chain]] = None):
76
+ self.chains = chains or []
77
+
78
+ def __or__(self, chain: Chain) -> "ChainExecutor":
79
+ """
80
+ Add a chain to the chain executor.
81
+
82
+ :param chain: chain to add.
83
+ :return ChainExecutor: chain executor with the added chain.
84
+ """
85
+ self.chains.append(chain)
86
+ return self
87
+
88
+ async def execute_async(self) -> List[ChainResult]:
89
+ """
90
+ Execute all chains in the chain executor asynchronously.
91
+
92
+ :return: list of results of each chain execution
93
+ """
94
+ results = []
95
+ prev_result = None
96
+
97
+ for chain in self.chains:
98
+ result = await chain.execute(prev_result)
99
+ results.append(result)
100
+ if not result.success:
101
+ break
102
+ prev_result = result
103
+
104
+ return results
@@ -1,6 +1,6 @@
1
1
  """Client for Nova Poshta API. """
2
2
 
3
- from typing import Callable, Final, Optional, Type, TypeVar
3
+ from typing import Final, Optional, Type, TypeVar
4
4
 
5
5
  import httpx
6
6
 
@@ -133,6 +133,8 @@ class InternetDocument(BaseModel):
133
133
  red_box_barcode: OptStr = None,
134
134
  backward_delivery_data: OptListOfDicts = None,
135
135
  recipient_address_note: OptStr = None,
136
+ additional_information: OptStr = None,
137
+ info_reg_client_barcodes: OptStr = None,
136
138
  ):
137
139
  """
138
140
  Create document (delivery).
@@ -219,6 +221,8 @@ class InternetDocument(BaseModel):
219
221
  RedBoxBarcode=red_box_barcode,
220
222
  BackwardDeliveryData=backward_delivery_data,
221
223
  RecipientAddressNote=recipient_address_note,
224
+ AdditionalInformation=additional_information,
225
+ InfoRegClientBarcodes=info_reg_client_barcodes,
222
226
  )
223
227
 
224
228
  @api_method("update")
@@ -7,6 +7,7 @@ class RequestData(TypedDict):
7
7
  """
8
8
  Request data for Nova Poshta API.
9
9
  """
10
+
10
11
  apiKey: str
11
12
  modelName: str
12
13
  calledMethod: str
@@ -17,6 +18,7 @@ class HttpRequest(TypedDict):
17
18
  """
18
19
  Request data for HTTP client.
19
20
  """
21
+
20
22
  url: str
21
23
  headers: Dict[str, str]
22
24
  json: RequestData
@@ -3,7 +3,7 @@ name = "novaposhta-python-client"
3
3
  packages = [
4
4
  { include = "novaposhta"}
5
5
  ]
6
- version = "0.1.10"
6
+ version = "0.1.12"
7
7
  description = "Python client for Nova Poshta API"
8
8
  authors = ["Oleksii <semolex@live.com>"]
9
9
  license = "MIT"
@@ -12,19 +12,31 @@ homepage = "https://github.com/semolex/novaposhta-python-client"
12
12
  repository = "https://github.com/semolex/novaposhta-python-client"
13
13
  keywords = [ "api", "nova-poshta", "novaposhta", "nova-poshta-api", "novaposhta-api"]
14
14
  classifiers = [
15
- "Development Status :: 4 - Beta",
15
+ "Development Status :: 5 - Production/Stable",
16
+ "Intended Audience :: Developers",
16
17
  "Topic :: Software Development :: Build Tools",
17
18
  "Topic :: Software Development :: Libraries :: Python Modules",
18
19
  "Operating System :: OS Independent",
19
20
  "Programming Language :: Python :: 3 :: Only",
20
21
  "Programming Language :: Python :: 3.9",
21
- "License :: OSI Approved :: MIT License"
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: Implementation :: CPython",
25
+ "License :: OSI Approved :: MIT License",
26
+ "Natural Language :: English",
27
+ "Typing :: Typed"
28
+ ]
29
+
30
+ exclude = [
31
+ "tests/*",
32
+ "tests/**/*",
33
+ "**/tests/*",
22
34
  ]
23
35
 
24
36
  [tool.poetry.dependencies]
25
37
  python = "^3.9"
26
38
  httpx = ">=0.24.0"
27
-
39
+ h11 = "^0.16.0"
28
40
 
29
41
  [tool.poetry.group.dev.dependencies]
30
42
  mypy = "^1.5.1"
@@ -34,6 +46,7 @@ pytest-httpx = "^0.26.0"
34
46
  coverage = "^7.3.2"
35
47
  pytest-asyncio = "^0.21.1"
36
48
  isort = "^5.13.2"
49
+ pytest-cov = "^6.0.0"
37
50
 
38
51
  [build-system]
39
52
  requires = ["poetry-core"]