pytonapi 2.0.0__tar.gz → 2.0.1__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 (83) hide show
  1. {pytonapi-2.0.0/pytonapi.egg-info → pytonapi-2.0.1}/PKG-INFO +20 -24
  2. pytonapi-2.0.1/README.md +64 -0
  3. pytonapi-2.0.1/pyproject.toml +155 -0
  4. pytonapi-2.0.1/pytonapi/__init__.py +1 -0
  5. pytonapi-2.0.0/pytonapi/__init__.py → pytonapi-2.0.1/pytonapi/__meta__.py +3 -8
  6. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/cli.py +1 -2
  7. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/client.py +45 -21
  8. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/exceptions.py +8 -9
  9. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/client.py +10 -10
  10. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/limiter.py +1 -2
  11. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/mixin.py +19 -0
  12. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/__init__.py +7 -16
  13. pytonapi-2.0.1/pytonapi/rest/models/accounts.py +465 -0
  14. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/blockchain.py +114 -114
  15. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/dns.py +12 -12
  16. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/emulation.py +1 -1
  17. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/events.py +5 -5
  18. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/gasless.py +5 -5
  19. pytonapi-2.0.1/pytonapi/rest/models/jettons.py +60 -0
  20. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/multisig.py +9 -9
  21. pytonapi-2.0.1/pytonapi/rest/models/nft.py +76 -0
  22. pytonapi-2.0.1/pytonapi/rest/models/purchases.py +26 -0
  23. pytonapi-2.0.1/pytonapi/rest/models/rates.py +20 -0
  24. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/staking.py +4 -6
  25. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/traces.py +3 -3
  26. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/wallet.py +10 -10
  27. pytonapi-2.0.1/pytonapi/rest/resources/_base.py +72 -0
  28. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/accounts.py +64 -82
  29. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/blockchain.py +30 -56
  30. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/connect.py +7 -7
  31. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/dns.py +7 -11
  32. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/emulation.py +20 -31
  33. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/events.py +8 -14
  34. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/extra_currency.py +3 -2
  35. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/gasless.py +8 -9
  36. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/jettons.py +11 -21
  37. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/lite_server.py +55 -69
  38. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/multisig.py +4 -4
  39. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/nft.py +19 -32
  40. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/purchases.py +4 -5
  41. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/rates.py +16 -18
  42. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/staking.py +17 -19
  43. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/storage.py +5 -4
  44. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/traces.py +6 -6
  45. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/utilities.py +10 -12
  46. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/wallet.py +16 -27
  47. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/streaming/client.py +13 -8
  48. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/streaming/models.py +2 -3
  49. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/streaming/sse.py +23 -23
  50. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/streaming/ws.py +23 -23
  51. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/types.py +8 -5
  52. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/utils.py +2 -3
  53. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/webhook/client.py +15 -12
  54. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/webhook/dispatcher.py +35 -37
  55. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/webhook/models.py +3 -3
  56. {pytonapi-2.0.0 → pytonapi-2.0.1/pytonapi.egg-info}/PKG-INFO +20 -24
  57. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi.egg-info/SOURCES.txt +1 -0
  58. {pytonapi-2.0.0 → pytonapi-2.0.1}/tests/test_utils.py +1 -1
  59. pytonapi-2.0.0/README.md +0 -68
  60. pytonapi-2.0.0/pyproject.toml +0 -69
  61. pytonapi-2.0.0/pytonapi/rest/models/accounts.py +0 -486
  62. pytonapi-2.0.0/pytonapi/rest/models/jettons.py +0 -55
  63. pytonapi-2.0.0/pytonapi/rest/models/nft.py +0 -75
  64. pytonapi-2.0.0/pytonapi/rest/models/purchases.py +0 -43
  65. pytonapi-2.0.0/pytonapi/rest/models/rates.py +0 -22
  66. pytonapi-2.0.0/pytonapi/rest/resources/_base.py +0 -46
  67. {pytonapi-2.0.0 → pytonapi-2.0.1}/LICENSE +0 -0
  68. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/py.typed +0 -0
  69. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/__init__.py +0 -0
  70. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/_enums.py +0 -0
  71. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/connect.py +0 -0
  72. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/extra_currency.py +0 -0
  73. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/lite_server.py +0 -0
  74. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/storage.py +0 -0
  75. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/models/utilities.py +0 -0
  76. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/rest/resources/__init__.py +0 -0
  77. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/streaming/__init__.py +0 -0
  78. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi/webhook/__init__.py +0 -0
  79. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi.egg-info/dependency_links.txt +0 -0
  80. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi.egg-info/entry_points.txt +0 -0
  81. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi.egg-info/requires.txt +0 -0
  82. {pytonapi-2.0.0 → pytonapi-2.0.1}/pytonapi.egg-info/top_level.txt +0 -0
  83. {pytonapi-2.0.0 → pytonapi-2.0.1}/setup.cfg +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytonapi
3
- Version: 2.0.0
3
+ Version: 2.0.1
4
4
  Summary: Python SDK for TONAPI — REST API, streaming, and webhooks for TON blockchain.
5
5
  Author: nessshon
6
6
  Maintainer: nessshon
7
7
  License-Expression: MIT
8
- Project-URL: Homepage, https://github.com/nessshon/pytonapi/
9
- Project-URL: Examples, https://github.com/nessshon/pytonapi/tree/main/examples/
8
+ Project-URL: Homepage, https://github.com/nessshon/tonapi/
9
+ Project-URL: Examples, https://github.com/nessshon/tonapi/tree/main/examples/
10
10
  Keywords: AsyncIO,REST API,SDK,TON,TON blockchain,TONAPI,The Open Network,blockchain,crypto,streaming,webhooks
11
11
  Classifier: Development Status :: 4 - Beta
12
12
  Classifier: Environment :: Console
@@ -32,10 +32,10 @@ Dynamic: license-file
32
32
  [![TON](https://img.shields.io/badge/TON-grey?logo=TON&logoColor=40AEF0)](https://ton.org)
33
33
  ![Python Versions](https://img.shields.io/badge/Python-3.10%20--%203.14-black?color=FFE873&labelColor=3776AB)
34
34
  [![PyPI](https://img.shields.io/pypi/v/pytonapi.svg?color=FFE873&labelColor=3776AB)](https://pypi.python.org/pypi/pytonapi)
35
- [![License](https://img.shields.io/github/license/nessshon/pytonapi)](https://github.com/nessshon/pytonapi/blob/main/LICENSE)
35
+ [![License](https://img.shields.io/github/license/nessshon/tonapi)](https://github.com/nessshon/tonapi/blob/main/LICENSE)
36
36
  [![Donate](https://img.shields.io/badge/Donate-TON-blue)](https://tonviewer.com/UQCZq3_Vd21-4y4m7Wc-ej9NFOhh_qvdfAkAYAOHoQ__Ness)
37
37
 
38
- ![Image](assets/banner.png)
38
+ ![Image](https://raw.githubusercontent.com/nessshon/tonapi/main/assets/banner.png)
39
39
 
40
40
  ![Downloads](https://pepy.tech/badge/pytonapi)
41
41
  ![Downloads](https://pepy.tech/badge/pytonapi/month)
@@ -43,8 +43,8 @@ Dynamic: license-file
43
43
 
44
44
  ### Python SDK for [TONAPI](https://tonapi.io)
45
45
 
46
- Providing access to TON blockchain data via REST API, real-time streaming, and webhooks.
47
- An API key is required and can be obtained at [tonconsole.com](https://tonconsole.com/). Documentation available
46
+ Access TON blockchain data via REST API, real-time streaming, and webhooks.
47
+ API key required obtain at [tonconsole.com](https://tonconsole.com/), docs
48
48
  at [docs.tonconsole.com](https://docs.tonconsole.com/).
49
49
 
50
50
  > For creating wallets, transferring TON, jettons, etc., use [tonutils](https://github.com/nessshon/tonutils).
@@ -55,8 +55,8 @@ at [docs.tonconsole.com](https://docs.tonconsole.com/).
55
55
  - **Streaming** — real-time events via SSE and WebSocket
56
56
  - **Webhooks** — push notifications with event dispatcher
57
57
 
58
- > If this project has been useful to you, consider supporting its development.
59
- > **TON**: `UQCZq3_Vd21-4y4m7Wc-ej9NFOhh_qvdfAkAYAOHoQ__Ness`
58
+ > Support this project TON: `donate.ness.ton`
59
+ > `UQCZq3_Vd21-4y4m7Wc-ej9NFOhh_qvdfAkAYAOHoQ__Ness`
60
60
 
61
61
  ## Installation
62
62
 
@@ -68,30 +68,26 @@ pip install pytonapi
68
68
 
69
69
  **REST API**
70
70
 
71
- - [Get account info](examples/get_account_info.py)
72
- - [Get account transactions](examples/get_account_transactions.py)
73
- - [Get NFTs by owner](examples/get_nft_by_owner.py)
74
- - [Get NFTs by collection](examples/get_nft_by_collection.py)
71
+ - [Get account info](https://github.com/nessshon/tonapi/blob/main/examples/get_account_info.py)
72
+ - [Get account transactions](https://github.com/nessshon/tonapi/blob/main/examples/get_account_transactions.py)
73
+ - [Get NFTs by owner](https://github.com/nessshon/tonapi/blob/main/examples/get_nft_by_owner.py)
74
+ - [Get NFTs by collection](https://github.com/nessshon/tonapi/blob/main/examples/get_nft_by_collection.py)
75
75
 
76
76
  **Streaming** (SSE & WebSocket)
77
77
 
78
- - [SSE subscriptions](examples/streaming_sse.py)
79
- - [WebSocket subscriptions](examples/streaming_websocket.py)
78
+ - [SSE subscriptions](https://github.com/nessshon/tonapi/blob/main/examples/streaming_sse.py)
79
+ - [WebSocket subscriptions](https://github.com/nessshon/tonapi/blob/main/examples/streaming_websocket.py)
80
80
 
81
81
  **Webhooks**
82
82
 
83
- - [FastAPI webhook server](examples/webhook_fastapi.py)
84
- - [aiohttp webhook server](examples/webhook_aiohttp.py)
83
+ - [FastAPI webhook server](https://github.com/nessshon/tonapi/blob/main/examples/webhook_fastapi.py)
84
+ - [aiohttp webhook server](https://github.com/nessshon/tonapi/blob/main/examples/webhook_aiohttp.py)
85
85
 
86
86
  **Transfers** (requires [tonutils](https://github.com/nessshon/tonutils))
87
87
 
88
- - [Transfer TON](examples/transfer_ton.py)
89
- - [Gasless transfer](examples/transfer_gasless.py)
90
-
91
- ## Support
92
-
93
- Supported by [TON Society](https://github.com/ton-society/grants-and-bounties) and [TONAPI](https://tonapi.io).
88
+ - [Transfer TON](https://github.com/nessshon/tonapi/blob/main/examples/transfer_ton.py)
89
+ - [Gasless transfer](https://github.com/nessshon/tonapi/blob/main/examples/transfer_gasless.py)
94
90
 
95
91
  ## License
96
92
 
97
- This repository is distributed under the [MIT License](LICENSE).
93
+ This repository is distributed under the [MIT License](https://github.com/nessshon/tonapi/blob/main/LICENSE).
@@ -0,0 +1,64 @@
1
+ # 📦 PyTONAPI
2
+
3
+ [![TON](https://img.shields.io/badge/TON-grey?logo=TON&logoColor=40AEF0)](https://ton.org)
4
+ ![Python Versions](https://img.shields.io/badge/Python-3.10%20--%203.14-black?color=FFE873&labelColor=3776AB)
5
+ [![PyPI](https://img.shields.io/pypi/v/pytonapi.svg?color=FFE873&labelColor=3776AB)](https://pypi.python.org/pypi/pytonapi)
6
+ [![License](https://img.shields.io/github/license/nessshon/tonapi)](https://github.com/nessshon/tonapi/blob/main/LICENSE)
7
+ [![Donate](https://img.shields.io/badge/Donate-TON-blue)](https://tonviewer.com/UQCZq3_Vd21-4y4m7Wc-ej9NFOhh_qvdfAkAYAOHoQ__Ness)
8
+
9
+ ![Image](https://raw.githubusercontent.com/nessshon/tonapi/main/assets/banner.png)
10
+
11
+ ![Downloads](https://pepy.tech/badge/pytonapi)
12
+ ![Downloads](https://pepy.tech/badge/pytonapi/month)
13
+ ![Downloads](https://pepy.tech/badge/pytonapi/week)
14
+
15
+ ### Python SDK for [TONAPI](https://tonapi.io)
16
+
17
+ Access TON blockchain data via REST API, real-time streaming, and webhooks.
18
+ API key required — obtain at [tonconsole.com](https://tonconsole.com/), docs
19
+ at [docs.tonconsole.com](https://docs.tonconsole.com/).
20
+
21
+ > For creating wallets, transferring TON, jettons, etc., use [tonutils](https://github.com/nessshon/tonutils).
22
+
23
+ **Features**
24
+
25
+ - **REST API** — accounts, NFTs, jettons, DNS, and more
26
+ - **Streaming** — real-time events via SSE and WebSocket
27
+ - **Webhooks** — push notifications with event dispatcher
28
+
29
+ > Support this project — TON: `donate.ness.ton`
30
+ > `UQCZq3_Vd21-4y4m7Wc-ej9NFOhh_qvdfAkAYAOHoQ__Ness`
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install pytonapi
36
+ ```
37
+
38
+ ## Examples
39
+
40
+ **REST API**
41
+
42
+ - [Get account info](https://github.com/nessshon/tonapi/blob/main/examples/get_account_info.py)
43
+ - [Get account transactions](https://github.com/nessshon/tonapi/blob/main/examples/get_account_transactions.py)
44
+ - [Get NFTs by owner](https://github.com/nessshon/tonapi/blob/main/examples/get_nft_by_owner.py)
45
+ - [Get NFTs by collection](https://github.com/nessshon/tonapi/blob/main/examples/get_nft_by_collection.py)
46
+
47
+ **Streaming** (SSE & WebSocket)
48
+
49
+ - [SSE subscriptions](https://github.com/nessshon/tonapi/blob/main/examples/streaming_sse.py)
50
+ - [WebSocket subscriptions](https://github.com/nessshon/tonapi/blob/main/examples/streaming_websocket.py)
51
+
52
+ **Webhooks**
53
+
54
+ - [FastAPI webhook server](https://github.com/nessshon/tonapi/blob/main/examples/webhook_fastapi.py)
55
+ - [aiohttp webhook server](https://github.com/nessshon/tonapi/blob/main/examples/webhook_aiohttp.py)
56
+
57
+ **Transfers** (requires [tonutils](https://github.com/nessshon/tonutils))
58
+
59
+ - [Transfer TON](https://github.com/nessshon/tonapi/blob/main/examples/transfer_ton.py)
60
+ - [Gasless transfer](https://github.com/nessshon/tonapi/blob/main/examples/transfer_gasless.py)
61
+
62
+ ## License
63
+
64
+ This repository is distributed under the [MIT License](https://github.com/nessshon/tonapi/blob/main/LICENSE).
@@ -0,0 +1,155 @@
1
+ [build-system]
2
+ requires = ["setuptools>=80"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pytonapi"
7
+ description = "Python SDK for TONAPI — REST API, streaming, and webhooks for TON blockchain."
8
+ requires-python = ">=3.10,<3.15"
9
+ authors = [
10
+ { name = "nessshon" },
11
+ ]
12
+ maintainers = [
13
+ { name = "nessshon" },
14
+ ]
15
+ dependencies = [
16
+ "aiohttp>=3.9.0",
17
+ "pydantic>=2.4.1,<3.0",
18
+ ]
19
+ keywords = [
20
+ "AsyncIO",
21
+ "REST API",
22
+ "SDK",
23
+ "TON",
24
+ "TON blockchain",
25
+ "TONAPI",
26
+ "The Open Network",
27
+ "blockchain",
28
+ "crypto",
29
+ "streaming",
30
+ "webhooks",
31
+ ]
32
+ classifiers = [
33
+ "Development Status :: 4 - Beta",
34
+ "Environment :: Console",
35
+ "Framework :: AsyncIO",
36
+ "Intended Audience :: Developers",
37
+ "Intended Audience :: Financial and Insurance Industry",
38
+ "Operating System :: OS Independent",
39
+ "Programming Language :: Python :: 3.10",
40
+ "Programming Language :: Python :: 3.11",
41
+ "Programming Language :: Python :: 3.12",
42
+ "Programming Language :: Python :: 3.13",
43
+ "Programming Language :: Python :: 3.14",
44
+ "Topic :: Software Development :: Libraries :: Python Modules",
45
+ ]
46
+ dynamic = ["version"]
47
+ readme = "README.md"
48
+ license = "MIT"
49
+
50
+ [project.scripts]
51
+ pytonapi = "pytonapi.cli:main"
52
+
53
+ [project.urls]
54
+ Homepage = "https://github.com/nessshon/tonapi/"
55
+ Examples = "https://github.com/nessshon/tonapi/tree/main/examples/"
56
+
57
+ [tool.setuptools.packages.find]
58
+ include = ["pytonapi", "pytonapi.*"]
59
+
60
+ [tool.setuptools.package-data]
61
+ pytonapi = ["py.typed"]
62
+
63
+ [tool.setuptools.dynamic]
64
+ version = { attr = "pytonapi.__meta__.__version__" }
65
+
66
+ [tool.ruff]
67
+ target-version = "py310"
68
+ line-length = 120
69
+
70
+ [tool.ruff.lint]
71
+ select = [
72
+ # pydocstyle
73
+ "D",
74
+ # pycodestyle
75
+ "E",
76
+ "W",
77
+ # pyflakes
78
+ "F",
79
+ # isort
80
+ "I",
81
+ # flake8-bugbear
82
+ "B",
83
+ # flake8-comprehensions
84
+ "C4",
85
+ # pyupgrade
86
+ "UP",
87
+ # flake8-simplify
88
+ "SIM",
89
+ # type-checking imports
90
+ "TCH",
91
+ # perflint
92
+ "PERF",
93
+ # flake8-debugger
94
+ "T10",
95
+ # flake8-print
96
+ "T20",
97
+ # flake8-pie
98
+ "PIE",
99
+ # pylint errors
100
+ "PLE",
101
+ # flake8-return
102
+ "RET",
103
+ # ruff-specific
104
+ "RUF",
105
+ ]
106
+ ignore = [
107
+ # line too long
108
+ "E501",
109
+ # docstring in public module
110
+ "D100",
111
+ # docstring in public package
112
+ "D104",
113
+ # docstring in magic method
114
+ "D105",
115
+ # docstring in __init__
116
+ "D107",
117
+ # blank line before class docstring (conflicts D211)
118
+ "D203",
119
+ # multi-line summary second line (conflicts D212)
120
+ "D213",
121
+ # first word capitalization (false positive for proper nouns like dApp)
122
+ "D403",
123
+ # type-checking import (false positive for Pydantic models)
124
+ "TC001",
125
+ "TC002",
126
+ ]
127
+
128
+ [tool.ruff.lint.per-file-ignores]
129
+ "__init__.py" = ["F401"]
130
+ "pytonapi/rest/models/*" = ["D101"]
131
+ "tests/*" = ["D101", "D102", "T20"]
132
+ "codegen/*" = ["T20"]
133
+ "examples/*" = ["D", "T20", "RUF006", "RUF059"]
134
+
135
+ [tool.ruff.lint.isort]
136
+ known-first-party = ["pytonapi"]
137
+
138
+ [tool.ruff.format]
139
+ quote-style = "double"
140
+
141
+ [tool.mypy]
142
+ plugins = ["pydantic.mypy"]
143
+ python_version = "3.10"
144
+ strict = true
145
+ pretty = true
146
+ show_error_codes = true
147
+ show_error_context = true
148
+ namespace_packages = true
149
+ follow_imports_for_stubs = true
150
+ warn_unreachable = true
151
+ enable_error_code = [
152
+ "ignore-without-code",
153
+ "redundant-cast",
154
+ "truthy-bool",
155
+ ]
@@ -0,0 +1 @@
1
+
@@ -3,11 +3,6 @@
3
3
  # This source code is licensed under the MIT License found in the
4
4
  # LICENSE file in the root directory of this source tree.
5
5
 
6
-
7
- __all__ = [
8
- "__uri__",
9
- "__version__",
10
- ]
11
-
12
- __version__ = "2.0.0"
13
- __uri__ = "https://github.com/nessshon/pytonapi"
6
+ __version__ = "2.0.1"
7
+ __author__ = "nessshon"
8
+ __url__ = "https://github.com/nessshon/tonapi"
@@ -1,6 +1,6 @@
1
1
  import argparse
2
2
 
3
- from pytonapi import __version__
3
+ from pytonapi.__meta__ import __version__
4
4
 
5
5
 
6
6
  def main() -> None:
@@ -16,7 +16,6 @@ def main() -> None:
16
16
  version=f"pytonapi {__version__}",
17
17
  )
18
18
  parser.parse_args()
19
- parser.print_help()
20
19
 
21
20
 
22
21
  if __name__ == "__main__":
@@ -32,10 +32,10 @@ class BaseClient:
32
32
  base_url: str,
33
33
  *,
34
34
  timeout: float = 10.0,
35
- session: t.Optional[aiohttp.ClientSession] = None,
36
- headers: t.Optional[t.Dict[str, str]] = None,
37
- cookies: t.Optional[t.Dict[str, str]] = None,
38
- retry_policy: t.Optional[RetryPolicy] = DEFAULT_RETRY_POLICY,
35
+ session: aiohttp.ClientSession | None = None,
36
+ headers: dict[str, str] | None = None,
37
+ cookies: dict[str, str] | None = None,
38
+ retry_policy: RetryPolicy | None = DEFAULT_RETRY_POLICY,
39
39
  ) -> None:
40
40
  """Initialize the base HTTP client.
41
41
 
@@ -55,7 +55,7 @@ class BaseClient:
55
55
  self._headers = headers or {}
56
56
  self._cookies = cookies or {}
57
57
  self._timeout = aiohttp.ClientTimeout(total=timeout)
58
- self._session: t.Optional[aiohttp.ClientSession] = session
58
+ self._session: aiohttp.ClientSession | None = session
59
59
 
60
60
  self._is_external_session = session is not None
61
61
  self._retry_policy = retry_policy
@@ -94,14 +94,14 @@ class BaseClient:
94
94
 
95
95
  async def __aexit__(
96
96
  self,
97
- exc_type: t.Optional[t.Type[BaseException]],
98
- exc_val: t.Optional[BaseException],
99
- exc_tb: t.Optional[t.Any],
97
+ exc_type: type[BaseException] | None,
98
+ exc_val: BaseException | None,
99
+ exc_tb: t.Any | None,
100
100
  ) -> None:
101
101
  """Exit the async context manager."""
102
102
  await self.close_session()
103
103
 
104
- def _build_headers(self) -> t.Dict[str, str]:
104
+ def _build_headers(self) -> dict[str, str]:
105
105
  """Build default request headers.
106
106
 
107
107
  :return: Merged headers dict.
@@ -114,7 +114,7 @@ class BaseClient:
114
114
  return base
115
115
 
116
116
  @staticmethod
117
- def _parse_body(text: str) -> t.Tuple[t.Any, str]:
117
+ def _parse_body(text: str) -> tuple[t.Any, str]:
118
118
  """Parse response text and extract error message.
119
119
 
120
120
  :param text: Raw response text.
@@ -122,7 +122,7 @@ class BaseClient:
122
122
  """
123
123
  try:
124
124
  data = json.loads(text)
125
- except (json.JSONDecodeError,):
125
+ except json.JSONDecodeError:
126
126
  return None, text
127
127
 
128
128
  if isinstance(data, dict):
@@ -133,16 +133,40 @@ class BaseClient:
133
133
 
134
134
  return data, str(data)
135
135
 
136
+ @t.overload
136
137
  async def request(
137
138
  self,
138
139
  method: str,
139
140
  path: str,
140
141
  *,
141
- params: t.Optional[t.Dict[str, t.Any]] = None,
142
- body: t.Optional[t.Any] = None,
143
- headers: t.Optional[t.Dict[str, t.Any]] = None,
144
- response_model: t.Optional[t.Type[T]] = None,
145
- ) -> t.Any:
142
+ params: dict[str, t.Any] | None = None,
143
+ body: t.Any | None = None,
144
+ headers: dict[str, t.Any] | None = None,
145
+ response_model: type[T],
146
+ ) -> T: ...
147
+
148
+ @t.overload
149
+ async def request(
150
+ self,
151
+ method: str,
152
+ path: str,
153
+ *,
154
+ params: dict[str, t.Any] | None = None,
155
+ body: t.Any | None = None,
156
+ headers: dict[str, t.Any] | None = None,
157
+ response_model: None = None,
158
+ ) -> t.Any: ...
159
+
160
+ async def request(
161
+ self,
162
+ method: str,
163
+ path: str,
164
+ *,
165
+ params: dict[str, t.Any] | None = None,
166
+ body: t.Any | None = None,
167
+ headers: dict[str, t.Any] | None = None,
168
+ response_model: type[T] | None = None,
169
+ ) -> T | t.Any:
146
170
  """Execute an HTTP request with retry.
147
171
 
148
172
  :param method: HTTP method (``GET``, ``POST``, etc.).
@@ -167,8 +191,8 @@ class BaseClient:
167
191
  raise TONAPISessionNotCreatedError(self.__class__.__name__)
168
192
 
169
193
  session = self._session
170
- last_error: t.Optional[Exception] = None
171
- last_status: t.Optional[int] = None
194
+ last_error: Exception | None = None
195
+ last_status: int | None = None
172
196
  max_attempts = 1
173
197
 
174
198
  if self._retry_policy:
@@ -207,9 +231,9 @@ class BaseClient:
207
231
  content_type = response.headers.get("Content-Type", "")
208
232
  raise_for_status(response.status, text, content_type)
209
233
 
210
- except (TONAPIError,):
234
+ except TONAPIError:
211
235
  raise
212
- except (aiohttp.ClientError,) as exc:
236
+ except aiohttp.ClientError as exc:
213
237
  last_error = exc
214
238
  if attempt < max_attempts - 1:
215
239
  await asyncio.sleep(1.0)
@@ -227,7 +251,7 @@ class BaseClient:
227
251
  async def _handle_success(
228
252
  self,
229
253
  response: aiohttp.ClientResponse,
230
- response_model: t.Optional[t.Type[T]],
254
+ response_model: type[T] | None,
231
255
  ) -> t.Any:
232
256
  """Process a successful (2xx) response.
233
257
 
@@ -34,8 +34,7 @@ class TONAPIError(Exception):
34
34
 
35
35
 
36
36
  class TONAPIConnectionError(TONAPIError):
37
- """Network-level error DNS resolution failure, connection timeout,
38
- refused connection, or other transport issues."""
37
+ """Network-level error (DNS failure, timeout, refused connection)."""
39
38
 
40
39
 
41
40
  class TONAPIStatusError(TONAPIError):
@@ -127,15 +126,15 @@ class TONAPIRetryLimitError(TONAPIError):
127
126
  """All retry attempts have been exhausted."""
128
127
 
129
128
  attempts: int
130
- last_status: t.Optional[int]
131
- last_error: t.Optional[Exception]
129
+ last_status: int | None
130
+ last_error: Exception | None
132
131
 
133
132
  def __init__(
134
133
  self,
135
134
  *,
136
135
  attempts: int,
137
- last_status: t.Optional[int] = None,
138
- last_error: t.Optional[Exception] = None,
136
+ last_status: int | None = None,
137
+ last_error: Exception | None = None,
139
138
  ) -> None:
140
139
  self.attempts = attempts
141
140
  self.last_status = last_status
@@ -148,13 +147,13 @@ class TONAPIRetryLimitError(TONAPIError):
148
147
  super().__init__(", ".join(parts))
149
148
 
150
149
 
151
- STREAMING_RECOVERABLE: t.Final[t.Tuple[t.Type[TONAPIError], ...]] = (
150
+ STREAMING_RECOVERABLE: t.Final[tuple[type[TONAPIError], ...]] = (
152
151
  TONAPIServerError,
153
152
  TONAPITooManyRequestsError,
154
153
  TONAPIStreamingError,
155
154
  )
156
155
 
157
- TONAPI_STATUS_TO_EXCEPTION: t.Final[t.Dict[int, t.Type[TONAPIStatusError]]] = {
156
+ TONAPI_STATUS_TO_EXCEPTION: t.Final[dict[int, type[TONAPIStatusError]]] = {
158
157
  400: TONAPIBadRequestError,
159
158
  401: TONAPIUnauthorizedError,
160
159
  403: TONAPIForbiddenError,
@@ -180,7 +179,7 @@ def raise_for_status(status: int, body: str, content_type: str = "") -> None:
180
179
  else:
181
180
  try:
182
181
  data = json.loads(body)
183
- except (json.JSONDecodeError,):
182
+ except json.JSONDecodeError:
184
183
  message = body
185
184
  else:
186
185
  if isinstance(data, dict):
@@ -27,14 +27,14 @@ class TonapiRestClient(BaseClient, ResourcesMixin):
27
27
  api_key: str,
28
28
  network: Network,
29
29
  *,
30
- base_url: t.Optional[str] = None,
30
+ base_url: str | None = None,
31
31
  timeout: float = 10.0,
32
- session: t.Optional[aiohttp.ClientSession] = None,
33
- headers: t.Optional[t.Dict[str, str]] = None,
34
- cookies: t.Optional[t.Dict[str, str]] = None,
32
+ session: aiohttp.ClientSession | None = None,
33
+ headers: dict[str, str] | None = None,
34
+ cookies: dict[str, str] | None = None,
35
35
  rps_limit: int = 0,
36
36
  rps_period: float = 1.0,
37
- retry_policy: t.Optional[RetryPolicy] = DEFAULT_RETRY_POLICY,
37
+ retry_policy: RetryPolicy | None = DEFAULT_RETRY_POLICY,
38
38
  ) -> None:
39
39
  """Initialize the TONAPI client.
40
40
 
@@ -60,7 +60,7 @@ class TonapiRestClient(BaseClient, ResourcesMixin):
60
60
  cookies=cookies,
61
61
  retry_policy=retry_policy,
62
62
  )
63
- self._rate_limiter: t.Optional[RateLimiter] = (
63
+ self._rate_limiter: RateLimiter | None = (
64
64
  RateLimiter(rps=rps_limit, period=rps_period) if rps_limit > 0 else None
65
65
  )
66
66
  ResourcesMixin.__init__(self, self)
@@ -70,10 +70,10 @@ class TonapiRestClient(BaseClient, ResourcesMixin):
70
70
  method: str,
71
71
  path: str,
72
72
  *,
73
- params: t.Optional[t.Dict[str, t.Any]] = None,
74
- body: t.Optional[t.Any] = None,
75
- headers: t.Optional[t.Dict[str, t.Any]] = None,
76
- response_model: t.Optional[t.Type[T]] = None,
73
+ params: dict[str, t.Any] | None = None,
74
+ body: t.Any | None = None,
75
+ headers: dict[str, t.Any] | None = None,
76
+ response_model: type[T] | None = None,
77
77
  ) -> t.Any:
78
78
  """Execute an HTTP request with retry and rate limiting.
79
79
 
@@ -1,6 +1,5 @@
1
1
  import asyncio
2
2
  import time
3
- import typing as t
4
3
 
5
4
 
6
5
  class RateLimiter:
@@ -13,7 +12,7 @@ class RateLimiter:
13
12
  def __init__(self, rps: int, period: float = 1.0) -> None:
14
13
  self._rps = rps
15
14
  self._period = period
16
- self._timestamps: t.List[float] = []
15
+ self._timestamps: list[float] = []
17
16
  self._lock = asyncio.Lock()
18
17
 
19
18
  async def acquire(self) -> None: