Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .cursor/rules/cloudinary.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
description: Cloudinary pycloudinary — agent guide
alwaysApply: true
---

Read and follow `AGENTS.md` in the repository root. It is the single
authoritative guide for this package: build/test commands, conventions,
gotchas, and when to use this SDK versus a sibling Cloudinary package.
5 changes: 5 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Cloudinary pycloudinary — instructions for AI coding agents

Read `AGENTS.md` in the repository root and follow it. It is the single
authoritative guide for this package: build/test commands, conventions,
gotchas, and when to use this SDK versus a sibling Cloudinary package.
75 changes: 75 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# AGENTS.md — pycloudinary

## What this package is (one line)
Official Cloudinary Python server-side SDK (PyPI `cloudinary`, imported as `import cloudinary`): upload assets, build transformation/delivery URLs, and call the Admin API from a backend — and it ships the Django integration in the same package.

## When to use this / when NOT to use this
- **Use this when:** you are in a Python server runtime (Django, Flask, FastAPI, Celery, serverless, scripts) and need to upload assets, administer assets via the Admin API, or generate signed delivery URLs/tags where the `api_secret` must stay private.
- **Do NOT use this when:** the code runs in a **browser/frontend bundle** — use [`@cloudinary/url-gen`](https://github.com/cloudinary/js-url-gen) there (no secret exposed); or you want the no-code/autonomous-agent path — use the Cloudinary MCP server.
- **Sibling packages:** there is **no separate Django package** — the `CloudinaryField` model field, forms, and `{% load cloudinary %}` template tags all live in this one package (`cloudinary.models` / `cloudinary.forms`). (Note: this package does **not** ship a Django file-storage backend; that's the separate third-party `django-cloudinary-storage` project.) `@cloudinary/url-gen` = browser URL builder, a different (JS) repo. Rule of thumb: server → this package; browser → not this package.

## Setup
```bash
pip install cloudinary
```
Required configuration / credentials (the SDK reads `CLOUDINARY_URL` automatically):
```bash
export CLOUDINARY_URL=cloudinary://<api_key>:<api_secret>@<cloud_name>
```

## Minimal runnable example
```python
import cloudinary
import cloudinary.uploader
import cloudinary.utils

# Config is read from the CLOUDINARY_URL env var; no explicit cloudinary.config() needed.

# Upload a local file
result = cloudinary.uploader.upload("my_picture.jpg")
public_id = result["public_id"]

# Build a 100x150 fill-crop delivery URL for it
url, options = cloudinary.utils.cloudinary_url(public_id, width=100, height=150, crop="fill")
print(url)
```

## Build / test commands (run these after editing)
CI is driven by `tox` (see `tox.ini`); run the matching env locally after any change to `cloudinary/`.
```bash
pip install tox pytest

# Core (non-Django) tests — what tox runs as the *-core envs:
python -m pytest test

# Or via tox, e.g. core on the active Python:
tox -e py313-core

# Django integration tests (modern Django; uses django_tests/settings.py):
DJANGO_SETTINGS_MODULE=django_tests.settings django-admin test -v2 django_tests
# Or via tox:
tox -e py313-django51
```
Tests hit a real cloud — set `CLOUDINARY_URL` first (CI derives it from `tools/get_test_cloud.sh`). CI (`.github/workflows/test.yml`) runs only the `tox` test matrix — there is no lint step (no flake8/ruff/black config in the repo).

## Conventions & gotchas
- **Django ships in this package.** Do not look for or create a separate Django install. Django code lives under `cloudinary/models.py`, `cloudinary/forms.py`, and the template tags; its tests live in `django_tests/` with `DJANGO_SETTINGS_MODULE=django_tests.settings`.
- **Two test suites, two runners.** Core tests use `pytest` (`python -m pytest test`); Django tests use the Django test runner (`django-admin test django_tests`), not pytest. The `tox` matrix pairs Python versions with Django versions — match it.
- **Signed uploads and Admin calls require server-side secrets** — never ship `api_secret` into a browser bundle. That is the entire reason this SDK is server-only.
- **Python version floor is implicit.** Neither `setup.py` nor `pyproject.toml` declares an explicit `python_requires`; supported versions come only from the classifiers (Python 2.7 and 3.10–3.14). CI (`.github/workflows/test.yml`) tests 3.10–3.14 against Django 4.2–6.0; Python 2.7 / Django 1.11 support is legacy, kept only in a `tox.ini` env and flagged in `setup.py` for removal in the next major. Don't assume `pip` will block an unsupported interpreter.
- **Legacy 2.7 path in setup.py.** `setup.py` branches on `version_info[0] >= 3` and only hard-codes metadata under Python 2; on Python 3 it calls bare `setup()` reading `pyproject.toml`. Edit the right place.
- Runtime deps are intentionally minimal: `six`, `urllib3>=1.26.5`, `certifi`.

## Canonical docs (leave the repo for depth)
- Python SDK / Django guide: https://cloudinary.com/documentation/django_integration
- Upload: https://cloudinary.com/documentation/django_image_and_video_upload
- Admin API (asset administration): https://cloudinary.com/documentation/django_asset_administration
- Transformation & API reference: https://cloudinary.com/documentation/cloudinary_references
- MCP server (agent/no-code path): https://github.com/cloudinary/mcp-servers

## Agent / MCP note
If this capability is also exposed via the Cloudinary MCP servers, prefer the MCP tool for autonomous task execution and use this SDK for code generation. See cloudinary/mcp-servers.

## Commit / PR conventions
- Ensure both relevant test suites run locally (core via pytest, Django via the Django runner) and pass in CI before opening a PR.
- See `CONTRIBUTING.md` in the repo root.
32 changes: 32 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
@AGENTS.md

# CLAUDE.md — pycloudinary

## What this repo is

The official Cloudinary Python server-side SDK (`pip install cloudinary`, `import cloudinary`). One package covers plain Python and Django — upload, Admin/Search API, signed URLs, `CloudinaryField` model field, and `{% load cloudinary %}` template tags all ship here.

## Key constraints / gotchas

- **Two test suites, two runners.** Core tests: `python -m pytest test`. Django integration tests: `django-admin test django_tests` with `DJANGO_SETTINGS_MODULE=django_tests.settings`. The `tox` matrix pairs Python versions with Django versions — match it.
- **Tests require a real cloud.** Set `CLOUDINARY_URL=cloudinary://<api_key>:<api_secret>@<cloud_name>` before running any suite. CI derives credentials from `tools/get_test_cloud.sh`.
- **No `python_requires` floor.** `pip` will not block an unsupported interpreter; the supported range comes from classifiers and CI (Python 3.10–3.14, Django 4.2–6.0). Python 2.7 support is legacy, kept only in a `tox.ini` env, and flagged for removal in the next major.
- **Django ships in this package.** Do not look for or create a separate Django install. The `CloudinaryField` model field, forms, and template tags are all in `cloudinary/models.py`, `cloudinary/forms.py`, and the template tags module. The Django file-storage backend (`DEFAULT_FILE_STORAGE` / `STORAGES`) is the separate third-party `django-cloudinary-storage` project — not part of this package.
- **No lint step in CI.** `.github/workflows/test.yml` runs the tox test matrix only — there is no flake8/ruff/black config.
- **Signed uploads and Admin API calls require server-side secrets.** Never ship `api_secret` into a browser bundle.

## Verified build / test commands

```bash
pip install tox pytest

# Core (non-Django) tests:
python -m pytest test

# Django integration tests (requires Django installed):
DJANGO_SETTINGS_MODULE=django_tests.settings django-admin test -v2 django_tests

# Via tox to match CI exactly:
tox -e py313-core
tox -e py313-django51
```
158 changes: 73 additions & 85 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,119 +1,107 @@
[![Tests](https://github.com/cloudinary/pycloudinary/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/cloudinary/pycloudinary/actions/workflows/test.yml)
[![PyPI Version](https://img.shields.io/pypi/v/cloudinary.svg)](https://pypi.python.org/pypi/cloudinary/)
[![PyPI PyVersions](https://img.shields.io/pypi/pyversions/cloudinary.svg)](https://pypi.python.org/pypi/cloudinary/)
[![PyPI DjangoVersions](https://img.shields.io/pypi/djversions/cloudinary.svg)](https://pypi.python.org/pypi/cloudinary/)
[![PyPI Version](https://img.shields.io/pypi/dm/cloudinary.svg)](https://pypi.python.org/pypi/cloudinary/)
[![PyPI License](https://img.shields.io/pypi/l/cloudinary.svg)](https://pypi.python.org/pypi/cloudinary/)


Cloudinary Python SDK
==================
# Cloudinary Python SDK

## About
The Cloudinary Python SDK allows you to quickly and easily integrate your application with Cloudinary.
Effortlessly optimize, transform, upload and manage your cloud's assets.
[![Tests](https://github.com/cloudinary/pycloudinary/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/cloudinary/pycloudinary/actions/workflows/test.yml)
[![PyPI version](https://img.shields.io/pypi/v/cloudinary.svg)](https://pypi.org/project/cloudinary/)
[![PyPI Python versions](https://img.shields.io/pypi/pyversions/cloudinary.svg)](https://pypi.org/project/cloudinary/)
[![PyPI license](https://img.shields.io/pypi/l/cloudinary.svg)](https://pypi.org/project/cloudinary/)

The `cloudinary` package is the server-side Cloudinary SDK for Python. Use it in a backend or build step to upload assets, build transformation and delivery URLs, and call the Admin API. It holds the API secret, so it handles the operations that can't run in a browser: signed uploads, signed delivery URLs, and asset administration. The same package covers plain Python and Django — the `CloudinaryField` model field, forms, and `{% load cloudinary %}` template tags ship inside it. The package and import name are both `cloudinary`. The current release (1.45.0) is tested on Python 3.10 through 3.14 and Django 4.2 through 6.0.

#### Note
This Readme provides basic installation and usage information.
For the complete documentation, see the [Python SDK Guide](https://cloudinary.com/documentation/django_integration).
## Installation

## Table of Contents
- [Key Features](#key-features)
- [Version Support](#Version-Support)
- [Installation](#installation)
- [Usage](#usage)
- [Setup](#Setup)
- [Transform and Optimize Assets](#Transform-and-Optimize-Assets)
- [Django](#Django)
```bash
pip install cloudinary
```

## Configuration

## Key Features
- [Transform](https://cloudinary.com/documentation/django_video_manipulation#video_transformation_examples) and
[optimize](https://cloudinary.com/documentation/django_image_manipulation#image_optimizations) assets.
- Generate [image](https://cloudinary.com/documentation/django_image_manipulation#deliver_and_transform_images) and
[video](https://cloudinary.com/documentation/django_video_manipulation#django_video_transformation_code_examples) tags.
- [Asset Management](https://cloudinary.com/documentation/django_asset_administration).
- [Secure URLs](https://cloudinary.com/documentation/video_manipulation_and_delivery#generating_secure_https_urls_using_sdks).
The SDK reads credentials automatically from the `CLOUDINARY_URL` environment variable on import:

```bash
export CLOUDINARY_URL=cloudinary://<API_KEY>:<API_SECRET>@<CLOUD_NAME>
```

To set them in code instead, call `cloudinary.config()`:

## Version Support
```python
import cloudinary

| SDK Version | Python 2.7 | Python 3.x |
|-------------|------------|------------|
| 1.x | ✔ | ✔ |
cloudinary.config(
cloud_name="my_cloud_name",
api_key="my_key",
api_secret="my_secret",
secure=True, # emit https:// delivery URLs
)
```

| SDK Version | Django 1.11 | Django 2.x | Django 3.x | Django 4.x | Django 5.x | Django 6.x |
|-------------|-------------|------------|------------|------------|------------|------------|
| 1.x | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
Keep the API secret on the server. Don't put it in client-side code or commit it to version control.

## Quick examples

## Installation
```bash
pip install cloudinary
```
### Upload a file

# Usage
`cloudinary.uploader.upload(file, **options)` accepts a local path, a remote URL, a data URI, a file object, or raw bytes as its first argument, and returns a dict of the uploaded asset's metadata, including `public_id` and `secure_url`:

### Setup
```python
import cloudinary
import cloudinary.uploader
# Credentials come from CLOUDINARY_URL in the environment.

result = cloudinary.uploader.upload(
"my_picture.jpg",
public_id="cms/hero", # optional: where the asset lives in your media library
)
print(result["public_id"], result["secure_url"])
```

### Transform and Optimize Assets
- [See full documentation](https://cloudinary.com/documentation/django_image_manipulation).
### Build and optimize a delivery URL

```python
cloudinary.utils.cloudinary_url("sample.jpg", width=100, height=150, crop="fill")
```
`cloudinary.utils.cloudinary_url(source, **options)` is synchronous and makes no network call. It returns a `(url, options)` tuple whose first element is the delivery URL string. This one resizes to a 100x150 fill crop and lets Cloudinary pick the format and quality for the requesting browser (`f_auto`, `q_auto`):

### Upload
- [See full documentation](https://cloudinary.com/documentation/django_image_and_video_upload).
- [Learn more about configuring your uploads with upload presets](https://cloudinary.com/documentation/upload_presets).
```python
cloudinary.uploader.upload("my_picture.jpg")
import cloudinary.utils

url, options = cloudinary.utils.cloudinary_url(
"sample.jpg",
width=100, height=150, crop="fill",
fetch_format="auto", quality="auto",
secure=True, # emit an https:// delivery URL
)
print(url)
# https://res.cloudinary.com/demo/image/upload/c_fill,f_auto,h_150,q_auto,w_100/sample.jpg
```

### Django
- [See full documentation](https://cloudinary.com/documentation/django_image_and_video_upload#django_forms_and_models).

### Security options
- [See full documentation](https://cloudinary.com/documentation/solution_overview#security).
### Retrieve asset details

### Sample projects
- [Sample projects](https://github.com/cloudinary/pycloudinary/tree/master/samples).
- [Django Photo Album](https://github.com/cloudinary/cloudinary-django-sample).
`cloudinary.api.resource(public_id, **options)` takes a public ID and returns the asset's metadata, including its dimensions, format, and `secure_url`:

```python
import cloudinary.api
# Credentials come from CLOUDINARY_URL in the environment.

## Contributions
- Ensure tests run locally.
- Open a PR and ensure Travis tests pass.
- See [CONTRIBUTING](CONTRIBUTING.md).
asset = cloudinary.api.resource("sample")
print(asset["format"], asset["width"], asset["height"], asset["secure_url"])
```

## Get Help
If you run into an issue or have a question, you can either:
- Issues related to the SDK: [Open a GitHub issue](https://github.com/cloudinary/pycloudinary/issues).
- Issues related to your account: [Open a support ticket](https://cloudinary.com/contact).
## For AI agents

`cloudinary` is the Python server-side SDK, and it's also the Django SDK — the `CloudinaryField` model field (`cloudinary.models`), forms (`cloudinary.forms`), and `{% load cloudinary %}` template tags ship in this one package, so there's no separate Django SDK to install. Choose it for backend upload, asset administration, the Search API, and signed URL or tag generation, where the API secret stays private. For tasks it doesn't cover, choose a different package:

## About Cloudinary
Cloudinary is a powerful media API for websites and mobile apps alike, Cloudinary enables developers to efficiently
manage, transform, optimize, and deliver images and videos through multiple CDNs. Ultimately, viewers enjoy responsive
and personalized visual-media experiences—irrespective of the viewing device.
| Task | Package |
|---|---|
| Build delivery URLs in the browser | [`@cloudinary/url-gen`](https://github.com/cloudinary/js-url-gen) |
| Wire Cloudinary in as Django's `DEFAULT_FILE_STORAGE` / `STORAGES` backend | [`django-cloudinary-storage`](https://github.com/klis87/django-cloudinary-storage) (third-party) |
| Run Cloudinary operations as agent tools | [Cloudinary MCP servers](https://github.com/cloudinary/mcp-servers) |

The Django file-storage backend is the only Django piece this package doesn't ship — `CloudinaryField` covers the common case without it.

## Additional Resources
- [Cloudinary Transformation and REST API References](https://cloudinary.com/documentation/cloudinary_references): Comprehensive references, including syntax and examples for all SDKs.
- [MediaJams.dev](https://mediajams.dev/): Bite-size use-case tutorials written by and for Cloudinary Developers
- [DevJams](https://www.youtube.com/playlist?list=PL8dVGjLA2oMr09amgERARsZyrOz_sPvqw): Cloudinary developer podcasts on YouTube.
- [Cloudinary Academy](https://training.cloudinary.com/): Free self-paced courses, instructor-led virtual courses, and on-site courses.
- [Code Explorers and Feature Demos](https://cloudinary.com/documentation/code_explorers_demos_index): A one-stop shop for all code explorers, Postman collections, and feature demos found in the docs.
- [Cloudinary Roadmap](https://cloudinary.com/roadmap): Your chance to follow, vote, or suggest what Cloudinary should develop next.
- [Cloudinary Facebook Community](https://www.facebook.com/groups/CloudinaryCommunity): Learn from and offer help to other Cloudinary developers.
- [Cloudinary Account Registration](https://cloudinary.com/users/register/free): Free Cloudinary account registration.
- [Cloudinary Website](https://cloudinary.com): Learn about Cloudinary's products, partners, customers, pricing, and more.
## Links

- [Python SDK guide](https://cloudinary.com/documentation/django_integration)
- [Upload](https://cloudinary.com/documentation/django_image_and_video_upload)
- [Asset administration (Admin API)](https://cloudinary.com/documentation/django_asset_administration)
- [Image transformations](https://cloudinary.com/documentation/django_image_manipulation)
- [Transformation and API references](https://cloudinary.com/documentation/cloudinary_references)
- [Documentation llms.txt index](https://cloudinary.com/documentation/llms.txt)
- [Package on PyPI](https://pypi.org/project/cloudinary/)

## Licence
Released under the MIT license.