Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

coho-codegen

Generates a typed content library from your Coho CMS content types: a Pydantic model per content type, and a client whose reads return them. And creates that library, from the template.

It belongs in your content library, the package your sites and services install, as a development dependency beside coho-delivery-sdk. coho-codegen create sets that library up for you:

uvx coho-codegen create acme-content
cd acme-content
uv sync
uv run coho-codegen init --url https://app.coho.example --ref v1.4.0

Commands

coho-codegen create <dir>  # a new content library from the template, named after <dir>
coho-codegen init          # point the library at a project: asks Coho whose token it is
coho-codegen pull          # fetch the type model for the configured ref into coho-ir.json
coho-codegen generate      # write the library's coho/ package from coho-ir.json
coho-codegen check         # fail if coho/ differs from what generate would write

Commit coho-ir.json and the generated package. generate removes the modules of types no longer on the ref, and leaves anything it did not write. A schema change then shows up as a diff in review, and check in CI catches generated code that is out of date. generate and check never call the server.

init and pull need a project token with read access, coho token create --role viewer. init takes it with --token, from COHO_TOKEN, or by asking, checks it with Coho, writes the account and project it is for into the config, and the token into .env. pull reads COHO_TOKEN from the environment, or for local runs from a .env beside the config, and never from the config itself. Keep it in CI secrets and out of every app that installs the library. pull --ref v1.4.0 pulls another tag than the config names. An unchanged type model costs a 304.

Configuration

coho.config.json, beside the library's pyproject.toml. Paths are relative to it.

{
  "url": "https://app.coho.example",
  "account": "0192…",
  "project": "0192…",
  "ref": "v1.4.0",
  "typeModel": "coho-ir.json",
  "outDir": "src/acme_content/coho"
}

Generate from a tag for a release. A branch's types can change, and generate warns when the model came from one.

What is generated

import os

from coho_delivery_sdk import config_from_env
from acme_content import Coho, resolved

coho = Coho(config_from_env(os.environ))

post = coho.blog_post.by_slug("hello-world", depth=2)
latest = coho.blog_post.list(order="-publishedAt", limit=3)
  • One model per content type, in its own module, named from its slug: blogPost becomes BlogPost, in blog_post.py. The package's __init__.py exports them all, with Coho and AsyncCoho, the same reads awaited. Each model derives from EntryBase, with id, type, slug and locale beside its fields.
  • Fields have Python names, aliased to Coho's: publishedAt is published_at. A field whose name would be a keyword, a system value or one of Pydantic's gets _ after it, class_, and keeps its id on the wire.
  • A field is optional when delivery can leave it out, which includes every localized field. A list is never None: it is empty. A choice is a Literal of its values, or any other str, so a value added after generation never fails to validate.
  • References are typed by their targets: Linked[TeamMember], which is the entry, or a stub saying why it is not there.
  • An asset field is an Asset | None, or a list[Asset] when it holds several, and an ImageAsset when it accepts only raster images, which always have dimensions and resize. A single asset is optional even when required, because an asset deleted on the ref is delivered as None; in a list it is left out.
  • A repeater holds typed items. Each component type is a model of its own, Citation in citation.py, deriving from ItemBase, and a repeater is a list of them: list[Citation], or list[Callout | Quote] when it holds several. An item of a component added after the code was generated is left out of the list, and reported. A repeater whose components are not on the ref holds RepeaterItems.
  • A type that extends another derives from its model. class ServicePage(Page) declares only what it adds or tightens. A type that others extend is read and linked as its family, AnyPage = Page | ServicePage | …, and each entry comes back as its own model, so isinstance tells them apart.
  • A trait is a Protocol of the fields it declares, Seo in seo.py, which every type with it satisfies, to mypy and to isinstance. So a function that takes a Seo takes an entry of any type with the trait.
  • order accepts only fields the type can be sorted by: BlogPostOrder, a Literal of each sortable field and its - descending form, so an unsortable order is a type error rather than a refused request.
  • AnyEntry is the union of every type an entry can be; content_types lists their slugs; source names the ref and schema the code was generated from.
  • The library reads no environment. The app passes its config to Coho.

If a type's name would collide with one the generated code defines (Coho, AsyncCoho, AnyEntry, Linked, Unresolved, RepeaterItem), its model gets Entry after it. A type read as one of Coho's own members (by_slug, by_id, by_ids, content, close, aclose) is read as coho.<name>_type. A family whose Any<Type> name a type already has is named <Type>Family. generate says when any of these happens.

License

Apache-2.0

Metadata

Release files for coho-codegen 2026.1.0a1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for coho-codegen 2026.1.0a1
File Size Uploaded Provenance
coho_codegen-2026.1.0a1.tar.gz 51.2 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for coho-codegen 2026.1.0a1
File Interpreter ABI Platform
coho_codegen-2026.1.0a1-py3-none-any.whl Python 3 none any Details

Total release size: 99.8 kB

Release files / coho_codegen-2026.1.0a1.tar.gz

Download URL coho_codegen-2026.1.0a1.tar.gz
Size 51.2 kB
Tags Source
SHA-256 checksum
How to use checksums
e4b3c98ae1a1ba06b86f95a06e9399ec5678abe96bc791a29d0524a0b7f5ec88
BLAKE2b-256 checksum
How to use checksums
d7765560b53757cff4abb6e6abbed67e660475e8bed9af3be8cc5a16c0a9a011
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Oct 24, 2026.

Transparency log

Release files / coho_codegen-2026.1.0a1-py3-none-any.whl

Download URL coho_codegen-2026.1.0a1-py3-none-any.whl
Size 48.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d6ac789f51d9ad9335535bfe3931e38dcf2d12a03a101fcba543edf207e7c821
BLAKE2b-256 checksum
How to use checksums
a8439d55dbcd6bc1c171c9d1d40a3115f93e808a8a6c025464ea26f50fdbb92c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Oct 24, 2026.

Transparency log

Security for coho-codegen 2026.1.0a1

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for coho_codegen-2026.1.0a1.tar.gz

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 Oct 24, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release
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