Миграция между альфами#

Eazy SDK в альфе переименовывает без deprecated-алиасов: старое имя исчезает, ImportError или AttributeError показывает, что именно нужно поменять. Эта страница служит единственной подсказкой. Каждая строка таблицы проверяется тестом: «стало» импортируется, «было» отсутствует.

Один пакет вместо десяти (0.2.0a8)#

Ядро и все интеграции поставляются одним пакетом eazy-sdk-core. Имена импорта не изменились: eazy_sdk, eazy_sdk_html, eazy_sdk_browser и остальные остаются прежними. Меняется только команда установки.

Было

Стало

eazy-sdk[httpx,pydantic]

eazy-sdk-core[httpx,pydantic]

eazy-sdk-openapi[yaml]

eazy-sdk-core[openapi,yaml]

eazy-sdk-asyncapi[yaml]

eazy-sdk-core[asyncapi,yaml]

eazy-sdk-browser[playwright]

eazy-sdk-core[browser,playwright]

eazy-sdk-sqlmodel

eazy-sdk-core[sqlmodel]

eazy-sdk-presets

eazy-sdk-core[presets]

eazy-sdk-adaptix

eazy-sdk-core[adaptix]

eazy-sdk-xml

eazy-sdk-core[xml]

Дополнение ставит сторонние библиотеки интеграции. Её код уже лежит в пакете, поэтому без дополнения импорт интеграции завершится ImportError с именем недостающей библиотеки.

Куки сессии: один способ (0.2.0a11)#

Куку, которую поставил сайт, библиотека несёт сама: корень SDK объявляет Cookies(...), а набор кук принадлежит Identity. Все прежние способы отправить такую куку удалены.

Было

Стало

eazy_sdk.auth.session_cookie

eazy_sdk.auth.Cookies

eazy_sdk.auth.Placed.cookie

eazy_sdk.auth.Cookies

eazy_sdk.auth.Placed.cookies

eazy_sdk.auth.Cookies

eazy_sdk.auth.cookies.parse_session_cookie

eazy_sdk.response.FromCookie

eazy_sdk.auth.cookies.HttpCookieSession

eazy_sdk.cookies.StoredCookie

eazy_sdk_browser.BrowserCookie

eazy_sdk.cookies.StoredCookie

eazy_sdk_browser.browser_cookie_auth

eazy_sdk.cookies.CookieState

eazy_sdk_browser.BrowserCookieBridge

eazy_sdk.cookies.CookieState

eazy_sdk_browser.CookieAuthAdopter

eazy_sdk.cookies.CookieState

Что поменять в коде:

  • Сессия на куках. Вместо session_cookie("sid", ...) объявите на корне cookies = Cookies(required=("sid",)) и обычную session_scheme(Model). Модель может не размещать ничего, если вся сессия живёт в куках.

  • Поля для кук в шагах входа. Удалите FromCookie в ответе и Cookie[str] в следующем запросе, если они только переносили куку сайта. FromCookie остаётся для значения, которое нужно как данные.

  • Браузерная сессия для HTTP. Вместо browser_cookie_auth(state, scheme, "sid") передайте Identity(cookies=CookieState(state.cookies)).

  • Запись куки. StoredCookie.domain пишется без ведущей точки. Куку для домена с поддоменами задаёт host_only=False; точка в домене приводит к ValueError.

  • Своё хранилище сессий. SessionStore.save получил необязательный аргумент cookies. Хранилищу токенной сессии менять нечего; хранилищу сайта с куками аргумент нужен.

  • База eazy_sdk_sqlmodel. Таблица сессий получила колонку. Для уже созданной базы выполните ALTER TABLE sessions ADD COLUMN cookie_state JSON.

  • Сохранённые браузерные сессии прежнего формата не читаются: по ним выполняется вход.

Переход с 0.2.0a5 на 0.3.0#

Корень SDK стал отдельным типом. SyncApi и AsyncApi являются роутерами: операции и атрибуты сервиса (base_url, errors, security, signing, crypto, wire, signed, allow). Композиция, владение клиентами и привязки живут в SyncRoot/AsyncRoot; api_group(...) объявляется только на корне. Подробности: Мультисервисный SDK.

Было

Стало

Комментарий

eazy_sdk.SyncApi.from_handler

eazy_sdk.SyncRoot.from_handler

Фабрика переехала на корень; она же создаёт и закрывает свой клиент.

eazy_sdk.AsyncApi.from_handler

eazy_sdk.AsyncRoot.from_handler

То же для async.

eazy_sdk.SyncApi.from_client

eazy_sdk.SyncRoot

Второго способа собрать корень нет: ShopSdk(client) вызывает обычный конструктор.

eazy_sdk.AsyncApi.from_client

eazy_sdk.AsyncRoot

То же для async.

eazy_sdk.SyncApi.close

eazy_sdk.SyncRoot.close

Роутер ничем не владеет; закрывает ресурсы корень.

eazy_sdk.AsyncApi.aclose

eazy_sdk.AsyncRoot.aclose

То же для async.

eazy_sdk.ApiDefaults

eazy_sdk.SyncApi

Дефолты роутера стали обычными атрибутами класса и наследуются по MRO.

Аутентификация уехала из транспорта в session scope. Identity объявляет auth-схемы, ключи подписи, DI и observer; он передаётся корню (ShopSdk(client, identity=…)) или отдельному роутеру (UsersApi(client, identity=…)). Один Identity обслуживает все сервисы корня как при общем клиенте, так и при отдельном клиенте у каждого сервиса.

Было

Стало

Комментарий

eazy_sdk.ClientConfig.auth

eazy_sdk.Identity.auth

Кортеж настроенных Auth; session_auth(...)/SessionScheme.configure(...) не изменились.

eazy_sdk.ClientConfig.key_provider

eazy_sdk.Identity.key_provider

Алгоритм подписи входит в контракт API; ключ остаётся секретом вызывающей стороны.

eazy_sdk.ClientConfig.dependencies

eazy_sdk.Identity.dependencies

DI зависит от окружения вызова, а не от пула соединений.

eazy_sdk.ClientConfig.observer

eazy_sdk.Identity.observer

Наблюдатель следует за вызывающей стороной.

eazy_sdk.Client.bind_sdk

eazy_sdk.Identity

Фабрику scoped SDK регистрирует тот, кому передан identity=.

Корень eazy_sdk экспортирует 39 имён вместо 55: то, что нужно автору SDK в первый час. Всё остальное импортируется из своего модуля. Это не сокрытие, а отказ от второго имени для одной вещи.

Было

Стало

Комментарий

eazy_sdk.ModelAdapter

eazy_sdk.models.ModelAdapter

Вместе с ModelAdapterRegistry, ModelField, default_model_adapters и ошибками адаптеров.

eazy_sdk.BodyCodec

eazy_sdk.codecs.BodyCodec

Вместе с ScalarCodec и DelimitedScalarCodec.

eazy_sdk.PlanError

eazy_sdk.core.errors.PlanError

Вместе с BindingError, GraphError, PatchError, OperationBindingError.

eazy_sdk.UnsafeReplayError

eazy_sdk.clients.UnsafeReplayError

Вместе с AttemptLimitError и RedirectLimitError.

eazy_sdk.CapabilityMismatchError

eazy_sdk.handlers.CapabilityMismatchError

eazy_sdk.MiddlewareProtocolError

eazy_sdk.middleware.MiddlewareProtocolError

eazy_sdk.PreparationIncompleteError

eazy_sdk.preparation.PreparationIncompleteError

Вместе с PreparedValue.

eazy_sdk.ResponseExtractor

eazy_sdk.response.ResponseExtractor

Вместе с AmbiguousResponseError и MalformedResponseError.

eazy_sdk.core.ports.CryptoProfile

eazy_sdk.compile.http_compiler.CryptoProfile

Порт переехал к единственному читателю; слоя ради разрыва импорта больше нет.

Синхронный клиент больше не создаёт event loop: тот же конвейер шагается на вызывающем потоке. Client теперь можно вызывать из кода, где loop уже работает; взамен колбэк, который сам уходит в сеть через await, поднимает SynchronousSuspensionError вместо того, чтобы молча крутиться в приватном loop.

Было

Стало

Комментарий

eazy_sdk.clients.EventLoopConflictError

eazy_sdk.clients.SynchronousSuspensionError

Ошибка сменила причину: не «loop уже работает», а «этот колбэк действительно приостанавливается».

ClientConfig перестал быть плоским списком из пятнадцати полей: остались три группы по владельцу плюс host-scoped crypto (его судьба решается в фазе 48). guards= понижается фабрикой Security.of(...), а не мутацией frozen-объекта в __post_init__.

Было

Стало

Комментарий

eazy_sdk.ClientConfig.retry

eazy_sdk.Resilience.retry

Вместе с auth_retries, max_redirects, timeout и rate_limiter.

eazy_sdk.ClientConfig.timeout

eazy_sdk.Resilience.timeout

Валидация бюджетов переехала в группу.

eazy_sdk.ClientConfig.rate_limiter

eazy_sdk.Resilience.rate_limiter

eazy_sdk.ClientConfig.protection

eazy_sdk.Security.protection

Пустой ProtectionBundle вместо None; ClientConfig.bundle не изменился.

eazy_sdk.ClientConfig.guards

eazy_sdk.Security.of

Публичного поля, которое всегда пусто, больше нет.

eazy_sdk.ClientConfig.middleware

eazy_sdk.Hooks.middleware

eazy_sdk.ClientConfig.models

eazy_sdk.Serialization.models

Библиотека моделей относится к реализации SDK и объявляется на корне.

eazy_sdk.ClientConfig.profile

eazy_sdk.request.Wire

WireProfile был наполовину мёртв: фаза 48 заменила его контрактом представления на операции.

Слово «wire» теперь означает ровно одно понятие: представление запроса на проводе. Всё, что влияет на байты, объявляется одним Wire на операции (и наследуется от роутера и миксина сервиса); всё, что не влияет, задаётся одним Serialization на корне. Подпись указывается только по месту: адресных правил sign(scope=…) больше нет, потому что опечатка в hosts= оставляла запрос молча неподписанным. Подробности: Представление запроса.

Было

Стало

Комментарий

eazy_sdk.request.WireOptions

eazy_sdk.request.Wire

order=FieldOrder(query=…, header=…, cookie=…, body=…), exact=, transport=.

eazy_sdk.request.SigningRule

eazy_sdk.request.hmac_sha256

Подпись объявляет операция или роутер параметром signing=; scoped-правил нет.

eazy_sdk.request.SigningOverride

eazy_sdk.SyncApi

Переопределение задаётся объявлением на более специфичном роутере.

eazy_sdk.crypto.CryptoWire

eazy_sdk.crypto.Encrypted

Тип шифрованного представления; у HTTP-операции это wire=Wire(encrypted=…).

eazy_sdk.crypto.CryptoRule.wire

eazy_sdk.crypto.CryptoRule.encrypted

Одно имя используется для одного понятия и в HTTP, и в WebSocket; ws.call(encrypted=…) использует его же.

Новое без замены: eazy_sdk.serialization.Serialization(json=…, documents=(…,)) задаёт JSON-бэкенд и парсер документов объявляются на корне, а бэкенд, не способный выполнить контракт операции, отвергается при компиляции, а не молча меняет байты.

Понятие конверта уехало из транспорта: Envelope, ProtocolMessage, CorrelationKey, ChannelKey, ControlKind и InboundMessageKind живут в eazy_sdk.protocols и описывают протокол прикладного уровня, а не WebSocket. WsProtocol объединяет Envelope с тем, что есть только у соединения. Подробности: Протоколы и конверты.

Было

Стало

Комментарий

eazy_sdk.websocket.CorrelationKey

eazy_sdk.protocols.CorrelationKey

Вместе с ChannelKey.

eazy_sdk.websocket.ProtocolMessage

eazy_sdk.protocols.ProtocolMessage

Вместе с ControlKind и InboundMessageKind.

Новое без замены: eazy_sdk.protocols.JsonRpc и @api.rpc("method") позволяют описать сервис, у которого имя метода лежит в теле, так же, как REST; rpc_result, rpc_error(code, model) и rpc_error_default(model) строят обычные Success/Error, второй модели ошибок не появляется. Реализация WsProtocol получает метод read(envelope), куда переезжает прежняя логика inspect(frame) после декодирования кадра.

Новое без замены: eazy_sdk.bind и eazy_sdk.Binding задают привязку роутера или его миксина к другому клиенту и/или адресу при сборке (bindings=(...)).

Операция стала классом. Поля класса являются полями запроса, а __http__ содержит всё, что операция объявляет, а op(...) публикует её на роутере. Декоратор остался короткой формой того же самого: он синтезирует такой же frozen-класс. Причина заключается не в стиле: у TypedDict нет значений по умолчанию и нет default_factory, а у класса есть, и сам запрос становится значением, которое можно построить, изменить и отправить. Подробности: Запросы и Запрос как значение.

Было

Стало

Причина

def op(self, **request: Unpack[Req]) -> T

класс Op(HttpOperation[T]) вместе с op(Op)

defaults и default_factory, запрос как значение

responses=Responses(…)

success=…, errors=…, fallback=…

один способ вместо трёх

response=Json()

return-аннотация операции либо success={200: Model}

семья выводится из модели

Annotated[int, Query()]

Query[int] или Annotated[int, markers.Query("name")]

короткая форма

eazy_sdk.Path (дата-класс)

eazy_sdk.request.markers.Path

корневые имена стали алиасами

eazy_sdk.request.Query (дата-класс)

eazy_sdk.request.markers.Query

то же для остальных маркеров

Inject(JsonField("x"), dep)

Inject(markers.JsonField("x"), dep)

то же

Wire(projection=…)

projection=BodyProjection(target=…, using=…, encoding=…) в __http__

проекция описывает представление, а не байтовый контракт

BodyProjection(source=TypedDict, ...)

source опускается, поскольку источником служит класс операции

одно объявление полей

eazy_sdk.Responses

eazy_sdk.response.Responses

бюджет корня; вместе с Success и Error

eazy_sdk.Text

eazy_sdk.response.Text

вместе с Bytes

Error(404, Json(Problem), exception=NotFound)

errors={404: NotFound} при class NotFound(ApiError[Model])

модель объявлена один раз

Error(..., exception=factory)

errors={404: (Model, factory)}

без наследования от библиотеки

eazy_sdk.response.JsonResponse

eazy_sdk.response.Json

одно имя для одного понятия

eazy_sdk.serialization.Serialization.html

eazy_sdk.serialization.Serialization.documents

несколько документных бэкендов, выбор по медиа

eazy_sdk.websocket.WsOperationKind

eazy_sdk.websocket._messages.WsOperationKind

плумбинг рантайма ушёл из публичной поверхности

eazy_sdk.websocket.RuntimeComposition

eazy_sdk.websocket.composition.RuntimeComposition

то же

eazy_sdk.websocket.FrameLimits

eazy_sdk.websocket.frames.FrameLimits

то же, вместе с frame_from_zapros/frame_to_zapros

eazy_sdk.response.HtmlExtractor

eazy_sdk.response.cases.HtmlExtractor

вместе с JsonExtractor

eazy_sdk.request.TransportProtocol

eazy_sdk.request.wire.TransportProtocol

читает компилятор, не автор SDK

eazy_sdk.crypto.ResolvedCrypto

eazy_sdk.crypto.core.ResolvedCrypto

результат компиляции, не объявление

@ws.call("event") async def f(self, *, ...)

по-прежнему работает; доступен класс F(WsCall[T]) вместе с op(F)

классы и для WebSocket

ApiError.context после pickle

ApiError.summary (ErrorSummary)

сводка вместо тела ответа и заголовков

Новое без замены: Omittable[T] = UNSET служит единственным способом не отправить поле; unwrap = "/data" на сервисе снимает конверт один раз; ClientConfig(errors={host: {...}}) задаёт ошибки, которыми хост отвечает любому SDK; RpcOperation/Rpc в eazy_sdk.protocols и WsCall/WsSubscribe/ WsSend/Ws в eazy_sdk.websocket предоставляют те же классы для других протоколов; eazy-sdk-adaptix предоставляет центральный Retort как адаптер моделей.

Переход с 0.2.0a4 на 0.2.0a5#

Было

Стало

Комментарий

eazy_sdk.protection.advanced.ChallengeMalformedError

eazy_sdk.protection.advanced.ChallengeParseError

Рантайм-ошибка «челлендж распознан, но не разобран». Детекторная MalformedChallengeError не изменилась.

eazy_sdk.handlers.EmitOptions.proxy

eazy_sdk.handlers.HandlerProfile.proxy

Proxy объявляет handler (Client.httpx(proxy=...) и др.), а не per-call опции. Поля verify_tls/stream_response удалены: их никто не читал.

eazy_sdk.codegen.session_auth

eazy_sdk.codegen.generated_session_auth

Codegen-хелпер получил своё имя; eazy_sdk.auth.session_auth является другой authoring-функцией.

eazy_sdk.codegen.session_scheme

eazy_sdk.codegen.generated_session_scheme

То же для схемы. Сгенерированные модули нужно перегенерировать.

extra eazy-sdk-html[parsel]

зависимость eazy-sdk-html

parsel стал обязательной зависимостью плагина; pip install "eazy-sdk-core[html]" достаточно.

Новые параметры без брейков: proxy= у Client.httpx/requests/curl_cffi и AsyncClient.httpx/curl_cffi, SolveContext.remaining().

Переход с 0.2.0a3 на 0.2.0a4#

Фасад и клиенты#

Было

Стало

Комментарий

eazy_sdk.SyncSdk

eazy_sdk.SyncApi

Корневой фасад слит с API-классом: api_group, from_client, from_handler.

eazy_sdk.AsyncSdk

eazy_sdk.AsyncApi

То же для async.

eazy_sdk.Client.get

eazy_sdk.Client.request

Сырые verb-методы (get/post/...) удалены; остался request(method, url, ...).

eazy_sdk.AsyncClient.post

eazy_sdk.AsyncClient.request

То же для async.

eazy_sdk.ClientConfig.challenge_policies

eazy_sdk.Security.of

Guard’ы и presets ставятся через security=Security.of(...) (в 0.2.0a4 это было guards=[...]).

eazy_sdk.ClientConfig.challenge_solvers

eazy_sdk.Security.protection

Advanced-политики и solver-биндинги входят в одну группу ProtectionBundle.

eazy_sdk.clients.AttemptLimitExceeded

eazy_sdk.clients.AttemptLimitError

Единый суффикс *Error.

eazy_sdk.clients.RedirectLimitExceeded

eazy_sdk.clients.RedirectLimitError

eazy_sdk.handlers.TransportFailure

eazy_sdk.handlers.TransportError

eazy_sdk.exceptions.EazySDKError

eazy_sdk.exceptions.EazySdkContextError

Базой всех исключений служит eazy_sdk.core.errors.EazySdkError.

Protection#

Было

Стало

Комментарий

eazy_sdk.protection.advanced.ChallengeSolverBindings

eazy_sdk.protection.advanced.SolverBindings

Один реестр биндингов.

eazy_sdk.protection.advanced.ProtectionSolver

eazy_sdk.protection.advanced.ChallengeSolver

Один протокол солвера.

eazy_sdk.protection.advanced.SolutionCookieSet

eazy_sdk.protection.advanced.PrivateCookieSetBinding

Фабрика solution_cookie_set() осталась.

Простой путь теперь использует класс Guard из eazy_sdk.protection и Security.of(...).

Вынесенные пакеты#

Было

Стало

Комментарий

eazy_sdk.extraction.CSS

eazy_sdk_html.CSS

Плагин eazy-sdk-html (pip install "eazy-sdk-core[html]").

eazy_sdk.extraction.XPath

eazy_sdk_html.XPath

eazy_sdk.extraction.Scope

eazy_sdk_html.Scope

eazy_sdk.accounts.storage.MemoryStorage

eazy_sdk_accounts.storage.MemoryStorage

Плагин eazy-sdk-accounts (pip install "eazy-sdk-core[accounts]").

eazy_sdk.accounts.registration

eazy_sdk_accounts.registration

eazy_sdk._internal

eazy_sdk.core

Ядро (kernel, errors, http, http_plan, ports) и компилятор eazy_sdk.compile.

Storage-хуки переименованы из middleware в observers: StorageObserver, LoggingObserver, EventRecordingObserver, параметр observers=.