s-clientkit 0.1.0__tar.gz → 0.2.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.
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/CHANGELOG.md +26 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/PKG-INFO +10 -6
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/README.md +6 -1
- s_clientkit-0.2.0/clientkit/__init__.py +126 -0
- s_clientkit-0.2.0/clientkit/_base.py +9 -0
- s_clientkit-0.2.0/clientkit/_candidates.py +9 -0
- s_clientkit-0.2.0/clientkit/builder.py +9 -0
- s_clientkit-0.2.0/clientkit/declaration.py +31 -0
- s_clientkit-0.2.0/clientkit/errors.py +14 -0
- s_clientkit-0.2.0/clientkit/hidden.py +9 -0
- s_clientkit-0.2.0/clientkit/identity.py +31 -0
- s_clientkit-0.2.0/clientkit/ports.py +21 -0
- s_clientkit-0.2.0/clientkit/white.py +9 -0
- s_clientkit-0.2.0/pyproject.toml +79 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/tests/test_limit_gate.py +4 -1
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/tests/test_same_call_both_kinds.py +22 -9
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/uv.lock +60 -24
- s_clientkit-0.1.0/clientkit/__init__.py +0 -124
- s_clientkit-0.1.0/clientkit/_base.py +0 -174
- s_clientkit-0.1.0/clientkit/_candidates.py +0 -150
- s_clientkit-0.1.0/clientkit/builder.py +0 -66
- s_clientkit-0.1.0/clientkit/declaration.py +0 -338
- s_clientkit-0.1.0/clientkit/errors.py +0 -48
- s_clientkit-0.1.0/clientkit/hidden.py +0 -194
- s_clientkit-0.1.0/clientkit/identity.py +0 -249
- s_clientkit-0.1.0/clientkit/ports.py +0 -71
- s_clientkit-0.1.0/clientkit/white.py +0 -84
- s_clientkit-0.1.0/pyproject.toml +0 -64
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/.gitignore +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/.gitlab-ci.yml +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/.importlinter +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/.skillgateignore +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/AGENTS.md +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/LICENSE +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/clientkit/_version.py +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/docs/adr/0000-template.md +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/docs/adr/README.md +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/examples/hidden_service.toml +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/examples/white_service.toml +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/scripts/check_dist_leaks.py +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/scripts/release_guard.py +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/tests/__init__.py +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/tests/test_declaration.py +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/tests/test_hidden_holds_access.py +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/tests/test_identity.py +0 -0
- {s_clientkit-0.1.0 → s_clientkit-0.2.0}/tests/test_ports_transport.py +0 -0
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog — s-clientkit
|
|
2
2
|
|
|
3
|
+
## [0.2.0] — 2026-09-08
|
|
4
|
+
|
|
5
|
+
Слияние в adapterkit (волна 5, задача 2, Atlas #2710): у кита не набралось
|
|
6
|
+
живой массы под отдельный релизный цикл — единственный внешний потребитель
|
|
7
|
+
(reverse-factory) ходит только за `clientkit.identity`, а адреса-кандидаты уже
|
|
8
|
+
были тонкой обёрткой над `adapterkit.endpoints.EndpointRegistry`.
|
|
9
|
+
|
|
10
|
+
### Breaking
|
|
11
|
+
|
|
12
|
+
- Весь код (декларация сервиса, сборка белого/скрытого клиента, каталог имён
|
|
13
|
+
сервисов, адреса-кандидаты) переехал в `adapterkit.clientkit`. Пакет
|
|
14
|
+
`clientkit` — ТЕПЕРЬ ТОНКИЙ АЛИАС: каждый модуль (`clientkit.identity`,
|
|
15
|
+
`clientkit.declaration`, `clientkit.builder`, `clientkit.hidden`,
|
|
16
|
+
`clientkit.white`, `clientkit.ports`, `clientkit.errors`, `clientkit._base`,
|
|
17
|
+
`clientkit._candidates`) реэкспортирует одноимённый модуль
|
|
18
|
+
`adapterkit.clientkit.*`. Публичная поверхность (`from clientkit import
|
|
19
|
+
build_from_toml`, `from clientkit.identity import CATALOG`, …) сохранена 1:1.
|
|
20
|
+
- `s-adapterkit` — теперь ОБЯЗАТЕЛЬНАЯ базовая зависимость (`>=0.2.0,<0.3`,
|
|
21
|
+
extra `client` внутри неё тянет `s-netkit`): даже `clientkit.identity` физически
|
|
22
|
+
лежит в `adapterkit.clientkit.identity`.
|
|
23
|
+
- Extra `endpoints` — теперь no-op (`s-adapterkit` и так обязателен, ставить
|
|
24
|
+
отдельно больше нечего). Оставлен пустым, а не удалён, чтобы старый
|
|
25
|
+
`pip install s-clientkit[endpoints]` не падал `ExtraNotFound`.
|
|
26
|
+
- Extra `hidden` теперь форвардит `s-adapterkit[client-hidden]` вместо прямого
|
|
27
|
+
`s-authkit-client` (тот же пакет приезжает транзитивно).
|
|
28
|
+
|
|
3
29
|
## [0.1.0] — 2026-09-06
|
|
4
30
|
|
|
5
31
|
Волна китов-оснований: транспорт только через netkit, свой `TokenBucket` удалён.
|
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: s-clientkit
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: КИТ-АЛИАС: код-сборщик клиента переехал в adapterkit.clientkit (волна 5, задача 2, Atlas #2710) — этот пакет тонко реэкспортирует его модули под прежними именами (clientkit.identity и остальные).
|
|
5
5
|
Author: Dmitry
|
|
6
6
|
License: MIT
|
|
7
7
|
License-File: LICENSE
|
|
8
8
|
Requires-Python: >=3.11
|
|
9
|
+
Requires-Dist: s-adapterkit[client]<0.3,>=0.2.0
|
|
9
10
|
Requires-Dist: s-corekit>=0.0.2
|
|
10
|
-
Requires-Dist: s-netkit<0.2,>=0.1.1
|
|
11
11
|
Provides-Extra: dev
|
|
12
12
|
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
13
13
|
Requires-Dist: pytest>=8; extra == 'dev'
|
|
14
14
|
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
15
15
|
Provides-Extra: endpoints
|
|
16
|
-
Requires-Dist: s-adapterkit>=0.1.8; extra == 'endpoints'
|
|
17
16
|
Provides-Extra: hidden
|
|
18
|
-
Requires-Dist: s-
|
|
17
|
+
Requires-Dist: s-adapterkit[client-hidden]<0.3,>=0.2.0; extra == 'hidden'
|
|
19
18
|
Provides-Extra: http
|
|
20
19
|
Requires-Dist: httpx>=0.27; extra == 'http'
|
|
21
20
|
Description-Content-Type: text/markdown
|
|
22
21
|
|
|
23
|
-
# s-clientkit —
|
|
22
|
+
# s-clientkit — тонкий алиас поверх adapterkit.clientkit
|
|
23
|
+
|
|
24
|
+
> **Волна 5, задача 2 (Atlas #2710):** живой код переехал в
|
|
25
|
+
> `adapterkit.clientkit` — здесь остались тонкие модули-реэкспорты. Публичная
|
|
26
|
+
> поверхность (всё, что описано ниже) не изменилась; изменился только адрес
|
|
27
|
+
> кода под ней.
|
|
24
28
|
|
|
25
29
|
Готовый клиент сервиса **собирается по декларации**, а не пишется заново.
|
|
26
30
|
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
# s-clientkit —
|
|
1
|
+
# s-clientkit — тонкий алиас поверх adapterkit.clientkit
|
|
2
|
+
|
|
3
|
+
> **Волна 5, задача 2 (Atlas #2710):** живой код переехал в
|
|
4
|
+
> `adapterkit.clientkit` — здесь остались тонкие модули-реэкспорты. Публичная
|
|
5
|
+
> поверхность (всё, что описано ниже) не изменилась; изменился только адрес
|
|
6
|
+
> кода под ней.
|
|
2
7
|
|
|
3
8
|
Готовый клиент сервиса **собирается по декларации**, а не пишется заново.
|
|
4
9
|
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""clientkit — ТОНКИЙ АЛИАС поверх ``adapterkit.clientkit`` (волна 5, задача 2,
|
|
2
|
+
Atlas #2710).
|
|
3
|
+
|
|
4
|
+
БЫЛО СВОИМ КИТОМ-СБОРЩИКОМ, СТАЛО АЛИАСОМ. Живой код (декларация сервиса,
|
|
5
|
+
сборка белого/скрытого клиента, каталог имён сервисов, адреса-кандидаты)
|
|
6
|
+
переехал в :mod:`adapterkit.clientkit` — рядом с реестром адресов
|
|
7
|
+
(:class:`adapterkit.endpoints.EndpointRegistry`), которым адреса-кандидаты и
|
|
8
|
+
раньше пользовались (см. историю ``clientkit._candidates``). Единственный
|
|
9
|
+
известный внешний потребитель на момент переноса — reverse-factory, и он ходит
|
|
10
|
+
ТОЛЬКО за :mod:`clientkit.identity` (``CATALOG``/``ServiceIdentity``/
|
|
11
|
+
``UnknownService``/``canonical``): этот путь работает как раньше, включая
|
|
12
|
+
установку без extra-флагов.
|
|
13
|
+
|
|
14
|
+
Каждый модуль здесь (``clientkit.identity``, ``clientkit.declaration``,
|
|
15
|
+
``clientkit.builder``, ``clientkit.hidden``, ``clientkit.white``,
|
|
16
|
+
``clientkit.ports``, ``clientkit.errors``, ``clientkit._base``,
|
|
17
|
+
``clientkit._candidates``) — тонкий файл-реэкспорт одноимённого модуля
|
|
18
|
+
``adapterkit.clientkit.*``: ``import clientkit.builder`` и т.п. продолжает
|
|
19
|
+
работать, даже если что-то в экосистеме импортирует их напрямую, а не через
|
|
20
|
+
корень пакета.
|
|
21
|
+
|
|
22
|
+
ОДИН ВЫЗОВ НА ОБА МИРА (без изменений)::
|
|
23
|
+
|
|
24
|
+
from clientkit import build_from_toml
|
|
25
|
+
|
|
26
|
+
white = build_from_toml("examples/white_service.toml", secrets=os.environ.get)
|
|
27
|
+
hidden = build_from_toml("examples/hidden_service.toml", session_store=store)
|
|
28
|
+
|
|
29
|
+
await white.call("me") # белый REST с api-ключом
|
|
30
|
+
await hidden.call("me") # скрытый API с сессией и лестницей деградации
|
|
31
|
+
"""
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import importlib
|
|
35
|
+
from typing import TYPE_CHECKING
|
|
36
|
+
|
|
37
|
+
if TYPE_CHECKING: # pragma: no cover — для тайпчекера/IDE
|
|
38
|
+
from adapterkit.clientkit._base import ServiceClient
|
|
39
|
+
from adapterkit.clientkit.builder import build_client, build_from_toml
|
|
40
|
+
from adapterkit.clientkit.declaration import (
|
|
41
|
+
AccessRecipe,
|
|
42
|
+
AuthDecl,
|
|
43
|
+
AuthScheme,
|
|
44
|
+
EndpointDecl,
|
|
45
|
+
LimitDecl,
|
|
46
|
+
ServiceDecl,
|
|
47
|
+
ServiceKind,
|
|
48
|
+
decl_from_data,
|
|
49
|
+
decl_to_data,
|
|
50
|
+
load_toml,
|
|
51
|
+
)
|
|
52
|
+
from adapterkit.clientkit.errors import AccessUnavailable, ClientBuildError, OperationFailed
|
|
53
|
+
from adapterkit.clientkit.hidden import HiddenApiClient
|
|
54
|
+
from adapterkit.clientkit.identity import (
|
|
55
|
+
CATALOG,
|
|
56
|
+
Instancing,
|
|
57
|
+
ServiceIdentity,
|
|
58
|
+
UnknownService,
|
|
59
|
+
canonical,
|
|
60
|
+
resolve_service,
|
|
61
|
+
suggest_service,
|
|
62
|
+
)
|
|
63
|
+
from adapterkit.clientkit.ports import RequestPort, SecretLookup
|
|
64
|
+
from adapterkit.clientkit.white import WhiteApiClient
|
|
65
|
+
|
|
66
|
+
#: имя -> модуль-владелец В adapterkit.clientkit (не в этом пакете — этот
|
|
67
|
+
#: пакет сам ничего не реализует). `hidden` в этой таблице стоит РЯДОМ с
|
|
68
|
+
#: `white`, но цена у них разная: обращение к `HiddenApiClient` подтягивает
|
|
69
|
+
#: слой доступа, а к `WhiteApiClient` — нет. Ленивость здесь и защищает эту
|
|
70
|
+
#: разницу.
|
|
71
|
+
_LAZY_NAMES: dict[str, str] = {
|
|
72
|
+
"build_client": "adapterkit.clientkit.builder",
|
|
73
|
+
"build_from_toml": "adapterkit.clientkit.builder",
|
|
74
|
+
"ServiceClient": "adapterkit.clientkit._base",
|
|
75
|
+
# ИМЯ сервиса — тоже данные, и притом нужные тем, кто базы не держит:
|
|
76
|
+
# навыку назвать свою сессию, записи трафика — положить снимок.
|
|
77
|
+
"ServiceIdentity": "adapterkit.clientkit.identity",
|
|
78
|
+
"Instancing": "adapterkit.clientkit.identity",
|
|
79
|
+
"UnknownService": "adapterkit.clientkit.identity",
|
|
80
|
+
"CATALOG": "adapterkit.clientkit.identity",
|
|
81
|
+
"canonical": "adapterkit.clientkit.identity",
|
|
82
|
+
"resolve_service": "adapterkit.clientkit.identity",
|
|
83
|
+
"suggest_service": "adapterkit.clientkit.identity",
|
|
84
|
+
# декларация — данные
|
|
85
|
+
"ServiceDecl": "adapterkit.clientkit.declaration",
|
|
86
|
+
"ServiceKind": "adapterkit.clientkit.declaration",
|
|
87
|
+
"AuthDecl": "adapterkit.clientkit.declaration",
|
|
88
|
+
"AuthScheme": "adapterkit.clientkit.declaration",
|
|
89
|
+
"LimitDecl": "adapterkit.clientkit.declaration",
|
|
90
|
+
"EndpointDecl": "adapterkit.clientkit.declaration",
|
|
91
|
+
"AccessRecipe": "adapterkit.clientkit.declaration",
|
|
92
|
+
"decl_from_data": "adapterkit.clientkit.declaration",
|
|
93
|
+
"decl_to_data": "adapterkit.clientkit.declaration",
|
|
94
|
+
"load_toml": "adapterkit.clientkit.declaration",
|
|
95
|
+
# порты
|
|
96
|
+
"RequestPort": "adapterkit.clientkit.ports",
|
|
97
|
+
"SecretLookup": "adapterkit.clientkit.ports",
|
|
98
|
+
# клиенты (обычно не нужны напрямую — собирает build_client)
|
|
99
|
+
"WhiteApiClient": "adapterkit.clientkit.white",
|
|
100
|
+
"HiddenApiClient": "adapterkit.clientkit.hidden",
|
|
101
|
+
# ошибки
|
|
102
|
+
"ClientBuildError": "adapterkit.clientkit.errors",
|
|
103
|
+
"AccessUnavailable": "adapterkit.clientkit.errors",
|
|
104
|
+
"OperationFailed": "adapterkit.clientkit.errors",
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
__all__ = ["__version__", *sorted(_LAZY_NAMES)]
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def __getattr__(name: str):
|
|
111
|
+
if name == "__version__":
|
|
112
|
+
from ._version import resolve_version
|
|
113
|
+
|
|
114
|
+
value = resolve_version()
|
|
115
|
+
globals()["__version__"] = value
|
|
116
|
+
return value
|
|
117
|
+
module_name = _LAZY_NAMES.get(name)
|
|
118
|
+
if module_name is None:
|
|
119
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
120
|
+
value = getattr(importlib.import_module(module_name), name)
|
|
121
|
+
globals()[name] = value
|
|
122
|
+
return value
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def __dir__() -> list[str]:
|
|
126
|
+
return sorted({*globals(), *_LAZY_NAMES})
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Тонкий алиас — код переехал в ``adapterkit.clientkit._base`` (волна 5,
|
|
2
|
+
задача 2, Atlas #2710). Реэкспорт ради back-compat: ``from clientkit._base
|
|
3
|
+
import ServiceClient`` работает идентично.
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from adapterkit.clientkit._base import ServiceClient, ServiceClientBase
|
|
8
|
+
|
|
9
|
+
__all__ = ["ServiceClient", "ServiceClientBase"]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Тонкий алиас — код переехал в ``adapterkit.clientkit._candidates`` (волна 5,
|
|
2
|
+
задача 2, Atlas #2710). Реэкспорт ради back-compat: ``from clientkit._candidates
|
|
3
|
+
import CandidateBook`` работает идентично.
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from adapterkit.clientkit._candidates import CandidateBook
|
|
8
|
+
|
|
9
|
+
__all__ = ["CandidateBook"]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Тонкий алиас — код переехал в ``adapterkit.clientkit.builder`` (волна 5,
|
|
2
|
+
задача 2, Atlas #2710). Реэкспорт ради back-compat: ``from clientkit.builder
|
|
3
|
+
import build_client`` работает идентично.
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from adapterkit.clientkit.builder import build_client, build_from_toml
|
|
8
|
+
|
|
9
|
+
__all__ = ["build_client", "build_from_toml"]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Тонкий алиас — код переехал в ``adapterkit.clientkit.declaration`` (волна 5,
|
|
2
|
+
задача 2, Atlas #2710). Реэкспорт ради back-compat: ``from clientkit.declaration
|
|
3
|
+
import ServiceDecl`` и т.п. работают идентично.
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from adapterkit.clientkit.declaration import (
|
|
8
|
+
AccessRecipe,
|
|
9
|
+
AuthDecl,
|
|
10
|
+
AuthScheme,
|
|
11
|
+
EndpointDecl,
|
|
12
|
+
LimitDecl,
|
|
13
|
+
ServiceDecl,
|
|
14
|
+
ServiceKind,
|
|
15
|
+
decl_from_data,
|
|
16
|
+
decl_to_data,
|
|
17
|
+
load_toml,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"AccessRecipe",
|
|
22
|
+
"AuthDecl",
|
|
23
|
+
"AuthScheme",
|
|
24
|
+
"EndpointDecl",
|
|
25
|
+
"LimitDecl",
|
|
26
|
+
"ServiceDecl",
|
|
27
|
+
"ServiceKind",
|
|
28
|
+
"decl_from_data",
|
|
29
|
+
"decl_to_data",
|
|
30
|
+
"load_toml",
|
|
31
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Тонкий алиас — код переехал в ``adapterkit.clientkit.errors`` (волна 5,
|
|
2
|
+
задача 2, Atlas #2710). Реэкспорт ради back-compat: ``from clientkit.errors
|
|
3
|
+
import AccessUnavailable`` и т.п. работают идентично.
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from adapterkit.clientkit.errors import (
|
|
8
|
+
AccessUnavailable,
|
|
9
|
+
ClientBuildError,
|
|
10
|
+
OperationFailed,
|
|
11
|
+
TransportUnavailable,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = ["AccessUnavailable", "ClientBuildError", "OperationFailed", "TransportUnavailable"]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Тонкий алиас — код переехал в ``adapterkit.clientkit.hidden`` (волна 5,
|
|
2
|
+
задача 2, Atlas #2710). Реэкспорт ради back-compat: ``from clientkit.hidden
|
|
3
|
+
import HiddenApiClient`` работает идентично.
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from adapterkit.clientkit.hidden import HiddenApiClient
|
|
8
|
+
|
|
9
|
+
__all__ = ["HiddenApiClient"]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Тонкий алиас — код переехал в ``adapterkit.clientkit.identity`` (волна 5,
|
|
2
|
+
задача 2, Atlas #2710). Реэкспорт ради back-compat: ``from clientkit.identity
|
|
3
|
+
import CATALOG, ServiceIdentity, UnknownService, canonical`` — единственный
|
|
4
|
+
путь, которым сегодня ходит reverse-factory — работает идентично, БЕЗ каких-либо
|
|
5
|
+
extra-флагов.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from adapterkit.clientkit.identity import (
|
|
10
|
+
CATALOG,
|
|
11
|
+
Instancing,
|
|
12
|
+
ServiceIdentity,
|
|
13
|
+
UnknownService,
|
|
14
|
+
canonical,
|
|
15
|
+
resolve,
|
|
16
|
+
resolve_service,
|
|
17
|
+
suggest,
|
|
18
|
+
suggest_service,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"CATALOG",
|
|
23
|
+
"resolve_service",
|
|
24
|
+
"suggest_service",
|
|
25
|
+
"Instancing",
|
|
26
|
+
"ServiceIdentity",
|
|
27
|
+
"UnknownService",
|
|
28
|
+
"canonical",
|
|
29
|
+
"resolve",
|
|
30
|
+
"suggest",
|
|
31
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Тонкий алиас — код переехал в ``adapterkit.clientkit.ports`` (волна 5,
|
|
2
|
+
задача 2, Atlas #2710). Реэкспорт ради back-compat: ``from clientkit.ports
|
|
3
|
+
import RequestPort`` и т.п. работают идентично.
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from adapterkit.clientkit.ports import (
|
|
8
|
+
RequestPort,
|
|
9
|
+
ResponseLike,
|
|
10
|
+
SecretLookup,
|
|
11
|
+
TransportUnavailable,
|
|
12
|
+
resolve_transport,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"RequestPort",
|
|
17
|
+
"ResponseLike",
|
|
18
|
+
"SecretLookup",
|
|
19
|
+
"TransportUnavailable",
|
|
20
|
+
"resolve_transport",
|
|
21
|
+
]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Тонкий алиас — код переехал в ``adapterkit.clientkit.white`` (волна 5,
|
|
2
|
+
задача 2, Atlas #2710). Реэкспорт ради back-compat: ``from clientkit.white
|
|
3
|
+
import WhiteApiClient`` работает идентично.
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from adapterkit.clientkit.white import WhiteApiClient
|
|
8
|
+
|
|
9
|
+
__all__ = ["WhiteApiClient"]
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "s-clientkit"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "КИТ-АЛИАС: код-сборщик клиента переехал в adapterkit.clientkit (волна 5, задача 2, Atlas #2710) — этот пакет тонко реэкспортирует его модули под прежними именами (clientkit.identity и остальные)."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
authors = [{ name = "Dmitry" }]
|
|
13
|
+
# СЛИЯНИЕ В ADAPTERKIT (волна 5, задача 2, Atlas #2710). Живой код (сборщик
|
|
14
|
+
# клиента по декларации, каталог имён сервисов, адреса-кандидаты) переехал в
|
|
15
|
+
# `adapterkit.clientkit` — там же, где уже жил `EndpointRegistry`, которым
|
|
16
|
+
# кандидаты и раньше пользовались (extra `endpoints`). Этот пакет остался
|
|
17
|
+
# ТОНКИМ АЛИАСОМ: каждый модуль `clientkit.*` — реэкспорт одноимённого модуля
|
|
18
|
+
# `adapterkit.clientkit.*`. `s-adapterkit` поэтому — ОБЯЗАТЕЛЬНАЯ зависимость
|
|
19
|
+
# (не extra): даже самый частый путь потребителя, `from clientkit.identity
|
|
20
|
+
# import CATALOG` (reverse-factory), теперь физически лежит в adapterkit, и
|
|
21
|
+
# без него алиас не соберётся, никакой extra тут не спасает.
|
|
22
|
+
#
|
|
23
|
+
# netkit остаётся ОБЯЗАТЕЛЬНЫМ по той же причине, что и раньше: белый путь
|
|
24
|
+
# (`WhiteApiClient`, за ним ходит и `build_client`/`build_from_toml`) поднимает
|
|
25
|
+
# транспорт и лимиты только через netkit — но теперь это `adapterkit[client]`.
|
|
26
|
+
dependencies = [
|
|
27
|
+
"s-corekit>=0.0.2",
|
|
28
|
+
"s-adapterkit[client]>=0.2.0,<0.3",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
# Скрытый API: сессии, чеканка через порт, лестница деградации — теперь
|
|
33
|
+
# `adapterkit[client-hidden]` (сам модуль `adapterkit.clientkit.hidden`).
|
|
34
|
+
hidden = ["s-adapterkit[client-hidden]>=0.2.0,<0.3"]
|
|
35
|
+
# Back-compat no-op: адреса-кандидаты (`clientkit._candidates` ->
|
|
36
|
+
# `adapterkit.clientkit._candidates`) поверх `EndpointRegistry` теперь ВСЕГДА
|
|
37
|
+
# доступны — оба модуля живут в одном пакете `s-adapterkit`, отдельно ставить
|
|
38
|
+
# больше нечего. Extra оставлен ПУСТЫМ (а не удалён), чтобы старый
|
|
39
|
+
# `pip install s-clientkit[endpoints]` не падал `ExtraNotFound`.
|
|
40
|
+
endpoints = []
|
|
41
|
+
http = ["httpx>=0.27"]
|
|
42
|
+
dev = ["pytest>=8", "pytest-asyncio>=0.24", "ruff>=0.8"]
|
|
43
|
+
|
|
44
|
+
[tool.hatch.build.targets.wheel]
|
|
45
|
+
packages = ["clientkit"]
|
|
46
|
+
|
|
47
|
+
[tool.ruff]
|
|
48
|
+
line-length = 100
|
|
49
|
+
target-version = "py311"
|
|
50
|
+
src = ["."]
|
|
51
|
+
|
|
52
|
+
[tool.ruff.lint]
|
|
53
|
+
select = ["E", "F", "I", "B", "UP", "N", "SIM", "RUF"]
|
|
54
|
+
ignore = ["RUF002", "RUF003", "RUF022"]
|
|
55
|
+
|
|
56
|
+
[tool.ruff.lint.per-file-ignores]
|
|
57
|
+
# Русская проза В СТРОКАХ (тексты отказов и сообщения провалов): RUF001 ловит
|
|
58
|
+
# там «двусмысленную» латиницу пачками, а защищать нечего — маркеры-улики живут
|
|
59
|
+
# в corekit.diagnosis и проходятся его тестами.
|
|
60
|
+
"tests/*.py" = ["RUF001"]
|
|
61
|
+
"clientkit/declaration.py" = ["RUF001"]
|
|
62
|
+
"clientkit/hidden.py" = ["RUF001"]
|
|
63
|
+
"clientkit/_base.py" = ["RUF001"]
|
|
64
|
+
"clientkit/ports.py" = ["RUF001"]
|
|
65
|
+
"clientkit/identity.py" = ["RUF001"]
|
|
66
|
+
"clientkit/white.py" = ["RUF001"]
|
|
67
|
+
# Ленивый фасад (PEP 562): `__all__` собирается из `_LAZY_NAMES` в рантайме,
|
|
68
|
+
# статически ruff его не видит и считает TYPE_CHECKING-реэкспорты «неиспользуемыми».
|
|
69
|
+
"clientkit/__init__.py" = ["F401"]
|
|
70
|
+
# scripts/release_guard.py и scripts/check_dist_leaks.py копируются буквально
|
|
71
|
+
# из общего канона tools/kits/template/ (devcontour) — правка точечно в ките
|
|
72
|
+
# сломает сверку `apply_template.py --check` у всех китов экосистемы. Русская
|
|
73
|
+
# проза в их строках — та же намеренная кириллица, что и выше.
|
|
74
|
+
"scripts/*.py" = ["RUF001"]
|
|
75
|
+
|
|
76
|
+
[tool.pytest.ini_options]
|
|
77
|
+
asyncio_mode = "auto"
|
|
78
|
+
testpaths = ["tests"]
|
|
79
|
+
pythonpath = ["."]
|
|
@@ -86,7 +86,10 @@ async def test_burst_passes_first_calls_then_gate_waits(monkeypatch: pytest.Monk
|
|
|
86
86
|
waits.append(seconds)
|
|
87
87
|
clock.now += seconds # «поспали» — часы гейта должны это увидеть на следующем acquire
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
# `clientkit._base` — тонкий алиас (волна 5, задача 2, Atlas #2710): сам
|
|
90
|
+
# объект `ServiceClientBase` живёт в `adapterkit.clientkit._base`, и именно
|
|
91
|
+
# там смотрит на `asyncio.sleep` (тот же класс, что импортирован выше).
|
|
92
|
+
monkeypatch.setattr("adapterkit.clientkit._base.asyncio.sleep", fake_sleep)
|
|
90
93
|
|
|
91
94
|
await client.call("me") # в пределах burst — без ожидания
|
|
92
95
|
assert waits == []
|
|
@@ -200,13 +200,26 @@ async def test_placeholders_and_method_come_from_the_declaration():
|
|
|
200
200
|
# --------------------------------------------------------------------------- #
|
|
201
201
|
# 2. ЦЕНА ВЫЗОВА: белый путь ничего лишнего не поднимает #
|
|
202
202
|
# --------------------------------------------------------------------------- #
|
|
203
|
+
# После слияния clientkit -> adapterkit.clientkit (волна 5, задача 2, Atlas
|
|
204
|
+
# #2710) `import adapterkit` (а с ним и `librarykit.contract`) стал БАЗОВОЙ
|
|
205
|
+
# ценой любого вызова `clientkit.build_from_toml` — сборщик теперь физически
|
|
206
|
+
# лежит внутри adapterkit. Это НЕ то же самое, что «поднять оркестратор
|
|
207
|
+
# целиком»: `adapterkit`/`librarykit.contract` — тонкие DTO/Protocol-модули без
|
|
208
|
+
# сети, браузера и антибота (см. ЯДРО-контракты `[tool.importlinter]` в
|
|
209
|
+
# adapterkit/pyproject.toml). Настоящая цена, которую белый путь платить НЕ
|
|
210
|
+
# должен, — слой доступа скрытого API и всё тяжёлое окружение ниже.
|
|
211
|
+
#
|
|
212
|
+
# `authkit_client.sessions` (хранилище сессий) сюда НЕ входит: он приезжает
|
|
213
|
+
# ЕЩЁ РАНЬШЕ, самим `librarykit.sessions` (self-alias на `authkit_client.sessions`
|
|
214
|
+
# в `librarykit/__init__.py`) — то есть уже базовой ценой `import adapterkit`,
|
|
215
|
+
# а не решением клиента-сборщика. `authkit_client.ports` (порт ЧЕКАНКИ) —
|
|
216
|
+
# другое дело: librarykit его eager не тянет, и он должен остаться СВЯЗАН
|
|
217
|
+
# именно со скрытым путём (см. `adapterkit.clientkit.hidden._do_mint`).
|
|
203
218
|
FORBIDDEN_ON_WHITE = (
|
|
204
|
-
"authkit_client.sessions", # хранилище сессий
|
|
205
219
|
"authkit_client.ports", # порт чеканки
|
|
206
|
-
"clientkit.hidden", # весь скрытый путь
|
|
207
|
-
"clientkit._candidates",
|
|
208
|
-
"adapterkit", # реестр
|
|
209
|
-
"librarykit",
|
|
220
|
+
"adapterkit.clientkit.hidden", # весь скрытый путь
|
|
221
|
+
"adapterkit.clientkit._candidates",
|
|
222
|
+
"adapterkit.endpoints", # реестр адресов-кандидатов (не нужен белому)
|
|
210
223
|
"browserkit",
|
|
211
224
|
"playwright",
|
|
212
225
|
"nodriver",
|
|
@@ -263,8 +276,8 @@ def test_white_path_initialises_nothing_it_does_not_need():
|
|
|
263
276
|
)
|
|
264
277
|
assert snap["loaded"] == [], (
|
|
265
278
|
f"белый путь поднял лишнее: {snap['loaded']}. Ищи импорт на уровне модуля "
|
|
266
|
-
"в clientkit/builder.py или clientkit/white.py —
|
|
267
|
-
"подтягиваться ВНУТРИ ветки HIDDEN."
|
|
279
|
+
"в adapterkit/clientkit/builder.py или adapterkit/clientkit/white.py — "
|
|
280
|
+
"скрытая машинерия обязана подтягиваться ВНУТРИ ветки HIDDEN."
|
|
268
281
|
)
|
|
269
282
|
assert snap["requests"] == 1, (
|
|
270
283
|
f"белый вызов стоил {snap['requests']} запросов вместо одного — "
|
|
@@ -278,9 +291,9 @@ def test_hidden_path_does_load_the_access_layer():
|
|
|
278
291
|
Если бы «ничего не загружено» было верно и для скрытого, предыдущий тест
|
|
279
292
|
доказывал бы лишь то, что мы разучились импортировать.
|
|
280
293
|
"""
|
|
281
|
-
snap = _measure(_BUILD_HIDDEN, ("clientkit.hidden", "authkit_client.ports"))
|
|
294
|
+
snap = _measure(_BUILD_HIDDEN, ("adapterkit.clientkit.hidden", "authkit_client.ports"))
|
|
282
295
|
assert snap["result"] == PAYLOAD
|
|
283
|
-
assert "clientkit.hidden" in snap["loaded"], (
|
|
296
|
+
assert "adapterkit.clientkit.hidden" in snap["loaded"], (
|
|
284
297
|
f"скрытый путь не поднял свой модуль: {snap['loaded']}"
|
|
285
298
|
)
|
|
286
299
|
|