Skip to content

Commit 7be8ba1

Browse files
nokomerowanc1
andauthored
Set up oxa-types PyPI package (#18)
* feat(python): add `oxa-types` Python package * chore(prettier): ignore generated json schema * feat(python): add `oxa-types` Python package * chore(prettier): ignore generated json schema * test(python): add typecheck of generated types --------- Co-authored-by: Rowan Cockett <[email protected]>
1 parent df75e1b commit 7be8ba1

File tree

10 files changed

+751
-2
lines changed

10 files changed

+751
-2
lines changed

.github/workflows/primary.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ jobs:
2525
node-version: 22
2626
cache: "pnpm"
2727

28+
- uses: astral-sh/setup-uv@v5
29+
2830
- run: pnpm install --frozen-lockfile
2931

30-
# Typecheck first (before format/lint possibly change line numbers)
32+
# Typecheck generation code in scripts/ (before format/lint possibly change line numbers)
3133
- run: pnpm typecheck
3234

3335
# On push: auto-fix formatting and linting (will be committed)
@@ -42,7 +44,12 @@ jobs:
4244
- run: pnpm lint
4345
if: github.event_name == 'pull_request'
4446

45-
- run: pnpm codegen all
47+
- name: Generate types
48+
run: pnpm codegen all
49+
50+
# Typecheck generated code (Python via ty, TypeScript via tsc)
51+
- run: uv run ty check src/
52+
working-directory: packages/oxa-types-py
4653
- run: pnpm test
4754

4855
- name: Commit changes

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1+
# Node.js
12
node_modules
23
dist
4+
5+
# Python
6+
__pycache__
7+
*.pyc
8+
.venv
9+
.mypy_cache
10+
*.egg-info
11+
12+
# Documentation
313
docs/_build
414
docs/schema

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ dist/
22
node_modules/
33
target/
44
pnpm-lock.yaml
5+
schema/schema.json

packages/oxa-types-py/README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# oxa-types
2+
3+
Pydantic models generated from the OXA JSON Schema.
4+
5+
## Installation
6+
7+
```bash
8+
pip install oxa-types
9+
```
10+
11+
Or with uv:
12+
13+
```bash
14+
uv add oxa-types
15+
```
16+
17+
## Usage
18+
19+
```python
20+
from oxa_types import Document, Paragraph, Text, Block, Inline
21+
22+
# Create a simple document
23+
doc = Document(
24+
metadata={},
25+
title=[Text(value="Hello World")],
26+
children=[
27+
Paragraph(children=[Text(value="This is a paragraph.")])
28+
]
29+
)
30+
31+
# Serialize to JSON
32+
print(doc.model_dump_json(indent=2))
33+
```
34+
35+
## Development
36+
37+
This package is automatically generated from the OXA JSON Schema. Do not edit the generated files directly.
38+
39+
To regenerate the types:
40+
41+
```bash
42+
pnpm codegen py
43+
```
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
[project]
2+
name = "oxa-types"
3+
version = "0.1.0"
4+
description = "Pydantic models generated from the OXA schema"
5+
readme = "README.md"
6+
license = "MIT"
7+
requires-python = ">=3.10"
8+
keywords = ["oxa", "types", "pydantic", "schema"]
9+
classifiers = [
10+
"Development Status :: 3 - Alpha",
11+
"Intended Audience :: Developers",
12+
"License :: OSI Approved :: MIT License",
13+
"Programming Language :: Python :: 3",
14+
"Programming Language :: Python :: 3.10",
15+
"Programming Language :: Python :: 3.11",
16+
"Programming Language :: Python :: 3.12",
17+
"Programming Language :: Python :: 3.13",
18+
"Typing :: Typed",
19+
]
20+
dependencies = [
21+
"pydantic>=2.0",
22+
]
23+
24+
[project.urls]
25+
Homepage = "https://github.com/oxa-dev/oxa"
26+
Repository = "https://github.com/oxa-dev/oxa.git"
27+
28+
[build-system]
29+
requires = ["hatchling"]
30+
build-backend = "hatchling.build"
31+
32+
[tool.hatch.build.targets.wheel]
33+
packages = ["src/oxa_types"]
34+
35+
[tool.uv]
36+
dev-dependencies = [
37+
"ruff>=0.14",
38+
"ty>=0.0.1a13",
39+
]
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
"""
2+
Pydantic models generated from the OXA JSON Schema.
3+
4+
Do not edit this file directly. Instead, edit the YAML schema files
5+
in the schema/ directory and run `pnpm codegen py`.
6+
"""
7+
8+
from __future__ import annotations
9+
10+
from typing import Annotated, Any, Literal, Union
11+
12+
from pydantic import BaseModel, ConfigDict, Field
13+
14+
15+
class Document(BaseModel):
16+
"""A document with metadata, title, and block content."""
17+
18+
model_config = ConfigDict(strict=True)
19+
20+
type: Literal["Document"] = "Document"
21+
id: str | None = Field(
22+
default=None, description="A unique identifier for the node."
23+
)
24+
classes: list[str] | None = Field(
25+
default=None, description="A list of class names for styling or semantics."
26+
)
27+
data: dict[str, Any] | None = Field(
28+
default=None, description="Arbitrary key-value data attached to the node."
29+
)
30+
metadata: dict[str, Any] = Field(description="Arbitrary document metadata.")
31+
title: list["Inline"] = Field(description="The document title as inline content.")
32+
children: list["Block"] = Field(description="The block content of the document.")
33+
34+
35+
class Heading(BaseModel):
36+
"""A heading with a level and inline content."""
37+
38+
model_config = ConfigDict(strict=True)
39+
40+
type: Literal["Heading"] = "Heading"
41+
id: str | None = Field(
42+
default=None, description="A unique identifier for the node."
43+
)
44+
classes: list[str] = Field(
45+
description="A list of class names for styling or semantics."
46+
)
47+
data: dict[str, Any] = Field(
48+
description="Arbitrary key-value data attached to the node."
49+
)
50+
level: int = Field(description="The heading level (1-6).")
51+
children: list["Inline"] = Field(description="The inline content of the heading.")
52+
53+
54+
class Paragraph(BaseModel):
55+
"""A paragraph of inline content."""
56+
57+
model_config = ConfigDict(strict=True)
58+
59+
type: Literal["Paragraph"] = "Paragraph"
60+
id: str | None = Field(
61+
default=None, description="A unique identifier for the node."
62+
)
63+
classes: list[str] = Field(
64+
description="A list of class names for styling or semantics."
65+
)
66+
data: dict[str, Any] = Field(
67+
description="Arbitrary key-value data attached to the node."
68+
)
69+
children: list["Inline"] = Field(description="The inline content of the paragraph.")
70+
71+
72+
class Strong(BaseModel):
73+
"""Strongly emphasized content (typically bold)."""
74+
75+
model_config = ConfigDict(strict=True)
76+
77+
type: Literal["Strong"] = "Strong"
78+
id: str | None = Field(
79+
default=None, description="A unique identifier for the node."
80+
)
81+
classes: list[str] = Field(
82+
description="A list of class names for styling or semantics."
83+
)
84+
data: dict[str, Any] = Field(
85+
description="Arbitrary key-value data attached to the node."
86+
)
87+
children: list["Inline"] = Field(description="The inline content to emphasize.")
88+
89+
90+
class Text(BaseModel):
91+
"""A text node containing a string value."""
92+
93+
model_config = ConfigDict(strict=True)
94+
95+
type: Literal["Text"] = "Text"
96+
id: str | None = Field(
97+
default=None, description="A unique identifier for the node."
98+
)
99+
classes: list[str] = Field(
100+
description="A list of class names for styling or semantics."
101+
)
102+
data: dict[str, Any] = Field(
103+
description="Arbitrary key-value data attached to the node."
104+
)
105+
value: str = Field(description="The text content.")
106+
107+
108+
# Union of all block content types.
109+
Block = Annotated[Union[Heading, Paragraph], Field(discriminator="type")]
110+
111+
112+
# Union of all inline content types.
113+
Inline = Annotated[Union[Text, Strong], Field(discriminator="type")]
114+
115+
116+
# Rebuild models to resolve forward references
117+
Document.model_rebuild()
118+
Heading.model_rebuild()
119+
Paragraph.model_rebuild()
120+
Strong.model_rebuild()
121+
Text.model_rebuild()
122+
123+
124+
__all__ = [
125+
"Block",
126+
"Document",
127+
"Heading",
128+
"Inline",
129+
"Paragraph",
130+
"Strong",
131+
"Text",
132+
]

packages/oxa-types-py/src/oxa_types/py.typed

Whitespace-only changes.

0 commit comments

Comments
 (0)