Skip to content

Commit e0a3248

Browse files
committed
docs: agent-optimize README + add AGENTS.md/CLAUDE.md and IDE pointer files
1 parent e1aef05 commit e0a3248

5 files changed

Lines changed: 193 additions & 85 deletions

File tree

.cursor/rules/cloudinary.mdc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
description: Cloudinary pycloudinary — agent guide
3+
alwaysApply: true
4+
---
5+
6+
Read and follow `AGENTS.md` in the repository root. It is the single
7+
authoritative guide for this package: build/test commands, conventions,
8+
gotchas, and when to use this SDK versus a sibling Cloudinary package.

.github/copilot-instructions.md

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

AGENTS.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# AGENTS.md — pycloudinary
2+
3+
## What this package is (one line)
4+
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.
5+
6+
## When to use this / when NOT to use this
7+
- **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.
8+
- **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.
9+
- **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.
10+
11+
## Setup
12+
```bash
13+
pip install cloudinary
14+
```
15+
Required configuration / credentials (the SDK reads `CLOUDINARY_URL` automatically):
16+
```bash
17+
export CLOUDINARY_URL=cloudinary://<api_key>:<api_secret>@<cloud_name>
18+
```
19+
20+
## Minimal runnable example
21+
```python
22+
import cloudinary
23+
import cloudinary.uploader
24+
import cloudinary.utils
25+
26+
# Config is read from the CLOUDINARY_URL env var; no explicit cloudinary.config() needed.
27+
28+
# Upload a local file
29+
result = cloudinary.uploader.upload("my_picture.jpg")
30+
public_id = result["public_id"]
31+
32+
# Build a 100x150 fill-crop delivery URL for it
33+
url, options = cloudinary.utils.cloudinary_url(public_id, width=100, height=150, crop="fill")
34+
print(url)
35+
```
36+
37+
## Build / test commands (run these after editing)
38+
CI is driven by `tox` (see `tox.ini`); run the matching env locally after any change to `cloudinary/`.
39+
```bash
40+
pip install tox pytest
41+
42+
# Core (non-Django) tests — what tox runs as the *-core envs:
43+
python -m pytest test
44+
45+
# Or via tox, e.g. core on the active Python:
46+
tox -e py313-core
47+
48+
# Django integration tests (modern Django; uses django_tests/settings.py):
49+
DJANGO_SETTINGS_MODULE=django_tests.settings django-admin test -v2 django_tests
50+
# Or via tox:
51+
tox -e py313-django51
52+
```
53+
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).
54+
55+
## Conventions & gotchas
56+
- **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`.
57+
- **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.
58+
- **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.
59+
- **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.
60+
- **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.
61+
- Runtime deps are intentionally minimal: `six`, `urllib3>=1.26.5`, `certifi`.
62+
63+
## Canonical docs (leave the repo for depth)
64+
- Python SDK / Django guide: https://cloudinary.com/documentation/django_integration
65+
- Upload: https://cloudinary.com/documentation/django_image_and_video_upload
66+
- Admin API (asset administration): https://cloudinary.com/documentation/django_asset_administration
67+
- Transformation & API reference: https://cloudinary.com/documentation/cloudinary_references
68+
- MCP server (agent/no-code path): https://github.com/cloudinary/mcp-servers
69+
70+
## Agent / MCP note
71+
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.
72+
73+
## Commit / PR conventions
74+
- Ensure both relevant test suites run locally (core via pytest, Django via the Django runner) and pass in CI before opening a PR.
75+
- See `CONTRIBUTING.md` in the repo root.

CLAUDE.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
@AGENTS.md
2+
3+
# CLAUDE.md — pycloudinary
4+
5+
## What this repo is
6+
7+
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.
8+
9+
## Key constraints / gotchas
10+
11+
- **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.
12+
- **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`.
13+
- **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.
14+
- **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.
15+
- **No lint step in CI.** `.github/workflows/test.yml` runs the tox test matrix only — there is no flake8/ruff/black config.
16+
- **Signed uploads and Admin API calls require server-side secrets.** Never ship `api_secret` into a browser bundle.
17+
18+
## Verified build / test commands
19+
20+
```bash
21+
pip install tox pytest
22+
23+
# Core (non-Django) tests:
24+
python -m pytest test
25+
26+
# Django integration tests (requires Django installed):
27+
DJANGO_SETTINGS_MODULE=django_tests.settings django-admin test -v2 django_tests
28+
29+
# Via tox to match CI exactly:
30+
tox -e py313-core
31+
tox -e py313-django51
32+
```

README.md

Lines changed: 73 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,107 @@
1-
[![Tests](https://github.com/cloudinary/pycloudinary/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/cloudinary/pycloudinary/actions/workflows/test.yml)
2-
[![PyPI Version](https://img.shields.io/pypi/v/cloudinary.svg)](https://pypi.python.org/pypi/cloudinary/)
3-
[![PyPI PyVersions](https://img.shields.io/pypi/pyversions/cloudinary.svg)](https://pypi.python.org/pypi/cloudinary/)
4-
[![PyPI DjangoVersions](https://img.shields.io/pypi/djversions/cloudinary.svg)](https://pypi.python.org/pypi/cloudinary/)
5-
[![PyPI Version](https://img.shields.io/pypi/dm/cloudinary.svg)](https://pypi.python.org/pypi/cloudinary/)
6-
[![PyPI License](https://img.shields.io/pypi/l/cloudinary.svg)](https://pypi.python.org/pypi/cloudinary/)
7-
8-
9-
Cloudinary Python SDK
10-
==================
1+
# Cloudinary Python SDK
112

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

8+
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.
169

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

21-
## Table of Contents
22-
- [Key Features](#key-features)
23-
- [Version Support](#Version-Support)
24-
- [Installation](#installation)
25-
- [Usage](#usage)
26-
- [Setup](#Setup)
27-
- [Transform and Optimize Assets](#Transform-and-Optimize-Assets)
28-
- [Django](#Django)
12+
```bash
13+
pip install cloudinary
14+
```
2915

16+
## Configuration
3017

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

20+
```bash
21+
export CLOUDINARY_URL=cloudinary://<API_KEY>:<API_SECRET>@<CLOUD_NAME>
22+
```
3923

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

41-
## Version Support
26+
```python
27+
import cloudinary
4228

43-
| SDK Version | Python 2.7 | Python 3.x |
44-
|-------------|------------|------------|
45-
| 1.x |||
29+
cloudinary.config(
30+
cloud_name="my_cloud_name",
31+
api_key="my_key",
32+
api_secret="my_secret",
33+
secure=True, # emit https:// delivery URLs
34+
)
35+
```
4636

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

39+
## Quick examples
5140

52-
## Installation
53-
```bash
54-
pip install cloudinary
55-
```
41+
### Upload a file
5642

57-
# Usage
43+
`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`:
5844

59-
### Setup
6045
```python
61-
import cloudinary
46+
import cloudinary.uploader
47+
# Credentials come from CLOUDINARY_URL in the environment.
48+
49+
result = cloudinary.uploader.upload(
50+
"my_picture.jpg",
51+
public_id="cms/hero", # optional: where the asset lives in your media library
52+
)
53+
print(result["public_id"], result["secure_url"])
6254
```
6355

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

67-
```python
68-
cloudinary.utils.cloudinary_url("sample.jpg", width=100, height=150, crop="fill")
69-
```
58+
`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`):
7059

71-
### Upload
72-
- [See full documentation](https://cloudinary.com/documentation/django_image_and_video_upload).
73-
- [Learn more about configuring your uploads with upload presets](https://cloudinary.com/documentation/upload_presets).
7460
```python
75-
cloudinary.uploader.upload("my_picture.jpg")
61+
import cloudinary.utils
62+
63+
url, options = cloudinary.utils.cloudinary_url(
64+
"sample.jpg",
65+
width=100, height=150, crop="fill",
66+
fetch_format="auto", quality="auto",
67+
secure=True, # emit an https:// delivery URL
68+
)
69+
print(url)
70+
# https://res.cloudinary.com/demo/image/upload/c_fill,f_auto,h_150,q_auto,w_100/sample.jpg
7671
```
7772

78-
### Django
79-
- [See full documentation](https://cloudinary.com/documentation/django_image_and_video_upload#django_forms_and_models).
80-
81-
### Security options
82-
- [See full documentation](https://cloudinary.com/documentation/solution_overview#security).
73+
### Retrieve asset details
8374

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

77+
```python
78+
import cloudinary.api
79+
# Credentials come from CLOUDINARY_URL in the environment.
8880

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

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

87+
`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:
9988

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

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

106-
## Additional Resources
107-
- [Cloudinary Transformation and REST API References](https://cloudinary.com/documentation/cloudinary_references): Comprehensive references, including syntax and examples for all SDKs.
108-
- [MediaJams.dev](https://mediajams.dev/): Bite-size use-case tutorials written by and for Cloudinary Developers
109-
- [DevJams](https://www.youtube.com/playlist?list=PL8dVGjLA2oMr09amgERARsZyrOz_sPvqw): Cloudinary developer podcasts on YouTube.
110-
- [Cloudinary Academy](https://training.cloudinary.com/): Free self-paced courses, instructor-led virtual courses, and on-site courses.
111-
- [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.
112-
- [Cloudinary Roadmap](https://cloudinary.com/roadmap): Your chance to follow, vote, or suggest what Cloudinary should develop next.
113-
- [Cloudinary Facebook Community](https://www.facebook.com/groups/CloudinaryCommunity): Learn from and offer help to other Cloudinary developers.
114-
- [Cloudinary Account Registration](https://cloudinary.com/users/register/free): Free Cloudinary account registration.
115-
- [Cloudinary Website](https://cloudinary.com): Learn about Cloudinary's products, partners, customers, pricing, and more.
97+
## Links
11698

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

118-
## Licence
119107
Released under the MIT license.

0 commit comments

Comments
 (0)