Skip to main content

Imager Client — Python

Клиент микросервиса Imager на Python: построение путей/URL ассетов и админ-методы.


Установка

Пакет imager_client (Python ≥ 3.10, без внешних зависимостей):

pip install imager_client

Или из репозитория:

pip install git+https://gitverse.ru/pkg-ru/imager-client

Импорт

from imager import Imager
from imager import AssetType, AssetPath, ImagerOptions, ImagerServerOptions, Segment

Инициализация

imager = Imager(options: ImagerOptions | dict | None = None)
Опция Тип По умолчанию Описание
token str "" токен админ-методов (только AdminGenerate/AdminDelete)
dpr int 0 итоговое dpr по умолчанию; 0-1 — не используется, 2-3 — используется
format str "" формат генерации по умолчанию (пусто — формат исходника)
formats list[str] [] список форматов по умолчанию; если пуст — используется format
baseURL str "/" база URL ассетов; нормализуется (всегда с завершающим /)
adminURL str "" базовый URL админ-API (без завершающего /)

Нормализация baseURL: пустой/не задан → "/"; без завершающего / → добавляется. adminURL: завершающий / удаляется.

imager = Imager({
    "baseURL": "https://imgs.example.com/images",
    "format": "webp",
    "dpr": 2,
    "token": "secret",
    "adminURL": "https://imager.example.com",
})

Методы

GetAsset

def GetAsset(
    self,
    source: str,
    segment: Segment | None = None,
    format: str | None = None,
    dpr: int | str | None = None,
) -> AssetType: ...

Возвращает один AssetType. paths содержит все варианты dpr от 1 до итогового.

Параметр Тип Описание
source str путь к исходнику (/test.gif, test.gif, thumbs/photo.jpg)
segment str | {width,height} | [w,h] | None сегмент; не задан → "x"
format str | None итоговый формат; не задан → настройки format → формат исходника
dpr int | str | None итоговое dpr; не задан → настройки dpr; < 1 → не используется

GetAssets

def GetAssets(
    self,
    source: str,
    segments: Segment | list[Segment] | None = None,
    formats: str | list[str] | None = None,
    dprs: int | str | None = None,
) -> list[AssetType]: ...

Возвращает список AssetType — по одному на каждый формат (все ассеты с одинаковым типом объединяются в один AssetType). Внутри paths порядок сегмент-мажорный: для каждого сегмента все dpr-шаги подряд. dpr каждого пути пересчитывается из фактических размеров: база — ширина (или высота) первого участника с известным размером, dpr = фактическая ширина / базовая ширина. segments не задан → ["x"]. formats не задан → настройки formats → [format] → [формат исходника].

GetAssetsHtml

def GetAssetsHtml(
    self,
    source: str,
    segments: Segment | list[Segment] | None = None,
    formats: str | list[str] | None = None,
    dprs: int | str | None = None,
    options: dict | None = None,
) -> str: ...

Возвращает строку — HTML-разметку <picture>/<img> по тем же ассетам, что и GetAssets (ассеты группируются по типу). Один вызов генерирует ровно один тег <picture> (или <img>, если формат один).

options — HTML-атрибуты:

Атрибут Куда попадает Примечание
class, id, data-*, прочие <picture> —
alt, sizes, loading <img> —
decoding, fetchpriority <img> нативные атрибуты <img> (async-декодирование, приоритет загрузки)
lazy <img> булев: превращается в loading="lazy"
width, height <img> перекрываются автоматическими значениями из базового path (для CLS)
imgAttrs <img> объект атрибутов, попадающих именно на <img>; объединяется с перенаправленными атрибутами, имеет приоритет

Правила:

  • Атрибуты выводятся в алфавитном порядке имён (детерминированный вывод).
  • Булевы атрибуты (lazy: true, loading: true) — без значения; false/null — пропускаются.
  • Значения HTML-экранируются (& → &, < → <, > → >, " → ", ' → &#x27;).
  • Внутри <picture> теги делятся по типу (формату): все пути одного формата объединяются в один srcset.
  • Для <img> выбирается группа: 1) формат исходника (source_format: true); 2) первый поддерживаемый всеми браузерами (all_support: true); 3) последняя. Остальные форматы — <source type="...">.
  • srcset-дескрипторы: если в options передан sizes — w-режим: w-дескрипторы по ширине (200w, 400w); пути без ширины (сегмент x, оригинальный размер) в srcset не попадают — оригинал остаётся только в src у <img> как fallback; если в группе только x-пути — srcset пуст. Иначе — x-режим: x-дескрипторы по dpr (1x, 2x, 3x); если dpr нет, но есть высота — dpr вычисляется из отношения высот (дробные допустимы, напр. 1.5x); x-пути включаются в srcset с эвристикой max+1: max_dpr вычисляется только из размерных путей (у которых есть width или height); dpr-поля x-путей (шаги 1, 2, 3...) в расчёт не участвуют. Если размерные пути есть (max_dpr > 0) — дескриптор = (max_dpr + 1) × dpr-шаг (приблизительный, т.к. реальный размер оригинала неизвестен); если размерных путей нет, но есть dpr-шаги (dprs ≥ 2) — дескриптор = dpr-шаг (1x, 2x, 3x...); если нет ни размерных путей, ни dpr-шагов (dprs = 0) — путь в srcset без дескриптора (просто путь, без 1x). Размеры автоматически не генерируются.
  • <source> всегда содержит srcset (никогда src), даже при одном пути в группе; если srcset пуст (в w-режиме все пути — x) — <source> не выводится.
  • <img>: srcset добавляется только если путей > 1 и srcset не пуст; иначе у <img> только src.
  • width/height на <img> добавляются из базового (первого) path, если известны — для CLS. Если пользователь задал свои width/height (напрямую или через imgAttrs) — автоматические не добавляются (без дублирования).
  • imgAttrs объединяется с перенаправленными img-атрибутами (alt, sizes, loading, width, height, decoding, fetchpriority): значения из imgAttrs имеют приоритет. Сам ключ imgAttrs в <picture> не попадает.
  • Если ассетов нет — возвращается пустая строка.

Пример:

html = imager.GetAssetsHtml(
    "/test.png",
    "200x200",
    ["webp", "png"],
    2,
    {"class": "photo", "id": "main", "alt": "Hello & <world>", "lazy": True},
)
<picture class="photo" id="main">
    <source type="image/webp" srcset="/test-png/200x200.webp 1x, /test-png/200x200@2.webp 2x">
    <img src="/test-png/200x200.png" srcset="/test-png/200x200.png 1x, /test-png/200x200@2.png 2x" alt="Hello & <world>" loading="lazy" width="200" height="200">
</picture>

GetAssetPath

def GetAssetPath(
    self,
    source: str,
    segment: Segment | None = None,
    format: str | None = None,
    dpr: int | str | None = None,
) -> str: ...

Возвращает строку — URL основного варианта ассета. Эквивалент GetAsset(...).paths[0].path.

AdminGenerate

def AdminGenerate(
    self,
    target: str | AssetType | list[AssetType] | list[str],
    wait: bool = False,
) -> bool: ...

POST {adminURL}/admin/assets/generate, заголовок Authorization: Bearer <token>. Возвращает True при HTTP 200/202, иначе False.

AdminDelete

def AdminDelete(
    self,
    target: str | AssetType | list[AssetType] | list[str],
    wait: bool = False,
) -> bool: ...

DELETE {adminURL}/admin/assets/delete — то же тело и заголовок. Возвращает True при HTTP 200, иначе False.

Маппинг типов входа target

Тип входа target Режим Тело запроса
str A (source) {"source": "<строка как есть>", "wait": ...}
AssetType B (assets) {"assets": [paths[].path из AssetType], "wait": ...}
list[AssetType] B (assets) {"assets": [paths[].path из ВСЕХ AssetType, подряд], "wait": ...}
list[str] B (assets) {"assets": ["<элемент 1>", "<элемент 2>", ...], "wait": ...}
  • str — режим A: путь к исходнику передаётся в source как есть.
  • AssetType / list[AssetType] — режим B: собираются все paths[].path в один список assets.
  • list[str] — режим B: элементы — уже готовые пути к ассетам, передаются в assets как есть, без валидации и без преобразований.

Если token или adminURL пусты — админ-методы возвращают False без HTTP-запроса. HTTP-клиент — urllib.request (стандартная библиотека).

Segment

segment — строка как есть ("preset", "200x200", "200x", "x200", "x"), словарь {width, height} (оба необязательны), список/кортеж [width, height] (оба обязательны) или не задан → "x".

Вход Результат
"preset" "preset"
{"width": 200, "height": 200} "200x200"
{"width": 200} "200x"
{"height": 200} "x200"
{} / {"width": 0, "height": 0} "x"
[200, 200] "200x200"
[0, 400] "x400"

dpr

  • dpr/dprs — число или строка-цифра ("2").
  • Итог < 1 → не используется (один path-объект без суффикса и без поля dpr).
  • Итог = 1 (задан явно) → один path-объект без поля dpr (1x — дефолтный дескриптор; dpr: 1 добавляется только если в группе есть путь с dpr > 1).
  • Итог = 2 → [без суффикса, @2].
  • Итог = 3 → [без суффикса, @2, @3].
  • Итог > 3 → трактуется как 3.

Формат URL ассета

{baseURL}{path}/{source_name}-{source_format}/{segment}@{dpr}.{output_format}
  • path — логический путь исходника (ведущий / отбрасывается): /thumbs/photo.jpg → path="thumbs", name="photo", format="jpg".
  • source_format — расширение в нижнем регистре.
  • @{dpr} — добавляется к сегменту только при dpr ≥ 2.
  • output_format — итоговый формат (аргумент → настройки → формат исходника).

Структура AssetType

class AssetPath(TypedDict, total=False):
    path: str
    dpr: int
    width: int
    height: int

class AssetType(TypedDict):
    type: str
    paths: list[AssetPath]
    source_format: bool  # только при true
    all_support: bool    # только при true

Пример результата GetAsset("/test.gif", {"width": 200, "height": 200}, "gif", 2):

{
  "type": "image/gif",
  "paths": [
    {"path": "https://imgs.example.com/images/test-gif/200x200.gif", "width": 200, "height": 200},
    {"path": "https://imgs.example.com/images/test-gif/200x200@2.gif", "width": 400, "height": 400, "dpr": 2}
  ],
  "source_format": true,
  "all_support": true
}

Правила заполнения path-объектов:

  • path — полный URL, всегда.
  • dpr — при dpr ≥ 2; dpr: 1 — только если в группе есть путь с dpr > 1 (иначе 1x — дефолтный дескриптор, без поля).
  • width/height — только для size-сегмента (200x200, {w,h}, [w,h], x и т.п.); при dpr ≥ 2 умножаются на dpr. Для именованного пресета не добавляются.
  • type — MIME итогового формата; видео (mp4, webm, mov, mkv, avi, m4v) и неизвестный формат → "".
  • source_format — true, если итоговый формат совпадает с исходным форматом файла; в JSON присутствует только при true.
  • all_support — true, если итоговый формат ∈ {jpg, jpeg, gif, png} (поддерживается всеми браузерами); в JSON присутствует только при true.

MIME по формату

Формат MIME
jpeg, jpg image/jpeg
png image/png
webp image/webp
gif image/gif
avif image/avif
heif image/heif
heic image/heic
apng image/apng
jxl image/jxl

Разные варианты вызова

# segment: четыре формы записи
imager.GetAsset("/test.gif")                     # не задан → "x", формат исходника
imager.GetAsset("/test.gif", "thumb")            # строка: именованный пресет
imager.GetAsset("/test.gif", "200x200")          # строка: размер
imager.GetAsset("/test.gif", {"width": 200})     # dict: только ширина → "200x"
imager.GetAsset("/test.gif", {"height": 400})    # dict: только высота → "x400"
imager.GetAsset("/test.gif", (200, 200))         # кортеж → "200x200"

# format: строка или список, dpr: число или строка
imager.GetAsset("/test.gif", "200x200", "webp")          # + формат
imager.GetAsset("/test.gif", "200x200", "webp", 2)       # + dpr
imager.GetAsset("/test.gif", "200x200", "webp", "2")     # dpr строкой
imager.GetAssets("/test.gif", ["200x200", "x400"], ["webp", "gif"], 2)  # 2 ассета (по одному на формат)

Примеры

from imager import Imager

imager = Imager({"baseURL": "https://imgs.example.com/images/", "format": "webp"})

# Один ассет
asset = imager.GetAsset("/test.gif", {"width": 200, "height": 200}, "gif", 2)
print(asset["type"])   # image/gif
print(asset["paths"])  # [{'path': '.../200x200.gif', 'width': 200, 'height': 200},
                       #  {'path': '.../200x200@2.gif', 'width': 400, 'height': 400, 'dpr': 2}]

# Список ассетов (по одному AssetType на формат)
assets = imager.GetAssets("/test.gif", [{"width": 200, "height": 200}, {"height": 400}], ["webp", "gif"], 1)
print(len(assets))  # 2

# Только URL основного варианта
url = imager.GetAssetPath("/test.gif", "200x200", "webp")
print(url)  # https://imgs.example.com/images/test-gif/200x200.webp

# Админ-методы
admin = Imager({"token": "secret", "adminURL": "https://imager.example.com"})
ok = admin.AdminGenerate("/test.gif", wait=True)   # POST .../admin/assets/generate
ok = admin.AdminDelete(asset, wait=False)          # DELETE .../admin/assets/delete

Тесты

python test/test.py

Раннер читает test/fixture.json и выполняет golden-кейсы. Полный прогон всех языков — make test (оркестратор — go run test/test.go).

© 2025 Алтухов Владислав Владимирович

Metadata

Release files for imager-client 2.0.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for imager-client 2.0.5
File Size Uploaded
imager_client-2.0.5.tar.gz 74.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for imager-client 2.0.5
File Interpreter ABI Platform
imager_client-2.0.5-py3-none-any.whl Python 3 none any Details

Total release size: 121.1 kB

Release files / imager_client-2.0.5.tar.gz

Download URL imager_client-2.0.5.tar.gz
Size 74.8 kB
Tags Source
SHA-256 checksum
How to use checksums
d0dc16dd3de7775972a98cfd8fcaff5a1a74daf81827970d2ea4b1ad58fe4dea
BLAKE2b-256 checksum
How to use checksums
573eb144950186a9a4074428249b6fad0a7930ee9bb4283da84ff87abe2ae28d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Release files / imager_client-2.0.5-py3-none-any.whl

Download URL imager_client-2.0.5-py3-none-any.whl
Size 46.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4e21147982974ca838abbac2140a8074788affc5f81a39eb26cc581bcf788492
BLAKE2b-256 checksum
How to use checksums
825c54e1d2a4cd33d5f39a31ac5c6002123583bfa7985f8390a33c1091ea9cf8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Release history Release notifications | RSS feed

2.0.6

2 release files

This release

2.0.5 This release

2 release files

2.0.4

2 release files

2.0.3

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page