aioqzone 1.9.9.dev1__tar.gz → 1.10.2.dev1__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.
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/PKG-INFO +3 -3
- aioqzone-1.10.2.dev1/pyproject.toml +102 -0
- aioqzone-1.9.9.dev1/pyproject.toml → aioqzone-1.10.2.dev1/pyproject.toml.orig +5 -6
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/api/login/__init__.py +23 -2
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/utils/jsjson.py +4 -3
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/README.md +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/__init__.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/api/__init__.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/api/h5/__init__.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/api/h5/model.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/api/login/_base.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/exception.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/message.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/model/__init__.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/model/api/__init__.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/model/api/feed.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/model/api/profile.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/model/api/request.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/model/api/response.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/model/protocol/__init__.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/model/protocol/config.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/model/protocol/entity.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/utils/__init__.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/utils/entity.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/utils/regex.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/utils/retry.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/aioqzone/utils/time.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/__init__.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/base.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/constant.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/exception.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/message.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/py.typed +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/qr/__init__.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/qr/type.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/type.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/up/__init__.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/up/_model.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/up/captcha/__init__.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/up/captcha/_model.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/up/captcha/capsess.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/up/captcha/click/__init__.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/up/captcha/click/_types.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/up/captcha/pil_utils.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/up/captcha/select/__init__.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/up/captcha/select/_types.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/up/captcha/slide/__init__.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/up/captcha/slide/_types.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/up/encrypt.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/up/h5.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/up/web.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/utils/encrypt.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/utils/iter.py +0 -0
- {aioqzone-1.9.9.dev1 → aioqzone-1.10.2.dev1}/src/qqqr/utils/net.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aioqzone
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10.2.dev1
|
|
4
4
|
Summary: A Python wrapper for Qzone login and H5 APIs.
|
|
5
5
|
Keywords: qzone-api,autologin,asyncio-spider
|
|
6
6
|
Author: aioqzone
|
|
@@ -15,12 +15,12 @@ Requires-Dist: pydantic-settings>=2.9.0
|
|
|
15
15
|
Requires-Dist: rsa>=4.9.1
|
|
16
16
|
Requires-Dist: tenacity>=8.2.3,<10.0.0
|
|
17
17
|
Requires-Dist: tylisten>=2.2.1
|
|
18
|
-
Requires-Dist: pillow>=
|
|
18
|
+
Requires-Dist: pillow>=13.0.0
|
|
19
19
|
Requires-Dist: pychaosvm~=0.5.4
|
|
20
20
|
Requires-Dist: slide-tc~=0.1.4 ; extra == 'slide-captcha'
|
|
21
21
|
Maintainer: JamzumSum
|
|
22
22
|
Maintainer-email: JamzumSum <22952836+JamzumSum@users.noreply.github.com>
|
|
23
|
-
Requires-Python: >=3.
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
24
|
Project-URL: Homepage, https://github.com/aioqzone/aioqzone
|
|
25
25
|
Project-URL: Repository, https://github.com/aioqzone/aioqzone
|
|
26
26
|
Project-URL: Documentation, https://aioqzone.github.io/aioqzone
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "aioqzone"
|
|
3
|
+
version = "1.10.2.dev1"
|
|
4
|
+
description = "A Python wrapper for Qzone login and H5 APIs."
|
|
5
|
+
license = "AGPL-3.0-or-later"
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
requires-python = ">=3.11"
|
|
8
|
+
keywords = [
|
|
9
|
+
"qzone-api",
|
|
10
|
+
"autologin",
|
|
11
|
+
"asyncio-spider",
|
|
12
|
+
]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
17
|
+
"Typing :: Typed",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"aiohttp~=3.14",
|
|
21
|
+
"pydantic~=2.12",
|
|
22
|
+
"pydantic-settings>=2.9.0",
|
|
23
|
+
"rsa>=4.9.1",
|
|
24
|
+
"tenacity>=8.2.3,<10.0.0",
|
|
25
|
+
"tylisten>=2.2.1",
|
|
26
|
+
"pillow>=13.0.0",
|
|
27
|
+
"pychaosvm~=0.5.4",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[[project.authors]]
|
|
31
|
+
name = "aioqzone"
|
|
32
|
+
|
|
33
|
+
[[project.maintainers]]
|
|
34
|
+
name = "JamzumSum"
|
|
35
|
+
email = "22952836+JamzumSum@users.noreply.github.com"
|
|
36
|
+
|
|
37
|
+
[project.urls]
|
|
38
|
+
Homepage = "https://github.com/aioqzone/aioqzone"
|
|
39
|
+
Repository = "https://github.com/aioqzone/aioqzone"
|
|
40
|
+
Documentation = "https://aioqzone.github.io/aioqzone"
|
|
41
|
+
"Bug Tracker" = "https://github.com/aioqzone/aioqzone/issues"
|
|
42
|
+
Discussion = "https://t.me/aioqzone_chatroom"
|
|
43
|
+
|
|
44
|
+
[project.optional-dependencies]
|
|
45
|
+
slide-captcha = ["slide-tc~=0.1.4"]
|
|
46
|
+
|
|
47
|
+
[dependency-groups]
|
|
48
|
+
test = [
|
|
49
|
+
"pytest>=9.0.3",
|
|
50
|
+
"pytest-asyncio~=1.1",
|
|
51
|
+
]
|
|
52
|
+
dev = [
|
|
53
|
+
"pre-commit",
|
|
54
|
+
"ruff",
|
|
55
|
+
"ty",
|
|
56
|
+
]
|
|
57
|
+
doc = [
|
|
58
|
+
"Sphinx~=9.0",
|
|
59
|
+
"autodoc-pydantic>=2.2.0",
|
|
60
|
+
"sphinx-autodoc-typehints~=3.0",
|
|
61
|
+
"furo",
|
|
62
|
+
"sphinx-intl",
|
|
63
|
+
"sphinx-inline-tabs",
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
[tool.uv]
|
|
67
|
+
prerelease = "if-necessary-or-explicit"
|
|
68
|
+
|
|
69
|
+
[tool.uv.sources.pychaosvm]
|
|
70
|
+
index = "aioqzone-index"
|
|
71
|
+
|
|
72
|
+
[tool.uv.sources.slide-tc]
|
|
73
|
+
index = "aioqzone-index"
|
|
74
|
+
|
|
75
|
+
[[tool.uv.index]]
|
|
76
|
+
name = "aioqzone-index"
|
|
77
|
+
url = "https://aioqzone.github.io/aioqzone-index/simple/"
|
|
78
|
+
|
|
79
|
+
[tool.uv.build-backend]
|
|
80
|
+
module-name = [
|
|
81
|
+
"aioqzone",
|
|
82
|
+
"qqqr",
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
[tool.pytest.ini_options]
|
|
86
|
+
pythonpath = "src"
|
|
87
|
+
log_cli = true
|
|
88
|
+
log_cli_level = "WARNING"
|
|
89
|
+
asyncio_default_fixture_loop_scope = "module"
|
|
90
|
+
|
|
91
|
+
[tool.ruff]
|
|
92
|
+
line-length = 99
|
|
93
|
+
|
|
94
|
+
[tool.ruff.lint]
|
|
95
|
+
ignore = [
|
|
96
|
+
"F403",
|
|
97
|
+
"F405",
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
[build-system]
|
|
101
|
+
requires = ["uv_build"]
|
|
102
|
+
build-backend = "uv_build"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "aioqzone"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.10.2.dev1"
|
|
4
4
|
description = "A Python wrapper for Qzone login and H5 APIs."
|
|
5
5
|
authors = [{ name = "aioqzone" }]
|
|
6
6
|
maintainers = [
|
|
@@ -8,7 +8,7 @@ maintainers = [
|
|
|
8
8
|
]
|
|
9
9
|
license = "AGPL-3.0-or-later"
|
|
10
10
|
readme = "README.md"
|
|
11
|
-
requires-python = ">=3.
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
12
|
keywords = ["qzone-api", "autologin", "asyncio-spider"]
|
|
13
13
|
classifiers = [
|
|
14
14
|
"Development Status :: 4 - Beta",
|
|
@@ -25,7 +25,7 @@ dependencies = [
|
|
|
25
25
|
"tenacity>=8.2.3,<10.0.0",
|
|
26
26
|
# "exceptiongroup>=1.1.1",
|
|
27
27
|
"tylisten>=2.2.1",
|
|
28
|
-
"pillow>=
|
|
28
|
+
"pillow>=13.0.0",
|
|
29
29
|
"pychaosvm~=0.5.4",
|
|
30
30
|
]
|
|
31
31
|
|
|
@@ -37,15 +37,14 @@ Documentation = "https://aioqzone.github.io/aioqzone"
|
|
|
37
37
|
"Discussion" = "https://t.me/aioqzone_chatroom"
|
|
38
38
|
|
|
39
39
|
[dependency-groups]
|
|
40
|
-
test = ["pytest>=9.0.3", "pytest-asyncio
|
|
40
|
+
test = ["pytest>=9.0.3", "pytest-asyncio~=1.1"]
|
|
41
41
|
dev = [
|
|
42
42
|
"pre-commit",
|
|
43
43
|
"ruff",
|
|
44
44
|
"ty",
|
|
45
45
|
]
|
|
46
46
|
doc = [
|
|
47
|
-
"Sphinx
|
|
48
|
-
"Sphinx~=9.0; python_version>='3.11'",
|
|
47
|
+
"Sphinx~=9.0",
|
|
49
48
|
"autodoc-pydantic>=2.2.0",
|
|
50
49
|
"sphinx-autodoc-typehints~=3.0",
|
|
51
50
|
"furo",
|
|
@@ -8,7 +8,14 @@ import logging
|
|
|
8
8
|
import typing as t
|
|
9
9
|
|
|
10
10
|
from aiohttp import ClientError
|
|
11
|
-
from tenacity import
|
|
11
|
+
from tenacity import (
|
|
12
|
+
RetryCallState,
|
|
13
|
+
TryAgain,
|
|
14
|
+
retry,
|
|
15
|
+
retry_if_exception_type,
|
|
16
|
+
stop_after_attempt,
|
|
17
|
+
wait_exponential,
|
|
18
|
+
)
|
|
12
19
|
from tylisten import FutureStore
|
|
13
20
|
from typing_extensions import Self
|
|
14
21
|
|
|
@@ -31,6 +38,20 @@ __all__ = [
|
|
|
31
38
|
]
|
|
32
39
|
|
|
33
40
|
|
|
41
|
+
def _reraise_last_attempt(retry_state: RetryCallState) -> t.NoReturn:
|
|
42
|
+
"""Re-raise the last attempt exception instead of tenacity's ``RetryError``.
|
|
43
|
+
|
|
44
|
+
tenacity >= 9.2.1 unwraps ``TryAgain`` to its cause when ``reraise=True``,
|
|
45
|
+
which would surface the underlying ``ClientError`` (or ``GeneratorExit``)
|
|
46
|
+
rather than the documented :exc:`TryAgain`. Re-raising the attempt's own
|
|
47
|
+
exception keeps the public contract stable across tenacity versions.
|
|
48
|
+
"""
|
|
49
|
+
outcome = retry_state.outcome
|
|
50
|
+
if outcome is None:
|
|
51
|
+
raise RuntimeError("retry outcome is unexpectedly None")
|
|
52
|
+
raise outcome.result()
|
|
53
|
+
|
|
54
|
+
|
|
34
55
|
@t.final
|
|
35
56
|
class ConstLoginMan(Loginable):
|
|
36
57
|
"""A basic login manager which uses external provided cookie."""
|
|
@@ -99,7 +120,7 @@ class UpLoginManager(Loginable):
|
|
|
99
120
|
stop=stop_after_attempt(2),
|
|
100
121
|
wait=wait_exponential(min=1, max=6),
|
|
101
122
|
retry=retry_if_exception_type(TryAgain),
|
|
102
|
-
|
|
123
|
+
retry_error_callback=_reraise_last_attempt,
|
|
103
124
|
)
|
|
104
125
|
async def _new_cookie(self) -> t.Dict[str, str]:
|
|
105
126
|
"""
|
|
@@ -41,10 +41,11 @@ class AstLoader:
|
|
|
41
41
|
:return: A :obj:`JsonValue` object.
|
|
42
42
|
"""
|
|
43
43
|
js = dedent(js).replace(r"\/", "/")
|
|
44
|
-
node = ast.parse(js, mode="eval")
|
|
44
|
+
node = ast.parse(js, filename=filename, mode="eval")
|
|
45
45
|
node = ast.fix_missing_locations(cls.RewriteUndef().visit(node))
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
# Parse as a data literal only. Never compile/eval the input: it comes from
|
|
47
|
+
# remote responses and must not be executed as Python code.
|
|
48
|
+
return ast.literal_eval(node)
|
|
48
49
|
|
|
49
50
|
|
|
50
51
|
def json_loads(js: str) -> JsonValue:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|