novaposhta-python-client 0.1.9__tar.gz → 0.1.11__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 (20) hide show
  1. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/PKG-INFO +101 -8
  2. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/README.md +93 -6
  3. novaposhta_python_client-0.1.11/novaposhta/chains.py +104 -0
  4. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/novaposhta/client.py +35 -19
  5. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/novaposhta/models/additional_service.py +1 -2
  6. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/novaposhta/models/address.py +1 -2
  7. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/novaposhta/models/common.py +1 -2
  8. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/novaposhta/models/counterparty.py +1 -2
  9. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/novaposhta/models/internet_document.py +1 -8
  10. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/novaposhta/models/scan_sheet.py +2 -1
  11. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/novaposhta/models/tracking_document.py +2 -2
  12. novaposhta_python_client-0.1.11/novaposhta/types.py +41 -0
  13. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/pyproject.toml +18 -4
  14. novaposhta_python_client-0.1.9/novaposhta/types.py +0 -15
  15. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/LICENSE.md +0 -0
  16. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/novaposhta/__init__.py +0 -0
  17. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/novaposhta/models/__init__.py +0 -0
  18. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/novaposhta/models/base.py +0 -0
  19. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/novaposhta/models/contact_person.py +0 -0
  20. {novaposhta_python_client-0.1.9 → novaposhta_python_client-0.1.11}/novaposhta/mypi.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: novaposhta-python-client
3
- Version: 0.1.9
3
+ Version: 0.1.11
4
4
  Summary: Python client for Nova Poshta API
5
5
  Home-page: https://github.com/semolex/novaposhta-python-client
6
6
  License: MIT
@@ -8,17 +8,23 @@ 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
19
22
  Classifier: Programming Language :: Python :: 3 :: Only
23
+ Classifier: Programming Language :: Python :: Implementation :: CPython
20
24
  Classifier: Topic :: Software Development :: Build Tools
21
25
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Classifier: Typing :: Typed
27
+ Requires-Dist: h11 (>=0.16.0,<0.17.0)
22
28
  Requires-Dist: httpx (>=0.24.0)
23
29
  Project-URL: Repository, https://github.com/semolex/novaposhta-python-client
24
30
  Description-Content-Type: text/markdown
@@ -28,8 +34,14 @@ Description-Content-Type: text/markdown
28
34
  A Python client for interfacing with the Nova Poshta API. Designed to provide easy access to all API functionalities
29
35
  with emphasis on consistency and usability.
30
36
 
31
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
32
-
37
+ [![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)
38
+ [![License](https://img.shields.io/github/license/semolex/novaposhta-python-client)](https://github.com/semolex/novaposhta-python-client/blob/master/LICENSE.md)
39
+ [![PyPI](https://img.shields.io/pypi/v/novaposhta-python-client)](https://pypi.org/project/novaposhta-python-client/)
40
+ [![Downloads](https://pepy.tech/badge/novaposhta-python-client)](https://pepy.tech/project/novaposhta-python-client)
41
+ [![Downloads](https://pepy.tech/badge/novaposhta-python-client/month)](https://pepy.tech/project/novaposhta-python-client)
42
+ [![Python Versions](https://img.shields.io/pypi/pyversions/novaposhta-python-client.svg)](https://pypi.org/project/novaposhta-python-client/)
43
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
44
+ [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1)](https://pycqa.github.io/isort/)
33
45
 
34
46
  ## Description
35
47
 
@@ -161,17 +173,98 @@ To get your custom model instance, use the get method:
161
173
  my_custom_model = client.get(MyCustomModel.name)
162
174
  ```
163
175
 
164
- ## Testing and linting
176
+ ## Experimental: Chain Operations
177
+
178
+ 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.
179
+ Each result of `prepare_next` is passed to the next operation as updated `kwargs`.
180
+ > ⚠️ **Note**: This feature is experimental and currently optimized for async usage.
181
+
182
+ ### Basic Usage
183
+
184
+ ```python
185
+ from novaposhta.client import NovaPoshtaApi
186
+ from novaposhta.chains import Chain
187
+
188
+ # Initialize client in async mode
189
+ client = NovaPoshtaApi("API_KEY", async_mode=True)
190
+
191
+ # Create a chain of operations
192
+ chain = (
193
+ Chain(
194
+ client.address.get_areas,
195
+ prepare_next=lambda x: {'ref': x['data'][0]['AreasCenter']}
196
+ ) |
197
+ Chain(
198
+ client.address.get_cities,
199
+ prepare_next=lambda x: {'city_ref': x['data'][0]['Ref']}
200
+ ) |
201
+ Chain(
202
+ client.address.get_street,
203
+ kwargs={'find_by_string': 'Street Name'}
204
+ )
205
+ )
206
+
207
+ # Execute chain
208
+ results = await chain.execute_async()
209
+ ```
210
+
211
+ ### Features
212
+
213
+ - Chain multiple API operations using the `|` operator
214
+ - Transform operation results for next operation using `prepare_next`
215
+ - Automatic error handling and chain interruption on failure
216
+ - Preserve both original API responses and transformed data
217
+ - Initial parameters via `kwargs`
218
+
219
+ ### Common Patterns
165
220
 
221
+ ```python
222
+ # Address search chain
223
+ from novaposhta.client import NovaPoshtaApi
224
+
225
+ client = NovaPoshtaApi("API_KEY", async_mode=True)
226
+ from novaposhta.chains import Chain
227
+ address = client.address
228
+ chain = (
229
+ Chain(
230
+ address.search_settlements,
231
+ kwargs={'city_name': 'Київ'},
232
+ prepare_next=lambda x: {'settlement_ref': x['data'][0]['Ref']}
233
+ ) |
234
+ Chain(
235
+ address.search_settlement_streets,
236
+ kwargs={'street_name': 'Main'}
237
+ )
238
+ )
239
+
240
+ # Execute and process results
241
+ results = await chain.execute_async()
242
+ for result in results:
243
+ print(f"Success: {result.success}")
244
+ print(f"Data: {result.data}")
245
+ print(f"Next kwargs: {result.next_kwargs}")
246
+ ```
247
+
248
+ ### Limitations
249
+
250
+ - Currently optimized for async usage
251
+ - Experimental API that may change
252
+ - Sequential execution only (no parallel operations)
253
+
254
+
255
+
256
+ ## Testing and linting
257
+ Note: install dev dependencies first
166
258
  ```bash
167
- poetry run black novaposhta
259
+ poetry run black novaposhta/
260
+ poetry run isort novaposhta/
168
261
  poetry run mypy novaposhta/
169
- poetry run pytest tests/
262
+ poetry run pytest --cov=novaposhta tests/
170
263
  ```
171
264
 
172
265
  ## Contributing
173
266
 
174
267
  We welcome contributions that can help in enhancing the functionality and improving the consistency of the client. For
175
268
  bugs or feature requests, please open an issue on the GitHub repository.
176
- Please, use `black` and `mypy` as your instrument for code formatting and type checking.
269
+ Please, use `black`, `isort` and `mypy` as your instrument for code formatting and type checking.
177
270
 
@@ -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,16 +142,97 @@ 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
- poetry run black novaposhta
228
+ poetry run black novaposhta/
229
+ poetry run isort novaposhta/
143
230
  poetry run mypy novaposhta/
144
- poetry run pytest tests/
231
+ poetry run pytest --cov=novaposhta tests/
145
232
  ```
146
233
 
147
234
  ## Contributing
148
235
 
149
236
  We welcome contributions that can help in enhancing the functionality and improving the consistency of the client. For
150
237
  bugs or feature requests, please open an issue on the GitHub repository.
151
- Please, use `black` and `mypy` as your instrument for code formatting and type checking.
238
+ Please, use `black`, `isort` and `mypy` as your instrument for code formatting and type checking.
@@ -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 Type, TypeVar, Optional, Callable
3
+ from typing import Final, Optional, Type, TypeVar
4
4
 
5
5
  import httpx
6
6
 
@@ -13,9 +13,11 @@ from .models.counterparty import Counterparty
13
13
  from .models.internet_document import InternetDocument
14
14
  from .models.scan_sheet import ScanSheet
15
15
  from .models.tracking_document import TrackingDocument
16
- from .types import DictStrAny, MaybeAsync
16
+ from .types import DictStrAny, HttpRequest, MaybeAsync, RequestData, RequestSender
17
17
 
18
- HEADERS = {"Content-Type": "application/json"}
18
+ HEADERS: Final[dict[str, str]] = {"Content-Type": "application/json"}
19
+ API_DEFAULT_ENDPOINT: Final[str] = "https://api.novaposhta.ua/v2.0/json/"
20
+ DEFAULT_TIMEOUT: Final[int] = 10
19
21
 
20
22
  BaseModelType = TypeVar("BaseModelType", bound=BaseModel)
21
23
 
@@ -35,7 +37,7 @@ class NovaPoshtaApi:
35
37
  def __init__(
36
38
  self,
37
39
  api_key: str,
38
- api_endpoint: str = "https://api.novaposhta.ua/v2.0/json/",
40
+ api_endpoint: str = API_DEFAULT_ENDPOINT,
39
41
  http_client=httpx,
40
42
  timeout: int = 10,
41
43
  raise_for_errors: bool = False,
@@ -51,10 +53,17 @@ class NovaPoshtaApi:
51
53
  :param raise_for_errors: Whether to check and raise errors as exceptions.
52
54
  :param async_mode: Whether to use async mode.
53
55
  """
56
+ if not api_key:
57
+ raise ValueError("API key is required")
58
+ if timeout <= 0:
59
+ raise ValueError("Timeout must be positive")
60
+ if not api_endpoint or not api_endpoint.startswith(("http://", "https://")):
61
+ raise ValueError("Invalid API endpoint URL")
62
+
54
63
  self.api_key = api_key
55
64
  self.api_endpoint = api_endpoint
56
65
  self.timeout = timeout
57
- self._send: Callable[[DictStrAny], MaybeAsync]
66
+ self._send: RequestSender
58
67
  if async_mode:
59
68
  self.async_http_client: Optional[httpx.AsyncClient] = (
60
69
  http_client.AsyncClient(timeout=timeout)
@@ -65,11 +74,12 @@ class NovaPoshtaApi:
65
74
  timeout=timeout
66
75
  )
67
76
  self._send = self._send_sync
77
+ self._send = self._send_sync
68
78
  self.raise_for_errors = raise_for_errors
69
79
  self.async_mode = async_mode
70
80
  self._models_pool: DictStrAny = {}
71
81
 
72
- def _send_sync(self, request: DictStrAny) -> DictStrAny:
82
+ def _send_sync(self, request: HttpRequest) -> DictStrAny:
73
83
  """
74
84
  Sends sync request to the API.
75
85
 
@@ -81,7 +91,7 @@ class NovaPoshtaApi:
81
91
  response = self.sync_http_client.post(**request)
82
92
  return self._maybe_check_errors(response.json())
83
93
 
84
- async def _send_async(self, request: DictStrAny) -> DictStrAny:
94
+ async def _send_async(self, request: HttpRequest) -> DictStrAny:
85
95
  """
86
96
  Sends async request to the API.
87
97
 
@@ -104,13 +114,13 @@ class NovaPoshtaApi:
104
114
  :param method_props: properties to pass to the method.
105
115
  :return: response dict.
106
116
  """
107
- data = {
117
+ data: RequestData = {
108
118
  "apiKey": self.api_key,
109
119
  "modelName": model_name,
110
120
  "calledMethod": api_method,
111
121
  "methodProperties": method_props,
112
122
  }
113
- request = {
123
+ request: HttpRequest = {
114
124
  "url": self.api_endpoint,
115
125
  "headers": HEADERS,
116
126
  "json": data,
@@ -147,23 +157,29 @@ class NovaPoshtaApi:
147
157
 
148
158
  :param response: response dict.
149
159
  :return: response dict.
160
+ :raises InvalidAPIKeyError: if API key is invalid
161
+ :raises APIRequestError: if any other API error occurs
150
162
  """
151
163
  if not self.raise_for_errors:
152
164
  return response
153
165
 
154
166
  if response["success"]:
155
167
  return response
168
+
156
169
  errors = response["errors"]
157
- error = ""
158
- if isinstance(errors, list):
159
- error = ", ".join(errors)
160
- elif isinstance(errors, dict):
161
- error = ", ".join([f"{k}: {v}" for k, v in errors.items()])
162
-
163
- if "API key" in error:
164
- raise InvalidAPIKeyError(error)
165
- else:
166
- raise APIRequestError(error)
170
+ error_msg = (
171
+ ", ".join(errors)
172
+ if isinstance(errors, list)
173
+ else (
174
+ ", ".join(f"{k}: {v}" for k, v in errors.items())
175
+ if isinstance(errors, dict)
176
+ else str(errors)
177
+ )
178
+ )
179
+
180
+ if "API key" in error_msg:
181
+ raise InvalidAPIKeyError(error_msg)
182
+ raise APIRequestError(error_msg)
167
183
 
168
184
  def close_sync(self):
169
185
  """
@@ -1,8 +1,7 @@
1
1
  """AdditionalService model module."""
2
2
 
3
- from .base import BaseModel, api_method
4
-
5
3
  from ..types import OptStr, StrOrNum
4
+ from .base import BaseModel, api_method
6
5
 
7
6
 
8
7
  class AdditionalService(BaseModel):
@@ -1,9 +1,8 @@
1
1
  """Address model module."""
2
2
 
3
+ from ..types import OptBool, OptStr
3
4
  from .base import BaseModel, api_method
4
5
 
5
- from ..types import OptStr, OptBool
6
-
7
6
 
8
7
  class Address(BaseModel):
9
8
  """
@@ -1,9 +1,8 @@
1
1
  """Common model module."""
2
2
 
3
+ from ..types import OptInt, OptStr
3
4
  from .base import BaseModel, api_method
4
5
 
5
- from ..types import OptStr, OptInt
6
-
7
6
 
8
7
  class Common(BaseModel):
9
8
  """
@@ -1,8 +1,7 @@
1
1
  """Counterparty model module."""
2
2
 
3
- from .base import BaseModel, api_method
4
-
5
3
  from ..types import OptStr
4
+ from .base import BaseModel, api_method
6
5
 
7
6
 
8
7
  class Counterparty(BaseModel):
@@ -2,15 +2,8 @@
2
2
 
3
3
  from typing import List
4
4
 
5
+ from ..types import OptDict, OptInt, OptListOfDicts, OptStr, OptStrOrNum, StrOrNum
5
6
  from .base import BaseModel, api_method
6
- from ..types import (
7
- OptStr,
8
- StrOrNum,
9
- OptListOfDicts,
10
- OptDict,
11
- OptInt,
12
- OptStrOrNum,
13
- )
14
7
 
15
8
 
16
9
  class InternetDocument(BaseModel):
@@ -1,8 +1,9 @@
1
1
  """ScanSheet model module."""
2
2
 
3
- from .base import BaseModel, api_method
4
3
  from typing import List
5
4
 
5
+ from .base import BaseModel, api_method
6
+
6
7
 
7
8
  class ScanSheet(BaseModel):
8
9
  """
@@ -1,8 +1,8 @@
1
1
  """TrackingDocument model module."""
2
2
 
3
- from .base import BaseModel, api_method
3
+ from typing import Dict, List
4
4
 
5
- from typing import List, Dict
5
+ from .base import BaseModel, api_method
6
6
 
7
7
 
8
8
  class TrackingDocument(BaseModel):
@@ -0,0 +1,41 @@
1
+ """Type aliases for novaposhta package."""
2
+
3
+ from typing import Any, Callable, Coroutine, Dict, List, Optional, TypedDict, Union
4
+
5
+
6
+ class RequestData(TypedDict):
7
+ """
8
+ Request data for Nova Poshta API.
9
+ """
10
+
11
+ apiKey: str
12
+ modelName: str
13
+ calledMethod: str
14
+ methodProperties: Dict[str, Any]
15
+
16
+
17
+ class HttpRequest(TypedDict):
18
+ """
19
+ Request data for HTTP client.
20
+ """
21
+
22
+ url: str
23
+ headers: Dict[str, str]
24
+ json: RequestData
25
+ timeout: int
26
+
27
+
28
+ OptStr = Optional[str]
29
+ StrOrNum = Union[str, float, int]
30
+ DictStrAny = Dict[str, Any]
31
+ MaybeAsync = Union[Dict[str, Any], Coroutine[Any, Any, Dict[str, Any]]]
32
+ SyncSender = Callable[[HttpRequest], Dict[str, Any]]
33
+ AsyncSender = Callable[[HttpRequest], Coroutine[Any, Any, Dict[str, Any]]]
34
+ RequestSender = Union[SyncSender, AsyncSender]
35
+ OptStrOrNum = Optional[StrOrNum]
36
+ OptDict = Optional[Dict[str, str]]
37
+ OptListOfDicts = Optional[List[Dict[str, Any]]]
38
+ OptInt = Optional[int]
39
+ OptBool = Optional[
40
+ Union[bool, int]
41
+ ] # assume that support for cases: 0 is False, 1 is True
@@ -3,7 +3,7 @@ name = "novaposhta-python-client"
3
3
  packages = [
4
4
  { include = "novaposhta"}
5
5
  ]
6
- version = "0.1.9"
6
+ version = "0.1.11"
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"
@@ -33,6 +45,8 @@ pytest = "^7.4.2"
33
45
  pytest-httpx = "^0.26.0"
34
46
  coverage = "^7.3.2"
35
47
  pytest-asyncio = "^0.21.1"
48
+ isort = "^5.13.2"
49
+ pytest-cov = "^6.0.0"
36
50
 
37
51
  [build-system]
38
52
  requires = ["poetry-core"]
@@ -1,15 +0,0 @@
1
- """Type aliases for novaposhta package."""
2
-
3
- from typing import List, Optional, Dict, Union, Any, Coroutine
4
-
5
- OptStr = Optional[str]
6
- StrOrNum = Union[str, float, int]
7
- DictStrAny = Dict[str, Any]
8
- MaybeAsync = Union[DictStrAny, Coroutine[Any, Any, Any]]
9
- OptStrOrNum = Optional[StrOrNum]
10
- OptDict = Optional[Dict[str, str]]
11
- OptListOfDicts = Optional[List[Dict[str, Any]]]
12
- OptInt = Optional[int]
13
- OptBool = Optional[
14
- Union[bool, int]
15
- ] # assume that support for cases: 0 is False, 1 is True