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)

Класс Imager использует __slots__ (фиксированный набор полей, без __dict__).

ImagerOptions vs ImagerServerOptions

  • ImagerOptions — TypedDict клиентской части: dpr, format, formats, baseURL, sort. Не содержит token/adminURL.
  • ImagerServerOptions(ImagerOptions) — расширяет его полями token, adminURL (для админ-методов).

Конструктор Imager принимает любой dict и читает из него все семь ключей (включая token/adminURL), поэтому для админ-методов можно передавать как ImagerServerOptions, так и обычный dict. Типизация ImagerOptions просто не описывает серверные ключи.

Опция Тип По умолчанию Описание
token str "" токен админ-методов (только AdminGenerate/AdminDelete); есть в ImagerServerOptions
dpr int 0 итоговое dpr по умолчанию; 0-1 — не используется, 2-3 — используется
format str "" формат генерации по умолчанию (""/"auto" — формат исходника; если исходник не картинка — jpg)
formats list[str] [] список форматов по умолчанию; если пуст — используется format; дубли удаляются (jpeg → jpg)
baseURL str "/" база URL ассетов; нормализуется (всегда с завершающим /)
adminURL str "" базовый URL админ-API (без завершающего /); есть в ImagerServerOptions
sort bool False сортировать размерные сегменты в GetAssets по width/height (см. ниже)

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

Сортировка сегментов (sort: true)

При sort: true сегменты в GetAssets сортируются до построения путей и вычисления dpr:

  1. Сегменты с width > 0 — по возрастанию width; при равном width — по возрастанию height.
  2. height = 0/отсутствует — в конец своей width-группы.
  3. Сегменты без width (x400, thumb) — в самый конец, между собой не сортируются (сохраняют исходный порядок).
  4. Если ни у одного сегмента нет ни width, ни height — сортировка не выполняется.
  5. dpr вычисляется после сортировки: первый (наименьший) размерный сегмент задаёт base_width/base_height, поэтому все коэффициенты ≥ 1.

Пример: ["300x", "100x100", "200x", "x400", "thumb"] → 100x100 → 200x → 300x → x400 → thumb.

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 итоговый формат; "auto"/"" → формат исходника (если исходник не картинка — jpg); не задан → настройки 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] → [формат исходника].

Список форматов дедуплицируется: jpeg нормализуется к jpg, дубли удаляются (первое вхождение сохраняет позицию). Элемент "auto" (или "") означает формат исходника; если исходник не картинка (видео, нет расширения) — подставляется jpg. Поддерживаемые форматы картинок: jpg, jpeg, png, webp, avif, heif, heic, apng, jxl, gif.

imager.GetAssets("/test.jpg", "100x100", ["webp", "avif", "jpg", "webp", "auto"])  # → webp, avif, jpg
imager.GetAssets("/test.jpg", "100x100", ["webp", "auto"])                         # → webp, jpg
imager.GetAssets("/test.jpg", "100x100", ["jpg", "auto"])                          # → jpg
imager.GetAssets("/test.mov", "100x100", ["jpg", "auto"])                          # → jpg
imager.GetAssets("/test.jpg", "100x100", ["webp", "jpg", "auto"])                  # → webp, jpg

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>; объединяется с перенаправленными атрибутами, имеет приоритет

Правила:

  • Атрибуты выводятся в порядке вставки (порядок ключей dict/options); никакой сортировки не выполняется.
  • Булевы атрибуты (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> не попадает.
  • Если ассетов нет — возвращается пустая строка.
  • Python-реализация при пустом результате GetAssets бросает IndexError (обращение к paths[0]) — известная особенность, см. README.

Пример:

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 | float
    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 итогового формата: всегда "image/" + format (для jpg — image/jpeg). Пустая строка невозможна: mime_for определён для любого формата.
  • source_format — true, если итоговый формат совпадает с исходным форматом файла; в JSON присутствует только при true.
  • all_support — true, если итоговый формат ∈ {jpg, jpeg, gif, png} (поддерживается всеми браузерами); в JSON присутствует только при true.

Функции форматов

Модуль imager.ImagerTypes экспортирует:

  • IMAGE_FORMATS — frozenset поддерживаемых форматов картинок: jpg, jpeg, png, webp, avif, heif, heic, apng, jxl, gif. Всё, что не входит в список (видео и прочее), при format="auto"/"" трактуется как не-картинка.
  • normalize_format(format) — нормализация: lower-case, jpeg → jpg.
  • resolve_format(format, source_format) — резолв одного формата: "auto"/"" → исходный формат, если он картинка, иначе jpg.
  • dedupe_formats(formats) — дедупликация списка форматов (jpeg → jpg, первое вхождение сохраняет позицию).
  • mime_for(format) — MIME по итоговому формату: всегда "image/" + format (для jpg — image/jpeg). Не входит в __all__ пакета, но доступен через from imager.ImagerTypes import mime_for.

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 ассета (по одному на формат)

Кэш source

Imager кэширует разбор последнего source (_src_cache: source → path, имя, формат, префикс). Повторные вызовы методов с тем же source переиспользуют разбор и работают быстрее. Кэш хранит только одну запись — при смене source происходит полный пересчёт. Это внутренняя оптимизация: на результат она не влияет.

Примеры

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.6

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.6
File Size Uploaded
imager_client-2.0.6.tar.gz 82.8 kB Details

Built distribution (wheel)

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

Total release size: 133.3 kB

Release files / imager_client-2.0.6.tar.gz

Download URL imager_client-2.0.6.tar.gz
Size 82.8 kB
Tags Source
SHA-256 checksum
How to use checksums
aaf1491cd63f61b7d082e92d79b9bd403d76599914c3b1eede28b02631f34a77
BLAKE2b-256 checksum
How to use checksums
da50d846eaddd2e3083c3ec76c4bdf4efbedae953b74e7e1490a126d97c865aa
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 17, 2026.

Transparency log

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

Download URL imager_client-2.0.6-py3-none-any.whl
Size 50.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c232c142dfdc14cc14a8435c027eb22a512d5cd28010340c40cf4a9accd576ce
BLAKE2b-256 checksum
How to use checksums
2d331ae7ba4e97e10db11a229f49f2f0a5ed809cf1c9df823495625303da8d4f
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 17, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

2.0.6 This release

2 release files

2.0.5

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