Skip to main content

Python client for the Unsplash API

Project description

Unsplash Wrapper

Typed async Python client for the Unsplash API focused on the photo search endpoint.

Features:

  • Async HTTP via httpx
  • Pydantic models (requests & responses)
  • Fluent builder (UnsplashSearchParamsBuilder) OR direct kwargs
  • Returns a simple list[UnsplashPhoto]
  • Automatic retry of 429 (rate limit) responses

Installation

Requires Python 3.13+.

pip install unsplash-wrapper

Set your Unsplash access key (Create one in your Unsplash developer dashboard):

export UNSPLASH_API_KEY=your_access_key_here  # macOS/Linux
$env:UNSPLASH_API_KEY='your_access_key_here'  # PowerShell

Quick Start (async context manager)

from unsplash_wrapper import UnsplashClient, UnsplashSearchParamsBuilder

params = UnsplashSearchParamsBuilder().query("mountains").build()

async with UnsplashClient() as client:
    photos = await client.search_photos(params)

for photo in photos:
    print(photo.id, photo.url)

Without Context Manager

UnsplashClient can also be used without async with — it creates and closes an httpx.AsyncClient per call automatically:

from unsplash_wrapper import UnsplashClient, UnsplashSearchParamsBuilder

params = UnsplashSearchParamsBuilder().query("ocean").build()

client = UnsplashClient()
photos = await client.search_photos(params)

for photo in photos:
    print(photo.id, photo.url)

Sync Usage Helper

If you're not already inside an async context:

import asyncio
from unsplash_wrapper import UnsplashClient, UnsplashSearchParamsBuilder

def main() -> None:
    params = UnsplashSearchParamsBuilder().query("ocean").build()
    photos = asyncio.run(UnsplashClient().search_photos(params))
    for p in photos:
        print(p.id, p.url)

if __name__ == "__main__":
    main()

Search Parameter Builder

All builder methods are chainable. Pass the result of .build() to search_photos.

from unsplash_wrapper import (
    UnsplashClient,
    UnsplashSearchParamsBuilder,
)

params = (
    UnsplashSearchParamsBuilder()
    .query("sunset beach")
    .limit(20)
    .landscape_orientation()
    .high_quality()
    .order_by_latest()
    .page(2)
    .build()
)

async with UnsplashClient() as client:
    photos = await client.search_photos(params)

for photo in photos:
    print(photo.id, photo.description, photo.url)

Available builder methods:

Method Description
.query(str) Search query
.limit(int) Results per page (default: 10)
.page(int) Page number (default: 1)
.orientation(Orientation) Set orientation enum directly
.landscape_orientation() Shortcut for landscape
.portrait_orientation() Shortcut for portrait
.squarish_orientation() Shortcut for squarish
.content_filter(ContentFilter) Set filter enum directly
.high_quality() Shortcut for high content filter
.low_quality() Shortcut for low content filter
.order_by(OrderBy) Set order enum directly
.order_by_relevant() Shortcut for relevance ordering
.order_by_latest() Shortcut for latest ordering

Manual Params

from unsplash_wrapper import UnsplashSearchParams, UnsplashClient, Orientation

params = UnsplashSearchParams(query="minimal", per_page=5, orientation=Orientation.SQUARISH)

async with UnsplashClient() as client:
    photos = await client.search_photos(params)

Models Overview

UnsplashPhoto attributes:

id: str
description: str | None
alt_description: str | None
urls: UnsplashUrls (raw/full/regular/small/thumb)
user: UnsplashUser (username, name, portfolio_url, ...)
width, height, color, likes, created_at
url (property -> regular URL string)

Error Handling

Exceptions from unsplash_wrapper.exceptions:

  • UnsplashAuthenticationException (401)
  • UnsplashNotFoundException (404)
  • UnsplashRateLimitException (429) — includes retry_after if provided
  • UnsplashServerException (5xx)
  • UnsplashClientException (other 4xx)
  • UnsplashTimeoutException (request timeout)
from unsplash_wrapper import (
    UnsplashClient,
    UnsplashRateLimitException,
    UnsplashAuthenticationException,
)

client = UnsplashClient()
try:
    photos = await client.search_photos(query="forest")
except UnsplashRateLimitException as e:
    msg = f"retry after {e.retry_after}s" if e.retry_after else "no retry window"
    print("Rate limited:", msg)
except UnsplashAuthenticationException:
    print("Invalid API key configured")

Retry Behavior

429 responses are retried up to 3 times (delays: 1s → 2s → 4s). Other failures propagate immediately.

Logging

Logger name: unsplash_wrapper.UnsplashClient

import logging
logging.basicConfig(level=logging.INFO)

Development

Run tests:

uv run pytest -q

Type check (if mypy configured):

mypy unsplash_wrapper

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

unsplash_wrapper-0.3.0.tar.gz (36.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

unsplash_wrapper-0.3.0-py3-none-any.whl (8.9 kB view details)

Uploaded Python 3

File details

Details for the file unsplash_wrapper-0.3.0.tar.gz.

File metadata

  • Download URL: unsplash_wrapper-0.3.0.tar.gz
  • Upload date:
  • Size: 36.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.2

File hashes

Hashes for unsplash_wrapper-0.3.0.tar.gz
Algorithm Hash digest
SHA256 373fe2d0b88806c7b3f41507c3604c64d407169a62d3fe27bd18bb5ca02da233
MD5 abcc2799735348b81b97cf6fc47b3bce
BLAKE2b-256 5b6936be0319305b8538e5d4ac5da14740b6ef286666632d5f698f1b45663da0

See more details on using hashes here.

File details

Details for the file unsplash_wrapper-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for unsplash_wrapper-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 500bacc06260410edf3a79af2d7084f3a4bdb3557d004159e761e12fc34c2bd6
MD5 4b5c2c74f026c85753d81905cb45ca7b
BLAKE2b-256 13d7d3a40031a02f1fd2582a14259fdd3b087c237fd5669cf15bf341107ac000

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page