Variants¶
Variants define a named group of image versions, each with its own
transformation. Pass a mapping of names to Transform
objects to variants() to generate a dictionary of
URLs. Pass a dataclass class to return a typed instance with URL attributes.
Tip
Use the local Docker server on port 8080 for the examples in this chapter.
Generate variants¶
Define a complete transformation for each name, then generate URLs for a source image:
from pprint import pprint
from imgproxykit import Client, Transform
client = Client('http://localhost:8080')
source_url = 'https://picsum.photos/id/237/1600/1200'
products = { # (1)!
'small': Transform(width=320),
'medium': Transform(width=640),
'large': Transform(width=1280),
}
product_urls = client.variants(source=source_url, variants=products) # (2)!
pprint(product_urls, sort_dicts=False)
Choose names for your application and a complete transformation for each variant.
Generate one URL per variant using the same source and client settings.
Show Output
{'small': 'http://localhost:8080/unsafe/width:320/aHR0cHM6Ly9waWNzdW0ucGhvdG9zL2lkLzIzNy8xNjAwLzEyMDA',
'medium': 'http://localhost:8080/unsafe/width:640/aHR0cHM6Ly9waWNzdW0ucGhvdG9zL2lkLzIzNy8xNjAwLzEyMDA',
'large': 'http://localhost:8080/unsafe/width:1280/aHR0cHM6Ly9waWNzdW0ucGhvdG9zL2lkLzIzNy8xNjAwLzEyMDA'}
Access URLs by name, such as product_urls['small'], or pass the dictionary
to a template or API response.
Reuse a variant set¶
Define a set once and reuse it across source images. Keep shared settings
in a base transformation and use extend() to
add a width for each variant:
from pprint import pprint
from imgproxykit import Client, Transform
client = Client('http://localhost:8080')
dog_source = 'https://picsum.photos/id/237/1600/1200'
pug_source = 'https://picsum.photos/id/1025/1600/1200'
base = Transform(quality=85, format='webp') # (1)!
sizes = {
'small': base.extend(width=320),
'medium': base.extend(width=640),
'large': base.extend(width=1280),
}
dog_urls = client.variants(source=dog_source, variants=sizes) # (2)!
pug_urls = client.variants(source=pug_source, variants=sizes)
pprint({'Dog': dog_urls}, sort_dicts=False)
pprint({'Pug': pug_urls}, sort_dicts=False)
Share quality and format, then use
extend()to add each width.Reuse
sizeswith different sources. You can keep the mapping at module level and reuse it across requests.
Show Output
{'Dog': {'small': 'http://localhost:8080/unsafe/quality:85/format:webp/width:320/aHR0cHM6Ly9waWNzdW0ucGhvdG9zL2lkLzIzNy8xNjAwLzEyMDA',
'medium': 'http://localhost:8080/unsafe/quality:85/format:webp/width:640/aHR0cHM6Ly9waWNzdW0ucGhvdG9zL2lkLzIzNy8xNjAwLzEyMDA',
'large': 'http://localhost:8080/unsafe/quality:85/format:webp/width:1280/aHR0cHM6Ly9waWNzdW0ucGhvdG9zL2lkLzIzNy8xNjAwLzEyMDA'}}
{'Pug': {'small': 'http://localhost:8080/unsafe/quality:85/format:webp/width:320/aHR0cHM6Ly9waWNzdW0ucGhvdG9zL2lkLzEwMjUvMTYwMC8xMjAw',
'medium': 'http://localhost:8080/unsafe/quality:85/format:webp/width:640/aHR0cHM6Ly9waWNzdW0ucGhvdG9zL2lkLzEwMjUvMTYwMC8xMjAw',
'large': 'http://localhost:8080/unsafe/quality:85/format:webp/width:1280/aHR0cHM6Ly9waWNzdW0ucGhvdG9zL2lkLzEwMjUvMTYwMC8xMjAw'}}
Both dictionaries have the same variant names and transformations, with URLs pointing to their respective sources.
Type variant names¶
Annotate the input mapping with a Literal union to check variant names
when accessing the generated URLs:
from pprint import pprint
from typing import Literal, assert_type
from imgproxykit import Client, Transform
client = Client('http://localhost:8080')
source_url = 'https://picsum.photos/id/237/1600/1200'
type ProductKeys = Literal['small', 'medium', 'large'] # (1)!
products: dict[ProductKeys, Transform] = {
'small': Transform(width=320),
'medium': Transform(width=640),
'large': Transform(width=1280),
}
product_urls = client.variants(source=source_url, variants=products)
assert_type(product_urls, dict[ProductKeys, str]) # (2)!
pprint(product_urls, sort_dicts=False)
Limit variant names to a
Literalunion and use it as the mapping’s key type.The returned dictionary preserves that key type. A type checker accepts
product_urls['small']and rejectsproduct_urls['profile'].
Show Output
{'small': 'http://localhost:8080/unsafe/width:320/aHR0cHM6Ly9waWNzdW0ucGhvdG9zL2lkLzIzNy8xNjAwLzEyMDA',
'medium': 'http://localhost:8080/unsafe/width:640/aHR0cHM6Ly9waWNzdW0ucGhvdG9zL2lkLzIzNy8xNjAwLzEyMDA',
'large': 'http://localhost:8080/unsafe/width:1280/aHR0cHM6Ly9waWNzdW0ucGhvdG9zL2lkLzIzNy8xNjAwLzEyMDA'}
Without an explicit key annotation, a regular string-keyed mapping typically
produces dict[str, str].
Return a dataclass¶
Declare a standard-library dataclass when you want a named result type
for an API response or application code. Each field combines its result
type, str, with a transformation in Annotated:
from dataclasses import dataclass
from pprint import pprint
from typing import Annotated, assert_type
from imgproxykit import Client, Transform
base = Transform(quality=85, format='webp')
@dataclass(frozen=True, slots=True)
class ProductImages:
"""Declare the result fields and their transformations together."""
small: Annotated[str, base.extend(width=320)] # (1)!
medium: Annotated[str, base.extend(width=640)]
large: Annotated[str, base.extend(width=1280)]
client = Client('http://localhost:8080')
source_url = 'https://picsum.photos/id/237/1600/1200'
product_urls = client.variants(source_url, variants=ProductImages) # (2)!
assert_type(product_urls, ProductImages)
assert_type(product_urls.small, str)
pprint(product_urls)
Declare each URL field as
Annotated[str, Transform(...)].Pass the class to return a
ProductImagesinstance containing URLs.
Show Output
ProductImages(small='http://localhost:8080/unsafe/quality:85/format:webp/width:320/aHR0cHM6Ly9waWNzdW0ucGhvdG9zL2lkLzIzNy8xNjAwLzEyMDA',
medium='http://localhost:8080/unsafe/quality:85/format:webp/width:640/aHR0cHM6Ly9waWNzdW0ucGhvdG9zL2lkLzIzNy8xNjAwLzEyMDA',
large='http://localhost:8080/unsafe/quality:85/format:webp/width:1280/aHR0cHM6Ly9waWNzdW0ucGhvdG9zL2lkLzIzNy8xNjAwLzEyMDA')
Access URLs as attributes, such as product_urls.small. Reuse the class
with other sources or clients.
Note
Each field must declare exactly one Transform in
Annotated[str, Transform(...)]. Use Transform() for a URL without
processing options. InitVar and init=False fields are unsupported.
Use ProductImages as a field type in a Pydantic model or msgspec Struct,
and pass the result of client.variants() to that field. See the
FastAPI example.
Next steps¶
See the Client API reference for the complete
variants() signature and return type.