diff --git a/.github/workflows/docs-preview.yml b/.github/workflows/docs-preview.yml index 4ec85ebe..776f7eef 100644 --- a/.github/workflows/docs-preview.yml +++ b/.github/workflows/docs-preview.yml @@ -28,16 +28,13 @@ jobs: - name: Install mdBook and mdbook-keeper run: | - # Only install if not already cached if ! command -v mdbook &> /dev/null; then - cargo install mdbook + cargo install mdbook --version "~0.4" fi - if ! command -v mdbook-keeper &> /dev/null; then - cargo install mdbook-keeper + cargo install mdbook-keeper --version "~0.5" fi - - name: Build mdBook documentation run: | cd docs diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 60767139..cff585b9 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -36,19 +36,18 @@ jobs: - name: Install mdBook and mdbook-keeper run: | - # Only install if not already cached + # Pin to mdbook 0.4.x (0.5.x changed preprocessor JSON format, + # breaking mdbook-keeper compatibility) if ! command -v mdbook &> /dev/null; then - cargo install mdbook + cargo install mdbook --version "~0.4" fi - if ! command -v mdbook-keeper &> /dev/null; then - cargo install mdbook-keeper + cargo install mdbook-keeper --version "~0.5" fi - + - name: Test mdBook examples run: | cd docs - # mdbook-keeper runs doctests during build with real dependencies mdbook build # Build and deploy documentation site @@ -75,15 +74,13 @@ jobs: - name: Install mdBook and mdbook-keeper run: | - # Only install if not already cached if ! command -v mdbook &> /dev/null; then - cargo install mdbook + cargo install mdbook --version "~0.4" fi - if ! command -v mdbook-keeper &> /dev/null; then - cargo install mdbook-keeper + cargo install mdbook-keeper --version "~0.5" fi - + - name: Build mdBook documentation run: | cd docs diff --git a/.gitignore b/.gitignore index 6f41d0cc..b83ae0e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ /target docs/book +.vscode/settings.json +*.pyc +__pycache__/ diff --git a/Cargo.lock b/Cargo.lock index 756dd0ec..80f12f03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -141,50 +141,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" -[[package]] -name = "askama" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" -dependencies = [ - "askama_derive", - "askama_escape", - "humansize", - "num-traits", - "percent-encoding", -] - -[[package]] -name = "askama_derive" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" -dependencies = [ - "askama_parser", - "basic-toml", - "mime", - "mime_guess", - "proc-macro2", - "quote", - "serde", - "syn 2.0.106", -] - -[[package]] -name = "askama_escape" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" - -[[package]] -name = "askama_parser" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" -dependencies = [ - "nom", -] - [[package]] name = "async-trait" version = "0.1.89" @@ -289,15 +245,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "basic-toml" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" -dependencies = [ - "serde", -] - [[package]] name = "bit-set" version = "0.8.0" @@ -926,15 +873,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "humansize" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" -dependencies = [ - "libm", -] - [[package]] name = "hyper" version = "1.7.0" @@ -1225,12 +1163,6 @@ version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" -[[package]] -name = "libm" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" - [[package]] name = "libredox" version = "0.1.9" @@ -1316,12 +1248,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1377,16 +1303,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -1714,7 +1630,6 @@ name = "reflectapi" version = "0.16.8" dependencies = [ "anyhow", - "askama", "axum", "bytes", "check_keyword", @@ -1741,7 +1656,6 @@ name = "reflectapi-cli" version = "0.16.8" dependencies = [ "anyhow", - "askama", "clap", "clap_derive", "reflectapi", diff --git a/README.md b/README.md index ca79054c..26435bb9 100644 --- a/README.md +++ b/README.md @@ -33,10 +33,10 @@ ## Documentation -- 📦 [Crates.io](https://crates.io/crates/reflectapi) - Package information and versions -- 📖 [API Documentation](https://docs.rs/reflectapi) - Complete API reference -- 📚 [User Guide](https://reflectapi.partly.workers.dev/) - Tutorials and examples -- 🚀 [Quick Start](https://reflectapi.partly.workers.dev/getting-started/quick-start.html) - Get up and running in 5 minutes +- [Crates.io](https://crates.io/crates/reflectapi) - Package information and versions +- [API Documentation](https://docs.rs/reflectapi) - Complete API reference +- [User Guide](docs/src/SUMMARY.md) - Tutorials and examples (build locally with `mdbook serve` in `docs/`) +- [Architecture](docs/architecture.md) - System design and internals ## Development notes diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 00000000..db281d02 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,533 @@ +# ReflectAPI Architecture + +## 1. Overview + +ReflectAPI is a Rust framework for defining web API services and generating type-safe clients in multiple languages. Developers write Rust handler functions with typed inputs and outputs. Derive macros capture type metadata into a JSON schema (`reflectapi.json`). Code generation backends produce idiomatic clients for TypeScript, Rust, and Python, plus OpenAPI specifications. + +Handler functions follow a fixed signature convention: + +```rust +async fn handler(state: State, input: Input, headers: Headers) -> Result +``` + +- **Input** — the request body type (implements `reflectapi::Input + DeserializeOwned`) +- **Headers** — typed header extraction (implements `reflectapi::Input`; struct fields map to HTTP header names) +- **Output** — the success response type (implements `reflectapi::Output + Serialize`) +- **Error** — the error response type (implements `reflectapi::Output + Serialize + StatusCode`) +- **`reflectapi::Empty`** — sentinel for no input/output body +- **`reflectapi::Infallible`** — sentinel for handlers that cannot fail + +The `Input` and `Output` traits (defined in `reflectapi/src/traits.rs`) are the mechanism by which types self-register into the schema. Each trait provides a `reflectapi_input_type(schema: &mut Typespace) -> TypeReference` (or `_output_type`) method that the derive macros implement. + +The system is a multi-stage pipeline: + +1. **Derive macros** extract type metadata at compile time into a `Schema`. +2. The schema is serialized to JSON (`reflectapi.json`), forming the contract between server and clients. +3. At codegen time, the schema is deserialized, normalized through a pipeline of transformations, and fed to language-specific backends that emit client code. + +## 2. Crate Structure + +``` +reflectapi/ Workspace root + reflectapi-schema/ Schema types, semantic IR, normalization pipeline + reflectapi-derive/ Proc macros: #[derive(Input, Output)] + reflectapi/ Builder, codegen backends, runtime (axum, serialization) + reflectapi-cli/ CLI tool wrapping codegen (clap-based) + reflectapi-demo/ Demo application with snapshot tests (insta) + reflectapi-python-runtime/ Python runtime support library (Pydantic helpers, client base classes) + docs/ User-facing documentation (mdbook) +``` + +### reflectapi-schema + +The foundational crate. Contains: + +- **Schema types** (`Schema`, `Function`, `Type`, `Struct`, `Enum`, `Field`, `Variant`, `TypeReference`, `Representation`, `Primitive`, `Typespace`) -- the serializable representation of an API. +- **SymbolId and SymbolKind** -- stable unique identifiers for all schema symbols. +- **ensure_symbol_ids()** -- post-deserialization ID assignment. +- **NormalizationPipeline** -- multi-stage schema transformation (type consolidation, naming, circular dependency resolution). +- **Normalizer** -- converts `Schema` into validated `SemanticSchema`. +- **SemanticSchema** -- immutable, fully-resolved intermediate representation. +- **Visitor/VisitMut** -- generic traversal utilities. +- **Substitute/Instantiate** -- generic type parameter substitution. +- **Rename/Glob** -- type renaming and glob-based filtering. + +### reflectapi-derive + +Procedural macros that implement `#[derive(Input)]` and `#[derive(Output)]`. These macros parse Rust struct/enum definitions (including serde attributes) and emit code that populates the `Schema` at compile time. + +Key source files: +- `lib.rs` -- macro entry points +- `parser.rs` -- serde attribute parsing +- `context.rs` -- code generation context +- `derive.rs` -- the derive implementation +- `tokenizable_schema.rs` -- converts schema types to token streams + +Beyond serde attributes, the macros recognize `#[reflectapi(...)]` attributes: + +**Type-level:** `type = "..."` (override reflected type), `input_type` / `output_type` (per-direction override), `discriminant` (use Rust enum discriminant values), `derive(...)` (add derives to codegen config). + +**Field-level:** `skip` / `input_skip` / `output_skip` (omit from schema), `type = "..."` / `input_type` / `output_type` (override field type), `input_transform` / `output_transform` (transform callbacks). + +### reflectapi + +The main user-facing crate. Contains: +- **Builder** (`src/builder/`) -- runtime schema construction and handler registration. +- **Codegen backends** -- `typescript.rs`, `rust.rs`, `python.rs`, `openapi.rs` in `src/codegen/`. +- **Runtime integration** -- axum handler adapters, serialization modes (JSON, msgpack). +- **Format utilities** (`src/codegen/format.rs`) -- invokes prettier, rustfmt, or ruff on generated output. + +### reflectapi-cli + +A thin CLI wrapper using `clap`. Reads a `reflectapi.json` schema file and invokes the appropriate codegen backend: + +``` +reflectapi codegen --language typescript --schema reflectapi.json --output ./clients/ts +``` + +Flags control output formatting, type checking, tag-based endpoint filtering, shared Rust module imports, and tracing instrumentation. + +### reflectapi-demo + +A working demo server with snapshot tests. The `reflectapi.json` file and generated clients (TypeScript, Rust, Python) are checked in and validated by `cargo insta` snapshot tests. The `assert_snapshot!` macro in `src/tests/assert.rs` generates **5 snapshots** per test: JSON schema, TypeScript, Rust, OpenAPI, and Python. Tests are organized in `basic.rs`, `enums.rs`, `generics.rs`, `serde.rs`, and `namespace.rs`. Compile-fail and compile-pass tests use `trybuild`. + +### reflectapi-python-runtime + +Python package providing base classes and utilities for generated Python clients: `AsyncClientBase`, `ClientBase`, `ApiResponse`, `ReflectapiOption`, mock testing utilities, and middleware support. + +## 3. Schema Types + +The schema is a JSON-serializable representation of a Rust API. The core types live in `reflectapi-schema/src/lib.rs`. + +### Schema + +Top-level container holding the API definition: + +```rust +pub struct Schema { + pub id: SymbolId, // Assigned by ensure_symbol_ids() + pub name: String, + pub description: String, + pub functions: Vec, + pub input_types: Typespace, // Types used in request positions + pub output_types: Typespace, // Types used in response positions +} +``` + +Separating `input_types` from `output_types` allows the same Rust type name to carry different shapes in request and response contexts. The `TypeConsolidationStage` merges these during normalization. + +### Function + +An API endpoint: + +```rust +pub struct Function { + pub id: SymbolId, + pub name: String, // e.g. "users.login" + pub path: String, // URL path, e.g. "/api/v1" + pub description: String, + pub deprecation_note: Option, + pub input_type: Option, + pub input_headers: Option, + pub output_type: Option, + pub error_type: Option, + pub serialization: Vec, // Json, Msgpack + pub readonly: bool, + pub tags: BTreeSet, +} +``` + +### Type + +A sum type covering all possible type definitions: + +```rust +pub enum Type { + Primitive(Primitive), // Opaque types (String, i32, Uuid, etc.) + Struct(Struct), // Named/unnamed fields, tuple structs + Enum(Enum), // Tagged/untagged unions with variants +} +``` + +### TypeReference + +A reference to a type, including generic arguments: + +```rust +pub struct TypeReference { + pub name: String, // Fully-qualified name, e.g. "std::vec::Vec" + pub arguments: Vec, // Generic type arguments +} +``` + +### Representation + +Captures serde's enum tagging strategy: + +```rust +pub enum Representation { + External, // {"variant": {...}} + Internal { tag: String }, // {"type": "variant", ...} + Adjacent { tag: String, content: String }, // {"t": "variant", "c": {...}} + None, // untagged +} +``` + +### Primitive and the Fallback Mechanism + +`Primitive` types are opaque to codegen — they have no inspectable fields. The `fallback` field enables codegen backends to resolve types they do not natively handle: + +```rust +pub struct Primitive { + pub name: String, + pub parameters: Vec, + pub fallback: Option, // e.g., NonZeroU8 -> u8, BTreeMap -> HashMap +} +``` + +`TypeReference::fallback_recursively()` follows the fallback chain until reaching a type the backend supports. Examples: `Arc` falls back to `T`, `BTreeMap` falls back to `HashMap`, `HashSet` falls back to `Vec`. + +### reflectapi::Option\ + +A three-state type (`Undefined | None | Some(T)`) defined in `reflectapi/src/option.rs`. Essential for PATCH-style APIs where "field absent" differs from "field set to null": + +- **Undefined** — field not present in the request body +- **None** — field explicitly set to `null` +- **Some(T)** — field present with a value + +Each codegen backend represents this distinctly: TypeScript uses `T | null | undefined`, Python uses `ReflectapiOption` from the runtime library. + +### Fields, Field, Variant + +Fields can be `Named`, `Unnamed` (tuple), or `None` (unit). Each `Field` carries: +- `name` / `serde_name` -- the Rust name and the wire name (after serde rename) +- `type_ref` -- the field's type +- `required` -- whether the field must be present +- `flattened` -- whether `#[serde(flatten)]` is applied +- `description` / `deprecation_note` -- documentation metadata + +## 4. Semantic IR Pipeline + +The pipeline transforms a deserialized `Schema` into a validated, immutable `SemanticSchema` suitable for code generation. + +### Pipeline Overview + +``` + reflectapi.json + | + v + +--------------------------+ + | JSON Deserialization | + +--------------------------+ + | + v + +--------------------------+ + | ensure_symbol_ids() | Assign stable SymbolIds + +--------------------------+ + | + v + +-------------------------------+ + | PipelineBuilder | Configures which stages run + | .consolidation(Standard|Skip)| + | .naming(Standard|Skip|Custom)| + | .circular_dependency_strategy| + | .add_stage(custom) | + +-------------------------------+ + | .build() + +--------------------------------------------------+ + | standard() | for_codegen() + | (all defaults) | (Skip, Skip) + v v + +---------------------------+ +------------------------------+ + | 1. TypeConsolidation | | Schema::consolidate_types() | + | 2. NamingResolution | | (caller runs separately) | + | 3. CircularDependency | +------------------------------+ + +---------------------------+ | + | v + | +------------------------------+ + | | CircularDependency only | + | +------------------------------+ + | | + +------------------+-----------------------+ + | + v + +-------------------+ + | Normalizer | + | 1. Discovery | Register symbols + | 2. Resolution | Resolve type references + | 3. Dependencies | Build dependency graph + | 4. Validation | Semantic checks + | 5. IR Build | Construct SemanticSchema + +-------------------+ + | + v + +-------------------+ + | SemanticSchema | Immutable, validated IR + +-------------------+ +``` + +Pipelines are configured via `PipelineBuilder`. The convenience methods `NormalizationPipeline::standard()` and `for_codegen()` delegate to the builder internally. The Python backend uses `PipelineBuilder` directly: + +```rust +PipelineBuilder::new() + .consolidation(Consolidation::Skip) + .naming(Naming::Skip) + .build() +``` + +### SymbolId + +Every symbol in the schema (types, functions, fields, variants) receives a stable, unique identifier: + +```rust +pub struct SymbolId { + pub kind: SymbolKind, // Struct, Enum, Endpoint, Field, Variant, Primitive, TypeAlias + pub path: Vec, // e.g. ["api", "User"] + pub disambiguator: u32, // Distinguishes same-name types across input/output +} +``` + +The `SymbolId` is the primary key for all lookups throughout the pipeline and in the final `SemanticSchema`. The `disambiguator` field handles the case where input and output typespaces define different types with the same fully-qualified name. + +### ensure_symbol_ids() + +When a schema is deserialized from JSON, all `SymbolId` fields have their default ("unknown") values. `ensure_symbol_ids()` walks the schema and assigns stable IDs based on canonical names: + +1. Pre-registers well-known stdlib types (`String`, `Vec`, `Option`, `HashMap`, etc.) from `STDLIB_TYPES`. +2. Assigns IDs to functions based on their names. +3. Assigns IDs to types in each typespace, using separate seen-maps so cross-typespace conflicts are detected. +4. When the same FQN appears in both typespaces with different type definitions, the output typespace's copy receives a disambiguated ID (`disambiguator = 1`). +5. Assigns IDs to struct fields and enum variants as children of their parent's path. + +### NormalizationPipeline and PipelineBuilder + +Pipelines are assembled via `PipelineBuilder`, which controls three dimensions: + +- **`Consolidation`** (`Standard` | `Skip`) -- whether to run `TypeConsolidationStage`. +- **`Naming`** (`Standard` | `Skip` | `Custom(Box)`) -- whether/how to run naming resolution. +- **`ResolutionStrategy`** (`Intelligent` | `Boxing` | `ForwardDeclarations` | `OptionalBreaking` | `ReferenceCounted`) -- passed to `CircularDependencyResolutionStage`. + +Additional custom stages can be appended via `add_stage()`. The convenience methods `NormalizationPipeline::standard()` and `for_codegen()` delegate to `PipelineBuilder` internally and remain the recommended shorthand for common configurations. + +The standard pipeline applies three stages in sequence: + +**Stage 1: TypeConsolidationStage** -- Merges `input_types` and `output_types` into a single unified `input_types` collection. When a simple type name appears in both typespaces, both copies are renamed with `input.` / `output.` prefixes and all type references throughout the schema are rewritten to point to the new names. Types that appear in only one typespace are added as-is. + +**Stage 2: NamingResolutionStage** -- Strips module path prefixes from type names (e.g. `myapp::api::User` becomes `User`). When stripping creates a conflict (two different types both resolve to `User`), a unique name is generated by incorporating the last meaningful module component (e.g. `ApiUser` vs `BillingUser`). Common module names (`model`, `proto`) are skipped when building the prefix. + +**Stage 3: CircularDependencyResolutionStage** -- Detects circular type dependencies using Tarjan's strongly-connected components (SCC) algorithm. Supports multiple resolution strategies: +- `Intelligent` (default) -- self-references use boxing; multi-type cycles use forward declarations. +- `Boxing` -- a no-op because Rust schemas already encode `Box` in their type references. +- `ForwardDeclarations`, `OptionalBreaking`, `ReferenceCounted` -- defined in `ResolutionStrategy` but their `apply_*` methods return `Ok(())` without modifying the schema. + +Downstream codegen backends query the detected cycles to emit forward-reference annotations regardless of the resolution strategy. + +### Normalizer + +The `Normalizer` orchestrates the full conversion from `Schema` to `SemanticSchema`. It accepts a custom pipeline via `normalize_with_pipeline()`, or uses `NormalizationPipeline::standard()` by default. Codegen backends that handle their own naming build a pipeline with `PipelineBuilder` (skipping consolidation and naming) and pass it to `normalize_with_pipeline()`. + +1. **Phase 0**: Calls `ensure_symbol_ids()` and runs the selected pipeline. +2. **Phase 1 (Symbol Discovery)**: Registers all types, functions, fields, and variants in the `SymbolTable`. +3. **Phase 2 (Type Resolution)**: Resolves `TypeReference` names to `SymbolId` targets. +4. **Phase 3 (Dependency Analysis)**: Builds dependency graph and performs topological sorting. +5. **Phase 4 (Semantic Validation)**: Checks for semantic errors. +6. **Phase 5 (IR Construction)**: Builds the `SemanticSchema` with `BTreeMap`-ordered collections. + +### SemanticSchema + +The output of the pipeline: + +```rust +pub struct SemanticSchema { + pub id: SymbolId, + pub name: String, + pub description: String, + pub functions: BTreeMap, + pub types: BTreeMap, + pub symbol_table: SymbolTable, +} +``` + +Key properties compared to `Schema`: +- **Fully resolved** -- all type references are `ResolvedTypeReference` with `SymbolId` targets. +- **Deterministically ordered** -- `BTreeMap`/`BTreeSet` everywhere for stable codegen output. +- **Single typespace** -- input/output distinction has been resolved by `TypeConsolidationStage`. +- **Dependency graph** -- the `SymbolTable` contains dependency edges and supports topological sorting. + +## 5. Code Generation Backends + +All backends live in `reflectapi/src/codegen/`. The Python backend uses `SemanticSchema` for type iteration ordering and the consolidated raw `Schema` for rendering. TypeScript, Rust, and OpenAPI backends read the `Schema` directly. + +### TypeScript + +Uses `std::fmt::Write` for code generation. Key design decisions: + +- **Interfaces** for struct types with named fields. +- **Type aliases** for tuple structs and transparent wrappers. +- **Intersection types** (`&`) for `#[serde(flatten)]` -- flattened fields are rendered as separate type references joined with `&`. +- **Discriminated unions** for tagged enums. +- **`NullToEmptyObject`** helper to handle the interaction between Rust `()` (which maps to `null`) and intersection types. +- Output is formatted with `prettier`. + +### Rust + +Mirrors the source Rust types, re-emitting struct/enum definitions with appropriate `#[serde(...)]` attributes. Key features: + +- Preserves `#[serde(flatten)]` on fields that had it in the original. +- Handles shared modules -- types from specified module prefixes are imported rather than regenerated. +- Generates a client module with async functions for each endpoint. +- Output is formatted with `rustfmt`. + +### Python + +Generates Pydantic v2 models with namespace classes mirroring the Rust module structure. Uses `SemanticSchema` for type iteration ordering via `PipelineBuilder::new().consolidation(Consolidation::Skip).naming(Naming::Skip).build()` (skips NamingResolution since Python handles its own naming via `improve_class_name`). The consolidated raw `Schema` provides concrete type data for rendering. + +- **BaseModel classes** for structs, with `ConfigDict(extra="ignore", populate_by_name=True)`. +- **Namespace alias classes** mirror the Rust module hierarchy for dotted access (e.g., `auth.UsersSignInRequest`). Type definitions are at module top-level with flat PascalCase names; namespace classes provide aliases. +- **Discriminated unions** (`Union[..., Field(discriminator="tag")]`) for internally-tagged enums. +- **RootModel** wrappers with `model_validator`/`model_serializer` for externally-tagged and adjacently-tagged enums. +- **Per-variant model expansion** for `#[serde(flatten)]` with internally-tagged enums (see Section 6). +- **Field descriptions** via `Field(description="...")` propagated from the schema. +- **Typed error returns** — `ApiResponse[OutputType, ErrorType]` in method signatures. +- **Field aliases** via `Field(serialization_alias=..., validation_alias=...)` for serde-renamed fields and underscore-prefixed fields. +- **Literal types** for discriminator fields, with alias handling for Python reserved words (e.g., `type` becomes `type_`). +- **TypeVar collision resolution** — renames TypeVars that collide with class names (e.g., `Identity` → `_T_Identity`). +- Python reserved words are sanitized in field names, method names, and parameters. +- Output is formatted with `ruff`. + +### OpenAPI + +Generates an OpenAPI 3.1 specification (JSON). Key features: + +- **`$ref`** for type references, with inline expansion for simple cases. +- **`allOf`** composition for `#[serde(flatten)]` -- the parent object schema and each flattened type schema are combined under `allOf`. +- **`oneOf`** for enum variants (tagged and untagged). +- **`const`** values for discriminator tag fields in internally-tagged enum variants. + +## 6. Flattened Type Handling + +`#[serde(flatten)]` merges fields from one type into another at the wire level. This requires distinct code generation strategies per target language. Internally-tagged enums compound this: the tag field and variant fields merge flat into the parent struct. + +### Wire Format + +Given this Rust code: + +```rust +#[derive(Serialize, Deserialize)] +struct Request { + id: String, + #[serde(flatten)] + payload: Action, +} + +#[derive(Serialize, Deserialize)] +#[serde(tag = "type")] +enum Action { + Create { name: String }, + Delete { reason: Option }, +} +``` + +Serde produces this JSON for `Request { id: "1", payload: Action::Create { name: "foo" } }`: + +```json +{"id": "1", "type": "Create", "name": "foo"} +``` + +All fields are merged flat -- there is no nesting. The codegen backends must produce types that match this exact wire format. + +### TypeScript + +Uses intersection types to compose the parent fields with the flattened type: + +```typescript +type Request = { + id: string; +} & NullToEmptyObject; +``` + +### Python (struct flatten) + +For flattened structs (not enums), all fields from the flattened type are expanded inline into the parent Pydantic model: + +```python +class Request(BaseModel): + id: str + # Fields from FlattenedStruct expanded here: + extra_field: str +``` + +### Python (internally-tagged enum flatten) + +When a struct flattens an internally-tagged enum, per-variant models are generated that merge the parent's fields, the tag discriminator, and the variant's fields: + +```python +class RequestCreate(BaseModel): + """'Create' variant of Request""" + id: str + type_: Literal['Create'] = Field(default="Create", serialization_alias='type', validation_alias='type') + name: str + +class RequestDelete(BaseModel): + """'Delete' variant of Request""" + id: str + type_: Literal['Delete'] = Field(default="Delete", serialization_alias='type', validation_alias='type') + reason: str | None = None + +class Request(RootModel): + root: Annotated[ + Union[RequestCreate, RequestDelete], + Field(discriminator="type_"), + ] +``` + +Each per-variant model contains all parent struct fields, the `Literal`-typed tag discriminator, and the variant-specific fields. The parent type becomes a `RootModel` with a discriminated union. + +The implementation handles several edge cases: +- **Unnamed variants** with a single field: the inner struct's fields are expanded. +- **Box-wrapped variants**: `Box` is unwrapped to get the inner type. +- **Optional flattened fields**: all expanded fields become optional. +- **Multiple flattened structs**: non-enum flattened structs are also expanded into each variant model. + +For other enum representations (external, adjacent, untagged), the flattened enum is emitted as a regular typed field. This preserves data but does not match the flat wire format that serde produces. + +### OpenAPI + +Uses `allOf` composition: + +```json +{ + "allOf": [ + { "$ref": "#/components/schemas/Action" }, + { + "type": "object", + "properties": { "id": { "type": "string" } }, + "required": ["id"] + } + ] +} +``` + +For enums, `oneOf` is used for the variant schemas with `const` values on tag fields. + +### Rust + +Preserves the original `#[serde(flatten)]` attribute on the field, since the generated Rust client uses serde directly. + +## 7. Limitations and Design Gaps + +### TypeScript, Rust, and OpenAPI backends use raw Schema + +The Python backend uses `SemanticSchema` for iteration ordering via `PipelineBuilder` (with consolidation and naming skipped). The TypeScript, Rust, and OpenAPI backends still consume the raw `Schema` directly. Migrating them to `SemanticSchema` would provide deterministic ordering and dependency-aware topological sorting. + +### Flattened enum handling varies by representation + +The Python backend generates per-variant models for flattened internally-tagged enums (wire-compatible). For externally-tagged, adjacently-tagged, and untagged enums, the flattened field is emitted as a regular nested field, which does not match the flat wire format. TypeScript uses intersection types for all representations. OpenAPI uses `allOf` composition. The backends do not share a common strategy. + +### CircularDependencyResolutionStage + +Cycle detection uses Tarjan's SCC algorithm. The `Boxing` strategy is a no-op because Rust schemas already encode `Box`. The `ForwardDeclarations`, `OptionalBreaking`, and `ReferenceCounted` strategies are defined in `ResolutionStrategy` but their `apply_*` methods return `Ok(())` without modifying the schema. + +### Python codegen coverage + +Validated against a production 284-endpoint API (59K-line generated client, 284 endpoints). Remaining gap: externally-tagged enums generate more boilerplate than TypeScript equivalents (multiple classes + RootModel + model_validator vs inline union syntax). diff --git a/docs/book.toml b/docs/book.toml index 58a0a67a..ddd306bb 100644 --- a/docs/book.toml +++ b/docs/book.toml @@ -5,10 +5,6 @@ src = "src" title = "ReflectAPI Documentation" description = "Code-first Rust web service API declaration and client generation" -[serve] -address = "0.0.0.0" -port = 3000 - [preprocessor.links] [output.html] diff --git a/reflectapi-cli/Cargo.toml b/reflectapi-cli/Cargo.toml index c1a1fc57..264a0439 100644 --- a/reflectapi-cli/Cargo.toml +++ b/reflectapi-cli/Cargo.toml @@ -27,7 +27,6 @@ rouille = "3" clap = { version = "4.5.3", features = ["derive"] } clap_derive = "4.5.3" -askama = "0.12.1" anyhow = "1.0.81" serde_json = "1.0.114" diff --git a/reflectapi-demo/clients/python/generated.py b/reflectapi-demo/clients/python/generated.py index da86409e..4b59f5c4 100644 --- a/reflectapi-demo/clients/python/generated.py +++ b/reflectapi-demo/clients/python/generated.py @@ -29,7 +29,6 @@ from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiOption from reflectapi_runtime import ReflectapiEmpty -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -44,20 +43,13 @@ class MyapiHealthCheckFail(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) -class MyapiProtoPetsRemoveError(str, Enum): - """Generated enum.""" - - NOT_FOUND = "NotFound" - NOT_AUTHORIZED = "NotAuthorized" - - class MyapiModelBehaviorAggressiveVariant(BaseModel): """Aggressive variant""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - field_0: float - field_1: str + field_0: float = Field(description="aggressiveness level") + field_1: str = Field(description="some notes") class MyapiModelBehaviorOtherVariant(BaseModel): @@ -65,8 +57,10 @@ class MyapiModelBehaviorOtherVariant(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - description: str - notes: str | None = None + description: str = Field(description="Custom provided description of a behavior") + notes: str | None = Field( + default=None, description="Additional notes\nUp to a user to put free text here" + ) # Externally tagged enum using RootModel @@ -115,141 +109,97 @@ def _serialize_externally_tagged(self): if isinstance(self.root, MyapiModelBehaviorAggressiveVariant): return {"Aggressive": [self.root.field_0, self.root.field_1]} if isinstance(self.root, MyapiModelBehaviorOtherVariant): - return {"Other": self.root.model_dump(exclude_none=True)} + return {"Other": self.root.model_dump()} raise ValueError( f"Cannot serialize MyapiModelBehavior variant: {type(self.root)}" ) -class MyapiProtoHeaders(BaseModel): - """Generated data model.""" +class MyapiModelKindDog(BaseModel): + """A dog""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - authorization: str + type: Literal["dog"] = Field(default="dog", description="Discriminator field") + breed: str = Field(description="breed of the dog") -class MyapiProtoInternalError(BaseModel): - """Generated data model.""" +class MyapiModelKindCat(BaseModel): + """A cat""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - message: str + type: Literal["cat"] = Field(default="cat", description="Discriminator field") + lives: int = Field(description="lives left") -class MyapiProtoPetsCreateErrorInvalidIdentityVariant(BaseModel): - """InvalidIdentity variant""" +class MyapiModelKindBird(BaseModel): + """Test for unit variants in internally tagged enums""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - message: str - - -# Externally tagged enum using RootModel -MyapiProtoPetsCreateErrorVariants = Union[ - Literal["Conflict"], - Literal["NotAuthorized"], - MyapiProtoPetsCreateErrorInvalidIdentityVariant, -] - - -class MyapiProtoPetsCreateError(RootModel[MyapiProtoPetsCreateErrorVariants]): - """Externally tagged enum""" - - @model_validator(mode="before") - @classmethod - def _validate_externally_tagged(cls, data): - # Handle direct variant instances (for programmatic creation) - if isinstance(data, MyapiProtoPetsCreateErrorInvalidIdentityVariant): - return data - - # Handle JSON data (for deserialization) - if isinstance(data, str) and data == "Conflict": - return data - if isinstance(data, str) and data == "NotAuthorized": - return data - - if isinstance(data, dict): - if len(data) != 1: - raise ValueError("Externally tagged enum must have exactly one key") - - key, value = next(iter(data.items())) - if key == "InvalidIdentity": - return MyapiProtoPetsCreateErrorInvalidIdentityVariant(**value) - - raise ValueError(f"Unknown variant for MyapiProtoPetsCreateError: {data}") + type: Literal["bird"] = Field(default="bird", description="Discriminator field") - @model_serializer - def _serialize_externally_tagged(self): - if self.root == "Conflict": - return "Conflict" - if self.root == "NotAuthorized": - return "NotAuthorized" - if isinstance(self.root, MyapiProtoPetsCreateErrorInvalidIdentityVariant): - return {"InvalidIdentity": self.root.model_dump(exclude_none=True)} - raise ValueError( - f"Cannot serialize MyapiProtoPetsCreateError variant: {type(self.root)}" - ) +class MyapiModelKind(RootModel): + root: Annotated[ + Union[MyapiModelKindDog, MyapiModelKindCat, MyapiModelKindBird], + Field(discriminator="type"), + ] -class MyapiProtoPetsRemoveRequest(BaseModel): +class MyapiModelInputPet(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - name: str + name: str = Field(description="identity") + kind: myapi.model.Kind = Field(description="kind of pet") + age: int | None = Field(default=None, description="age of the pet") + updated_at: datetime | None = None + behaviors: list[myapi.model.Behavior] | None = Field( + default=None, description="behaviors of the pet" + ) -class MyapiProtoValidationA(BaseModel): +class MyapiModelOutputPet(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - message: str + name: str = Field(description="identity") + kind: myapi.model.Kind = Field(description="kind of pet") + age: int | None = Field(default=None, description="age of the pet") + updated_at: datetime + behaviors: list[myapi.model.Behavior] | None = Field( + default=None, description="behaviors of the pet" + ) -class MyapiProtoPaginated(BaseModel, Generic[T]): +class MyapiProtoHeaders(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - items: list[T] - cursor: str | None = None - - -class MyapiModelKindDog(BaseModel): - """A dog""" - - model_config = ConfigDict(extra="ignore", populate_by_name=True) - - type: Literal["dog"] = "dog" - breed: str + authorization: str = Field(description="Authorization header") -class MyapiModelKindCat(BaseModel): - """A cat""" +class MyapiProtoInternalError(BaseModel): + """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["cat"] = "cat" - lives: int + message: str -class MyapiModelKindBird(BaseModel): - """Test for unit variants in internally tagged enums""" +class MyapiProtoPaginated(BaseModel, Generic[T]): + """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["bird"] = "bird" - - -class MyapiModelKind(RootModel): - root: Annotated[ - Union[MyapiModelKindDog, MyapiModelKindCat, MyapiModelKindBird], - Field(discriminator="type"), - ] + items: list[T] = Field(description="slice of a collection") + cursor: str | None = Field(default=None, description="cursor for getting next page") class MyapiProtoPetsListRequest(BaseModel): @@ -261,119 +211,142 @@ class MyapiProtoPetsListRequest(BaseModel): cursor: str | None = None -class MyapiProtoPetsListErrorInvalidCursor(BaseModel): +class MyapiProtoPetsRemoveRequest(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - kind: Literal["InvalidCursor"] = "InvalidCursor" + name: str = Field(description="identity") -class MyapiProtoPetsListErrorUnauthorized(BaseModel): +class MyapiProtoPetsUpdateRequest(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - kind: Literal["Unauthorized"] = "Unauthorized" + name: str = Field(description="identity") + kind: myapi.model.Kind | None = Field( + default=None, description="kind of pet, non nullable in the model" + ) + age: ReflectapiOption[int] = Field( + default=None, description="age of the pet, nullable in the model" + ) + behaviors: ReflectapiOption[list[myapi.model.Behavior]] = Field( + default=None, description="behaviors of the pet, nullable in the model" + ) -class MyapiProtoPetsListErrorInternal(BaseModel): +class MyapiProtoValidationA(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - kind: Literal["Internal"] = "Internal" message: str -class MyapiProtoPetsListError(RootModel): - root: Annotated[ - Union[ - MyapiProtoPetsListErrorInvalidCursor, - MyapiProtoPetsListErrorUnauthorized, - MyapiProtoPetsListErrorInternal, - ], - Field(discriminator="kind"), - ] - - -class MyapiProtoValidationErrorValidationAVariant(BaseModel): - """ValidationA variant""" +class MyapiProtoPetsCreateErrorInvalidIdentityVariant(BaseModel): + """InvalidIdentity variant""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - field_0: MyapiProtoValidationA + message: str # Externally tagged enum using RootModel -MyapiProtoValidationErrorVariants = MyapiProtoValidationErrorValidationAVariant +MyapiProtoPetsCreateErrorVariants = Union[ + Literal["Conflict"], + Literal["NotAuthorized"], + MyapiProtoPetsCreateErrorInvalidIdentityVariant, +] -class MyapiProtoValidationError(RootModel[MyapiProtoValidationErrorVariants]): +class MyapiProtoPetsCreateError(RootModel[MyapiProtoPetsCreateErrorVariants]): """Externally tagged enum""" @model_validator(mode="before") @classmethod def _validate_externally_tagged(cls, data): # Handle direct variant instances (for programmatic creation) - if isinstance(data, MyapiProtoValidationErrorValidationAVariant): + if isinstance(data, MyapiProtoPetsCreateErrorInvalidIdentityVariant): return data # Handle JSON data (for deserialization) + if isinstance(data, str) and data == "Conflict": + return data + if isinstance(data, str) and data == "NotAuthorized": + return data if isinstance(data, dict): if len(data) != 1: raise ValueError("Externally tagged enum must have exactly one key") key, value = next(iter(data.items())) - if key == "ValidationA": - return MyapiProtoValidationErrorValidationAVariant(field_0=value) + if key == "InvalidIdentity": + return MyapiProtoPetsCreateErrorInvalidIdentityVariant(**value) - raise ValueError(f"Unknown variant for MyapiProtoValidationError: {data}") + raise ValueError(f"Unknown variant for MyapiProtoPetsCreateError: {data}") @model_serializer def _serialize_externally_tagged(self): - if isinstance(self.root, MyapiProtoValidationErrorValidationAVariant): - return {"ValidationA": self.root.field_0} + if self.root == "Conflict": + return "Conflict" + if self.root == "NotAuthorized": + return "NotAuthorized" + if isinstance(self.root, MyapiProtoPetsCreateErrorInvalidIdentityVariant): + return {"InvalidIdentity": self.root.model_dump()} raise ValueError( - f"Cannot serialize MyapiProtoValidationError variant: {type(self.root)}" + f"Cannot serialize MyapiProtoPetsCreateError variant: {type(self.root)}" ) -class MyapiModelInputPet(BaseModel): +class MyapiProtoPetsListErrorInvalidCursor(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - name: str - kind: MyapiModelKind - age: int | None = None - updated_at: datetime | None = None - behaviors: list[MyapiModelBehavior] | None = None + kind: Literal["InvalidCursor"] = Field( + default="InvalidCursor", description="Discriminator field" + ) -class MyapiModelOutputPet(BaseModel): +class MyapiProtoPetsListErrorUnauthorized(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - name: str - kind: MyapiModelKind - age: int | None = None - updated_at: datetime - behaviors: list[MyapiModelBehavior] | None = None + kind: Literal["Unauthorized"] = Field( + default="Unauthorized", description="Discriminator field" + ) -class MyapiProtoPetsUpdateRequest(BaseModel): +class MyapiProtoPetsListErrorInternal(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - name: str - kind: MyapiModelKind | None = None - age: ReflectapiOption[int] = None - behaviors: ReflectapiOption[list[MyapiModelBehavior]] = None + kind: Literal["Internal"] = Field( + default="Internal", description="Discriminator field" + ) + message: str + + +class MyapiProtoPetsListError(RootModel): + root: Annotated[ + Union[ + MyapiProtoPetsListErrorInvalidCursor, + MyapiProtoPetsListErrorUnauthorized, + MyapiProtoPetsListErrorInternal, + ], + Field(discriminator="kind"), + ] + + +class MyapiProtoPetsRemoveError(str, Enum): + """Generated enum.""" + + NOT_FOUND = "NotFound" + NOT_AUTHORIZED = "NotAuthorized" class MyapiProtoPetsUpdateErrorValidationVariant(BaseModel): @@ -381,7 +354,7 @@ class MyapiProtoPetsUpdateErrorValidationVariant(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - field_0: list[MyapiProtoValidationError] + field_0: list[myapi.proto.ValidationError] # Externally tagged enum using RootModel @@ -432,6 +405,102 @@ def _serialize_externally_tagged(self): ) +class MyapiProtoValidationErrorValidationAVariant(BaseModel): + """ValidationA variant""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + field_0: myapi.proto.ValidationA + + +# Externally tagged enum using RootModel +MyapiProtoValidationErrorVariants = MyapiProtoValidationErrorValidationAVariant + + +class MyapiProtoValidationError(RootModel[MyapiProtoValidationErrorVariants]): + """Externally tagged enum""" + + @model_validator(mode="before") + @classmethod + def _validate_externally_tagged(cls, data): + # Handle direct variant instances (for programmatic creation) + if isinstance(data, MyapiProtoValidationErrorValidationAVariant): + return data + + # Handle JSON data (for deserialization) + + if isinstance(data, dict): + if len(data) != 1: + raise ValueError("Externally tagged enum must have exactly one key") + + key, value = next(iter(data.items())) + if key == "ValidationA": + return MyapiProtoValidationErrorValidationAVariant(field_0=value) + + raise ValueError(f"Unknown variant for MyapiProtoValidationError: {data}") + + @model_serializer + def _serialize_externally_tagged(self): + if isinstance(self.root, MyapiProtoValidationErrorValidationAVariant): + return {"ValidationA": self.root.field_0} + + raise ValueError( + f"Cannot serialize MyapiProtoValidationError variant: {type(self.root)}" + ) + + +# Namespace classes for dotted access to types +class myapi: + """Namespace for myapi types.""" + + HealthCheckFail = MyapiHealthCheckFail + + class model: + """Namespace for model types.""" + + BehaviorAggressiveVariant = MyapiModelBehaviorAggressiveVariant + BehaviorOtherVariant = MyapiModelBehaviorOtherVariant + Behavior = MyapiModelBehavior + KindDog = MyapiModelKindDog + KindCat = MyapiModelKindCat + KindBird = MyapiModelKindBird + Kind = MyapiModelKind + + class input: + """Namespace for input types.""" + + Pet = MyapiModelInputPet + + class output: + """Namespace for output types.""" + + Pet = MyapiModelOutputPet + + class proto: + """Namespace for proto types.""" + + Headers = MyapiProtoHeaders + InternalError = MyapiProtoInternalError + Paginated = MyapiProtoPaginated + PetsListRequest = MyapiProtoPetsListRequest + PetsRemoveRequest = MyapiProtoPetsRemoveRequest + PetsUpdateRequest = MyapiProtoPetsUpdateRequest + ValidationA = MyapiProtoValidationA + PetsCreateErrorInvalidIdentityVariant = ( + MyapiProtoPetsCreateErrorInvalidIdentityVariant + ) + PetsCreateError = MyapiProtoPetsCreateError + PetsListErrorInvalidCursor = MyapiProtoPetsListErrorInvalidCursor + PetsListErrorUnauthorized = MyapiProtoPetsListErrorUnauthorized + PetsListErrorInternal = MyapiProtoPetsListErrorInternal + PetsListError = MyapiProtoPetsListError + PetsRemoveError = MyapiProtoPetsRemoveError + PetsUpdateErrorValidationVariant = MyapiProtoPetsUpdateErrorValidationVariant + PetsUpdateError = MyapiProtoPetsUpdateError + ValidationErrorValidationAVariant = MyapiProtoValidationErrorValidationAVariant + ValidationError = MyapiProtoValidationError + + class AsyncHealthClient: """Async client for health operations.""" @@ -440,11 +509,11 @@ def __init__(self, client: AsyncClientBase) -> None: async def check( self, - ) -> ApiResponse[Any]: + ) -> ApiResponse[Any, myapi.HealthCheckFail]: """Check the health of the service Returns: - ApiResponse[Any]: Response containing Any data + ApiResponse[Any, myapi.HealthCheckFail]: Success=Any, Error=myapi.HealthCheckFail """ path = "/health.check" @@ -454,6 +523,7 @@ async def check( path, params=params if params else None, response_model=None, + error_model=myapi.HealthCheckFail, ) @@ -465,16 +535,16 @@ def __init__(self, client: AsyncClientBase) -> None: async def create( self, - data: Optional[MyapiModelInputPet] = None, - headers: Optional[MyapiProtoHeaders] = None, - ) -> ApiResponse[Any]: + data: Optional[myapi.model.input.Pet] = None, + headers: Optional[myapi.proto.Headers] = None, + ) -> ApiResponse[Any, myapi.proto.PetsCreateError]: """Create a new pet Args: data: Request data for the create operation. Returns: - ApiResponse[Any]: Response containing Any data + ApiResponse[Any, myapi.proto.PetsCreateError]: Success=Any, Error=myapi.proto.PetsCreateError """ path = "/pets.create" @@ -486,20 +556,21 @@ async def create( json_model=data, headers_model=headers, response_model=None, + error_model=myapi.proto.PetsCreateError, ) async def delete( self, - data: Optional[MyapiProtoPetsRemoveRequest] = None, - headers: Optional[MyapiProtoHeaders] = None, - ) -> ApiResponse[Any]: + data: Optional[myapi.proto.PetsRemoveRequest] = None, + headers: Optional[myapi.proto.Headers] = None, + ) -> ApiResponse[Any, myapi.proto.PetsRemoveError]: """Remove an existing pet Args: data: Request data for the delete operation. Returns: - ApiResponse[Any]: Response containing Any data + ApiResponse[Any, myapi.proto.PetsRemoveError]: Success=Any, Error=myapi.proto.PetsRemoveError .. deprecated:: Use pets.remove instead @@ -521,16 +592,17 @@ async def delete( json_model=data, headers_model=headers, response_model=None, + error_model=myapi.proto.PetsRemoveError, ) async def get_first( self, - headers: Optional[MyapiProtoHeaders] = None, - ) -> ApiResponse[MyapiModelOutputPet | None]: + headers: Optional[myapi.proto.Headers] = None, + ) -> ApiResponse[myapi.model.output.Pet | None, None]: """Fetch first pet, if any exists Returns: - ApiResponse[MyapiModelOutputPet | None]: Response containing MyapiModelOutputPet | None data + ApiResponse[myapi.model.output.Pet | None, None]: Success=myapi.model.output.Pet | None, Error=None """ path = "/pets.get-first" @@ -540,21 +612,24 @@ async def get_first( path, params=params if params else None, headers_model=headers, - response_model=MyapiModelOutputPet | None, + response_model=myapi.model.output.Pet | None, + error_model=None, ) async def list( self, - data: Optional[MyapiProtoPetsListRequest] = None, - headers: Optional[MyapiProtoHeaders] = None, - ) -> ApiResponse[MyapiProtoPaginated[MyapiModelOutputPet]]: + data: Optional[myapi.proto.PetsListRequest] = None, + headers: Optional[myapi.proto.Headers] = None, + ) -> ApiResponse[ + myapi.proto.Paginated[myapi.model.output.Pet], myapi.proto.PetsListError + ]: """List available pets Args: data: Request data for the list operation. Returns: - ApiResponse[MyapiProtoPaginated[MyapiModelOutputPet]]: Response containing MyapiProtoPaginated[MyapiModelOutputPet] data + ApiResponse[myapi.proto.Paginated[myapi.model.output.Pet], myapi.proto.PetsListError]: Success=myapi.proto.Paginated[myapi.model.output.Pet], Error=myapi.proto.PetsListError """ path = "/pets.list" @@ -565,21 +640,22 @@ async def list( params=params if params else None, json_model=data, headers_model=headers, - response_model=MyapiProtoPaginated[MyapiModelOutputPet], + response_model=myapi.proto.Paginated[myapi.model.output.Pet], + error_model=myapi.proto.PetsListError, ) async def remove( self, - data: Optional[MyapiProtoPetsRemoveRequest] = None, - headers: Optional[MyapiProtoHeaders] = None, - ) -> ApiResponse[Any]: + data: Optional[myapi.proto.PetsRemoveRequest] = None, + headers: Optional[myapi.proto.Headers] = None, + ) -> ApiResponse[Any, myapi.proto.PetsRemoveError]: """Remove an existing pet Args: data: Request data for the remove operation. Returns: - ApiResponse[Any]: Response containing Any data + ApiResponse[Any, myapi.proto.PetsRemoveError]: Success=Any, Error=myapi.proto.PetsRemoveError """ path = "/pets.remove" @@ -591,20 +667,21 @@ async def remove( json_model=data, headers_model=headers, response_model=None, + error_model=myapi.proto.PetsRemoveError, ) async def update( self, - data: Optional[MyapiProtoPetsUpdateRequest] = None, - headers: Optional[MyapiProtoHeaders] = None, - ) -> ApiResponse[Any]: + data: Optional[myapi.proto.PetsUpdateRequest] = None, + headers: Optional[myapi.proto.Headers] = None, + ) -> ApiResponse[Any, myapi.proto.PetsUpdateError]: """Update an existing pet Args: data: Request data for the update operation. Returns: - ApiResponse[Any]: Response containing Any data + ApiResponse[Any, myapi.proto.PetsUpdateError]: Success=Any, Error=myapi.proto.PetsUpdateError """ path = "/pets.update" @@ -616,6 +693,7 @@ async def update( json_model=data, headers_model=headers, response_model=None, + error_model=myapi.proto.PetsUpdateError, ) @@ -642,11 +720,11 @@ def __init__(self, client: ClientBase) -> None: def check( self, - ) -> ApiResponse[Any]: + ) -> ApiResponse[Any, myapi.HealthCheckFail]: """Check the health of the service Returns: - ApiResponse[Any]: Response containing Any data + ApiResponse[Any, myapi.HealthCheckFail]: Success=Any, Error=myapi.HealthCheckFail """ path = "/health.check" @@ -656,6 +734,7 @@ def check( path, params=params if params else None, response_model=None, + error_model=myapi.HealthCheckFail, ) @@ -667,16 +746,16 @@ def __init__(self, client: ClientBase) -> None: def create( self, - data: Optional[MyapiModelInputPet] = None, - headers: Optional[MyapiProtoHeaders] = None, - ) -> ApiResponse[Any]: + data: Optional[myapi.model.input.Pet] = None, + headers: Optional[myapi.proto.Headers] = None, + ) -> ApiResponse[Any, myapi.proto.PetsCreateError]: """Create a new pet Args: data: Request data for the create operation. Returns: - ApiResponse[Any]: Response containing Any data + ApiResponse[Any, myapi.proto.PetsCreateError]: Success=Any, Error=myapi.proto.PetsCreateError """ path = "/pets.create" @@ -688,20 +767,21 @@ def create( json_model=data, headers_model=headers, response_model=None, + error_model=myapi.proto.PetsCreateError, ) def delete( self, - data: Optional[MyapiProtoPetsRemoveRequest] = None, - headers: Optional[MyapiProtoHeaders] = None, - ) -> ApiResponse[Any]: + data: Optional[myapi.proto.PetsRemoveRequest] = None, + headers: Optional[myapi.proto.Headers] = None, + ) -> ApiResponse[Any, myapi.proto.PetsRemoveError]: """Remove an existing pet Args: data: Request data for the delete operation. Returns: - ApiResponse[Any]: Response containing Any data + ApiResponse[Any, myapi.proto.PetsRemoveError]: Success=Any, Error=myapi.proto.PetsRemoveError .. deprecated:: Use pets.remove instead @@ -723,16 +803,17 @@ def delete( json_model=data, headers_model=headers, response_model=None, + error_model=myapi.proto.PetsRemoveError, ) def get_first( self, - headers: Optional[MyapiProtoHeaders] = None, - ) -> ApiResponse[MyapiModelOutputPet | None]: + headers: Optional[myapi.proto.Headers] = None, + ) -> ApiResponse[myapi.model.output.Pet | None, None]: """Fetch first pet, if any exists Returns: - ApiResponse[MyapiModelOutputPet | None]: Response containing MyapiModelOutputPet | None data + ApiResponse[myapi.model.output.Pet | None, None]: Success=myapi.model.output.Pet | None, Error=None """ path = "/pets.get-first" @@ -742,21 +823,24 @@ def get_first( path, params=params if params else None, headers_model=headers, - response_model=MyapiModelOutputPet | None, + response_model=myapi.model.output.Pet | None, + error_model=None, ) def list( self, - data: Optional[MyapiProtoPetsListRequest] = None, - headers: Optional[MyapiProtoHeaders] = None, - ) -> ApiResponse[MyapiProtoPaginated[MyapiModelOutputPet]]: + data: Optional[myapi.proto.PetsListRequest] = None, + headers: Optional[myapi.proto.Headers] = None, + ) -> ApiResponse[ + myapi.proto.Paginated[myapi.model.output.Pet], myapi.proto.PetsListError + ]: """List available pets Args: data: Request data for the list operation. Returns: - ApiResponse[MyapiProtoPaginated[MyapiModelOutputPet]]: Response containing MyapiProtoPaginated[MyapiModelOutputPet] data + ApiResponse[myapi.proto.Paginated[myapi.model.output.Pet], myapi.proto.PetsListError]: Success=myapi.proto.Paginated[myapi.model.output.Pet], Error=myapi.proto.PetsListError """ path = "/pets.list" @@ -767,21 +851,22 @@ def list( params=params if params else None, json_model=data, headers_model=headers, - response_model=MyapiProtoPaginated[MyapiModelOutputPet], + response_model=myapi.proto.Paginated[myapi.model.output.Pet], + error_model=myapi.proto.PetsListError, ) def remove( self, - data: Optional[MyapiProtoPetsRemoveRequest] = None, - headers: Optional[MyapiProtoHeaders] = None, - ) -> ApiResponse[Any]: + data: Optional[myapi.proto.PetsRemoveRequest] = None, + headers: Optional[myapi.proto.Headers] = None, + ) -> ApiResponse[Any, myapi.proto.PetsRemoveError]: """Remove an existing pet Args: data: Request data for the remove operation. Returns: - ApiResponse[Any]: Response containing Any data + ApiResponse[Any, myapi.proto.PetsRemoveError]: Success=Any, Error=myapi.proto.PetsRemoveError """ path = "/pets.remove" @@ -793,20 +878,21 @@ def remove( json_model=data, headers_model=headers, response_model=None, + error_model=myapi.proto.PetsRemoveError, ) def update( self, - data: Optional[MyapiProtoPetsUpdateRequest] = None, - headers: Optional[MyapiProtoHeaders] = None, - ) -> ApiResponse[Any]: + data: Optional[myapi.proto.PetsUpdateRequest] = None, + headers: Optional[myapi.proto.Headers] = None, + ) -> ApiResponse[Any, myapi.proto.PetsUpdateError]: """Update an existing pet Args: data: Request data for the update operation. Returns: - ApiResponse[Any]: Response containing Any data + ApiResponse[Any, myapi.proto.PetsUpdateError]: Success=Any, Error=myapi.proto.PetsUpdateError """ path = "/pets.update" @@ -818,6 +904,7 @@ def update( json_model=data, headers_model=headers, response_model=None, + error_model=myapi.proto.PetsUpdateError, ) @@ -836,23 +923,6 @@ def __init__( self.pets = PetsClient(self) -# Nested class definitions for better organization - - -class Pet: - """Grouped types for better organization.""" - - Input = MyapiModelInputPet - Output = MyapiModelOutputPet - - class Kind: - """Kind variants for this type.""" - - Union = MyapiModelKind - Dog = MyapiModelKindDog - Cat = MyapiModelKindCat - - # External type definitions StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] @@ -861,273 +931,23 @@ class Kind: # Rebuild models to resolve forward references try: - MyapiHealthCheckFail.model_rebuild() - MyapiModelBehavior.model_rebuild() - MyapiModelInputPet.model_rebuild() - MyapiModelKind.model_rebuild() - MyapiModelOutputPet.model_rebuild() - MyapiProtoHeaders.model_rebuild() - MyapiProtoInternalError.model_rebuild() - MyapiProtoPaginated.model_rebuild() - MyapiProtoPetsCreateError.model_rebuild() - MyapiProtoPetsListError.model_rebuild() - MyapiProtoPetsListRequest.model_rebuild() - MyapiProtoPetsRemoveError.model_rebuild() - MyapiProtoPetsRemoveRequest.model_rebuild() - MyapiProtoPetsUpdateError.model_rebuild() - MyapiProtoPetsUpdateRequest.model_rebuild() - MyapiProtoValidationA.model_rebuild() - MyapiProtoValidationError.model_rebuild() + myapi.HealthCheckFail.model_rebuild() + myapi.model.Behavior.model_rebuild() + myapi.model.Kind.model_rebuild() + myapi.model.input.Pet.model_rebuild() + myapi.model.output.Pet.model_rebuild() + myapi.proto.Headers.model_rebuild() + myapi.proto.InternalError.model_rebuild() + myapi.proto.Paginated.model_rebuild() + myapi.proto.PetsCreateError.model_rebuild() + myapi.proto.PetsListError.model_rebuild() + myapi.proto.PetsListRequest.model_rebuild() + myapi.proto.PetsRemoveError.model_rebuild() + myapi.proto.PetsRemoveRequest.model_rebuild() + myapi.proto.PetsUpdateError.model_rebuild() + myapi.proto.PetsUpdateRequest.model_rebuild() + myapi.proto.ValidationA.model_rebuild() + myapi.proto.ValidationError.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class MyapiModelBehaviorFactory: - """Factory class for creating MyapiModelBehavior variants with ergonomic syntax. - - MyapiModelBehavior variants - """ - - @staticmethod - def calm() -> MyapiModelBehavior: - """Creates the 'Calm' variant of the MyapiModelBehavior enum.""" - return MyapiModelBehavior("Calm") - - @staticmethod - def aggressive(field_0, field_1) -> MyapiModelBehavior: - """Creates the 'Aggressive' variant of the MyapiModelBehavior enum.""" - return MyapiModelBehavior( - MyapiModelBehaviorAggressiveVariant(field_0=field_0, field_1=field_1) - ) - - @staticmethod - def other(description, notes=None) -> MyapiModelBehavior: - """Creates the 'Other' variant of the MyapiModelBehavior enum.""" - return MyapiModelBehavior( - MyapiModelBehaviorOtherVariant(description=description, notes=notes) - ) - - -class MyapiProtoPetsCreateErrorFactory: - """Factory class for creating MyapiProtoPetsCreateError variants with ergonomic syntax. - - MyapiProtoPetsCreateError variants - """ - - @staticmethod - def conflict() -> MyapiProtoPetsCreateError: - """Creates the 'Conflict' variant of the MyapiProtoPetsCreateError enum.""" - return MyapiProtoPetsCreateError("Conflict") - - @staticmethod - def not_authorized() -> MyapiProtoPetsCreateError: - """Creates the 'NotAuthorized' variant of the MyapiProtoPetsCreateError enum.""" - return MyapiProtoPetsCreateError("NotAuthorized") - - @staticmethod - def invalid_identity(message) -> MyapiProtoPetsCreateError: - """Creates the 'InvalidIdentity' variant of the MyapiProtoPetsCreateError enum.""" - return MyapiProtoPetsCreateError( - MyapiProtoPetsCreateErrorInvalidIdentityVariant(message=message) - ) - - -class MyapiModelKindFactory: - """Factory class for creating MyapiModelKind variants with ergonomic syntax. - - MyapiModelKind variants - """ - - BIRD = MyapiModelKindBird() - - @staticmethod - def dog(breed) -> MyapiModelKindDog: - """Creates the 'dog' variant of the MyapiModelKind enum.""" - return MyapiModelKindDog(breed=breed) - - @staticmethod - def cat(lives) -> MyapiModelKindCat: - """Creates the 'cat' variant of the MyapiModelKind enum.""" - return MyapiModelKindCat(lives=lives) - - -class MyapiProtoPetsListErrorFactory: - """Factory class for creating MyapiProtoPetsListError variants with ergonomic syntax. - - MyapiProtoPetsListError variants - """ - - INVALIDCURSOR = MyapiProtoPetsListErrorInvalidCursor() - UNAUTHORIZED = MyapiProtoPetsListErrorUnauthorized() - - @staticmethod - def internal(field_0) -> MyapiProtoPetsListErrorInternal: - """Creates the 'Internal' variant of the MyapiProtoPetsListError enum.""" - return MyapiProtoPetsListErrorInternal(field_0=field_0) - - -class MyapiProtoValidationErrorFactory: - """Factory class for creating MyapiProtoValidationError variants with ergonomic syntax. - - MyapiProtoValidationError variants - """ - - @staticmethod - def validation_a(field_0) -> MyapiProtoValidationError: - """Creates the 'ValidationA' variant of the MyapiProtoValidationError enum.""" - return MyapiProtoValidationError( - MyapiProtoValidationErrorValidationAVariant(field_0=field_0) - ) - - -class MyapiProtoPetsUpdateErrorFactory: - """Factory class for creating MyapiProtoPetsUpdateError variants with ergonomic syntax. - - MyapiProtoPetsUpdateError variants - """ - - @staticmethod - def not_found() -> MyapiProtoPetsUpdateError: - """Creates the 'NotFound' variant of the MyapiProtoPetsUpdateError enum.""" - return MyapiProtoPetsUpdateError("NotFound") - - @staticmethod - def not_authorized() -> MyapiProtoPetsUpdateError: - """Creates the 'NotAuthorized' variant of the MyapiProtoPetsUpdateError enum.""" - return MyapiProtoPetsUpdateError("NotAuthorized") - - @staticmethod - def validation(field_0) -> MyapiProtoPetsUpdateError: - """Creates the 'Validation' variant of the MyapiProtoPetsUpdateError enum.""" - return MyapiProtoPetsUpdateError( - MyapiProtoPetsUpdateErrorValidationVariant(field_0=field_0) - ) - - -# Testing utilities - - -def create_myapihealthcheckfail_response( - value: MyapiHealthCheckFail, -) -> ApiResponse[MyapiHealthCheckFail]: - """Create a mock ApiResponse for MyapiHealthCheckFail.""" - return create_api_response(value) - - -def create_myapimodelbehavior_response( - value: MyapiModelBehavior, -) -> ApiResponse[MyapiModelBehavior]: - """Create a mock ApiResponse for MyapiModelBehavior.""" - return create_api_response(value) - - -def create_myapimodelinputpet_response( - value: MyapiModelInputPet, -) -> ApiResponse[MyapiModelInputPet]: - """Create a mock ApiResponse for MyapiModelInputPet.""" - return create_api_response(value) - - -def create_myapimodelkind_response( - value: MyapiModelKind, -) -> ApiResponse[MyapiModelKind]: - """Create a mock ApiResponse for MyapiModelKind.""" - return create_api_response(value) - - -def create_myapimodeloutputpet_response( - value: MyapiModelOutputPet, -) -> ApiResponse[MyapiModelOutputPet]: - """Create a mock ApiResponse for MyapiModelOutputPet.""" - return create_api_response(value) - - -def create_myapiprotoheaders_response( - value: MyapiProtoHeaders, -) -> ApiResponse[MyapiProtoHeaders]: - """Create a mock ApiResponse for MyapiProtoHeaders.""" - return create_api_response(value) - - -def create_myapiprotointernalerror_response( - value: MyapiProtoInternalError, -) -> ApiResponse[MyapiProtoInternalError]: - """Create a mock ApiResponse for MyapiProtoInternalError.""" - return create_api_response(value) - - -def create_myapiprotopaginated_response( - value: MyapiProtoPaginated, -) -> ApiResponse[MyapiProtoPaginated]: - """Create a mock ApiResponse for MyapiProtoPaginated.""" - return create_api_response(value) - - -def create_myapiprotopetscreateerror_response( - value: MyapiProtoPetsCreateError, -) -> ApiResponse[MyapiProtoPetsCreateError]: - """Create a mock ApiResponse for MyapiProtoPetsCreateError.""" - return create_api_response(value) - - -def create_myapiprotopetslisterror_response( - value: MyapiProtoPetsListError, -) -> ApiResponse[MyapiProtoPetsListError]: - """Create a mock ApiResponse for MyapiProtoPetsListError.""" - return create_api_response(value) - - -def create_myapiprotopetslistrequest_response( - value: MyapiProtoPetsListRequest, -) -> ApiResponse[MyapiProtoPetsListRequest]: - """Create a mock ApiResponse for MyapiProtoPetsListRequest.""" - return create_api_response(value) - - -def create_myapiprotopetsremoveerror_response( - value: MyapiProtoPetsRemoveError, -) -> ApiResponse[MyapiProtoPetsRemoveError]: - """Create a mock ApiResponse for MyapiProtoPetsRemoveError.""" - return create_api_response(value) - - -def create_myapiprotopetsremoverequest_response( - value: MyapiProtoPetsRemoveRequest, -) -> ApiResponse[MyapiProtoPetsRemoveRequest]: - """Create a mock ApiResponse for MyapiProtoPetsRemoveRequest.""" - return create_api_response(value) - - -def create_myapiprotopetsupdateerror_response( - value: MyapiProtoPetsUpdateError, -) -> ApiResponse[MyapiProtoPetsUpdateError]: - """Create a mock ApiResponse for MyapiProtoPetsUpdateError.""" - return create_api_response(value) - - -def create_myapiprotopetsupdaterequest_response( - value: MyapiProtoPetsUpdateRequest, -) -> ApiResponse[MyapiProtoPetsUpdateRequest]: - """Create a mock ApiResponse for MyapiProtoPetsUpdateRequest.""" - return create_api_response(value) - - -def create_myapiprotovalidationa_response( - value: MyapiProtoValidationA, -) -> ApiResponse[MyapiProtoValidationA]: - """Create a mock ApiResponse for MyapiProtoValidationA.""" - return create_api_response(value) - - -def create_myapiprotovalidationerror_response( - value: MyapiProtoValidationError, -) -> ApiResponse[MyapiProtoValidationError]: - """Create a mock ApiResponse for MyapiProtoValidationError.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/clients/python/uv.lock b/reflectapi-demo/clients/python/uv.lock new file mode 100644 index 00000000..07ae0558 --- /dev/null +++ b/reflectapi-demo/clients/python/uv.lock @@ -0,0 +1,346 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" }, +] + +[[package]] +name = "certifi" +version = "2026.2.25" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pydantic" +version = "2.12.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, + { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, + { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, + { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, + { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, + { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, + { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, + { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" }, + { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" }, + { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" }, + { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" }, + { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, + { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, + { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/90/2c/8af215c0f776415f3590cac4f9086ccefd6fd463befeae41cd4d3f193e5a/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087, upload-time = "2025-11-10T16:07:47.256Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" }, +] + +[[package]] +name = "reflectapi-demo-python-client" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "reflectapi-runtime" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [{ name = "reflectapi-runtime", editable = "../../../reflectapi-python-runtime" }] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.0.0" }, + { name = "pytest-asyncio", specifier = ">=0.21.0" }, + { name = "ruff", specifier = ">=0.12.5" }, +] + +[[package]] +name = "reflectapi-runtime" +version = "0.1.0" +source = { editable = "../../../reflectapi-python-runtime" } +dependencies = [ + { name = "httpx" }, + { name = "pydantic" }, +] + +[package.metadata] +requires-dist = [ + { name = "httpx", specifier = ">=0.25.0" }, + { name = "hypothesis", marker = "extra == 'dev'", specifier = ">=6.0.0" }, + { name = "hypothesis", marker = "extra == 'test'", specifier = ">=6.0.0" }, + { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.5.0" }, + { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0.0" }, + { name = "pytest", marker = "extra == 'test'", specifier = ">=7.0.0" }, + { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.21.0" }, + { name = "pytest-asyncio", marker = "extra == 'test'", specifier = ">=0.21.0" }, + { name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=4.0.0" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1.0" }, +] +provides-extras = ["dev", "test"] + +[package.metadata.requires-dev] +dev = [ + { name = "mypy", specifier = ">=1.17.0" }, + { name = "pytest", specifier = ">=8.4.1" }, + { name = "pytest-asyncio", specifier = ">=1.1.0" }, + { name = "pytest-cov", specifier = ">=6.2.1" }, + { name = "ruff", specifier = ">=0.12.5" }, + { name = "ty", specifier = ">=0.0.1a16" }, +] + +[[package]] +name = "ruff" +version = "0.15.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/14/b0/73cf7550861e2b4824950b8b52eebdcc5adc792a00c514406556c5b80817/ruff-0.15.8.tar.gz", hash = "sha256:995f11f63597ee362130d1d5a327a87cb6f3f5eae3094c620bcc632329a4d26e", size = 4610921, upload-time = "2026-03-26T18:39:38.675Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/92/c445b0cd6da6e7ae51e954939cb69f97e008dbe750cfca89b8cedc081be7/ruff-0.15.8-py3-none-linux_armv6l.whl", hash = "sha256:cbe05adeba76d58162762d6b239c9056f1a15a55bd4b346cfd21e26cd6ad7bc7", size = 10527394, upload-time = "2026-03-26T18:39:41.566Z" }, + { url = "https://files.pythonhosted.org/packages/eb/92/f1c662784d149ad1414cae450b082cf736430c12ca78367f20f5ed569d65/ruff-0.15.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d3e3d0b6ba8dca1b7ef9ab80a28e840a20070c4b62e56d675c24f366ef330570", size = 10905693, upload-time = "2026-03-26T18:39:30.364Z" }, + { url = "https://files.pythonhosted.org/packages/ca/f2/7a631a8af6d88bcef997eb1bf87cc3da158294c57044aafd3e17030613de/ruff-0.15.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6ee3ae5c65a42f273f126686353f2e08ff29927b7b7e203b711514370d500de3", size = 10323044, upload-time = "2026-03-26T18:39:33.37Z" }, + { url = "https://files.pythonhosted.org/packages/67/18/1bf38e20914a05e72ef3b9569b1d5c70a7ef26cd188d69e9ca8ef588d5bf/ruff-0.15.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdce027ada77baa448077ccc6ebb2fa9c3c62fd110d8659d601cf2f475858d94", size = 10629135, upload-time = "2026-03-26T18:39:44.142Z" }, + { url = "https://files.pythonhosted.org/packages/d2/e9/138c150ff9af60556121623d41aba18b7b57d95ac032e177b6a53789d279/ruff-0.15.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12e617fc01a95e5821648a6df341d80456bd627bfab8a829f7cfc26a14a4b4a3", size = 10348041, upload-time = "2026-03-26T18:39:52.178Z" }, + { url = "https://files.pythonhosted.org/packages/02/f1/5bfb9298d9c323f842c5ddeb85f1f10ef51516ac7a34ba446c9347d898df/ruff-0.15.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:432701303b26416d22ba696c39f2c6f12499b89093b61360abc34bcc9bf07762", size = 11121987, upload-time = "2026-03-26T18:39:55.195Z" }, + { url = "https://files.pythonhosted.org/packages/10/11/6da2e538704e753c04e8d86b1fc55712fdbdcc266af1a1ece7a51fff0d10/ruff-0.15.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d910ae974b7a06a33a057cb87d2a10792a3b2b3b35e33d2699fdf63ec8f6b17a", size = 11951057, upload-time = "2026-03-26T18:39:19.18Z" }, + { url = "https://files.pythonhosted.org/packages/83/f0/c9208c5fd5101bf87002fed774ff25a96eea313d305f1e5d5744698dc314/ruff-0.15.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2033f963c43949d51e6fdccd3946633c6b37c484f5f98c3035f49c27395a8ab8", size = 11464613, upload-time = "2026-03-26T18:40:06.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/22/d7f2fabdba4fae9f3b570e5605d5eb4500dcb7b770d3217dca4428484b17/ruff-0.15.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f29b989a55572fb885b77464cf24af05500806ab4edf9a0fd8977f9759d85b1", size = 11257557, upload-time = "2026-03-26T18:39:57.972Z" }, + { url = "https://files.pythonhosted.org/packages/71/8c/382a9620038cf6906446b23ce8632ab8c0811b8f9d3e764f58bedd0c9a6f/ruff-0.15.8-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:ac51d486bf457cdc985a412fb1801b2dfd1bd8838372fc55de64b1510eff4bec", size = 11169440, upload-time = "2026-03-26T18:39:22.205Z" }, + { url = "https://files.pythonhosted.org/packages/4d/0d/0994c802a7eaaf99380085e4e40c845f8e32a562e20a38ec06174b52ef24/ruff-0.15.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c9861eb959edab053c10ad62c278835ee69ca527b6dcd72b47d5c1e5648964f6", size = 10605963, upload-time = "2026-03-26T18:39:46.682Z" }, + { url = "https://files.pythonhosted.org/packages/19/aa/d624b86f5b0aad7cef6bbf9cd47a6a02dfdc4f72c92a337d724e39c9d14b/ruff-0.15.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8d9a5b8ea13f26ae90838afc33f91b547e61b794865374f114f349e9036835fb", size = 10357484, upload-time = "2026-03-26T18:39:49.176Z" }, + { url = "https://files.pythonhosted.org/packages/35/c3/e0b7835d23001f7d999f3895c6b569927c4d39912286897f625736e1fd04/ruff-0.15.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c2a33a529fb3cbc23a7124b5c6ff121e4d6228029cba374777bd7649cc8598b8", size = 10830426, upload-time = "2026-03-26T18:40:03.702Z" }, + { url = "https://files.pythonhosted.org/packages/f0/51/ab20b322f637b369383adc341d761eaaa0f0203d6b9a7421cd6e783d81b9/ruff-0.15.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:75e5cd06b1cf3f47a3996cfc999226b19aa92e7cce682dcd62f80d7035f98f49", size = 11345125, upload-time = "2026-03-26T18:39:27.799Z" }, + { url = "https://files.pythonhosted.org/packages/37/e6/90b2b33419f59d0f2c4c8a48a4b74b460709a557e8e0064cf33ad894f983/ruff-0.15.8-py3-none-win32.whl", hash = "sha256:bc1f0a51254ba21767bfa9a8b5013ca8149dcf38092e6a9eb704d876de94dc34", size = 10571959, upload-time = "2026-03-26T18:39:36.117Z" }, + { url = "https://files.pythonhosted.org/packages/1f/a2/ef467cb77099062317154c63f234b8a7baf7cb690b99af760c5b68b9ee7f/ruff-0.15.8-py3-none-win_amd64.whl", hash = "sha256:04f79eff02a72db209d47d665ba7ebcad609d8918a134f86cb13dd132159fc89", size = 11743893, upload-time = "2026-03-26T18:39:25.01Z" }, + { url = "https://files.pythonhosted.org/packages/15/e2/77be4fff062fa78d9b2a4dea85d14785dac5f1d0c1fb58ed52331f0ebe28/ruff-0.15.8-py3-none-win_arm64.whl", hash = "sha256:cf891fa8e3bb430c0e7fac93851a5978fc99c8fa2c053b57b118972866f8e5f2", size = 11048175, upload-time = "2026-03-26T18:40:01.06Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] diff --git a/reflectapi-demo/clients/rust/generated/src/generated.rs b/reflectapi-demo/clients/rust/generated/src/generated.rs index 2fdf2db4..0e2e1f31 100644 --- a/reflectapi-demo/clients/rust/generated/src/generated.rs +++ b/reflectapi-demo/clients/rust/generated/src/generated.rs @@ -218,7 +218,6 @@ pub mod interface { } } pub mod types { - pub mod myapi { #[derive(Debug, serde::Deserialize, serde::Serialize)] diff --git a/reflectapi-demo/clients/typescript/generated.ts b/reflectapi-demo/clients/typescript/generated.ts index a83c1b9e..48c1f537 100644 --- a/reflectapi-demo/clients/typescript/generated.ts +++ b/reflectapi-demo/clients/typescript/generated.ts @@ -250,9 +250,7 @@ class ClientInstance { } type UnionToIntersection = ( - U extends any - ? (k: U) => unknown - : never + U extends any ? (k: U) => unknown : never ) extends (k: infer I) => void ? I : never; diff --git a/reflectapi-demo/src/tests/serde.rs b/reflectapi-demo/src/tests/serde.rs index da32ed2c..c0cbd3e5 100644 --- a/reflectapi-demo/src/tests/serde.rs +++ b/reflectapi-demo/src/tests/serde.rs @@ -612,6 +612,99 @@ fn test_flatten_internally_tagged() { assert_snapshot!(Test); } +/// Regression test for issue #123: flattened internally-tagged enum fields +/// were silently dropped by the Python codegen. +#[test] +fn test_flatten_internally_tagged_enum_field() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + #[serde(tag = "type")] + enum OfferKind { + Single { business: String }, + Group { count: u32 }, + } + + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Offer { + id: String, + #[serde(flatten)] + payload: OfferKind, + } + + assert_snapshot!(Offer); +} + +#[test] +fn test_flatten_externally_tagged_enum_field() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + enum Shape { + Circle { radius: f64 }, + Rect { width: f64, height: f64 }, + } + + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Drawing { + name: String, + #[serde(flatten)] + shape: Shape, + } + + assert_snapshot!(Drawing); +} + +#[test] +fn test_flatten_adjacently_tagged_enum_field() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + #[serde(tag = "kind", content = "data")] + enum Payload { + Text { body: String }, + Binary { size: u32 }, + } + + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Message { + id: String, + #[serde(flatten)] + payload: Payload, + } + + assert_snapshot!(Message); +} + +#[test] +fn test_flatten_untagged_enum_field() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + #[serde(untagged)] + enum Value { + Num { value: f64 }, + Text { text: String }, + } + + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Cell { + label: String, + #[serde(flatten)] + content: Value, + } + + assert_snapshot!(Cell); +} + #[test] fn test_struct_repr_transparent_generic_inner_type() { #[derive(serde::Deserialize, serde::Serialize, reflectapi::Input, reflectapi::Output)] @@ -727,3 +820,377 @@ fn test_external_impls() { assert_snapshot!(Test); } + +// ────────────────────────────────────────────────────────────────────── +// Group 1: Namespace Edge Cases +// ────────────────────────────────────────────────────────────────────── + +#[test] +fn test_namespace_single_segment_type() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct SimpleTopLevel { + value: u32, + } + assert_snapshot!(SimpleTopLevel); +} + +#[test] +fn test_namespace_deeply_nested_modules() { + mod deep { + pub mod nested { + pub mod inner { + #[derive( + serde::Serialize, + serde::Deserialize, + Debug, + reflectapi::Input, + reflectapi::Output, + )] + pub struct DeepType { + pub data: String, + } + } + } + } + assert_snapshot!(deep::nested::inner::DeepType); +} + +#[test] +fn test_namespace_with_numeric_start() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct TypeWithNumbers { + #[serde(rename = "123start")] + field_123: String, + #[serde(rename = "kebab-field")] + kebab_field: u32, + } + assert_snapshot!(TypeWithNumbers); +} + +// ────────────────────────────────────────────────────────────────────── +// Group 2: Flatten Edge Cases +// ────────────────────────────────────────────────────────────────────── + +#[test] +fn test_flatten_struct_with_nested_flatten() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Inner { + z: String, + } + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Middle { + y: u32, + #[serde(flatten)] + inner: Inner, + } + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Outer { + x: String, + #[serde(flatten)] + nested: Middle, + } + assert_snapshot!(Outer); +} + +#[test] +fn test_flatten_optional_internally_tagged_enum() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + #[serde(tag = "kind")] + enum Priority { + High { deadline: String }, + Low, + } + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Task { + title: String, + #[serde(flatten)] + priority: Option, + } + assert_snapshot!(Task); +} + +#[test] +fn test_flatten_multiple_structs() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Timestamps { + created_at: String, + updated_at: String, + } + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Metadata { + author: String, + version: u32, + } + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Document { + title: String, + #[serde(flatten)] + timestamps: Timestamps, + #[serde(flatten)] + meta: Metadata, + } + assert_snapshot!(Document); +} + +#[test] +fn test_flatten_struct_and_internal_enum_combined() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Audit { + modified_by: String, + } + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + #[serde(tag = "type")] + enum Content { + Text { body: String }, + Image { url: String, width: u32 }, + } + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Post { + id: String, + #[serde(flatten)] + audit: Audit, + #[serde(flatten)] + content: Content, + } + assert_snapshot!(Post); +} + +#[test] +fn test_flatten_enum_with_unit_variants_only() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + #[serde(tag = "status")] + enum Status { + Active, + Inactive, + Pending, + } + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Item { + name: String, + #[serde(flatten)] + status: Status, + } + assert_snapshot!(Item); +} + +// ────────────────────────────────────────────────────────────────────── +// Group 3: Enum Representation Edge Cases +// ────────────────────────────────────────────────────────────────────── + +#[test] +fn test_generic_externally_tagged_enum() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + enum Wrapper { + Value(T), + Empty, + } + assert_snapshot!(Wrapper); +} + +#[test] +fn test_generic_adjacently_tagged_enum() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + #[serde(tag = "t", content = "c")] + enum Tagged { + Item(T), + Nothing, + } + assert_snapshot!(Tagged); +} + +#[test] +fn test_enum_mixed_variant_types_internally_tagged() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + #[serde(tag = "type")] + enum Mixed { + Unit, + // Note: tuple variants are not allowed in internally-tagged representation, + // so we use a struct variant instead. + Wrap { value: String }, + Full { x: i32, y: i32 }, + } + assert_snapshot!(Mixed); +} + +#[test] +fn test_enum_with_serde_rename_on_variants() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + #[serde(tag = "kind", content = "data")] + enum Action { + #[serde(rename = "create_item")] + Create { name: String }, + #[serde(rename = "delete_item")] + Delete { id: u32 }, + } + assert_snapshot!(Action); +} + +// ── Group 4: Type Reference Edge Cases ────────────────────────────────────── + +#[test] +fn test_box_field_unwrapping() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct TreeNode { + label: String, + child: Option>, + } + assert_snapshot!(TreeNode); +} + +#[test] +fn test_nested_generic_containers() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Complex { + matrix: Vec>, + lookup: std::collections::HashMap>>, + } + assert_snapshot!(Complex); +} + +#[test] +fn test_self_referential_struct() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Category { + name: String, + subcategories: Vec, + } + assert_snapshot!(Category); +} + +#[test] +fn test_option_of_option() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Nested { + value: Option>, + } + assert_snapshot!(Nested); +} + +// ── Group 5: Field Sanitization Edge Cases ────────────────────────────────── + +#[test] +fn test_field_all_python_keywords() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Keywords { + #[serde(rename = "type")] + type_field: String, + #[serde(rename = "class")] + class_field: String, + #[serde(rename = "from")] + from_field: String, + #[serde(rename = "import")] + import_field: String, + } + assert_snapshot!(Keywords); +} + +#[test] +fn test_field_names_with_special_chars() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct SpecialNames { + #[serde(rename = "Content-Type")] + content_type: String, + #[serde(rename = "x.nested.key")] + nested_key: String, + #[serde(rename = "has spaces")] + has_spaces: u32, + } + assert_snapshot!(SpecialNames); +} + +#[test] +fn test_multiple_underscore_prefix_fields() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + struct Underscored { + _single: u32, + __double: String, + ___triple: bool, + } + assert_snapshot!(Underscored); +} + +// ── Group 6: Factory & Client Edge Cases ──────────────────────────────────── + +#[test] +fn test_enum_with_many_variants() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + #[serde(tag = "type")] + enum LargeEnum { + Alpha, + Beta, + Gamma { x: i32 }, + Delta { value: String }, + Epsilon, + Zeta { y: bool }, + Eta, + Theta { value: u32 }, + Iota, + Kappa { z: f64 }, + Lambda, + Mu { w: String, v: i32 }, + } + assert_snapshot!(LargeEnum); +} + +#[test] +fn test_empty_enum() { + #[derive( + serde::Serialize, serde::Deserialize, Debug, reflectapi::Input, reflectapi::Output, + )] + enum Never {} + assert_snapshot!(Never); +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_deprecated-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_deprecated-3.snap index 13bc4884..2ba3e1fa 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_deprecated-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_deprecated-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < StructWithDeprecatedField > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_deprecated-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_deprecated-5.snap index 214e368f..4f635d94 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_deprecated-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_deprecated-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicStructWithDeprecatedField(BaseModel): @@ -30,9 +29,24 @@ class ReflectapiDemoTestsBasicStructWithDeprecatedField(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int - _g: int - _h: int + f: int = Field(serialization_alias="_f", validation_alias="_f") + g: int = Field(serialization_alias="_g", validation_alias="_g") + h: int = Field(serialization_alias="_h", validation_alias="_h") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + StructWithDeprecatedField = ( + ReflectapiDemoTestsBasicStructWithDeprecatedField + ) class AsyncInoutClient: @@ -43,15 +57,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicStructWithDeprecatedField] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicStructWithDeprecatedField]: + data: Optional[reflectapi_demo.tests.basic.StructWithDeprecatedField] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.StructWithDeprecatedField]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicStructWithDeprecatedField]: Response containing ReflectapiDemoTestsBasicStructWithDeprecatedField data + ApiResponse[reflectapi_demo.tests.basic.StructWithDeprecatedField]: Response containing reflectapi_demo.tests.basic.StructWithDeprecatedField data """ path = "/inout_test" @@ -61,7 +75,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicStructWithDeprecatedField, + response_model=reflectapi_demo.tests.basic.StructWithDeprecatedField, ) @@ -86,15 +100,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicStructWithDeprecatedField] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicStructWithDeprecatedField]: + data: Optional[reflectapi_demo.tests.basic.StructWithDeprecatedField] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.StructWithDeprecatedField]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicStructWithDeprecatedField]: Response containing ReflectapiDemoTestsBasicStructWithDeprecatedField data + ApiResponse[reflectapi_demo.tests.basic.StructWithDeprecatedField]: Response containing reflectapi_demo.tests.basic.StructWithDeprecatedField data """ path = "/inout_test" @@ -104,7 +118,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicStructWithDeprecatedField, + response_model=reflectapi_demo.tests.basic.StructWithDeprecatedField, ) @@ -129,23 +143,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicStructWithDeprecatedField.model_rebuild() + reflectapi_demo.tests.basic.StructWithDeprecatedField.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicstructwithdeprecatedfield_response( - value: ReflectapiDemoTestsBasicStructWithDeprecatedField, -) -> ApiResponse[ReflectapiDemoTestsBasicStructWithDeprecatedField]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicStructWithDeprecatedField.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_documented-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_documented-3.snap index 60cd75cf..c21d4305 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_documented-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_documented-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_input_rust_code::>()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestEnumDocumented:: > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_documented-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_documented-4.snap index 230f5680..b0bc3526 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_documented-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_documented-4.snap @@ -20,6 +20,7 @@ from typing import Annotated, Any, Generic, Optional, TypeVar, Union from pydantic import ( BaseModel, ConfigDict, + Field, PrivateAttr, RootModel, model_serializer, @@ -30,7 +31,6 @@ from pydantic import ( from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -39,15 +39,12 @@ from reflectapi_runtime.testing import MockClient, create_api_response T = TypeVar("T") -T = TypeVar("T") - - class ReflectapiDemoTestsBasicTestEnumDocumentedVariant1Variant(BaseModel, Generic[T]): """Variant1 variant""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - field_0: T + field_0: T = Field(description="variant1 field docs") class ReflectapiDemoTestsBasicTestEnumDocumentedVariant2Variant(BaseModel, Generic[T]): @@ -55,7 +52,7 @@ class ReflectapiDemoTestsBasicTestEnumDocumentedVariant2Variant(BaseModel, Gener model_config = ConfigDict(extra="ignore", populate_by_name=True) - named_field: T + named_field: T = Field(description="named field variant2 field docs") # Externally tagged enum using RootModel @@ -113,13 +110,32 @@ class ReflectapiDemoTestsBasicTestEnumDocumented( if isinstance( self.root, ReflectapiDemoTestsBasicTestEnumDocumentedVariant2Variant ): - return {"Variant2": self.root.model_dump(exclude_none=True)} + return {"Variant2": self.root.model_dump()} raise ValueError( f"Cannot serialize ReflectapiDemoTestsBasicTestEnumDocumented variant: {type(self.root)}" ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestEnumDocumentedVariant1Variant = ( + ReflectapiDemoTestsBasicTestEnumDocumentedVariant1Variant + ) + TestEnumDocumentedVariant2Variant = ( + ReflectapiDemoTestsBasicTestEnumDocumentedVariant2Variant + ) + TestEnumDocumented = ReflectapiDemoTestsBasicTestEnumDocumented + + class AsyncInputClient: """Async client for input_ operations.""" @@ -128,7 +144,7 @@ class AsyncInputClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestEnumDocumented[int]] = None, + data: Optional[reflectapi_demo.tests.basic.TestEnumDocumented[int]] = None, ) -> ApiResponse[Any]: """ @@ -171,7 +187,7 @@ class InputClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestEnumDocumented[int]] = None, + data: Optional[reflectapi_demo.tests.basic.TestEnumDocumented[int]] = None, ) -> ApiResponse[Any]: """ @@ -214,49 +230,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestEnumDocumented.model_rebuild() + reflectapi_demo.tests.basic.TestEnumDocumented.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsBasicTestEnumDocumentedFactory: - """Factory class for creating ReflectapiDemoTestsBasicTestEnumDocumented variants with ergonomic syntax. - - Some Enum docs - more - """ - - @staticmethod - def variant1(field_0) -> ReflectapiDemoTestsBasicTestEnumDocumented[T]: - """Creates the 'Variant1' variant of the ReflectapiDemoTestsBasicTestEnumDocumented enum.""" - return ReflectapiDemoTestsBasicTestEnumDocumented( - ReflectapiDemoTestsBasicTestEnumDocumentedVariant1Variant[T]( - field_0=field_0 - ) - ) - - @staticmethod - def variant2(named_field) -> ReflectapiDemoTestsBasicTestEnumDocumented[T]: - """Creates the 'Variant2' variant of the ReflectapiDemoTestsBasicTestEnumDocumented enum.""" - return ReflectapiDemoTestsBasicTestEnumDocumented( - ReflectapiDemoTestsBasicTestEnumDocumentedVariant2Variant[T]( - named_field=named_field - ) - ) - - -# Testing utilities - - -def create_reflectapidemotestsbasictestenumdocumented_response( - value: ReflectapiDemoTestsBasicTestEnumDocumented, -) -> ApiResponse[ReflectapiDemoTestsBasicTestEnumDocumented]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestEnumDocumented.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_with_skip_variant-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_with_skip_variant-3.snap index 609bbd3a..dcfe2c4a 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_with_skip_variant-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_with_skip_variant-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumWithSkipVariant > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_with_skip_variant-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_with_skip_variant-5.snap index ad213c69..35fa07a5 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_with_skip_variant-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_enum_with_skip_variant-5.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicInputTestEnumWithSkipVariant(str, Enum): @@ -40,6 +39,31 @@ class ReflectapiDemoTestsBasicOutputTestEnumWithSkipVariant(str, Enum): O = "O" +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + class input: + """Namespace for input types.""" + + TestEnumWithSkipVariant = ( + ReflectapiDemoTestsBasicInputTestEnumWithSkipVariant + ) + + class output: + """Namespace for output types.""" + + TestEnumWithSkipVariant = ( + ReflectapiDemoTestsBasicOutputTestEnumWithSkipVariant + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -48,15 +72,17 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicInputTestEnumWithSkipVariant] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicOutputTestEnumWithSkipVariant]: + data: Optional[ + reflectapi_demo.tests.basic.input.TestEnumWithSkipVariant + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.output.TestEnumWithSkipVariant]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicOutputTestEnumWithSkipVariant]: Response containing ReflectapiDemoTestsBasicOutputTestEnumWithSkipVariant data + ApiResponse[reflectapi_demo.tests.basic.output.TestEnumWithSkipVariant]: Response containing reflectapi_demo.tests.basic.output.TestEnumWithSkipVariant data """ path = "/inout_test" @@ -66,7 +92,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicOutputTestEnumWithSkipVariant, + response_model=reflectapi_demo.tests.basic.output.TestEnumWithSkipVariant, ) @@ -91,15 +117,17 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicInputTestEnumWithSkipVariant] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicOutputTestEnumWithSkipVariant]: + data: Optional[ + reflectapi_demo.tests.basic.input.TestEnumWithSkipVariant + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.output.TestEnumWithSkipVariant]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicOutputTestEnumWithSkipVariant]: Response containing ReflectapiDemoTestsBasicOutputTestEnumWithSkipVariant data + ApiResponse[reflectapi_demo.tests.basic.output.TestEnumWithSkipVariant]: Response containing reflectapi_demo.tests.basic.output.TestEnumWithSkipVariant data """ path = "/inout_test" @@ -109,7 +137,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicOutputTestEnumWithSkipVariant, + response_model=reflectapi_demo.tests.basic.output.TestEnumWithSkipVariant, ) @@ -134,31 +162,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicInputTestEnumWithSkipVariant.model_rebuild() - ReflectapiDemoTestsBasicOutputTestEnumWithSkipVariant.model_rebuild() + reflectapi_demo.tests.basic.input.TestEnumWithSkipVariant.model_rebuild() + reflectapi_demo.tests.basic.output.TestEnumWithSkipVariant.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicinputtestenumwithskipvariant_response( - value: ReflectapiDemoTestsBasicInputTestEnumWithSkipVariant, -) -> ApiResponse[ReflectapiDemoTestsBasicInputTestEnumWithSkipVariant]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicInputTestEnumWithSkipVariant.""" - return create_api_response(value) - - -def create_reflectapidemotestsbasicoutputtestenumwithskipvariant_response( - value: ReflectapiDemoTestsBasicOutputTestEnumWithSkipVariant, -) -> ApiResponse[ReflectapiDemoTestsBasicOutputTestEnumWithSkipVariant]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicOutputTestEnumWithSkipVariant.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_documented-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_documented-3.snap index 41f92391..fc61c444 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_documented-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_documented-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_input_rust_code::()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestStructDocumented > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_documented-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_documented-4.snap index 45a62884..7589927d 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_documented-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_documented-4.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructDocumented(BaseModel): @@ -32,7 +31,20 @@ class ReflectapiDemoTestsBasicTestStructDocumented(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - f: int + f: int = Field(description="field docs\nmultiline") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructDocumented = ReflectapiDemoTestsBasicTestStructDocumented class AsyncInputClient: @@ -43,7 +55,7 @@ class AsyncInputClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructDocumented] = None, + data: Optional[reflectapi_demo.tests.basic.TestStructDocumented] = None, ) -> ApiResponse[Any]: """ @@ -86,7 +98,7 @@ class InputClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructDocumented] = None, + data: Optional[reflectapi_demo.tests.basic.TestStructDocumented] = None, ) -> ApiResponse[Any]: """ @@ -129,23 +141,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructDocumented.model_rebuild() + reflectapi_demo.tests.basic.TestStructDocumented.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructdocumented_response( - value: ReflectapiDemoTestsBasicTestStructDocumented, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructDocumented]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructDocumented.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_empty-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_empty-3.snap index 353e34c6..fd92b737 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_empty-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_empty-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructEmpty > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_empty-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_empty-5.snap index b3e15219..f4276e04 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_empty-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_empty-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructEmpty(BaseModel): @@ -31,6 +30,19 @@ class ReflectapiDemoTestsBasicTestStructEmpty(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructEmpty = ReflectapiDemoTestsBasicTestStructEmpty + + class AsyncInoutClient: """Async client for inout operations.""" @@ -39,15 +51,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructEmpty] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructEmpty]: + data: Optional[reflectapi_demo.tests.basic.TestStructEmpty] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructEmpty]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructEmpty]: Response containing ReflectapiDemoTestsBasicTestStructEmpty data + ApiResponse[reflectapi_demo.tests.basic.TestStructEmpty]: Response containing reflectapi_demo.tests.basic.TestStructEmpty data """ path = "/inout_test" @@ -57,7 +69,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructEmpty, + response_model=reflectapi_demo.tests.basic.TestStructEmpty, ) @@ -82,15 +94,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructEmpty] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructEmpty]: + data: Optional[reflectapi_demo.tests.basic.TestStructEmpty] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructEmpty]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructEmpty]: Response containing ReflectapiDemoTestsBasicTestStructEmpty data + ApiResponse[reflectapi_demo.tests.basic.TestStructEmpty]: Response containing reflectapi_demo.tests.basic.TestStructEmpty data """ path = "/inout_test" @@ -100,7 +112,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructEmpty, + response_model=reflectapi_demo.tests.basic.TestStructEmpty, ) @@ -125,23 +137,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructEmpty.model_rebuild() + reflectapi_demo.tests.basic.TestStructEmpty.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructempty_response( - value: ReflectapiDemoTestsBasicTestStructEmpty, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructEmpty]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructEmpty.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_newtype-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_newtype-3.snap index 824e6281..850517b0 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_newtype-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_newtype-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructNewtype > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_newtype-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_newtype-5.snap index 9a3cc970..c8045d02 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_newtype-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_newtype-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class AsyncInoutClient: @@ -31,7 +30,6 @@ class AsyncInoutClient: def __init__(self, client: AsyncClientBase) -> None: self._client = client - async def test( self, data: Optional[str] = None, @@ -53,7 +51,7 @@ class AsyncInoutClient: params=params if params else None, json_model=data, response_model=str, -) + ) class AsyncClient(AsyncClientBase): @@ -66,6 +64,7 @@ class AsyncClient(AsyncClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = AsyncInoutClient(self) @@ -75,7 +74,6 @@ class InoutClient: def __init__(self, client: ClientBase) -> None: self._client = client - def test( self, data: Optional[str] = None, @@ -97,7 +95,7 @@ class InoutClient: params=params if params else None, json_model=data, response_model=str, -) + ) class Client(ClientBase): @@ -110,6 +108,7 @@ class Client(ClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = InoutClient(self) @@ -124,12 +123,3 @@ try: except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_static_str-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_static_str-3.snap index 587a7c27..35ef3a91 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_static_str-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_static_str-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_output_rust_code::()" -snapshot_kind: text +expression: "super :: into_output_rust_code :: < TestStructOneBasicFieldStaticStr > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_static_str-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_static_str-4.snap index 41d61f17..7aa9890a 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_static_str-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_static_str-4.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructOneBasicFieldStaticStr(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsBasicTestStructOneBasicFieldStaticStr(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: str + f: str = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructOneBasicFieldStaticStr = ( + ReflectapiDemoTestsBasicTestStructOneBasicFieldStaticStr + ) class AsyncOutputClient: @@ -41,11 +55,11 @@ class AsyncOutputClient: async def test( self, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructOneBasicFieldStaticStr]: + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructOneBasicFieldStaticStr]: """ Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructOneBasicFieldStaticStr]: Response containing ReflectapiDemoTestsBasicTestStructOneBasicFieldStaticStr data + ApiResponse[reflectapi_demo.tests.basic.TestStructOneBasicFieldStaticStr]: Response containing reflectapi_demo.tests.basic.TestStructOneBasicFieldStaticStr data """ path = "/output_test" @@ -54,7 +68,7 @@ class AsyncOutputClient: "POST", path, params=params if params else None, - response_model=ReflectapiDemoTestsBasicTestStructOneBasicFieldStaticStr, + response_model=reflectapi_demo.tests.basic.TestStructOneBasicFieldStaticStr, ) @@ -79,11 +93,11 @@ class OutputClient: def test( self, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructOneBasicFieldStaticStr]: + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructOneBasicFieldStaticStr]: """ Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructOneBasicFieldStaticStr]: Response containing ReflectapiDemoTestsBasicTestStructOneBasicFieldStaticStr data + ApiResponse[reflectapi_demo.tests.basic.TestStructOneBasicFieldStaticStr]: Response containing reflectapi_demo.tests.basic.TestStructOneBasicFieldStaticStr data """ path = "/output_test" @@ -92,7 +106,7 @@ class OutputClient: "POST", path, params=params if params else None, - response_model=ReflectapiDemoTestsBasicTestStructOneBasicFieldStaticStr, + response_model=reflectapi_demo.tests.basic.TestStructOneBasicFieldStaticStr, ) @@ -117,23 +131,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructOneBasicFieldStaticStr.model_rebuild() + reflectapi_demo.tests.basic.TestStructOneBasicFieldStaticStr.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructonebasicfieldstaticstr_response( - value: ReflectapiDemoTestsBasicTestStructOneBasicFieldStaticStr, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructOneBasicFieldStaticStr]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructOneBasicFieldStaticStr.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string-3.snap index 8d961a48..8e877e9e 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_input_rust_code::()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestStructOneBasicFieldString > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string-4.snap index b980a99c..f8c17f3c 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string-4.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructOneBasicFieldString(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsBasicTestStructOneBasicFieldString(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: str + f: str = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructOneBasicFieldString = ( + ReflectapiDemoTestsBasicTestStructOneBasicFieldString + ) class AsyncInputClient: @@ -41,7 +55,9 @@ class AsyncInputClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructOneBasicFieldString] = None, + data: Optional[ + reflectapi_demo.tests.basic.TestStructOneBasicFieldString + ] = None, ) -> ApiResponse[Any]: """ @@ -84,7 +100,9 @@ class InputClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructOneBasicFieldString] = None, + data: Optional[ + reflectapi_demo.tests.basic.TestStructOneBasicFieldString + ] = None, ) -> ApiResponse[Any]: """ @@ -127,23 +145,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructOneBasicFieldString.model_rebuild() + reflectapi_demo.tests.basic.TestStructOneBasicFieldString.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructonebasicfieldstring_response( - value: ReflectapiDemoTestsBasicTestStructOneBasicFieldString, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructOneBasicFieldString]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructOneBasicFieldString.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both-3.snap index ee6e1774..c1ffc4d3 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructOneBasicFieldStringReflectBoth > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both-5.snap index 8d72f071..369fb8e1 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth(BaseModel model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: str + f: str = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructOneBasicFieldStringReflectBoth = ( + ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth + ) class AsyncInoutClient: @@ -42,16 +56,18 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth + reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBoth ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth]: + ) -> ApiResponse[ + reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBoth + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth]: Response containing ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth data + ApiResponse[reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBoth]: Response containing reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBoth data """ path = "/inout_test" @@ -61,7 +77,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth, + response_model=reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBoth, ) @@ -87,16 +103,18 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth + reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBoth ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth]: + ) -> ApiResponse[ + reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBoth + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth]: Response containing ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth data + ApiResponse[reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBoth]: Response containing reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBoth data """ path = "/inout_test" @@ -106,7 +124,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth, + response_model=reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBoth, ) @@ -131,23 +149,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth.model_rebuild() + reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBoth.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructonebasicfieldstringreflectboth_response( - value: ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBoth.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally-3.snap index bbcbe6e9..8122e8f0 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructOneBasicFieldStringReflectBothEqually >\n()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -34,7 +33,7 @@ pub mod interface { Ok(Self { client, base_url }) } - pub async fn inout_test(&self, input: super::types::reflectapi_demo::tests::basic::TestStructOneBasicFieldStringReflectBothEqually, headers: reflectapi::Empty) + pub async fn inout_test(&self, input: super::types::reflectapi_demo::tests::basic::TestStructOneBasicFieldStringReflectBothEqually, headers: reflectapi::Empty) -> Result>{ reflectapi::rt::__request_impl( &self.client, @@ -49,7 +48,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally-5.snap index e09381c6..0ceb49dd 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually( @@ -32,7 +31,22 @@ class ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually( model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + f: int = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructOneBasicFieldStringReflectBothEqually = ( + ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually + ) class AsyncInoutClient: @@ -44,10 +58,10 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually + reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBothEqually ] = None, ) -> ApiResponse[ - ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually + reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBothEqually ]: """ @@ -55,7 +69,7 @@ class AsyncInoutClient: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually]: Response containing ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually data + ApiResponse[reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBothEqually]: Response containing reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBothEqually data """ path = "/inout_test" @@ -65,7 +79,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually, + response_model=reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBothEqually, ) @@ -91,10 +105,10 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually + reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBothEqually ] = None, ) -> ApiResponse[ - ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually + reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBothEqually ]: """ @@ -102,7 +116,7 @@ class InoutClient: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually]: Response containing ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually data + ApiResponse[reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBothEqually]: Response containing reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBothEqually data """ path = "/inout_test" @@ -112,7 +126,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually, + response_model=reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBothEqually, ) @@ -137,25 +151,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually.model_rebuild() + reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBothEqually.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructonebasicfieldstringreflectbothequally_response( - value: ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually, -) -> ApiResponse[ - ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually -]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally2-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally2-3.snap index e5da25fa..bdace3be 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally2-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally2-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_input_rust_code::()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: <\nTestStructOneBasicFieldStringReflectBothEqually > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally2-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally2-4.snap index d669e946..12082e68 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally2-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_equally2-4.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually( @@ -32,7 +31,22 @@ class ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually( model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + f: int = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructOneBasicFieldStringReflectBothEqually = ( + ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually + ) class AsyncInputClient: @@ -44,7 +58,7 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually + reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBothEqually ] = None, ) -> ApiResponse[Any]: """ @@ -89,7 +103,7 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually + reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBothEqually ] = None, ) -> ApiResponse[Any]: """ @@ -133,25 +147,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually.model_rebuild() + reflectapi_demo.tests.basic.TestStructOneBasicFieldStringReflectBothEqually.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructonebasicfieldstringreflectbothequally_response( - value: ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually, -) -> ApiResponse[ - ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually -]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructOneBasicFieldStringReflectBothEqually.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_with_attributes-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_with_attributes-3.snap index 7b8655a6..557a1898 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_with_attributes-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_with_attributes-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: <\nTestStructOneBasicFieldStringReflectBothDifferently > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -34,7 +33,7 @@ pub mod interface { Ok(Self { client, base_url }) } - pub async fn inout_test(&self, input: super::types::reflectapi_demo::tests::basic::input::TestStructOneBasicFieldStringReflectBothDifferently, headers: reflectapi::Empty) + pub async fn inout_test(&self, input: super::types::reflectapi_demo::tests::basic::input::TestStructOneBasicFieldStringReflectBothDifferently, headers: reflectapi::Empty) -> Result>{ reflectapi::rt::__request_impl( &self.client, @@ -49,7 +48,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_with_attributes-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_with_attributes-5.snap index 4a74e894..fb9ae717 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_with_attributes-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_string_reflectapi_both_with_attributes-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicInputTestStructOneBasicFieldStringReflectBothDifferently( @@ -32,7 +31,7 @@ class ReflectapiDemoTestsBasicInputTestStructOneBasicFieldStringReflectBothDiffe model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + f: int = Field(serialization_alias="_f", validation_alias="_f") class ReflectapiDemoTestsBasicOutputTestStructOneBasicFieldStringReflectBothDifferently( @@ -42,7 +41,28 @@ class ReflectapiDemoTestsBasicOutputTestStructOneBasicFieldStringReflectBothDiff model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + f: int = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + class input: + """Namespace for input types.""" + + TestStructOneBasicFieldStringReflectBothDifferently = ReflectapiDemoTestsBasicInputTestStructOneBasicFieldStringReflectBothDifferently + + class output: + """Namespace for output types.""" + + TestStructOneBasicFieldStringReflectBothDifferently = ReflectapiDemoTestsBasicOutputTestStructOneBasicFieldStringReflectBothDifferently class AsyncInoutClient: @@ -54,10 +74,10 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsBasicInputTestStructOneBasicFieldStringReflectBothDifferently + reflectapi_demo.tests.basic.input.TestStructOneBasicFieldStringReflectBothDifferently ] = None, ) -> ApiResponse[ - ReflectapiDemoTestsBasicOutputTestStructOneBasicFieldStringReflectBothDifferently + reflectapi_demo.tests.basic.output.TestStructOneBasicFieldStringReflectBothDifferently ]: """ @@ -65,7 +85,7 @@ class AsyncInoutClient: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicOutputTestStructOneBasicFieldStringReflectBothDifferently]: Response containing ReflectapiDemoTestsBasicOutputTestStructOneBasicFieldStringReflectBothDifferently data + ApiResponse[reflectapi_demo.tests.basic.output.TestStructOneBasicFieldStringReflectBothDifferently]: Response containing reflectapi_demo.tests.basic.output.TestStructOneBasicFieldStringReflectBothDifferently data """ path = "/inout_test" @@ -75,7 +95,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicOutputTestStructOneBasicFieldStringReflectBothDifferently, + response_model=reflectapi_demo.tests.basic.output.TestStructOneBasicFieldStringReflectBothDifferently, ) @@ -101,10 +121,10 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsBasicInputTestStructOneBasicFieldStringReflectBothDifferently + reflectapi_demo.tests.basic.input.TestStructOneBasicFieldStringReflectBothDifferently ] = None, ) -> ApiResponse[ - ReflectapiDemoTestsBasicOutputTestStructOneBasicFieldStringReflectBothDifferently + reflectapi_demo.tests.basic.output.TestStructOneBasicFieldStringReflectBothDifferently ]: """ @@ -112,7 +132,7 @@ class InoutClient: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicOutputTestStructOneBasicFieldStringReflectBothDifferently]: Response containing ReflectapiDemoTestsBasicOutputTestStructOneBasicFieldStringReflectBothDifferently data + ApiResponse[reflectapi_demo.tests.basic.output.TestStructOneBasicFieldStringReflectBothDifferently]: Response containing reflectapi_demo.tests.basic.output.TestStructOneBasicFieldStringReflectBothDifferently data """ path = "/inout_test" @@ -122,7 +142,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicOutputTestStructOneBasicFieldStringReflectBothDifferently, + response_model=reflectapi_demo.tests.basic.output.TestStructOneBasicFieldStringReflectBothDifferently, ) @@ -147,35 +167,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicInputTestStructOneBasicFieldStringReflectBothDifferently.model_rebuild() - ReflectapiDemoTestsBasicOutputTestStructOneBasicFieldStringReflectBothDifferently.model_rebuild() + reflectapi_demo.tests.basic.input.TestStructOneBasicFieldStringReflectBothDifferently.model_rebuild() + reflectapi_demo.tests.basic.output.TestStructOneBasicFieldStringReflectBothDifferently.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicinputteststructonebasicfieldstringreflectbothdifferently_response( - value: ReflectapiDemoTestsBasicInputTestStructOneBasicFieldStringReflectBothDifferently, -) -> ApiResponse[ - ReflectapiDemoTestsBasicInputTestStructOneBasicFieldStringReflectBothDifferently -]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicInputTestStructOneBasicFieldStringReflectBothDifferently.""" - return create_api_response(value) - - -def create_reflectapidemotestsbasicoutputteststructonebasicfieldstringreflectbothdifferently_response( - value: ReflectapiDemoTestsBasicOutputTestStructOneBasicFieldStringReflectBothDifferently, -) -> ApiResponse[ - ReflectapiDemoTestsBasicOutputTestStructOneBasicFieldStringReflectBothDifferently -]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicOutputTestStructOneBasicFieldStringReflectBothDifferently.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_u32-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_u32-3.snap index c04de76e..cd62a2ba 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_u32-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_u32-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_input_rust_code::()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestStructOneBasicFieldU32 > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_u32-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_u32-4.snap index ab862dfe..c1c1c38a 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_u32-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_one_basic_field_u32-4.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructOneBasicFieldU32(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsBasicTestStructOneBasicFieldU32(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + f: int = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructOneBasicFieldU32 = ( + ReflectapiDemoTestsBasicTestStructOneBasicFieldU32 + ) class AsyncInputClient: @@ -41,7 +55,7 @@ class AsyncInputClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructOneBasicFieldU32] = None, + data: Optional[reflectapi_demo.tests.basic.TestStructOneBasicFieldU32] = None, ) -> ApiResponse[Any]: """ @@ -84,7 +98,7 @@ class InputClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructOneBasicFieldU32] = None, + data: Optional[reflectapi_demo.tests.basic.TestStructOneBasicFieldU32] = None, ) -> ApiResponse[Any]: """ @@ -127,23 +141,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructOneBasicFieldU32.model_rebuild() + reflectapi_demo.tests.basic.TestStructOneBasicFieldU32.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructonebasicfieldu32_response( - value: ReflectapiDemoTestsBasicTestStructOneBasicFieldU32, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructOneBasicFieldU32]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructOneBasicFieldU32.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_option-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_option-3.snap index bbf3bc36..f72b4d14 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_option-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_option-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructOption > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_option-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_option-5.snap index 298156ed..c963a7ee 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_option-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_option-5.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructOption(BaseModel): @@ -31,7 +30,20 @@ class ReflectapiDemoTestsBasicTestStructOption(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int | None = None + f: int | None = Field(default=None, serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructOption = ReflectapiDemoTestsBasicTestStructOption class AsyncInoutClient: @@ -42,15 +54,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructOption] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructOption]: + data: Optional[reflectapi_demo.tests.basic.TestStructOption] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructOption]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructOption]: Response containing ReflectapiDemoTestsBasicTestStructOption data + ApiResponse[reflectapi_demo.tests.basic.TestStructOption]: Response containing reflectapi_demo.tests.basic.TestStructOption data """ path = "/inout_test" @@ -60,7 +72,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructOption, + response_model=reflectapi_demo.tests.basic.TestStructOption, ) @@ -85,15 +97,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructOption] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructOption]: + data: Optional[reflectapi_demo.tests.basic.TestStructOption] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructOption]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructOption]: Response containing ReflectapiDemoTestsBasicTestStructOption data + ApiResponse[reflectapi_demo.tests.basic.TestStructOption]: Response containing reflectapi_demo.tests.basic.TestStructOption data """ path = "/inout_test" @@ -103,7 +115,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructOption, + response_model=reflectapi_demo.tests.basic.TestStructOption, ) @@ -128,23 +140,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructOption.model_rebuild() + reflectapi_demo.tests.basic.TestStructOption.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructoption_response( - value: ReflectapiDemoTestsBasicTestStructOption, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructOption]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructOption.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_tuple-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_tuple-3.snap index 28f7d9e2..ce894de2 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_tuple-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_tuple-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructTuple > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_tuple-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_tuple-5.snap index 4e2d7091..b89f25d7 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_tuple-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_tuple-5.snap @@ -2,12 +2,12 @@ source: reflectapi-demo/src/tests/basic.rs expression: "super :: into_python_code :: < TestStructTuple > ()" --- -""" +''' Generated Python client for api_client. DO NOT MODIFY THIS FILE MANUALLY. This file is automatically generated by ReflectAPI. -""" +''' from __future__ import annotations @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructTuple(BaseModel): @@ -30,8 +29,20 @@ class ReflectapiDemoTestsBasicTestStructTuple(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _0: int = Field(serialization_alias="0", validation_alias="0") - _1: str = Field(serialization_alias="1", validation_alias="1") + 0: int + 1: str + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + TestStructTuple = ReflectapiDemoTestsBasicTestStructTuple class AsyncInoutClient: @@ -42,15 +53,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructTuple] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructTuple]: + data: Optional[reflectapi_demo.tests.basic.TestStructTuple] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructTuple]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructTuple]: Response containing ReflectapiDemoTestsBasicTestStructTuple data + ApiResponse[reflectapi_demo.tests.basic.TestStructTuple]: Response containing reflectapi_demo.tests.basic.TestStructTuple data """ path = "/inout_test" @@ -60,7 +71,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructTuple, + response_model=reflectapi_demo.tests.basic.TestStructTuple, ) @@ -74,6 +85,7 @@ class AsyncClient(AsyncClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = AsyncInoutClient(self) @@ -85,15 +97,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructTuple] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructTuple]: + data: Optional[reflectapi_demo.tests.basic.TestStructTuple] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructTuple]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructTuple]: Response containing ReflectapiDemoTestsBasicTestStructTuple data + ApiResponse[reflectapi_demo.tests.basic.TestStructTuple]: Response containing reflectapi_demo.tests.basic.TestStructTuple data """ path = "/inout_test" @@ -103,7 +115,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructTuple, + response_model=reflectapi_demo.tests.basic.TestStructTuple, ) @@ -117,6 +129,7 @@ class Client(ClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = InoutClient(self) @@ -128,23 +141,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructTuple.model_rebuild() + reflectapi_demo.tests.basic.TestStructTuple.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructtuple_response( - value: ReflectapiDemoTestsBasicTestStructTuple, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructTuple]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructTuple.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_unit_type-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_unit_type-3.snap index 79e558f7..7b2e9d8a 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_unit_type-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_unit_type-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructUnitType > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_unit_type-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_unit_type-5.snap index f71bd148..99904cf7 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_unit_type-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_unit_type-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class AsyncInoutClient: @@ -31,7 +30,6 @@ class AsyncInoutClient: def __init__(self, client: AsyncClientBase) -> None: self._client = client - async def test( self, data: Optional[None] = None, @@ -53,7 +51,7 @@ class AsyncInoutClient: params=params if params else None, json_model=data, response_model=None, -) + ) class AsyncClient(AsyncClientBase): @@ -66,6 +64,7 @@ class AsyncClient(AsyncClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = AsyncInoutClient(self) @@ -75,7 +74,6 @@ class InoutClient: def __init__(self, client: ClientBase) -> None: self._client = client - def test( self, data: Optional[None] = None, @@ -97,7 +95,7 @@ class InoutClient: params=params if params else None, json_model=data, response_model=None, -) + ) class Client(ClientBase): @@ -110,6 +108,7 @@ class Client(ClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = InoutClient(self) @@ -124,12 +123,3 @@ try: except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_additional_derives-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_additional_derives-3.snap index e47b41d6..995683e8 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_additional_derives-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_additional_derives-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < Test > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_additional_derives-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_additional_derives-5.snap index 18f2661b..b70547ad 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_additional_derives-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_additional_derives-5.snap @@ -17,13 +17,22 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response + + +class ReflectapiDemoTestsBasicTest(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + us: list[None] + xs: list[reflectapi_demo.tests.basic.X] + ys: list[reflectapi_demo.tests.basic.Y] class ReflectapiDemoTestsBasicX(BaseModel): @@ -38,14 +47,19 @@ class ReflectapiDemoTestsBasicY(str, Enum): Y = "Y" -class ReflectapiDemoTestsBasicTest(BaseModel): - """Generated data model.""" +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" - model_config = ConfigDict(extra="ignore", populate_by_name=True) + class tests: + """Namespace for tests types.""" - us: list[None] - xs: list[ReflectapiDemoTestsBasicX] - ys: list[ReflectapiDemoTestsBasicY] + class basic: + """Namespace for basic types.""" + + Test = ReflectapiDemoTestsBasicTest + X = ReflectapiDemoTestsBasicX + Y = ReflectapiDemoTestsBasicY class AsyncInoutClient: @@ -56,15 +70,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTest]: + data: Optional[reflectapi_demo.tests.basic.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTest]: Response containing ReflectapiDemoTestsBasicTest data + ApiResponse[reflectapi_demo.tests.basic.Test]: Response containing reflectapi_demo.tests.basic.Test data """ path = "/inout_test" @@ -74,7 +88,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTest, + response_model=reflectapi_demo.tests.basic.Test, ) @@ -99,15 +113,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTest]: + data: Optional[reflectapi_demo.tests.basic.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTest]: Response containing ReflectapiDemoTestsBasicTest data + ApiResponse[reflectapi_demo.tests.basic.Test]: Response containing reflectapi_demo.tests.basic.Test data """ path = "/inout_test" @@ -117,7 +131,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTest, + response_model=reflectapi_demo.tests.basic.Test, ) @@ -142,39 +156,9 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTest.model_rebuild() - ReflectapiDemoTestsBasicX.model_rebuild() - ReflectapiDemoTestsBasicY.model_rebuild() + reflectapi_demo.tests.basic.Test.model_rebuild() + reflectapi_demo.tests.basic.X.model_rebuild() + reflectapi_demo.tests.basic.Y.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasictest_response( - value: ReflectapiDemoTestsBasicTest, -) -> ApiResponse[ReflectapiDemoTestsBasicTest]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTest.""" - return create_api_response(value) - - -def create_reflectapidemotestsbasicx_response( - value: ReflectapiDemoTestsBasicX, -) -> ApiResponse[ReflectapiDemoTestsBasicX]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicX.""" - return create_api_response(value) - - -def create_reflectapidemotestsbasicy_response( - value: ReflectapiDemoTestsBasicY, -) -> ApiResponse[ReflectapiDemoTestsBasicY]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicY.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_all_primitive_type_fields-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_all_primitive_type_fields-3.snap index b6b5be3b..c16c7848 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_all_primitive_type_fields-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_all_primitive_type_fields-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithAllPrimitiveTypeFields > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_all_primitive_type_fields-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_all_primitive_type_fields-5.snap index 8a879d1e..39613578 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_all_primitive_type_fields-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_all_primitive_type_fields-5.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields(BaseModel): @@ -31,51 +30,110 @@ class ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f_u8: int - _f_u16: int - _f_u32: int - _f_u64: int - _f_u128: U128 - _f_usize: int - _f_i8: int - _f_i16: int - _f_i32: int - _f_i64: int - _f_i128: I128 - _f_isize: int - _f_f32: float - _f_f64: float - _f_bool: bool - _f_char: Char - _f_str: str - _f_unit: None - _f_option: int | None = None - _f_vec: bytes - _f_hashmap: dict[int, str] - _f_hashset: bytes - _f_tuple: StdTupleTuple2[int, str] - _f_tuple3: StdTupleTuple3[int, str, int] - _f_tuple4: StdTupleTuple4[int, str, int, str] - _f_tuple5: StdTupleTuple5[int, str, int, str, int] - _f_tuple6: StdTupleTuple6[int, str, int, str, int, str] - _f_tuple7: StdTupleTuple7[int, str, int, str, int, str, int] - _f_tuple8: StdTupleTuple8[int, str, int, str, int, str, int, str] - _f_tuple9: StdTupleTuple9[int, str, int, str, int, str, int, str, int] - _f_tuple10: StdTupleTuple10[int, str, int, str, int, str, int, str, int, str] - _f_tuple11: StdTupleTuple11[int, str, int, str, int, str, int, str, int, str, int] - _f_tuple12: StdTupleTuple12[ + f_u8: int = Field(serialization_alias="_f_u8", validation_alias="_f_u8") + f_u16: int = Field(serialization_alias="_f_u16", validation_alias="_f_u16") + f_u32: int = Field(serialization_alias="_f_u32", validation_alias="_f_u32") + f_u64: int = Field(serialization_alias="_f_u64", validation_alias="_f_u64") + f_u128: U128 = Field(serialization_alias="_f_u128", validation_alias="_f_u128") + f_usize: int = Field(serialization_alias="_f_usize", validation_alias="_f_usize") + f_i8: int = Field(serialization_alias="_f_i8", validation_alias="_f_i8") + f_i16: int = Field(serialization_alias="_f_i16", validation_alias="_f_i16") + f_i32: int = Field(serialization_alias="_f_i32", validation_alias="_f_i32") + f_i64: int = Field(serialization_alias="_f_i64", validation_alias="_f_i64") + f_i128: I128 = Field(serialization_alias="_f_i128", validation_alias="_f_i128") + f_isize: int = Field(serialization_alias="_f_isize", validation_alias="_f_isize") + f_f32: float = Field(serialization_alias="_f_f32", validation_alias="_f_f32") + f_f64: float = Field(serialization_alias="_f_f64", validation_alias="_f_f64") + f_bool: bool = Field(serialization_alias="_f_bool", validation_alias="_f_bool") + f_char: Char = Field(serialization_alias="_f_char", validation_alias="_f_char") + f_str: str = Field(serialization_alias="_f_str", validation_alias="_f_str") + f_unit: None = Field(serialization_alias="_f_unit", validation_alias="_f_unit") + f_option: int | None = Field( + default=None, serialization_alias="_f_option", validation_alias="_f_option" + ) + f_vec: bytes = Field(serialization_alias="_f_vec", validation_alias="_f_vec") + f_hashmap: dict[int, str] = Field( + serialization_alias="_f_hashmap", validation_alias="_f_hashmap" + ) + f_hashset: bytes = Field( + serialization_alias="_f_hashset", validation_alias="_f_hashset" + ) + f_tuple: std.tuple.Tuple2[int, str] = Field( + serialization_alias="_f_tuple", validation_alias="_f_tuple" + ) + f_tuple3: std.tuple.Tuple3[int, str, int] = Field( + serialization_alias="_f_tuple3", validation_alias="_f_tuple3" + ) + f_tuple4: std.tuple.Tuple4[int, str, int, str] = Field( + serialization_alias="_f_tuple4", validation_alias="_f_tuple4" + ) + f_tuple5: std.tuple.Tuple5[int, str, int, str, int] = Field( + serialization_alias="_f_tuple5", validation_alias="_f_tuple5" + ) + f_tuple6: std.tuple.Tuple6[int, str, int, str, int, str] = Field( + serialization_alias="_f_tuple6", validation_alias="_f_tuple6" + ) + f_tuple7: std.tuple.Tuple7[int, str, int, str, int, str, int] = Field( + serialization_alias="_f_tuple7", validation_alias="_f_tuple7" + ) + f_tuple8: std.tuple.Tuple8[int, str, int, str, int, str, int, str] = Field( + serialization_alias="_f_tuple8", validation_alias="_f_tuple8" + ) + f_tuple9: std.tuple.Tuple9[int, str, int, str, int, str, int, str, int] = Field( + serialization_alias="_f_tuple9", validation_alias="_f_tuple9" + ) + f_tuple10: std.tuple.Tuple10[int, str, int, str, int, str, int, str, int, str] = ( + Field(serialization_alias="_f_tuple10", validation_alias="_f_tuple10") + ) + f_tuple11: std.tuple.Tuple11[ + int, str, int, str, int, str, int, str, int, str, int + ] = Field(serialization_alias="_f_tuple11", validation_alias="_f_tuple11") + f_tuple12: std.tuple.Tuple12[ int, str, int, str, int, str, int, str, int, str, int, str - ] - _f_array: bytes - _f_pointer_box: int - _f_pointer_arc: int - _f_pointer_cell: int - _f_pointer_refcell: int - _f_pointer_mutex: int - _f_pointer_rwlock: int - _f_pointer_weak: int - _f_phantomdata: StdMarkerPhantomData[int] - _f_infallible: ReflectapiInfallible + ] = Field(serialization_alias="_f_tuple12", validation_alias="_f_tuple12") + f_array: bytes = Field(serialization_alias="_f_array", validation_alias="_f_array") + f_pointer_box: int = Field( + serialization_alias="_f_pointer_box", validation_alias="_f_pointer_box" + ) + f_pointer_arc: int = Field( + serialization_alias="_f_pointer_arc", validation_alias="_f_pointer_arc" + ) + f_pointer_cell: int = Field( + serialization_alias="_f_pointer_cell", validation_alias="_f_pointer_cell" + ) + f_pointer_refcell: int = Field( + serialization_alias="_f_pointer_refcell", validation_alias="_f_pointer_refcell" + ) + f_pointer_mutex: int = Field( + serialization_alias="_f_pointer_mutex", validation_alias="_f_pointer_mutex" + ) + f_pointer_rwlock: int = Field( + serialization_alias="_f_pointer_rwlock", validation_alias="_f_pointer_rwlock" + ) + f_pointer_weak: int = Field( + serialization_alias="_f_pointer_weak", validation_alias="_f_pointer_weak" + ) + f_phantomdata: std.marker.PhantomData[int] = Field( + serialization_alias="_f_phantomdata", validation_alias="_f_phantomdata" + ) + f_infallible: ReflectapiInfallible = Field( + serialization_alias="_f_infallible", validation_alias="_f_infallible" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithAllPrimitiveTypeFields = ( + ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields + ) class AsyncInoutClient: @@ -87,16 +145,16 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields + reflectapi_demo.tests.basic.TestStructWithAllPrimitiveTypeFields ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields]: + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithAllPrimitiveTypeFields]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields]: Response containing ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithAllPrimitiveTypeFields]: Response containing reflectapi_demo.tests.basic.TestStructWithAllPrimitiveTypeFields data """ path = "/inout_test" @@ -106,7 +164,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields, + response_model=reflectapi_demo.tests.basic.TestStructWithAllPrimitiveTypeFields, ) @@ -132,16 +190,16 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields + reflectapi_demo.tests.basic.TestStructWithAllPrimitiveTypeFields ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields]: + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithAllPrimitiveTypeFields]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields]: Response containing ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithAllPrimitiveTypeFields]: Response containing reflectapi_demo.tests.basic.TestStructWithAllPrimitiveTypeFields data """ path = "/inout_test" @@ -151,7 +209,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields, + response_model=reflectapi_demo.tests.basic.TestStructWithAllPrimitiveTypeFields, ) @@ -176,23 +234,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithAllPrimitiveTypeFields.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithallprimitivetypefields_response( - value: ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithAllPrimitiveTypeFields.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc-3.snap index 5ea60c39..f8787671 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithArc > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc-5.snap index 5d810ccd..309214f5 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithArc(BaseModel): @@ -30,7 +29,20 @@ class ReflectapiDemoTestsBasicTestStructWithArc(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + f: int = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithArc = ReflectapiDemoTestsBasicTestStructWithArc class AsyncInoutClient: @@ -41,15 +53,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithArc] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithArc]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithArc] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithArc]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithArc]: Response containing ReflectapiDemoTestsBasicTestStructWithArc data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithArc]: Response containing reflectapi_demo.tests.basic.TestStructWithArc data """ path = "/inout_test" @@ -59,7 +71,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithArc, + response_model=reflectapi_demo.tests.basic.TestStructWithArc, ) @@ -84,15 +96,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithArc] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithArc]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithArc] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithArc]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithArc]: Response containing ReflectapiDemoTestsBasicTestStructWithArc data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithArc]: Response containing reflectapi_demo.tests.basic.TestStructWithArc data """ path = "/inout_test" @@ -102,7 +114,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithArc, + response_model=reflectapi_demo.tests.basic.TestStructWithArc, ) @@ -127,23 +139,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithArc.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithArc.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwitharc_response( - value: ReflectapiDemoTestsBasicTestStructWithArc, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithArc]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithArc.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc_pointer_only-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc_pointer_only-3.snap index ecf28aae..16d30e81 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc_pointer_only-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc_pointer_only-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithArcPointerOnly > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc_pointer_only-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc_pointer_only-5.snap index b2acfb36..7baa4bac 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc_pointer_only-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_arc_pointer_only-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithArcPointerOnly(BaseModel): @@ -30,7 +29,24 @@ class ReflectapiDemoTestsBasicTestStructWithArcPointerOnly(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f_pointer_arc: int + f_pointer_arc: int = Field( + serialization_alias="_f_pointer_arc", validation_alias="_f_pointer_arc" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithArcPointerOnly = ( + ReflectapiDemoTestsBasicTestStructWithArcPointerOnly + ) class AsyncInoutClient: @@ -41,15 +57,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithArcPointerOnly] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithArcPointerOnly]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithArcPointerOnly] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithArcPointerOnly]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithArcPointerOnly]: Response containing ReflectapiDemoTestsBasicTestStructWithArcPointerOnly data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithArcPointerOnly]: Response containing reflectapi_demo.tests.basic.TestStructWithArcPointerOnly data """ path = "/inout_test" @@ -59,7 +75,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithArcPointerOnly, + response_model=reflectapi_demo.tests.basic.TestStructWithArcPointerOnly, ) @@ -84,15 +100,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithArcPointerOnly] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithArcPointerOnly]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithArcPointerOnly] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithArcPointerOnly]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithArcPointerOnly]: Response containing ReflectapiDemoTestsBasicTestStructWithArcPointerOnly data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithArcPointerOnly]: Response containing reflectapi_demo.tests.basic.TestStructWithArcPointerOnly data """ path = "/inout_test" @@ -102,7 +118,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithArcPointerOnly, + response_model=reflectapi_demo.tests.basic.TestStructWithArcPointerOnly, ) @@ -127,23 +143,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithArcPointerOnly.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithArcPointerOnly.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwitharcpointeronly_response( - value: ReflectapiDemoTestsBasicTestStructWithArcPointerOnly, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithArcPointerOnly]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithArcPointerOnly.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes-5.snap index 42fb6a07..b3c8c94b 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class AsyncInoutClient: @@ -31,7 +30,6 @@ class AsyncInoutClient: def __init__(self, client: AsyncClientBase) -> None: self._client = client - async def test( self, data: Optional[int] = None, @@ -53,7 +51,7 @@ class AsyncInoutClient: params=params if params else None, json_data=data, response_model=int, -) + ) class AsyncClient(AsyncClientBase): @@ -66,6 +64,7 @@ class AsyncClient(AsyncClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = AsyncInoutClient(self) @@ -75,7 +74,6 @@ class InoutClient: def __init__(self, client: ClientBase) -> None: self._client = client - def test( self, data: Optional[int] = None, @@ -97,7 +95,7 @@ class InoutClient: params=params if params else None, json_data=data, response_model=int, -) + ) class Client(ClientBase): @@ -110,6 +108,7 @@ class Client(ClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = InoutClient(self) @@ -124,12 +123,3 @@ try: except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_input_only-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_input_only-3.snap index 1db60fee..2e408ade 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_input_only-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_input_only-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithAttributesInputOnly > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_input_only-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_input_only-5.snap index 2b83eb2d..bbe42397 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_input_only-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_input_only-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithAttributesInputOnly(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsBasicTestStructWithAttributesInputOnly(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: str + f: str = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithAttributesInputOnly = ( + ReflectapiDemoTestsBasicTestStructWithAttributesInputOnly + ) class AsyncInoutClient: @@ -42,14 +56,14 @@ class AsyncInoutClient: async def test( self, data: Optional[str] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithAttributesInputOnly]: + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithAttributesInputOnly]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithAttributesInputOnly]: Response containing ReflectapiDemoTestsBasicTestStructWithAttributesInputOnly data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithAttributesInputOnly]: Response containing reflectapi_demo.tests.basic.TestStructWithAttributesInputOnly data """ path = "/inout_test" @@ -59,7 +73,7 @@ class AsyncInoutClient: path, params=params if params else None, json_data=data, - response_model=ReflectapiDemoTestsBasicTestStructWithAttributesInputOnly, + response_model=reflectapi_demo.tests.basic.TestStructWithAttributesInputOnly, ) @@ -85,14 +99,14 @@ class InoutClient: def test( self, data: Optional[str] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithAttributesInputOnly]: + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithAttributesInputOnly]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithAttributesInputOnly]: Response containing ReflectapiDemoTestsBasicTestStructWithAttributesInputOnly data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithAttributesInputOnly]: Response containing reflectapi_demo.tests.basic.TestStructWithAttributesInputOnly data """ path = "/inout_test" @@ -102,7 +116,7 @@ class InoutClient: path, params=params if params else None, json_data=data, - response_model=ReflectapiDemoTestsBasicTestStructWithAttributesInputOnly, + response_model=reflectapi_demo.tests.basic.TestStructWithAttributesInputOnly, ) @@ -127,23 +141,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithAttributesInputOnly.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithAttributesInputOnly.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithattributesinputonly_response( - value: ReflectapiDemoTestsBasicTestStructWithAttributesInputOnly, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithAttributesInputOnly]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithAttributesInputOnly.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_output_only-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_output_only-3.snap index 70155ac7..075c2162 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_output_only-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_output_only-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithAttributesOutputOnly > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -53,7 +52,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_output_only-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_output_only-5.snap index 323374fb..f3dafc2b 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_output_only-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_output_only-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithAttributesOutputOnly(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsBasicTestStructWithAttributesOutputOnly(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: str + f: str = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithAttributesOutputOnly = ( + ReflectapiDemoTestsBasicTestStructWithAttributesOutputOnly + ) class AsyncInoutClient: @@ -42,7 +56,7 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructWithAttributesOutputOnly + reflectapi_demo.tests.basic.TestStructWithAttributesOutputOnly ] = None, ) -> ApiResponse[str]: """ @@ -87,7 +101,7 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructWithAttributesOutputOnly + reflectapi_demo.tests.basic.TestStructWithAttributesOutputOnly ] = None, ) -> ApiResponse[str]: """ @@ -131,23 +145,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithAttributesOutputOnly.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithAttributesOutputOnly.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithattributesoutputonly_response( - value: ReflectapiDemoTestsBasicTestStructWithAttributesOutputOnly, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithAttributesOutputOnly]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithAttributesOutputOnly.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_type_only-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_type_only-5.snap index 20547d53..9032b21a 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_type_only-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_attributes_type_only-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class AsyncInoutClient: @@ -31,7 +30,6 @@ class AsyncInoutClient: def __init__(self, client: AsyncClientBase) -> None: self._client = client - async def test( self, data: Optional[str] = None, @@ -53,7 +51,7 @@ class AsyncInoutClient: params=params if params else None, json_data=data, response_model=str, -) + ) class AsyncClient(AsyncClientBase): @@ -66,6 +64,7 @@ class AsyncClient(AsyncClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = AsyncInoutClient(self) @@ -75,7 +74,6 @@ class InoutClient: def __init__(self, client: ClientBase) -> None: self._client = client - def test( self, data: Optional[str] = None, @@ -97,7 +95,7 @@ class InoutClient: params=params if params else None, json_data=data, response_model=str, -) + ) class Client(ClientBase): @@ -110,6 +108,7 @@ class Client(ClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = InoutClient(self) @@ -124,12 +123,3 @@ try: except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_external_generic_type_fallback-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_external_generic_type_fallback-3.snap index 6bb5c167..52ec81e0 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_external_generic_type_fallback-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_external_generic_type_fallback-3.snap @@ -54,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_external_generic_type_fallback-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_external_generic_type_fallback-5.snap index c2aeff1e..5675ba5f 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_external_generic_type_fallback-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_external_generic_type_fallback-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback(BaseModel): @@ -33,6 +32,21 @@ class ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback(BaseMode data: dict[str, int] +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithExternalGenericTypeFallback = ( + ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -42,16 +56,18 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback + reflectapi_demo.tests.basic.TestStructWithExternalGenericTypeFallback ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback]: + ) -> ApiResponse[ + reflectapi_demo.tests.basic.TestStructWithExternalGenericTypeFallback + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback]: Response containing ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithExternalGenericTypeFallback]: Response containing reflectapi_demo.tests.basic.TestStructWithExternalGenericTypeFallback data """ path = "/inout_test" @@ -61,7 +77,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback, + response_model=reflectapi_demo.tests.basic.TestStructWithExternalGenericTypeFallback, ) @@ -87,16 +103,18 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback + reflectapi_demo.tests.basic.TestStructWithExternalGenericTypeFallback ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback]: + ) -> ApiResponse[ + reflectapi_demo.tests.basic.TestStructWithExternalGenericTypeFallback + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback]: Response containing ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithExternalGenericTypeFallback]: Response containing reflectapi_demo.tests.basic.TestStructWithExternalGenericTypeFallback data """ path = "/inout_test" @@ -106,7 +124,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback, + response_model=reflectapi_demo.tests.basic.TestStructWithExternalGenericTypeFallback, ) @@ -131,23 +149,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithExternalGenericTypeFallback.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithexternalgenerictypefallback_response( - value: ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithExternalGenericTypeFallback.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_fixed_size_array-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_fixed_size_array-3.snap index 22daae5a..6afe1709 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_fixed_size_array-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_fixed_size_array-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithFixedSizeArray > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_fixed_size_array-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_fixed_size_array-5.snap index 6327fe7c..af3eec3a 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_fixed_size_array-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_fixed_size_array-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithFixedSizeArray(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsBasicTestStructWithFixedSizeArray(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: bytes + f: bytes = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithFixedSizeArray = ( + ReflectapiDemoTestsBasicTestStructWithFixedSizeArray + ) class AsyncInoutClient: @@ -41,15 +55,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithFixedSizeArray] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithFixedSizeArray]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithFixedSizeArray] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithFixedSizeArray]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithFixedSizeArray]: Response containing ReflectapiDemoTestsBasicTestStructWithFixedSizeArray data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithFixedSizeArray]: Response containing reflectapi_demo.tests.basic.TestStructWithFixedSizeArray data """ path = "/inout_test" @@ -59,7 +73,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithFixedSizeArray, + response_model=reflectapi_demo.tests.basic.TestStructWithFixedSizeArray, ) @@ -84,15 +98,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithFixedSizeArray] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithFixedSizeArray]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithFixedSizeArray] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithFixedSizeArray]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithFixedSizeArray]: Response containing ReflectapiDemoTestsBasicTestStructWithFixedSizeArray data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithFixedSizeArray]: Response containing reflectapi_demo.tests.basic.TestStructWithFixedSizeArray data """ path = "/inout_test" @@ -102,7 +116,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithFixedSizeArray, + response_model=reflectapi_demo.tests.basic.TestStructWithFixedSizeArray, ) @@ -127,23 +141,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithFixedSizeArray.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithFixedSizeArray.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithfixedsizearray_response( - value: ReflectapiDemoTestsBasicTestStructWithFixedSizeArray, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithFixedSizeArray]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithFixedSizeArray.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashmap-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashmap-3.snap index 681e47ec..e51bc84c 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashmap-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashmap-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithHashMap > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashmap-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashmap-5.snap index 826d0f08..be526eb9 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashmap-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashmap-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithHashMap(BaseModel): @@ -30,7 +29,20 @@ class ReflectapiDemoTestsBasicTestStructWithHashMap(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: dict[int, str] + f: dict[int, str] = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithHashMap = ReflectapiDemoTestsBasicTestStructWithHashMap class AsyncInoutClient: @@ -41,15 +53,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithHashMap] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithHashMap]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithHashMap] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithHashMap]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithHashMap]: Response containing ReflectapiDemoTestsBasicTestStructWithHashMap data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithHashMap]: Response containing reflectapi_demo.tests.basic.TestStructWithHashMap data """ path = "/inout_test" @@ -59,7 +71,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithHashMap, + response_model=reflectapi_demo.tests.basic.TestStructWithHashMap, ) @@ -84,15 +96,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithHashMap] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithHashMap]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithHashMap] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithHashMap]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithHashMap]: Response containing ReflectapiDemoTestsBasicTestStructWithHashMap data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithHashMap]: Response containing reflectapi_demo.tests.basic.TestStructWithHashMap data """ path = "/inout_test" @@ -102,7 +114,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithHashMap, + response_model=reflectapi_demo.tests.basic.TestStructWithHashMap, ) @@ -127,23 +139,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithHashMap.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithHashMap.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithhashmap_response( - value: ReflectapiDemoTestsBasicTestStructWithHashMap, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithHashMap]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithHashMap.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field-3.snap index cb2c6913..a8d62808 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithHashSetField > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field-5.snap index 82cf0a2c..ec4c116d 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithHashSetField(BaseModel): @@ -30,7 +29,24 @@ class ReflectapiDemoTestsBasicTestStructWithHashSetField(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f_hashset: bytes + f_hashset: bytes = Field( + serialization_alias="_f_hashset", validation_alias="_f_hashset" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithHashSetField = ( + ReflectapiDemoTestsBasicTestStructWithHashSetField + ) class AsyncInoutClient: @@ -41,15 +57,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithHashSetField] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithHashSetField]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithHashSetField] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithHashSetField]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithHashSetField]: Response containing ReflectapiDemoTestsBasicTestStructWithHashSetField data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithHashSetField]: Response containing reflectapi_demo.tests.basic.TestStructWithHashSetField data """ path = "/inout_test" @@ -59,7 +75,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithHashSetField, + response_model=reflectapi_demo.tests.basic.TestStructWithHashSetField, ) @@ -84,15 +100,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithHashSetField] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithHashSetField]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithHashSetField] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithHashSetField]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithHashSetField]: Response containing ReflectapiDemoTestsBasicTestStructWithHashSetField data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithHashSetField]: Response containing reflectapi_demo.tests.basic.TestStructWithHashSetField data """ path = "/inout_test" @@ -102,7 +118,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithHashSetField, + response_model=reflectapi_demo.tests.basic.TestStructWithHashSetField, ) @@ -127,23 +143,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithHashSetField.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithHashSetField.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithhashsetfield_response( - value: ReflectapiDemoTestsBasicTestStructWithHashSetField, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithHashSetField]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithHashSetField.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field_generic-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field_generic-3.snap index d1b19b3a..a873f7d1 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field_generic-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field_generic-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::>()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithHashSetFieldGeneric:: > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -59,7 +58,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field_generic-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field_generic-5.snap index b257b831..514bfa4e 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field_generic-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_hashset_field_generic-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -36,7 +35,24 @@ class ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric(BaseModel, Gener model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f_hashset: list[G] + f_hashset: list[G] = Field( + serialization_alias="_f_hashset", validation_alias="_f_hashset" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithHashSetFieldGeneric = ( + ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric + ) class AsyncInoutClient: @@ -48,16 +64,18 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric[str] + reflectapi_demo.tests.basic.TestStructWithHashSetFieldGeneric[str] ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric[str]]: + ) -> ApiResponse[ + reflectapi_demo.tests.basic.TestStructWithHashSetFieldGeneric[str] + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric[str]]: Response containing ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric[str] data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithHashSetFieldGeneric[str]]: Response containing reflectapi_demo.tests.basic.TestStructWithHashSetFieldGeneric[str] data """ path = "/inout_test" @@ -67,7 +85,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric[ + response_model=reflectapi_demo.tests.basic.TestStructWithHashSetFieldGeneric[ str ], ) @@ -95,16 +113,18 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric[str] + reflectapi_demo.tests.basic.TestStructWithHashSetFieldGeneric[str] ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric[str]]: + ) -> ApiResponse[ + reflectapi_demo.tests.basic.TestStructWithHashSetFieldGeneric[str] + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric[str]]: Response containing ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric[str] data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithHashSetFieldGeneric[str]]: Response containing reflectapi_demo.tests.basic.TestStructWithHashSetFieldGeneric[str] data """ path = "/inout_test" @@ -114,7 +134,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric[ + response_model=reflectapi_demo.tests.basic.TestStructWithHashSetFieldGeneric[ str ], ) @@ -141,23 +161,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithHashSetFieldGeneric.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithhashsetfieldgeneric_response( - value: ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithHashSetFieldGeneric.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested-3.snap index 462118d8..cfe2f37c 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithNested > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested-5.snap index 37b32b73..720c3d85 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructNested(BaseModel): @@ -30,7 +29,7 @@ class ReflectapiDemoTestsBasicTestStructNested(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: str + f: str = Field(serialization_alias="_f", validation_alias="_f") class ReflectapiDemoTestsBasicTestStructWithNested(BaseModel): @@ -38,7 +37,23 @@ class ReflectapiDemoTestsBasicTestStructWithNested(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: ReflectapiDemoTestsBasicTestStructNested + f: reflectapi_demo.tests.basic.TestStructNested = Field( + serialization_alias="_f", validation_alias="_f" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructNested = ReflectapiDemoTestsBasicTestStructNested + TestStructWithNested = ReflectapiDemoTestsBasicTestStructWithNested class AsyncInoutClient: @@ -49,15 +64,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithNested] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithNested]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithNested] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithNested]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithNested]: Response containing ReflectapiDemoTestsBasicTestStructWithNested data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithNested]: Response containing reflectapi_demo.tests.basic.TestStructWithNested data """ path = "/inout_test" @@ -67,7 +82,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithNested, + response_model=reflectapi_demo.tests.basic.TestStructWithNested, ) @@ -92,15 +107,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithNested] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithNested]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithNested] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithNested]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithNested]: Response containing ReflectapiDemoTestsBasicTestStructWithNested data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithNested]: Response containing reflectapi_demo.tests.basic.TestStructWithNested data """ path = "/inout_test" @@ -110,7 +125,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithNested, + response_model=reflectapi_demo.tests.basic.TestStructWithNested, ) @@ -135,31 +150,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructNested.model_rebuild() - ReflectapiDemoTestsBasicTestStructWithNested.model_rebuild() + reflectapi_demo.tests.basic.TestStructNested.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithNested.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructnested_response( - value: ReflectapiDemoTestsBasicTestStructNested, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructNested]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructNested.""" - return create_api_response(value) - - -def create_reflectapidemotestsbasicteststructwithnested_response( - value: ReflectapiDemoTestsBasicTestStructWithNested, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithNested]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithNested.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested_external-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested_external-3.snap index 754813f5..0be0f064 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested_external-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested_external-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithNestedExternal > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested_external-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested_external-5.snap index dd419c7e..39d30505 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested_external-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_nested_external-5.snap @@ -16,29 +16,50 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response -class ReflectapiDemoTestsTestLibTestStructNested(BaseModel): +class ReflectapiDemoTestsBasicTestStructWithNestedExternal(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: str + f: reflectapi_demo.tests.test_lib.TestStructNested = Field( + serialization_alias="_f", validation_alias="_f" + ) -class ReflectapiDemoTestsBasicTestStructWithNestedExternal(BaseModel): +class ReflectapiDemoTestsTestLibTestStructNested(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: ReflectapiDemoTestsTestLibTestStructNested + f: str = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithNestedExternal = ( + ReflectapiDemoTestsBasicTestStructWithNestedExternal + ) + + class test_lib: + """Namespace for test_lib types.""" + + TestStructNested = ReflectapiDemoTestsTestLibTestStructNested class AsyncInoutClient: @@ -49,15 +70,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithNestedExternal] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithNestedExternal]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithNestedExternal] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithNestedExternal]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithNestedExternal]: Response containing ReflectapiDemoTestsBasicTestStructWithNestedExternal data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithNestedExternal]: Response containing reflectapi_demo.tests.basic.TestStructWithNestedExternal data """ path = "/inout_test" @@ -67,7 +88,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithNestedExternal, + response_model=reflectapi_demo.tests.basic.TestStructWithNestedExternal, ) @@ -92,15 +113,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithNestedExternal] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithNestedExternal]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithNestedExternal] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithNestedExternal]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithNestedExternal]: Response containing ReflectapiDemoTestsBasicTestStructWithNestedExternal data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithNestedExternal]: Response containing reflectapi_demo.tests.basic.TestStructWithNestedExternal data """ path = "/inout_test" @@ -110,7 +131,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithNestedExternal, + response_model=reflectapi_demo.tests.basic.TestStructWithNestedExternal, ) @@ -135,31 +156,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithNestedExternal.model_rebuild() - ReflectapiDemoTestsTestLibTestStructNested.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithNestedExternal.model_rebuild() + reflectapi_demo.tests.test_lib.TestStructNested.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithnestedexternal_response( - value: ReflectapiDemoTestsBasicTestStructWithNestedExternal, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithNestedExternal]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithNestedExternal.""" - return create_api_response(value) - - -def create_reflectapidemoteststestlibteststructnested_response( - value: ReflectapiDemoTestsTestLibTestStructNested, -) -> ApiResponse[ReflectapiDemoTestsTestLibTestStructNested]: - """Create a mock ApiResponse for ReflectapiDemoTestsTestLibTestStructNested.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_self_via_arc-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_self_via_arc-3.snap index 99b8af06..cdfda325 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_self_via_arc-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_self_via_arc-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithSelfViaArc > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_self_via_arc-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_self_via_arc-5.snap index 74ecad73..d417ecd8 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_self_via_arc-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_self_via_arc-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithSelfViaArc(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsBasicTestStructWithSelfViaArc(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: ReflectapiDemoTestsBasicTestStructWithSelfViaArc + f: reflectapi_demo.tests.basic.TestStructWithSelfViaArc = Field( + serialization_alias="_f", validation_alias="_f" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithSelfViaArc = ReflectapiDemoTestsBasicTestStructWithSelfViaArc class AsyncInoutClient: @@ -41,15 +55,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithSelfViaArc] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithSelfViaArc]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithSelfViaArc] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithSelfViaArc]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithSelfViaArc]: Response containing ReflectapiDemoTestsBasicTestStructWithSelfViaArc data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithSelfViaArc]: Response containing reflectapi_demo.tests.basic.TestStructWithSelfViaArc data """ path = "/inout_test" @@ -59,7 +73,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithSelfViaArc, + response_model=reflectapi_demo.tests.basic.TestStructWithSelfViaArc, ) @@ -84,15 +98,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithSelfViaArc] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithSelfViaArc]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithSelfViaArc] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithSelfViaArc]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithSelfViaArc]: Response containing ReflectapiDemoTestsBasicTestStructWithSelfViaArc data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithSelfViaArc]: Response containing reflectapi_demo.tests.basic.TestStructWithSelfViaArc data """ path = "/inout_test" @@ -102,7 +116,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithSelfViaArc, + response_model=reflectapi_demo.tests.basic.TestStructWithSelfViaArc, ) @@ -127,23 +141,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithSelfViaArc.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithSelfViaArc.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithselfviaarc_response( - value: ReflectapiDemoTestsBasicTestStructWithSelfViaArc, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithSelfViaArc]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithSelfViaArc.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field-3.snap index cc33fef8..21ca4169 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithSkipField > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field-5.snap index 1b4a2e4f..54ac90a9 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithSkipField(BaseModel): @@ -31,6 +30,19 @@ class ReflectapiDemoTestsBasicTestStructWithSkipField(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithSkipField = ReflectapiDemoTestsBasicTestStructWithSkipField + + class AsyncInoutClient: """Async client for inout operations.""" @@ -39,15 +51,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithSkipField] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithSkipField]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithSkipField] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithSkipField]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithSkipField]: Response containing ReflectapiDemoTestsBasicTestStructWithSkipField data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithSkipField]: Response containing reflectapi_demo.tests.basic.TestStructWithSkipField data """ path = "/inout_test" @@ -57,7 +69,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithSkipField, + response_model=reflectapi_demo.tests.basic.TestStructWithSkipField, ) @@ -82,15 +94,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithSkipField] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithSkipField]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithSkipField] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithSkipField]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithSkipField]: Response containing ReflectapiDemoTestsBasicTestStructWithSkipField data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithSkipField]: Response containing reflectapi_demo.tests.basic.TestStructWithSkipField data """ path = "/inout_test" @@ -100,7 +112,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithSkipField, + response_model=reflectapi_demo.tests.basic.TestStructWithSkipField, ) @@ -125,23 +137,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithSkipField.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithSkipField.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithskipfield_response( - value: ReflectapiDemoTestsBasicTestStructWithSkipField, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithSkipField]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithSkipField.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_input-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_input-3.snap index 9f042d8e..e24444d9 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_input-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_input-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithSkipFieldInput > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_input-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_input-5.snap index 315c83dd..d052cf13 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_input-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_input-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicInputTestStructWithSkipFieldInput(BaseModel): @@ -36,7 +35,32 @@ class ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldInput(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + f: int = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + class input: + """Namespace for input types.""" + + TestStructWithSkipFieldInput = ( + ReflectapiDemoTestsBasicInputTestStructWithSkipFieldInput + ) + + class output: + """Namespace for output types.""" + + TestStructWithSkipFieldInput = ( + ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldInput + ) class AsyncInoutClient: @@ -48,16 +72,16 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsBasicInputTestStructWithSkipFieldInput + reflectapi_demo.tests.basic.input.TestStructWithSkipFieldInput ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldInput]: + ) -> ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithSkipFieldInput]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldInput]: Response containing ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldInput data + ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithSkipFieldInput]: Response containing reflectapi_demo.tests.basic.output.TestStructWithSkipFieldInput data """ path = "/inout_test" @@ -67,7 +91,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldInput, + response_model=reflectapi_demo.tests.basic.output.TestStructWithSkipFieldInput, ) @@ -93,16 +117,16 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsBasicInputTestStructWithSkipFieldInput + reflectapi_demo.tests.basic.input.TestStructWithSkipFieldInput ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldInput]: + ) -> ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithSkipFieldInput]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldInput]: Response containing ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldInput data + ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithSkipFieldInput]: Response containing reflectapi_demo.tests.basic.output.TestStructWithSkipFieldInput data """ path = "/inout_test" @@ -112,7 +136,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldInput, + response_model=reflectapi_demo.tests.basic.output.TestStructWithSkipFieldInput, ) @@ -137,31 +161,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicInputTestStructWithSkipFieldInput.model_rebuild() - ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldInput.model_rebuild() + reflectapi_demo.tests.basic.input.TestStructWithSkipFieldInput.model_rebuild() + reflectapi_demo.tests.basic.output.TestStructWithSkipFieldInput.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicinputteststructwithskipfieldinput_response( - value: ReflectapiDemoTestsBasicInputTestStructWithSkipFieldInput, -) -> ApiResponse[ReflectapiDemoTestsBasicInputTestStructWithSkipFieldInput]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicInputTestStructWithSkipFieldInput.""" - return create_api_response(value) - - -def create_reflectapidemotestsbasicoutputteststructwithskipfieldinput_response( - value: ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldInput, -) -> ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldInput]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldInput.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_output-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_output-3.snap index cfb50f9b..77e8ec3b 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_output-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_output-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithSkipFieldOutput > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_output-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_output-5.snap index e92b55f7..46c77102 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_output-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_skip_field_output-5.snap @@ -16,27 +16,51 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response -class ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldOutput(BaseModel): +class ReflectapiDemoTestsBasicInputTestStructWithSkipFieldOutput(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) + f: int = Field(serialization_alias="_f", validation_alias="_f") -class ReflectapiDemoTestsBasicInputTestStructWithSkipFieldOutput(BaseModel): + +class ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldOutput(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + class input: + """Namespace for input types.""" + + TestStructWithSkipFieldOutput = ( + ReflectapiDemoTestsBasicInputTestStructWithSkipFieldOutput + ) + + class output: + """Namespace for output types.""" + + TestStructWithSkipFieldOutput = ( + ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldOutput + ) class AsyncInoutClient: @@ -48,16 +72,16 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsBasicInputTestStructWithSkipFieldOutput + reflectapi_demo.tests.basic.input.TestStructWithSkipFieldOutput ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldOutput]: + ) -> ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithSkipFieldOutput]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldOutput]: Response containing ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldOutput data + ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithSkipFieldOutput]: Response containing reflectapi_demo.tests.basic.output.TestStructWithSkipFieldOutput data """ path = "/inout_test" @@ -67,7 +91,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldOutput, + response_model=reflectapi_demo.tests.basic.output.TestStructWithSkipFieldOutput, ) @@ -93,16 +117,16 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsBasicInputTestStructWithSkipFieldOutput + reflectapi_demo.tests.basic.input.TestStructWithSkipFieldOutput ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldOutput]: + ) -> ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithSkipFieldOutput]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldOutput]: Response containing ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldOutput data + ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithSkipFieldOutput]: Response containing reflectapi_demo.tests.basic.output.TestStructWithSkipFieldOutput data """ path = "/inout_test" @@ -112,7 +136,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldOutput, + response_model=reflectapi_demo.tests.basic.output.TestStructWithSkipFieldOutput, ) @@ -137,31 +161,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicInputTestStructWithSkipFieldOutput.model_rebuild() - ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldOutput.model_rebuild() + reflectapi_demo.tests.basic.input.TestStructWithSkipFieldOutput.model_rebuild() + reflectapi_demo.tests.basic.output.TestStructWithSkipFieldOutput.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicinputteststructwithskipfieldoutput_response( - value: ReflectapiDemoTestsBasicInputTestStructWithSkipFieldOutput, -) -> ApiResponse[ReflectapiDemoTestsBasicInputTestStructWithSkipFieldOutput]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicInputTestStructWithSkipFieldOutput.""" - return create_api_response(value) - - -def create_reflectapidemotestsbasicoutputteststructwithskipfieldoutput_response( - value: ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldOutput, -) -> ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldOutput]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicOutputTestStructWithSkipFieldOutput.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_array-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_array-3.snap index 123380cd..dc55a443 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_array-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_array-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithTransformArray > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_array-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_array-5.snap index 9647185a..c3d1e56b 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_array-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_array-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithTransformArray(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsBasicTestStructWithTransformArray(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: bytes + f: bytes = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithTransformArray = ( + ReflectapiDemoTestsBasicTestStructWithTransformArray + ) class AsyncInoutClient: @@ -41,15 +55,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithTransformArray] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformArray]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithTransformArray] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformArray]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformArray]: Response containing ReflectapiDemoTestsBasicTestStructWithTransformArray data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformArray]: Response containing reflectapi_demo.tests.basic.TestStructWithTransformArray data """ path = "/inout_test" @@ -59,7 +73,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithTransformArray, + response_model=reflectapi_demo.tests.basic.TestStructWithTransformArray, ) @@ -84,15 +98,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithTransformArray] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformArray]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithTransformArray] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformArray]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformArray]: Response containing ReflectapiDemoTestsBasicTestStructWithTransformArray data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformArray]: Response containing reflectapi_demo.tests.basic.TestStructWithTransformArray data """ path = "/inout_test" @@ -102,7 +116,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithTransformArray, + response_model=reflectapi_demo.tests.basic.TestStructWithTransformArray, ) @@ -127,23 +141,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithTransformArray.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithTransformArray.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithtransformarray_response( - value: ReflectapiDemoTestsBasicTestStructWithTransformArray, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformArray]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithTransformArray.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_both-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_both-3.snap index 4f118b7d..3984898f 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_both-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_both-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithTransformBoth > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_both-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_both-5.snap index 8712f778..cf78b4e5 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_both-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_both-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithTransformBoth(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsBasicTestStructWithTransformBoth(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + f: int = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithTransformBoth = ( + ReflectapiDemoTestsBasicTestStructWithTransformBoth + ) class AsyncInoutClient: @@ -41,15 +55,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithTransformBoth] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformBoth]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithTransformBoth] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformBoth]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformBoth]: Response containing ReflectapiDemoTestsBasicTestStructWithTransformBoth data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformBoth]: Response containing reflectapi_demo.tests.basic.TestStructWithTransformBoth data """ path = "/inout_test" @@ -59,7 +73,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithTransformBoth, + response_model=reflectapi_demo.tests.basic.TestStructWithTransformBoth, ) @@ -84,15 +98,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithTransformBoth] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformBoth]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithTransformBoth] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformBoth]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformBoth]: Response containing ReflectapiDemoTestsBasicTestStructWithTransformBoth data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformBoth]: Response containing reflectapi_demo.tests.basic.TestStructWithTransformBoth data """ path = "/inout_test" @@ -102,7 +116,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithTransformBoth, + response_model=reflectapi_demo.tests.basic.TestStructWithTransformBoth, ) @@ -127,23 +141,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithTransformBoth.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithTransformBoth.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithtransformboth_response( - value: ReflectapiDemoTestsBasicTestStructWithTransformBoth, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformBoth]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithTransformBoth.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback-3.snap index d629000c..c1b68ba2 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithTransformFallback > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback-5.snap index 5fa1279c..9fdd95c4 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithTransformFallback(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsBasicTestStructWithTransformFallback(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + f: int = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithTransformFallback = ( + ReflectapiDemoTestsBasicTestStructWithTransformFallback + ) class AsyncInoutClient: @@ -41,15 +55,17 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithTransformFallback] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformFallback]: + data: Optional[ + reflectapi_demo.tests.basic.TestStructWithTransformFallback + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformFallback]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformFallback]: Response containing ReflectapiDemoTestsBasicTestStructWithTransformFallback data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformFallback]: Response containing reflectapi_demo.tests.basic.TestStructWithTransformFallback data """ path = "/inout_test" @@ -59,7 +75,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithTransformFallback, + response_model=reflectapi_demo.tests.basic.TestStructWithTransformFallback, ) @@ -84,15 +100,17 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithTransformFallback] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformFallback]: + data: Optional[ + reflectapi_demo.tests.basic.TestStructWithTransformFallback + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformFallback]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformFallback]: Response containing ReflectapiDemoTestsBasicTestStructWithTransformFallback data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformFallback]: Response containing reflectapi_demo.tests.basic.TestStructWithTransformFallback data """ path = "/inout_test" @@ -102,7 +120,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithTransformFallback, + response_model=reflectapi_demo.tests.basic.TestStructWithTransformFallback, ) @@ -127,23 +145,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithTransformFallback.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithTransformFallback.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithtransformfallback_response( - value: ReflectapiDemoTestsBasicTestStructWithTransformFallback, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformFallback]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithTransformFallback.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback_nested-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback_nested-3.snap index 3a55ce12..182b6ff8 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback_nested-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback_nested-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithTransformFallbackNested > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback_nested-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback_nested-5.snap index 7a216424..600258d9 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback_nested-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_fallback_nested-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + f: int = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithTransformFallbackNested = ( + ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested + ) class AsyncInoutClient: @@ -42,16 +56,16 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested + reflectapi_demo.tests.basic.TestStructWithTransformFallbackNested ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested]: + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformFallbackNested]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested]: Response containing ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformFallbackNested]: Response containing reflectapi_demo.tests.basic.TestStructWithTransformFallbackNested data """ path = "/inout_test" @@ -61,7 +75,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested, + response_model=reflectapi_demo.tests.basic.TestStructWithTransformFallbackNested, ) @@ -87,16 +101,16 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested + reflectapi_demo.tests.basic.TestStructWithTransformFallbackNested ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested]: + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformFallbackNested]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested]: Response containing ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithTransformFallbackNested]: Response containing reflectapi_demo.tests.basic.TestStructWithTransformFallbackNested data """ path = "/inout_test" @@ -106,7 +120,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested, + response_model=reflectapi_demo.tests.basic.TestStructWithTransformFallbackNested, ) @@ -131,23 +145,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithTransformFallbackNested.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithtransformfallbacknested_response( - value: ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithTransformFallbackNested.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_input-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_input-3.snap index 05bf8b2a..90460d4f 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_input-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_input-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithTransformInput > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_input-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_input-5.snap index 54f0f6ed..15856e46 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_input-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_input-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicInputTestStructWithTransformInput(BaseModel): @@ -30,7 +29,7 @@ class ReflectapiDemoTestsBasicInputTestStructWithTransformInput(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + f: int = Field(serialization_alias="_f", validation_alias="_f") class ReflectapiDemoTestsBasicOutputTestStructWithTransformInput(BaseModel): @@ -38,7 +37,32 @@ class ReflectapiDemoTestsBasicOutputTestStructWithTransformInput(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + f: int = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + class input: + """Namespace for input types.""" + + TestStructWithTransformInput = ( + ReflectapiDemoTestsBasicInputTestStructWithTransformInput + ) + + class output: + """Namespace for output types.""" + + TestStructWithTransformInput = ( + ReflectapiDemoTestsBasicOutputTestStructWithTransformInput + ) class AsyncInoutClient: @@ -50,16 +74,16 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsBasicInputTestStructWithTransformInput + reflectapi_demo.tests.basic.input.TestStructWithTransformInput ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithTransformInput]: + ) -> ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithTransformInput]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithTransformInput]: Response containing ReflectapiDemoTestsBasicOutputTestStructWithTransformInput data + ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithTransformInput]: Response containing reflectapi_demo.tests.basic.output.TestStructWithTransformInput data """ path = "/inout_test" @@ -69,7 +93,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicOutputTestStructWithTransformInput, + response_model=reflectapi_demo.tests.basic.output.TestStructWithTransformInput, ) @@ -95,16 +119,16 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsBasicInputTestStructWithTransformInput + reflectapi_demo.tests.basic.input.TestStructWithTransformInput ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithTransformInput]: + ) -> ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithTransformInput]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithTransformInput]: Response containing ReflectapiDemoTestsBasicOutputTestStructWithTransformInput data + ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithTransformInput]: Response containing reflectapi_demo.tests.basic.output.TestStructWithTransformInput data """ path = "/inout_test" @@ -114,7 +138,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicOutputTestStructWithTransformInput, + response_model=reflectapi_demo.tests.basic.output.TestStructWithTransformInput, ) @@ -139,31 +163,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicInputTestStructWithTransformInput.model_rebuild() - ReflectapiDemoTestsBasicOutputTestStructWithTransformInput.model_rebuild() + reflectapi_demo.tests.basic.input.TestStructWithTransformInput.model_rebuild() + reflectapi_demo.tests.basic.output.TestStructWithTransformInput.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicinputteststructwithtransforminput_response( - value: ReflectapiDemoTestsBasicInputTestStructWithTransformInput, -) -> ApiResponse[ReflectapiDemoTestsBasicInputTestStructWithTransformInput]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicInputTestStructWithTransformInput.""" - return create_api_response(value) - - -def create_reflectapidemotestsbasicoutputteststructwithtransforminput_response( - value: ReflectapiDemoTestsBasicOutputTestStructWithTransformInput, -) -> ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithTransformInput]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicOutputTestStructWithTransformInput.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_output-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_output-3.snap index bd1e81b6..b5842ee3 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_output-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_output-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithTransformOutput > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_output-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_output-5.snap index 5e624b3e..eae22a12 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_output-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_transform_output-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicInputTestStructWithTransformOutput(BaseModel): @@ -30,7 +29,7 @@ class ReflectapiDemoTestsBasicInputTestStructWithTransformOutput(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + f: int = Field(serialization_alias="_f", validation_alias="_f") class ReflectapiDemoTestsBasicOutputTestStructWithTransformOutput(BaseModel): @@ -38,7 +37,32 @@ class ReflectapiDemoTestsBasicOutputTestStructWithTransformOutput(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + f: int = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + class input: + """Namespace for input types.""" + + TestStructWithTransformOutput = ( + ReflectapiDemoTestsBasicInputTestStructWithTransformOutput + ) + + class output: + """Namespace for output types.""" + + TestStructWithTransformOutput = ( + ReflectapiDemoTestsBasicOutputTestStructWithTransformOutput + ) class AsyncInoutClient: @@ -50,16 +74,16 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsBasicInputTestStructWithTransformOutput + reflectapi_demo.tests.basic.input.TestStructWithTransformOutput ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithTransformOutput]: + ) -> ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithTransformOutput]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithTransformOutput]: Response containing ReflectapiDemoTestsBasicOutputTestStructWithTransformOutput data + ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithTransformOutput]: Response containing reflectapi_demo.tests.basic.output.TestStructWithTransformOutput data """ path = "/inout_test" @@ -69,7 +93,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicOutputTestStructWithTransformOutput, + response_model=reflectapi_demo.tests.basic.output.TestStructWithTransformOutput, ) @@ -95,16 +119,16 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsBasicInputTestStructWithTransformOutput + reflectapi_demo.tests.basic.input.TestStructWithTransformOutput ] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithTransformOutput]: + ) -> ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithTransformOutput]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithTransformOutput]: Response containing ReflectapiDemoTestsBasicOutputTestStructWithTransformOutput data + ApiResponse[reflectapi_demo.tests.basic.output.TestStructWithTransformOutput]: Response containing reflectapi_demo.tests.basic.output.TestStructWithTransformOutput data """ path = "/inout_test" @@ -114,7 +138,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicOutputTestStructWithTransformOutput, + response_model=reflectapi_demo.tests.basic.output.TestStructWithTransformOutput, ) @@ -139,31 +163,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicInputTestStructWithTransformOutput.model_rebuild() - ReflectapiDemoTestsBasicOutputTestStructWithTransformOutput.model_rebuild() + reflectapi_demo.tests.basic.input.TestStructWithTransformOutput.model_rebuild() + reflectapi_demo.tests.basic.output.TestStructWithTransformOutput.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicinputteststructwithtransformoutput_response( - value: ReflectapiDemoTestsBasicInputTestStructWithTransformOutput, -) -> ApiResponse[ReflectapiDemoTestsBasicInputTestStructWithTransformOutput]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicInputTestStructWithTransformOutput.""" - return create_api_response(value) - - -def create_reflectapidemotestsbasicoutputteststructwithtransformoutput_response( - value: ReflectapiDemoTestsBasicOutputTestStructWithTransformOutput, -) -> ApiResponse[ReflectapiDemoTestsBasicOutputTestStructWithTransformOutput]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicOutputTestStructWithTransformOutput.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple-3.snap index d978e073..bb3c76b5 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithTuple > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple-5.snap index 471dbc23..b194eb1f 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithTuple(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsBasicTestStructWithTuple(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: StdTupleTuple2[int, str] + f: std.tuple.Tuple2[int, str] = Field( + serialization_alias="_f", validation_alias="_f" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithTuple = ReflectapiDemoTestsBasicTestStructWithTuple class AsyncInoutClient: @@ -41,15 +55,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithTuple] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTuple]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithTuple] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithTuple]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithTuple]: Response containing ReflectapiDemoTestsBasicTestStructWithTuple data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithTuple]: Response containing reflectapi_demo.tests.basic.TestStructWithTuple data """ path = "/inout_test" @@ -59,7 +73,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithTuple, + response_model=reflectapi_demo.tests.basic.TestStructWithTuple, ) @@ -84,15 +98,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithTuple] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTuple]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithTuple] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithTuple]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithTuple]: Response containing ReflectapiDemoTestsBasicTestStructWithTuple data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithTuple]: Response containing reflectapi_demo.tests.basic.TestStructWithTuple data """ path = "/inout_test" @@ -102,7 +116,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithTuple, + response_model=reflectapi_demo.tests.basic.TestStructWithTuple, ) @@ -127,23 +141,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithTuple.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithTuple.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithtuple_response( - value: ReflectapiDemoTestsBasicTestStructWithTuple, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTuple]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithTuple.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple12-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple12-3.snap index f58d93f4..a8bf5e6f 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple12-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple12-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithTuple12 > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple12-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple12-5.snap index d6868e1a..841473d7 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple12-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_tuple12-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithTuple12(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsBasicTestStructWithTuple12(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: StdTupleTuple12[int, str, int, str, int, str, int, str, int, str, int, str] + f: std.tuple.Tuple12[int, str, int, str, int, str, int, str, int, str, int, str] = ( + Field(serialization_alias="_f", validation_alias="_f") + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithTuple12 = ReflectapiDemoTestsBasicTestStructWithTuple12 class AsyncInoutClient: @@ -41,15 +55,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithTuple12] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTuple12]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithTuple12] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithTuple12]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithTuple12]: Response containing ReflectapiDemoTestsBasicTestStructWithTuple12 data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithTuple12]: Response containing reflectapi_demo.tests.basic.TestStructWithTuple12 data """ path = "/inout_test" @@ -59,7 +73,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithTuple12, + response_model=reflectapi_demo.tests.basic.TestStructWithTuple12, ) @@ -84,15 +98,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithTuple12] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTuple12]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithTuple12] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithTuple12]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithTuple12]: Response containing ReflectapiDemoTestsBasicTestStructWithTuple12 data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithTuple12]: Response containing reflectapi_demo.tests.basic.TestStructWithTuple12 data """ path = "/inout_test" @@ -102,7 +116,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithTuple12, + response_model=reflectapi_demo.tests.basic.TestStructWithTuple12, ) @@ -127,23 +141,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithTuple12.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithTuple12.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithtuple12_response( - value: ReflectapiDemoTestsBasicTestStructWithTuple12, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithTuple12]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithTuple12.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec-3.snap index 59493894..35722718 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithVec > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec-5.snap index 49b84db6..bea3b0f4 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithVec(BaseModel): @@ -30,7 +29,20 @@ class ReflectapiDemoTestsBasicTestStructWithVec(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: bytes + f: bytes = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithVec = ReflectapiDemoTestsBasicTestStructWithVec class AsyncInoutClient: @@ -41,15 +53,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithVec] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithVec]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithVec] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithVec]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithVec]: Response containing ReflectapiDemoTestsBasicTestStructWithVec data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithVec]: Response containing reflectapi_demo.tests.basic.TestStructWithVec data """ path = "/inout_test" @@ -59,7 +71,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithVec, + response_model=reflectapi_demo.tests.basic.TestStructWithVec, ) @@ -84,15 +96,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithVec] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithVec]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithVec] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithVec]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithVec]: Response containing ReflectapiDemoTestsBasicTestStructWithVec data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithVec]: Response containing reflectapi_demo.tests.basic.TestStructWithVec data """ path = "/inout_test" @@ -102,7 +114,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithVec, + response_model=reflectapi_demo.tests.basic.TestStructWithVec, ) @@ -127,23 +139,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithVec.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithVec.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithvec_response( - value: ReflectapiDemoTestsBasicTestStructWithVec, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithVec]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithVec.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_external-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_external-3.snap index c05ed3e5..11d14638 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_external-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_external-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithVecExternal > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_external-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_external-5.snap index 70e9a7a8..e714c4b8 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_external-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_external-5.snap @@ -16,29 +16,50 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response -class ReflectapiDemoTestsTestLibTestStructNested(BaseModel): +class ReflectapiDemoTestsBasicTestStructWithVecExternal(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: str + f: list[reflectapi_demo.tests.test_lib.TestStructNested] = Field( + serialization_alias="_f", validation_alias="_f" + ) -class ReflectapiDemoTestsBasicTestStructWithVecExternal(BaseModel): +class ReflectapiDemoTestsTestLibTestStructNested(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: list[ReflectapiDemoTestsTestLibTestStructNested] + f: str = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithVecExternal = ( + ReflectapiDemoTestsBasicTestStructWithVecExternal + ) + + class test_lib: + """Namespace for test_lib types.""" + + TestStructNested = ReflectapiDemoTestsTestLibTestStructNested class AsyncInoutClient: @@ -49,15 +70,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithVecExternal] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithVecExternal]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithVecExternal] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithVecExternal]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithVecExternal]: Response containing ReflectapiDemoTestsBasicTestStructWithVecExternal data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithVecExternal]: Response containing reflectapi_demo.tests.basic.TestStructWithVecExternal data """ path = "/inout_test" @@ -67,7 +88,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithVecExternal, + response_model=reflectapi_demo.tests.basic.TestStructWithVecExternal, ) @@ -92,15 +113,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithVecExternal] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithVecExternal]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithVecExternal] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithVecExternal]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithVecExternal]: Response containing ReflectapiDemoTestsBasicTestStructWithVecExternal data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithVecExternal]: Response containing reflectapi_demo.tests.basic.TestStructWithVecExternal data """ path = "/inout_test" @@ -110,7 +131,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithVecExternal, + response_model=reflectapi_demo.tests.basic.TestStructWithVecExternal, ) @@ -135,31 +156,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithVecExternal.model_rebuild() - ReflectapiDemoTestsTestLibTestStructNested.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithVecExternal.model_rebuild() + reflectapi_demo.tests.test_lib.TestStructNested.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithvecexternal_response( - value: ReflectapiDemoTestsBasicTestStructWithVecExternal, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithVecExternal]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithVecExternal.""" - return create_api_response(value) - - -def create_reflectapidemoteststestlibteststructnested_response( - value: ReflectapiDemoTestsTestLibTestStructNested, -) -> ApiResponse[ReflectapiDemoTestsTestLibTestStructNested]: - """Create a mock ApiResponse for ReflectapiDemoTestsTestLibTestStructNested.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_nested-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_nested-3.snap index 0df11eaf..b3452c12 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_nested-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_nested-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithVecNested > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_nested-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_nested-5.snap index 10c0e103..200bcee5 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_nested-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_nested-5.snap @@ -16,29 +16,48 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response -class ReflectapiDemoTestsTestLibTestStructNested(BaseModel): +class ReflectapiDemoTestsBasicTestStructWithVecNested(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: str + f: list[list[reflectapi_demo.tests.test_lib.TestStructNested]] = Field( + serialization_alias="_f", validation_alias="_f" + ) -class ReflectapiDemoTestsBasicTestStructWithVecNested(BaseModel): +class ReflectapiDemoTestsTestLibTestStructNested(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: list[list[ReflectapiDemoTestsTestLibTestStructNested]] + f: str = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithVecNested = ReflectapiDemoTestsBasicTestStructWithVecNested + + class test_lib: + """Namespace for test_lib types.""" + + TestStructNested = ReflectapiDemoTestsTestLibTestStructNested class AsyncInoutClient: @@ -49,15 +68,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithVecNested] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithVecNested]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithVecNested] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithVecNested]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithVecNested]: Response containing ReflectapiDemoTestsBasicTestStructWithVecNested data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithVecNested]: Response containing reflectapi_demo.tests.basic.TestStructWithVecNested data """ path = "/inout_test" @@ -67,7 +86,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithVecNested, + response_model=reflectapi_demo.tests.basic.TestStructWithVecNested, ) @@ -92,15 +111,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithVecNested] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithVecNested]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithVecNested] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithVecNested]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithVecNested]: Response containing ReflectapiDemoTestsBasicTestStructWithVecNested data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithVecNested]: Response containing reflectapi_demo.tests.basic.TestStructWithVecNested data """ path = "/inout_test" @@ -110,7 +129,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithVecNested, + response_model=reflectapi_demo.tests.basic.TestStructWithVecNested, ) @@ -135,31 +154,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithVecNested.model_rebuild() - ReflectapiDemoTestsTestLibTestStructNested.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithVecNested.model_rebuild() + reflectapi_demo.tests.test_lib.TestStructNested.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithvecnested_response( - value: ReflectapiDemoTestsBasicTestStructWithVecNested, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithVecNested]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithVecNested.""" - return create_api_response(value) - - -def create_reflectapidemoteststestlibteststructnested_response( - value: ReflectapiDemoTestsTestLibTestStructNested, -) -> ApiResponse[ReflectapiDemoTestsTestLibTestStructNested]: - """Create a mock ApiResponse for ReflectapiDemoTestsTestLibTestStructNested.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_two-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_two-3.snap index 825154ef..96c0983f 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_two-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_two-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/basic.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithVecTwo > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod basic { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_two-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_two-5.snap index 73e3bf8f..99d73b0b 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_two-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__basic__reflectapi_struct_with_vec_two-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsBasicTestStructWithVecTwo(BaseModel): @@ -30,8 +29,21 @@ class ReflectapiDemoTestsBasicTestStructWithVecTwo(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: bytes - _f2: list[int] + f: bytes = Field(serialization_alias="_f", validation_alias="_f") + f2: list[int] = Field(serialization_alias="_f2", validation_alias="_f2") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class basic: + """Namespace for basic types.""" + + TestStructWithVecTwo = ReflectapiDemoTestsBasicTestStructWithVecTwo class AsyncInoutClient: @@ -42,15 +54,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithVecTwo] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithVecTwo]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithVecTwo] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithVecTwo]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithVecTwo]: Response containing ReflectapiDemoTestsBasicTestStructWithVecTwo data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithVecTwo]: Response containing reflectapi_demo.tests.basic.TestStructWithVecTwo data """ path = "/inout_test" @@ -60,7 +72,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithVecTwo, + response_model=reflectapi_demo.tests.basic.TestStructWithVecTwo, ) @@ -85,15 +97,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsBasicTestStructWithVecTwo] = None, - ) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithVecTwo]: + data: Optional[reflectapi_demo.tests.basic.TestStructWithVecTwo] = None, + ) -> ApiResponse[reflectapi_demo.tests.basic.TestStructWithVecTwo]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsBasicTestStructWithVecTwo]: Response containing ReflectapiDemoTestsBasicTestStructWithVecTwo data + ApiResponse[reflectapi_demo.tests.basic.TestStructWithVecTwo]: Response containing reflectapi_demo.tests.basic.TestStructWithVecTwo data """ path = "/inout_test" @@ -103,7 +115,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsBasicTestStructWithVecTwo, + response_model=reflectapi_demo.tests.basic.TestStructWithVecTwo, ) @@ -128,23 +140,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsBasicTestStructWithVecTwo.model_rebuild() + reflectapi_demo.tests.basic.TestStructWithVecTwo.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsbasicteststructwithvectwo_response( - value: ReflectapiDemoTestsBasicTestStructWithVecTwo, -) -> ApiResponse[ReflectapiDemoTestsBasicTestStructWithVecTwo]: - """Create a mock ApiResponse for ReflectapiDemoTestsBasicTestStructWithVecTwo.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum-3.snap index 6a88129a..30c935ec 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/enums.rs -expression: "super::into_input_rust_code::()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestEnum > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod enums { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum-4.snap index 411d85ef..dd0929e3 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum-4.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsEnumsTestEnum(str, Enum): @@ -33,6 +32,19 @@ class ReflectapiDemoTestsEnumsTestEnum(str, Enum): VARIANT2 = "Variant2" +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class enums: + """Namespace for enums types.""" + + TestEnum = ReflectapiDemoTestsEnumsTestEnum + + class AsyncInputClient: """Async client for input_ operations.""" @@ -41,7 +53,7 @@ class AsyncInputClient: async def test( self, - data: Optional[ReflectapiDemoTestsEnumsTestEnum] = None, + data: Optional[reflectapi_demo.tests.enums.TestEnum] = None, ) -> ApiResponse[Any]: """ @@ -84,7 +96,7 @@ class InputClient: def test( self, - data: Optional[ReflectapiDemoTestsEnumsTestEnum] = None, + data: Optional[reflectapi_demo.tests.enums.TestEnum] = None, ) -> ApiResponse[Any]: """ @@ -127,23 +139,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsEnumsTestEnum.model_rebuild() + reflectapi_demo.tests.enums.TestEnum.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsenumstestenum_response( - value: ReflectapiDemoTestsEnumsTestEnum, -) -> ApiResponse[ReflectapiDemoTestsEnumsTestEnum]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsTestEnum.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_empty-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_empty-3.snap index cfe649c0..99b850f9 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_empty-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_empty-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/enums.rs -expression: "super::into_input_rust_code::()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestEnumEmpty > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod enums { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_empty-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_empty-4.snap index 494235d6..72b8e901 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_empty-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_empty-4.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsEnumsTestEnumEmpty(str, Enum): @@ -32,6 +31,19 @@ class ReflectapiDemoTestsEnumsTestEnumEmpty(str, Enum): pass +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class enums: + """Namespace for enums types.""" + + TestEnumEmpty = ReflectapiDemoTestsEnumsTestEnumEmpty + + class AsyncInputClient: """Async client for input_ operations.""" @@ -40,7 +52,7 @@ class AsyncInputClient: async def test( self, - data: Optional[ReflectapiDemoTestsEnumsTestEnumEmpty] = None, + data: Optional[reflectapi_demo.tests.enums.TestEnumEmpty] = None, ) -> ApiResponse[Any]: """ @@ -83,7 +95,7 @@ class InputClient: def test( self, - data: Optional[ReflectapiDemoTestsEnumsTestEnumEmpty] = None, + data: Optional[reflectapi_demo.tests.enums.TestEnumEmpty] = None, ) -> ApiResponse[Any]: """ @@ -126,23 +138,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsEnumsTestEnumEmpty.model_rebuild() + reflectapi_demo.tests.enums.TestEnumEmpty.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsenumstestenumempty_response( - value: ReflectapiDemoTestsEnumsTestEnumEmpty, -) -> ApiResponse[ReflectapiDemoTestsEnumsTestEnumEmpty]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsTestEnumEmpty.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_rename_num-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_rename_num-3.snap index e752db3f..e9fe0dd1 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_rename_num-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_rename_num-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/enums.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < Nums > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod enums { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_rename_num-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_rename_num-5.snap index 23c1d29f..d1d97873 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_rename_num-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_rename_num-5.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsEnumsNums(str, Enum): @@ -33,6 +32,19 @@ class ReflectapiDemoTestsEnumsNums(str, Enum): A = "A" +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class enums: + """Namespace for enums types.""" + + Nums = ReflectapiDemoTestsEnumsNums + + class AsyncInoutClient: """Async client for inout operations.""" @@ -41,15 +53,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsEnumsNums] = None, - ) -> ApiResponse[ReflectapiDemoTestsEnumsNums]: + data: Optional[reflectapi_demo.tests.enums.Nums] = None, + ) -> ApiResponse[reflectapi_demo.tests.enums.Nums]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsEnumsNums]: Response containing ReflectapiDemoTestsEnumsNums data + ApiResponse[reflectapi_demo.tests.enums.Nums]: Response containing reflectapi_demo.tests.enums.Nums data """ path = "/inout_test" @@ -59,7 +71,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsEnumsNums, + response_model=reflectapi_demo.tests.enums.Nums, ) @@ -84,15 +96,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsEnumsNums] = None, - ) -> ApiResponse[ReflectapiDemoTestsEnumsNums]: + data: Optional[reflectapi_demo.tests.enums.Nums] = None, + ) -> ApiResponse[reflectapi_demo.tests.enums.Nums]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsEnumsNums]: Response containing ReflectapiDemoTestsEnumsNums data + ApiResponse[reflectapi_demo.tests.enums.Nums]: Response containing reflectapi_demo.tests.enums.Nums data """ path = "/inout_test" @@ -102,7 +114,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsEnumsNums, + response_model=reflectapi_demo.tests.enums.Nums, ) @@ -127,23 +139,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsEnumsNums.model_rebuild() + reflectapi_demo.tests.enums.Nums.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsenumsnums_response( - value: ReflectapiDemoTestsEnumsNums, -) -> ApiResponse[ReflectapiDemoTestsEnumsNums]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsNums.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_basic_variant_and_fields_and_named_fields-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_basic_variant_and_fields_and_named_fields-3.snap index 87e70978..f5ebafd9 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_basic_variant_and_fields_and_named_fields-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_basic_variant_and_fields_and_named_fields-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/enums.rs -expression: "super::into_input_rust_code::()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: <\nTestEnumWithBasicVariantAndFieldsAndNamedFields > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod enums { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_basic_variant_and_fields_and_named_fields-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_basic_variant_and_fields_and_named_fields-4.snap index 108ec656..20061b55 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_basic_variant_and_fields_and_named_fields-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_basic_variant_and_fields_and_named_fields-4.snap @@ -20,6 +20,7 @@ from typing import Annotated, Any, Generic, Optional, TypeVar, Union from pydantic import ( BaseModel, ConfigDict, + Field, PrivateAttr, RootModel, model_serializer, @@ -30,7 +31,6 @@ from pydantic import ( from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFieldsVariant1Variant( @@ -123,13 +123,30 @@ class ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields( self.root, ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFieldsVariant2Variant, ): - return {"Variant2": self.root.model_dump(exclude_none=True)} + return {"Variant2": self.root.model_dump()} raise ValueError( f"Cannot serialize ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields variant: {type(self.root)}" ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class enums: + """Namespace for enums types.""" + + TestEnumWithBasicVariantAndFieldsAndNamedFieldsVariant1Variant = ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFieldsVariant1Variant + TestEnumWithBasicVariantAndFieldsAndNamedFieldsVariant2Variant = ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFieldsVariant2Variant + TestEnumWithBasicVariantAndFieldsAndNamedFields = ( + ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields + ) + + class AsyncInputClient: """Async client for input_ operations.""" @@ -139,7 +156,7 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields + reflectapi_demo.tests.enums.TestEnumWithBasicVariantAndFieldsAndNamedFields ] = None, ) -> ApiResponse[Any]: """ @@ -184,7 +201,7 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields + reflectapi_demo.tests.enums.TestEnumWithBasicVariantAndFieldsAndNamedFields ] = None, ) -> ApiResponse[Any]: """ @@ -228,63 +245,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields.model_rebuild() + reflectapi_demo.tests.enums.TestEnumWithBasicVariantAndFieldsAndNamedFields.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFieldsFactory: - """Factory class for creating ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields variants with ergonomic syntax. - - ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields variants - """ - - @staticmethod - def variant0() -> ( - ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields - ): - """Creates the 'Variant0' variant of the ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields enum.""" - return ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields( - "Variant0" - ) - - @staticmethod - def variant1( - field_0, field_1 - ) -> ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields: - """Creates the 'Variant1' variant of the ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields enum.""" - return ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields( - ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFieldsVariant1Variant( - field_0=field_0, field_1=field_1 - ) - ) - - @staticmethod - def variant2( - field1, field2 - ) -> ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields: - """Creates the 'Variant2' variant of the ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields enum.""" - return ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields( - ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFieldsVariant2Variant( - field1=field1, field2=field2 - ) - ) - - -# Testing utilities - - -def create_reflectapidemotestsenumstestenumwithbasicvariantandfieldsandnamedfields_response( - value: ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields, -) -> ApiResponse[ - ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields -]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsTestEnumWithBasicVariantAndFieldsAndNamedFields.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_input-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_input-3.snap index 422ba201..8fd35ff4 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_input-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_input-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/enums.rs -expression: "super::into_input_rust_code::()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestEnumWithDiscriminantIgnored > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod enums { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_input-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_input-4.snap index 5b61e26e..c2226d35 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_input-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_input-4.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored(str, Enum): @@ -33,6 +32,21 @@ class ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored(str, Enum): VARIANT2 = "Variant2" +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class enums: + """Namespace for enums types.""" + + TestEnumWithDiscriminantIgnored = ( + ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored + ) + + class AsyncInputClient: """Async client for input_ operations.""" @@ -41,7 +55,9 @@ class AsyncInputClient: async def test( self, - data: Optional[ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored] = None, + data: Optional[ + reflectapi_demo.tests.enums.TestEnumWithDiscriminantIgnored + ] = None, ) -> ApiResponse[Any]: """ @@ -84,7 +100,9 @@ class InputClient: def test( self, - data: Optional[ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored] = None, + data: Optional[ + reflectapi_demo.tests.enums.TestEnumWithDiscriminantIgnored + ] = None, ) -> ApiResponse[Any]: """ @@ -127,23 +145,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored.model_rebuild() + reflectapi_demo.tests.enums.TestEnumWithDiscriminantIgnored.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsenumstestenumwithdiscriminantignored_response( - value: ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored, -) -> ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_output-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_output-3.snap index 1b0e35c0..2eed9c2c 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_output-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_output-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/enums.rs -expression: "super::into_output_rust_code::()" -snapshot_kind: text +expression: "super :: into_output_rust_code :: < TestEnumWithDiscriminantIgnored > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod enums { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_output-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_output-4.snap index 7a57760a..a0359ef3 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_output-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_ignored_output-4.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored(str, Enum): @@ -33,6 +32,21 @@ class ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored(str, Enum): VARIANT2 = "Variant2" +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class enums: + """Namespace for enums types.""" + + TestEnumWithDiscriminantIgnored = ( + ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored + ) + + class AsyncOutputClient: """Async client for output operations.""" @@ -41,11 +55,11 @@ class AsyncOutputClient: async def test( self, - ) -> ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored]: + ) -> ApiResponse[reflectapi_demo.tests.enums.TestEnumWithDiscriminantIgnored]: """ Returns: - ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored]: Response containing ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored data + ApiResponse[reflectapi_demo.tests.enums.TestEnumWithDiscriminantIgnored]: Response containing reflectapi_demo.tests.enums.TestEnumWithDiscriminantIgnored data """ path = "/output_test" @@ -54,7 +68,7 @@ class AsyncOutputClient: "POST", path, params=params if params else None, - response_model=ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored, + response_model=reflectapi_demo.tests.enums.TestEnumWithDiscriminantIgnored, ) @@ -79,11 +93,11 @@ class OutputClient: def test( self, - ) -> ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored]: + ) -> ApiResponse[reflectapi_demo.tests.enums.TestEnumWithDiscriminantIgnored]: """ Returns: - ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored]: Response containing ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored data + ApiResponse[reflectapi_demo.tests.enums.TestEnumWithDiscriminantIgnored]: Response containing reflectapi_demo.tests.enums.TestEnumWithDiscriminantIgnored data """ path = "/output_test" @@ -92,7 +106,7 @@ class OutputClient: "POST", path, params=params if params else None, - response_model=ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored, + response_model=reflectapi_demo.tests.enums.TestEnumWithDiscriminantIgnored, ) @@ -117,23 +131,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored.model_rebuild() + reflectapi_demo.tests.enums.TestEnumWithDiscriminantIgnored.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsenumstestenumwithdiscriminantignored_response( - value: ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored, -) -> ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsTestEnumWithDiscriminantIgnored.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_input-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_input-3.snap index f50b24a9..93f03530 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_input-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_input-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/enums.rs -expression: "super::into_input_rust_code::()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestEnumWithDiscriminant > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod enums { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_input-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_input-4.snap index d8743926..4ebe0d2f 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_input-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_input-4.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response from enum import IntEnum @@ -39,6 +38,19 @@ class ReflectapiDemoTestsEnumsTestEnumWithDiscriminant(IntEnum): """""" +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class enums: + """Namespace for enums types.""" + + TestEnumWithDiscriminant = ReflectapiDemoTestsEnumsTestEnumWithDiscriminant + + class AsyncInputClient: """Async client for input_ operations.""" @@ -47,7 +59,7 @@ class AsyncInputClient: async def test( self, - data: Optional[ReflectapiDemoTestsEnumsTestEnumWithDiscriminant] = None, + data: Optional[reflectapi_demo.tests.enums.TestEnumWithDiscriminant] = None, ) -> ApiResponse[Any]: """ @@ -90,7 +102,7 @@ class InputClient: def test( self, - data: Optional[ReflectapiDemoTestsEnumsTestEnumWithDiscriminant] = None, + data: Optional[reflectapi_demo.tests.enums.TestEnumWithDiscriminant] = None, ) -> ApiResponse[Any]: """ @@ -133,23 +145,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsEnumsTestEnumWithDiscriminant.model_rebuild() + reflectapi_demo.tests.enums.TestEnumWithDiscriminant.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsenumstestenumwithdiscriminant_response( - value: ReflectapiDemoTestsEnumsTestEnumWithDiscriminant, -) -> ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithDiscriminant]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsTestEnumWithDiscriminant.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_output-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_output-3.snap index 8891a8eb..4aedd4ae 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_output-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_output-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/enums.rs -expression: "super::into_output_rust_code::()" -snapshot_kind: text +expression: "super :: into_output_rust_code :: < TestEnumWithDiscriminant > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod enums { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_output-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_output-4.snap index bedd7024..fa0609e5 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_output-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_discriminant_output-4.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response from enum import IntEnum @@ -39,6 +38,19 @@ class ReflectapiDemoTestsEnumsTestEnumWithDiscriminant(IntEnum): """""" +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class enums: + """Namespace for enums types.""" + + TestEnumWithDiscriminant = ReflectapiDemoTestsEnumsTestEnumWithDiscriminant + + class AsyncOutputClient: """Async client for output operations.""" @@ -47,11 +59,11 @@ class AsyncOutputClient: async def test( self, - ) -> ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithDiscriminant]: + ) -> ApiResponse[reflectapi_demo.tests.enums.TestEnumWithDiscriminant]: """ Returns: - ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithDiscriminant]: Response containing ReflectapiDemoTestsEnumsTestEnumWithDiscriminant data + ApiResponse[reflectapi_demo.tests.enums.TestEnumWithDiscriminant]: Response containing reflectapi_demo.tests.enums.TestEnumWithDiscriminant data """ path = "/output_test" @@ -60,7 +72,7 @@ class AsyncOutputClient: "POST", path, params=params if params else None, - response_model=ReflectapiDemoTestsEnumsTestEnumWithDiscriminant, + response_model=reflectapi_demo.tests.enums.TestEnumWithDiscriminant, ) @@ -85,11 +97,11 @@ class OutputClient: def test( self, - ) -> ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithDiscriminant]: + ) -> ApiResponse[reflectapi_demo.tests.enums.TestEnumWithDiscriminant]: """ Returns: - ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithDiscriminant]: Response containing ReflectapiDemoTestsEnumsTestEnumWithDiscriminant data + ApiResponse[reflectapi_demo.tests.enums.TestEnumWithDiscriminant]: Response containing reflectapi_demo.tests.enums.TestEnumWithDiscriminant data """ path = "/output_test" @@ -98,7 +110,7 @@ class OutputClient: "POST", path, params=params if params else None, - response_model=ReflectapiDemoTestsEnumsTestEnumWithDiscriminant, + response_model=reflectapi_demo.tests.enums.TestEnumWithDiscriminant, ) @@ -123,23 +135,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsEnumsTestEnumWithDiscriminant.model_rebuild() + reflectapi_demo.tests.enums.TestEnumWithDiscriminant.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsenumstestenumwithdiscriminant_response( - value: ReflectapiDemoTestsEnumsTestEnumWithDiscriminant, -) -> ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithDiscriminant]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsTestEnumWithDiscriminant.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_empty_variant_and_fields-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_empty_variant_and_fields-3.snap index 1712c21c..930dcff1 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_empty_variant_and_fields-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_empty_variant_and_fields-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/enums.rs -expression: "super::into_input_rust_code::()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestEnumWithEmptyVariantAndFields > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod enums { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_empty_variant_and_fields-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_empty_variant_and_fields-4.snap index b11f6919..57319bdb 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_empty_variant_and_fields-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_empty_variant_and_fields-4.snap @@ -20,6 +20,7 @@ from typing import Annotated, Any, Generic, Optional, TypeVar, Union from pydantic import ( BaseModel, ConfigDict, + Field, PrivateAttr, RootModel, model_serializer, @@ -30,7 +31,6 @@ from pydantic import ( from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFieldsVariant2Variant( @@ -98,6 +98,24 @@ class ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields( ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class enums: + """Namespace for enums types.""" + + TestEnumWithEmptyVariantAndFieldsVariant2Variant = ( + ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFieldsVariant2Variant + ) + TestEnumWithEmptyVariantAndFields = ( + ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields + ) + + class AsyncInputClient: """Async client for input_ operations.""" @@ -107,7 +125,7 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields + reflectapi_demo.tests.enums.TestEnumWithEmptyVariantAndFields ] = None, ) -> ApiResponse[Any]: """ @@ -152,7 +170,7 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields + reflectapi_demo.tests.enums.TestEnumWithEmptyVariantAndFields ] = None, ) -> ApiResponse[Any]: """ @@ -196,44 +214,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields.model_rebuild() + reflectapi_demo.tests.enums.TestEnumWithEmptyVariantAndFields.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFieldsFactory: - """Factory class for creating ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields variants with ergonomic syntax. - - ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields variants - """ - - @staticmethod - def variant1() -> ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields: - """Creates the 'Variant1' variant of the ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields enum.""" - return ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields("Variant1") - - @staticmethod - def variant2(field_0) -> ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields: - """Creates the 'Variant2' variant of the ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields enum.""" - return ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields( - ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFieldsVariant2Variant( - field_0=field_0 - ) - ) - - -# Testing utilities - - -def create_reflectapidemotestsenumstestenumwithemptyvariantandfields_response( - value: ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields, -) -> ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsTestEnumWithEmptyVariantAndFields.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_fields-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_fields-3.snap index 2d22f43b..cb95b8ab 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_fields-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_fields-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/enums.rs -expression: "super::into_input_rust_code::()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestEnumWithFields > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod enums { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_fields-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_fields-4.snap index 38ea266a..13c76fb5 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_fields-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_fields-4.snap @@ -20,6 +20,7 @@ from typing import Annotated, Any, Generic, Optional, TypeVar, Union from pydantic import ( BaseModel, ConfigDict, + Field, PrivateAttr, RootModel, model_serializer, @@ -30,7 +31,6 @@ from pydantic import ( from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsEnumsTestEnumWithFieldsVariant1Variant(BaseModel): @@ -110,6 +110,25 @@ class ReflectapiDemoTestsEnumsTestEnumWithFields( ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class enums: + """Namespace for enums types.""" + + TestEnumWithFieldsVariant1Variant = ( + ReflectapiDemoTestsEnumsTestEnumWithFieldsVariant1Variant + ) + TestEnumWithFieldsVariant2Variant = ( + ReflectapiDemoTestsEnumsTestEnumWithFieldsVariant2Variant + ) + TestEnumWithFields = ReflectapiDemoTestsEnumsTestEnumWithFields + + class AsyncInputClient: """Async client for input_ operations.""" @@ -118,7 +137,7 @@ class AsyncInputClient: async def test( self, - data: Optional[ReflectapiDemoTestsEnumsTestEnumWithFields] = None, + data: Optional[reflectapi_demo.tests.enums.TestEnumWithFields] = None, ) -> ApiResponse[Any]: """ @@ -161,7 +180,7 @@ class InputClient: def test( self, - data: Optional[ReflectapiDemoTestsEnumsTestEnumWithFields] = None, + data: Optional[reflectapi_demo.tests.enums.TestEnumWithFields] = None, ) -> ApiResponse[Any]: """ @@ -204,46 +223,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsEnumsTestEnumWithFields.model_rebuild() + reflectapi_demo.tests.enums.TestEnumWithFields.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsEnumsTestEnumWithFieldsFactory: - """Factory class for creating ReflectapiDemoTestsEnumsTestEnumWithFields variants with ergonomic syntax. - - ReflectapiDemoTestsEnumsTestEnumWithFields variants - """ - - @staticmethod - def variant1(field_0) -> ReflectapiDemoTestsEnumsTestEnumWithFields: - """Creates the 'Variant1' variant of the ReflectapiDemoTestsEnumsTestEnumWithFields enum.""" - return ReflectapiDemoTestsEnumsTestEnumWithFields( - ReflectapiDemoTestsEnumsTestEnumWithFieldsVariant1Variant(field_0=field_0) - ) - - @staticmethod - def variant2(field_0, field_1) -> ReflectapiDemoTestsEnumsTestEnumWithFields: - """Creates the 'Variant2' variant of the ReflectapiDemoTestsEnumsTestEnumWithFields enum.""" - return ReflectapiDemoTestsEnumsTestEnumWithFields( - ReflectapiDemoTestsEnumsTestEnumWithFieldsVariant2Variant( - field_0=field_0, field_1=field_1 - ) - ) - - -# Testing utilities - - -def create_reflectapidemotestsenumstestenumwithfields_response( - value: ReflectapiDemoTestsEnumsTestEnumWithFields, -) -> ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithFields]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsTestEnumWithFields.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics-3.snap index a75bc0a5..574c2826 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/enums.rs -expression: "super::into_input_rust_code::>()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestEnumWithGenerics:: > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod enums { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics-4.snap index a083ae1f..8550df10 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics-4.snap @@ -20,6 +20,7 @@ from typing import Annotated, Any, Generic, Optional, TypeVar, Union from pydantic import ( BaseModel, ConfigDict, + Field, PrivateAttr, RootModel, model_serializer, @@ -30,7 +31,6 @@ from pydantic import ( from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -39,9 +39,6 @@ from reflectapi_runtime.testing import MockClient, create_api_response T = TypeVar("T") -T = TypeVar("T") - - class ReflectapiDemoTestsEnumsTestEnumWithGenericsVariant1Variant( BaseModel, Generic[T] ): @@ -131,6 +128,25 @@ class ReflectapiDemoTestsEnumsTestEnumWithGenerics( ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class enums: + """Namespace for enums types.""" + + TestEnumWithGenericsVariant1Variant = ( + ReflectapiDemoTestsEnumsTestEnumWithGenericsVariant1Variant + ) + TestEnumWithGenericsVariant2Variant = ( + ReflectapiDemoTestsEnumsTestEnumWithGenericsVariant2Variant + ) + TestEnumWithGenerics = ReflectapiDemoTestsEnumsTestEnumWithGenerics + + class AsyncInputClient: """Async client for input_ operations.""" @@ -139,7 +155,7 @@ class AsyncInputClient: async def test( self, - data: Optional[ReflectapiDemoTestsEnumsTestEnumWithGenerics[int]] = None, + data: Optional[reflectapi_demo.tests.enums.TestEnumWithGenerics[int]] = None, ) -> ApiResponse[Any]: """ @@ -182,7 +198,7 @@ class InputClient: def test( self, - data: Optional[ReflectapiDemoTestsEnumsTestEnumWithGenerics[int]] = None, + data: Optional[reflectapi_demo.tests.enums.TestEnumWithGenerics[int]] = None, ) -> ApiResponse[Any]: """ @@ -225,48 +241,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsEnumsTestEnumWithGenerics.model_rebuild() + reflectapi_demo.tests.enums.TestEnumWithGenerics.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsEnumsTestEnumWithGenericsFactory: - """Factory class for creating ReflectapiDemoTestsEnumsTestEnumWithGenerics variants with ergonomic syntax. - - ReflectapiDemoTestsEnumsTestEnumWithGenerics variants - """ - - @staticmethod - def variant1(field_0) -> ReflectapiDemoTestsEnumsTestEnumWithGenerics[T]: - """Creates the 'Variant1' variant of the ReflectapiDemoTestsEnumsTestEnumWithGenerics enum.""" - return ReflectapiDemoTestsEnumsTestEnumWithGenerics( - ReflectapiDemoTestsEnumsTestEnumWithGenericsVariant1Variant[T]( - field_0=field_0 - ) - ) - - @staticmethod - def variant2(field_0, field_1) -> ReflectapiDemoTestsEnumsTestEnumWithGenerics[T]: - """Creates the 'Variant2' variant of the ReflectapiDemoTestsEnumsTestEnumWithGenerics enum.""" - return ReflectapiDemoTestsEnumsTestEnumWithGenerics( - ReflectapiDemoTestsEnumsTestEnumWithGenericsVariant2Variant[T]( - field_0=field_0, field_1=field_1 - ) - ) - - -# Testing utilities - - -def create_reflectapidemotestsenumstestenumwithgenerics_response( - value: ReflectapiDemoTestsEnumsTestEnumWithGenerics, -) -> ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithGenerics]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsTestEnumWithGenerics.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields-3.snap index 634a4efa..0ca5ab25 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/enums.rs -expression: "super::into_input_rust_code::>()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestEnumWithGenericsAndFields:: > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod enums { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields-4.snap index 2b8d3c2e..4482a317 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields-4.snap @@ -20,6 +20,7 @@ from typing import Annotated, Any, Generic, Optional, TypeVar, Union from pydantic import ( BaseModel, ConfigDict, + Field, PrivateAttr, RootModel, model_serializer, @@ -30,7 +31,6 @@ from pydantic import ( from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -39,9 +39,6 @@ from reflectapi_runtime.testing import MockClient, create_api_response T = TypeVar("T") -T = TypeVar("T") - - class ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsVariant1Variant( BaseModel, Generic[T] ): @@ -133,6 +130,27 @@ class ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields( ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class enums: + """Namespace for enums types.""" + + TestEnumWithGenericsAndFieldsVariant1Variant = ( + ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsVariant1Variant + ) + TestEnumWithGenericsAndFieldsVariant2Variant = ( + ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsVariant2Variant + ) + TestEnumWithGenericsAndFields = ( + ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields + ) + + class AsyncInputClient: """Async client for input_ operations.""" @@ -142,7 +160,7 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields[int] + reflectapi_demo.tests.enums.TestEnumWithGenericsAndFields[int] ] = None, ) -> ApiResponse[Any]: """ @@ -187,7 +205,7 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields[int] + reflectapi_demo.tests.enums.TestEnumWithGenericsAndFields[int] ] = None, ) -> ApiResponse[Any]: """ @@ -231,50 +249,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields.model_rebuild() + reflectapi_demo.tests.enums.TestEnumWithGenericsAndFields.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsFactory: - """Factory class for creating ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields variants with ergonomic syntax. - - ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields variants - """ - - @staticmethod - def variant1(field_0) -> ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields[T]: - """Creates the 'Variant1' variant of the ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields enum.""" - return ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields( - ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsVariant1Variant[T]( - field_0=field_0 - ) - ) - - @staticmethod - def variant2( - field_0, field_1 - ) -> ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields[T]: - """Creates the 'Variant2' variant of the ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields enum.""" - return ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields( - ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsVariant2Variant[T]( - field_0=field_0, field_1=field_1 - ) - ) - - -# Testing utilities - - -def create_reflectapidemotestsenumstestenumwithgenericsandfields_response( - value: ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields, -) -> ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFields.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields_and_named_fields-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields_and_named_fields-3.snap index d84ae88b..a31a746e 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields_and_named_fields-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields_and_named_fields-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/enums.rs -expression: "super::into_input_rust_code::>()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: <\nTestEnumWithGenericsAndFieldsAndNamedFields:: > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod enums { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields_and_named_fields-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields_and_named_fields-4.snap index 1a561a38..c20a1187 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields_and_named_fields-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__enum_with_generics_and_fields_and_named_fields-4.snap @@ -20,6 +20,7 @@ from typing import Annotated, Any, Generic, Optional, TypeVar, Union from pydantic import ( BaseModel, ConfigDict, + Field, PrivateAttr, RootModel, model_serializer, @@ -30,7 +31,6 @@ from pydantic import ( from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -39,9 +39,6 @@ from reflectapi_runtime.testing import MockClient, create_api_response T = TypeVar("T") -T = TypeVar("T") - - class ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFieldsVariant1Variant( BaseModel, Generic[T] ): @@ -163,13 +160,31 @@ class ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields( self.root, ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFieldsVariant3Variant, ): - return {"Variant3": self.root.model_dump(exclude_none=True)} + return {"Variant3": self.root.model_dump()} raise ValueError( f"Cannot serialize ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields variant: {type(self.root)}" ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class enums: + """Namespace for enums types.""" + + TestEnumWithGenericsAndFieldsAndNamedFieldsVariant1Variant = ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFieldsVariant1Variant + TestEnumWithGenericsAndFieldsAndNamedFieldsVariant2Variant = ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFieldsVariant2Variant + TestEnumWithGenericsAndFieldsAndNamedFieldsVariant3Variant = ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFieldsVariant3Variant + TestEnumWithGenericsAndFieldsAndNamedFields = ( + ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields + ) + + class AsyncInputClient: """Async client for input_ operations.""" @@ -179,7 +194,7 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields[int] + reflectapi_demo.tests.enums.TestEnumWithGenericsAndFieldsAndNamedFields[int] ] = None, ) -> ApiResponse[Any]: """ @@ -224,7 +239,7 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields[int] + reflectapi_demo.tests.enums.TestEnumWithGenericsAndFieldsAndNamedFields[int] ] = None, ) -> ApiResponse[Any]: """ @@ -268,63 +283,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields.model_rebuild() + reflectapi_demo.tests.enums.TestEnumWithGenericsAndFieldsAndNamedFields.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFieldsFactory: - """Factory class for creating ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields variants with ergonomic syntax. - - ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields variants - """ - - @staticmethod - def variant1( - field_0, - ) -> ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields[T]: - """Creates the 'Variant1' variant of the ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields enum.""" - return ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields( - ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFieldsVariant1Variant[ - T - ](field_0=field_0) - ) - - @staticmethod - def variant2( - field_0, field_1 - ) -> ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields[T]: - """Creates the 'Variant2' variant of the ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields enum.""" - return ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields( - ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFieldsVariant2Variant[ - T - ](field_0=field_0, field_1=field_1) - ) - - @staticmethod - def variant3( - field1, field2 - ) -> ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields[T]: - """Creates the 'Variant3' variant of the ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields enum.""" - return ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields( - ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFieldsVariant3Variant[ - T - ](field1=field1, field2=field2) - ) - - -# Testing utilities - - -def create_reflectapidemotestsenumstestenumwithgenericsandfieldsandnamedfields_response( - value: ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields, -) -> ApiResponse[ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsTestEnumWithGenericsAndFieldsAndNamedFields.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_tuple_variants-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_tuple_variants-3.snap index 481de001..b268e49e 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_tuple_variants-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_tuple_variants-3.snap @@ -1,6 +1,6 @@ --- source: reflectapi-demo/src/tests/enums.rs -expression: "super::into_rust_code::()" +expression: "super :: into_rust_code :: < E > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -54,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod enums { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_tuple_variants-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_tuple_variants-5.snap index 5adc1777..051d6de2 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_tuple_variants-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_tuple_variants-5.snap @@ -23,7 +23,6 @@ from pydantic import BaseModel, ConfigDict, Field, RootModel from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsEnumsA(str, Enum): @@ -38,14 +37,29 @@ class ReflectapiDemoTestsEnumsEA(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["a"] = "a" - value: ReflectapiDemoTestsEnumsA + type: Literal["a"] = Field(default="a", description="Discriminator field") + value: reflectapi_demo.tests.enums.A = Field(description="Tuple variant value") class ReflectapiDemoTestsEnumsE(RootModel): root: Annotated[Union[ReflectapiDemoTestsEnumsEA], Field(discriminator="type")] +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class enums: + """Namespace for enums types.""" + + A = ReflectapiDemoTestsEnumsA + EA = ReflectapiDemoTestsEnumsEA + E = ReflectapiDemoTestsEnumsE + + class AsyncInoutClient: """Async client for inout operations.""" @@ -54,15 +68,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsEnumsE] = None, - ) -> ApiResponse[ReflectapiDemoTestsEnumsE]: + data: Optional[reflectapi_demo.tests.enums.E] = None, + ) -> ApiResponse[reflectapi_demo.tests.enums.E]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsEnumsE]: Response containing ReflectapiDemoTestsEnumsE data + ApiResponse[reflectapi_demo.tests.enums.E]: Response containing reflectapi_demo.tests.enums.E data """ path = "/inout_test" @@ -72,7 +86,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsEnumsE, + response_model=reflectapi_demo.tests.enums.E, ) @@ -97,15 +111,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsEnumsE] = None, - ) -> ApiResponse[ReflectapiDemoTestsEnumsE]: + data: Optional[reflectapi_demo.tests.enums.E] = None, + ) -> ApiResponse[reflectapi_demo.tests.enums.E]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsEnumsE]: Response containing ReflectapiDemoTestsEnumsE data + ApiResponse[reflectapi_demo.tests.enums.E]: Response containing reflectapi_demo.tests.enums.E data """ path = "/inout_test" @@ -115,7 +129,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsEnumsE, + response_model=reflectapi_demo.tests.enums.E, ) @@ -140,43 +154,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsEnumsA.model_rebuild() - ReflectapiDemoTestsEnumsE.model_rebuild() + reflectapi_demo.tests.enums.A.model_rebuild() + reflectapi_demo.tests.enums.E.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsEnumsEFactory: - """Factory class for creating ReflectapiDemoTestsEnumsE variants with ergonomic syntax. - - ReflectapiDemoTestsEnumsE variants - """ - - @staticmethod - def a(field_0) -> ReflectapiDemoTestsEnumsEA: - """Creates the 'a' variant of the ReflectapiDemoTestsEnumsE enum.""" - return ReflectapiDemoTestsEnumsEA(field_0=field_0) - - -# Testing utilities - - -def create_reflectapidemotestsenumsa_response( - value: ReflectapiDemoTestsEnumsA, -) -> ApiResponse[ReflectapiDemoTestsEnumsA]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsA.""" - return create_api_response(value) - - -def create_reflectapidemotestsenumse_response( - value: ReflectapiDemoTestsEnumsE, -) -> ApiResponse[ReflectapiDemoTestsEnumsE]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsE.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_unit_variants-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_unit_variants-3.snap index 33155e4c..31fab3d3 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_unit_variants-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_unit_variants-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/enums.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < A > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod enums { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_unit_variants-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_unit_variants-5.snap index 54b69ba7..1b463415 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_unit_variants-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__enums__internally_tagged_enum_with_unit_variants-5.snap @@ -23,7 +23,6 @@ from pydantic import BaseModel, ConfigDict, Field, RootModel from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsEnumsAX(BaseModel): @@ -31,7 +30,7 @@ class ReflectapiDemoTestsEnumsAX(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["X"] = "X" + type: Literal["X"] = Field(default="X", description="Discriminator field") class ReflectapiDemoTestsEnumsAY(BaseModel): @@ -39,8 +38,8 @@ class ReflectapiDemoTestsEnumsAY(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["Y"] = "Y" - value: None + type: Literal["Y"] = Field(default="Y", description="Discriminator field") + value: None = Field(description="Tuple variant value") class ReflectapiDemoTestsEnumsA(RootModel): @@ -50,6 +49,21 @@ class ReflectapiDemoTestsEnumsA(RootModel): ] +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class enums: + """Namespace for enums types.""" + + AX = ReflectapiDemoTestsEnumsAX + AY = ReflectapiDemoTestsEnumsAY + A = ReflectapiDemoTestsEnumsA + + class AsyncInoutClient: """Async client for inout operations.""" @@ -58,15 +72,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsEnumsA] = None, - ) -> ApiResponse[ReflectapiDemoTestsEnumsA]: + data: Optional[reflectapi_demo.tests.enums.A] = None, + ) -> ApiResponse[reflectapi_demo.tests.enums.A]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsEnumsA]: Response containing ReflectapiDemoTestsEnumsA data + ApiResponse[reflectapi_demo.tests.enums.A]: Response containing reflectapi_demo.tests.enums.A data """ path = "/inout_test" @@ -76,7 +90,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsEnumsA, + response_model=reflectapi_demo.tests.enums.A, ) @@ -101,15 +115,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsEnumsA] = None, - ) -> ApiResponse[ReflectapiDemoTestsEnumsA]: + data: Optional[reflectapi_demo.tests.enums.A] = None, + ) -> ApiResponse[reflectapi_demo.tests.enums.A]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsEnumsA]: Response containing ReflectapiDemoTestsEnumsA data + ApiResponse[reflectapi_demo.tests.enums.A]: Response containing reflectapi_demo.tests.enums.A data """ path = "/inout_test" @@ -119,7 +133,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsEnumsA, + response_model=reflectapi_demo.tests.enums.A, ) @@ -144,37 +158,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsEnumsA.model_rebuild() + reflectapi_demo.tests.enums.A.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsEnumsAFactory: - """Factory class for creating ReflectapiDemoTestsEnumsA variants with ergonomic syntax. - - ReflectapiDemoTestsEnumsA variants - """ - - X = ReflectapiDemoTestsEnumsAX() - - @staticmethod - def y(field_0) -> ReflectapiDemoTestsEnumsAY: - """Creates the 'Y' variant of the ReflectapiDemoTestsEnumsA enum.""" - return ReflectapiDemoTestsEnumsAY(field_0=field_0) - - -# Testing utilities - - -def create_reflectapidemotestsenumsa_response( - value: ReflectapiDemoTestsEnumsA, -) -> ApiResponse[ReflectapiDemoTestsEnumsA]: - """Create a mock ApiResponse for ReflectapiDemoTestsEnumsA.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference-3.snap index c2358414..6c1bc983 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super::into_input_rust_code::()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestStructWithCircularReference > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod generics { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference-4.snap index a6a70860..075935c8 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference-4.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsGenericsTestStructWithCircularReference(BaseModel): @@ -30,7 +29,24 @@ class ReflectapiDemoTestsGenericsTestStructWithCircularReference(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: ReflectapiDemoTestsGenericsTestStructWithCircularReference + f: reflectapi_demo.tests.generics.TestStructWithCircularReference = Field( + serialization_alias="_f", validation_alias="_f" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class generics: + """Namespace for generics types.""" + + TestStructWithCircularReference = ( + ReflectapiDemoTestsGenericsTestStructWithCircularReference + ) class AsyncInputClient: @@ -42,7 +58,7 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithCircularReference + reflectapi_demo.tests.generics.TestStructWithCircularReference ] = None, ) -> ApiResponse[Any]: """ @@ -87,7 +103,7 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithCircularReference + reflectapi_demo.tests.generics.TestStructWithCircularReference ] = None, ) -> ApiResponse[Any]: """ @@ -131,23 +147,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsGenericsTestStructWithCircularReference.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithCircularReference.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsgenericsteststructwithcircularreference_response( - value: ReflectapiDemoTestsGenericsTestStructWithCircularReference, -) -> ApiResponse[ReflectapiDemoTestsGenericsTestStructWithCircularReference]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithCircularReference.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic-3.snap index 9c23b164..b9e928de 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super::into_input_rust_code::>()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: <\nTestStructWithCircularReferenceGeneric:: > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod generics { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic-4.snap index b9e5cf4b..510a7161 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic-4.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -38,8 +37,25 @@ class ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric( model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric[T] - _f2: T + f: reflectapi_demo.tests.generics.TestStructWithCircularReferenceGeneric[T] = Field( + serialization_alias="_f", validation_alias="_f" + ) + f2: T = Field(serialization_alias="_f2", validation_alias="_f2") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class generics: + """Namespace for generics types.""" + + TestStructWithCircularReferenceGeneric = ( + ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric + ) class AsyncInputClient: @@ -51,7 +67,7 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric[int] + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGeneric[int] ] = None, ) -> ApiResponse[Any]: """ @@ -96,7 +112,7 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric[int] + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGeneric[int] ] = None, ) -> ApiResponse[Any]: """ @@ -140,23 +156,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGeneric.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsgenericsteststructwithcircularreferencegeneric_response( - value: ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric, -) -> ApiResponse[ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_parent-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_parent-3.snap index c1f4714e..e88ad88b 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_parent-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_parent-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super::into_input_rust_code::>()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: <\nTestStructWithCircularReferenceGenericParent:: > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod generics { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_parent-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_parent-4.snap index 041b5066..3c2e3ab2 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_parent-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_parent-4.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -38,8 +37,10 @@ class ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric( model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric[T] - _f2: T + f: reflectapi_demo.tests.generics.TestStructWithCircularReferenceGeneric[T] = Field( + serialization_alias="_f", validation_alias="_f" + ) + f2: T = Field(serialization_alias="_f2", validation_alias="_f2") class ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericParent( @@ -49,10 +50,30 @@ class ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericParent( model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericParent[T] - ] - _f2: StdMarkerPhantomData[T] + f: reflectapi_demo.tests.generics.TestStructWithCircularReferenceGeneric[ + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericParent[T] + ] = Field(serialization_alias="_f", validation_alias="_f") + f2: std.marker.PhantomData[T] = Field( + serialization_alias="_f2", validation_alias="_f2" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class generics: + """Namespace for generics types.""" + + TestStructWithCircularReferenceGeneric = ( + ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric + ) + TestStructWithCircularReferenceGenericParent = ( + ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericParent + ) class AsyncInputClient: @@ -64,7 +85,9 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericParent[int] + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericParent[ + int + ] ] = None, ) -> ApiResponse[Any]: """ @@ -109,7 +132,9 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericParent[int] + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericParent[ + int + ] ] = None, ) -> ApiResponse[Any]: """ @@ -153,33 +178,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric.model_rebuild() - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericParent.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGeneric.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericParent.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsgenericsteststructwithcircularreferencegeneric_response( - value: ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric, -) -> ApiResponse[ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGeneric.""" - return create_api_response(value) - - -def create_reflectapidemotestsgenericsteststructwithcircularreferencegenericparent_response( - value: ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericParent, -) -> ApiResponse[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericParent -]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericParent.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box-2.snap index 62242037..8fc6fb00 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box-2.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box-2.snap @@ -1,6 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super :: into_input_typescript_code :: <\nTestStructWithCircularReferenceGenericWithoutBox::<\nTestStructWithCircularReferenceGenericWithoutBox,\nTestStructWithCircularReferenceGenericWithoutBox, >\n> ()" +expression: "super :: into_input_typescript_code :: <\nTestStructWithCircularReferenceGenericWithoutBox::<\nTestStructWithCircularReferenceGenericWithoutBox,\nTestStructWithCircularReferenceGenericWithoutBox, > > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box-3.snap index 68739f03..fb259197 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super::into_input_rust_code::,\n TestStructWithCircularReferenceGenericWithoutBox>>()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: <\nTestStructWithCircularReferenceGenericWithoutBox::<\nTestStructWithCircularReferenceGenericWithoutBox,\nTestStructWithCircularReferenceGenericWithoutBox, > > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod generics { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box-4.snap index 44b6012a..fb7a6721 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box-4.snap @@ -1,6 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super :: into_input_python_code :: <\nTestStructWithCircularReferenceGenericWithoutBox::<\nTestStructWithCircularReferenceGenericWithoutBox,\nTestStructWithCircularReferenceGenericWithoutBox, >\n> ()" +expression: "super :: into_input_python_code :: <\nTestStructWithCircularReferenceGenericWithoutBox::<\nTestStructWithCircularReferenceGenericWithoutBox,\nTestStructWithCircularReferenceGenericWithoutBox, > > ()" --- """ Generated Python client for api_client. @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -40,8 +39,21 @@ class ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBo model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f1: A - _f2: B + f1: A = Field(serialization_alias="_f1", validation_alias="_f1") + f2: B = Field(serialization_alias="_f2", validation_alias="_f2") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class generics: + """Namespace for generics types.""" + + TestStructWithCircularReferenceGenericWithoutBox = ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox class AsyncInputClient: @@ -53,11 +65,11 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox[ + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBox[ + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBox[ int, int ], - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox[ + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBox[ str, int ], ] @@ -105,11 +117,11 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox[ + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBox[ + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBox[ int, int ], - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox[ + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBox[ str, int ], ] @@ -156,25 +168,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBox.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsgenericsteststructwithcircularreferencegenericwithoutbox_response( - value: ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox, -) -> ApiResponse[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox -]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent-2.snap index 62d30ee7..ac0eecf4 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent-2.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent-2.snap @@ -1,6 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super :: into_input_typescript_code :: <\nTestStructWithCircularReferenceGenericWithoutBoxParent::<\nTestStructWithCircularReferenceGenericWithoutBoxParent,\nTestStructWithCircularReferenceGenericWithoutBoxParent, >\n> ()" +expression: "super :: into_input_typescript_code :: <\nTestStructWithCircularReferenceGenericWithoutBoxParent::<\nTestStructWithCircularReferenceGenericWithoutBoxParent,\nTestStructWithCircularReferenceGenericWithoutBoxParent, > > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent-3.snap index dc0760d8..8711ed7b 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super::into_input_rust_code::,\n TestStructWithCircularReferenceGenericWithoutBoxParent>>()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: <\nTestStructWithCircularReferenceGenericWithoutBoxParent::<\nTestStructWithCircularReferenceGenericWithoutBoxParent,\nTestStructWithCircularReferenceGenericWithoutBoxParent, > > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod generics { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent-4.snap index dac6ab13..2b462663 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent-4.snap @@ -1,6 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super :: into_input_python_code :: <\nTestStructWithCircularReferenceGenericWithoutBoxParent::<\nTestStructWithCircularReferenceGenericWithoutBoxParent,\nTestStructWithCircularReferenceGenericWithoutBoxParent, >\n> ()" +expression: "super :: into_input_python_code :: <\nTestStructWithCircularReferenceGenericWithoutBoxParent::<\nTestStructWithCircularReferenceGenericWithoutBoxParent,\nTestStructWithCircularReferenceGenericWithoutBoxParent, > > ()" --- """ Generated Python client for api_client. @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -44,8 +43,8 @@ class ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBo model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f1: A - _f2: B + f1: A = Field(serialization_alias="_f1", validation_alias="_f1") + f2: B = Field(serialization_alias="_f2", validation_alias="_f2") class ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParent( @@ -55,9 +54,23 @@ class ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBo model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox[ + f: reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBox[ D, C - ] + ] = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class generics: + """Namespace for generics types.""" + + TestStructWithCircularReferenceGenericWithoutBox = ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox + TestStructWithCircularReferenceGenericWithoutBoxParent = ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParent class AsyncInputClient: @@ -69,11 +82,11 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParent[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParent[ + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBoxParent[ + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBoxParent[ int, int ], - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParent[ + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBoxParent[ str, int ], ] @@ -121,11 +134,11 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParent[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParent[ + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBoxParent[ + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBoxParent[ int, int ], - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParent[ + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBoxParent[ str, int ], ] @@ -172,35 +185,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox.model_rebuild() - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParent.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBox.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBoxParent.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsgenericsteststructwithcircularreferencegenericwithoutbox_response( - value: ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox, -) -> ApiResponse[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox -]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox.""" - return create_api_response(value) - - -def create_reflectapidemotestsgenericsteststructwithcircularreferencegenericwithoutboxparent_response( - value: ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParent, -) -> ApiResponse[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParent -]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParent.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent_specific-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent_specific-3.snap index 56d949a4..a94b3d77 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent_specific-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent_specific-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super::into_input_rust_code::()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: <\nTestStructWithCircularReferenceGenericWithoutBoxParentSpecific > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod generics { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent_specific-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent_specific-4.snap index 84fd51cd..5332fd41 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent_specific-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_circular_reference_generic_without_box_parent_specific-4.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -40,8 +39,8 @@ class ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBo model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f1: A - _f2: B + f1: A = Field(serialization_alias="_f1", validation_alias="_f1") + f2: B = Field(serialization_alias="_f2", validation_alias="_f2") class ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParentSpecific( @@ -51,14 +50,28 @@ class ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBo model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox[ + f: reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBox[ + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBox[ int, int ], - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox[ + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBox[ str, int ], - ] + ] = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class generics: + """Namespace for generics types.""" + + TestStructWithCircularReferenceGenericWithoutBox = ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox + TestStructWithCircularReferenceGenericWithoutBoxParentSpecific = ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParentSpecific class AsyncInputClient: @@ -70,7 +83,7 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParentSpecific + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBoxParentSpecific ] = None, ) -> ApiResponse[Any]: """ @@ -115,7 +128,7 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParentSpecific + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBoxParentSpecific ] = None, ) -> ApiResponse[Any]: """ @@ -159,35 +172,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox.model_rebuild() - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParentSpecific.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBox.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithCircularReferenceGenericWithoutBoxParentSpecific.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsgenericsteststructwithcircularreferencegenericwithoutbox_response( - value: ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox, -) -> ApiResponse[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox -]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBox.""" - return create_api_response(value) - - -def create_reflectapidemotestsgenericsteststructwithcircularreferencegenericwithoutboxparentspecific_response( - value: ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParentSpecific, -) -> ApiResponse[ - ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParentSpecific -]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithCircularReferenceGenericWithoutBoxParentSpecific.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct-3.snap index 925f7f5c..83ab6e32 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super::into_input_rust_code::()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestStructWithNestedGenericStruct > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod generics { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct-4.snap index 09df653f..364f6ddf 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct-4.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -31,22 +30,40 @@ from reflectapi_runtime.testing import MockClient, create_api_response A = TypeVar("A") -class ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric(BaseModel, Generic[A]): +class ReflectapiDemoTestsGenericsTestStructWithNestedGenericStruct(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: A + f: reflectapi_demo.tests.generics.TestStructWithSimpleGeneric[ + reflectapi_demo.tests.generics.TestStructWithSimpleGeneric[int] + ] = Field(serialization_alias="_f", validation_alias="_f") -class ReflectapiDemoTestsGenericsTestStructWithNestedGenericStruct(BaseModel): +class ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric(BaseModel, Generic[A]): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric[ - ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric[int] - ] + f: A = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class generics: + """Namespace for generics types.""" + + TestStructWithNestedGenericStruct = ( + ReflectapiDemoTestsGenericsTestStructWithNestedGenericStruct + ) + TestStructWithSimpleGeneric = ( + ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric + ) class AsyncInputClient: @@ -58,7 +75,7 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithNestedGenericStruct + reflectapi_demo.tests.generics.TestStructWithNestedGenericStruct ] = None, ) -> ApiResponse[Any]: """ @@ -103,7 +120,7 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithNestedGenericStruct + reflectapi_demo.tests.generics.TestStructWithNestedGenericStruct ] = None, ) -> ApiResponse[Any]: """ @@ -147,31 +164,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsGenericsTestStructWithNestedGenericStruct.model_rebuild() - ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithNestedGenericStruct.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithSimpleGeneric.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsgenericsteststructwithnestedgenericstruct_response( - value: ReflectapiDemoTestsGenericsTestStructWithNestedGenericStruct, -) -> ApiResponse[ReflectapiDemoTestsGenericsTestStructWithNestedGenericStruct]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithNestedGenericStruct.""" - return create_api_response(value) - - -def create_reflectapidemotestsgenericsteststructwithsimplegeneric_response( - value: ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric, -) -> ApiResponse[ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct_twice-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct_twice-3.snap index 67fb7214..3aa89247 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct_twice-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct_twice-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super::into_input_rust_code::()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestStructWithNestedGenericStructTwice > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod generics { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct_twice-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct_twice-4.snap index 9577e87f..6197e8c1 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct_twice-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_nested_generic_struct_twice-4.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -31,21 +30,43 @@ from reflectapi_runtime.testing import MockClient, create_api_response A = TypeVar("A") -class ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric(BaseModel, Generic[A]): +class ReflectapiDemoTestsGenericsTestStructWithNestedGenericStructTwice(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: A + f: reflectapi_demo.tests.generics.TestStructWithSimpleGeneric[int] = Field( + serialization_alias="_f", validation_alias="_f" + ) + f2: reflectapi_demo.tests.generics.TestStructWithSimpleGeneric[str] = Field( + serialization_alias="_f2", validation_alias="_f2" + ) -class ReflectapiDemoTestsGenericsTestStructWithNestedGenericStructTwice(BaseModel): +class ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric(BaseModel, Generic[A]): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric[int] - _f2: ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric[str] + f: A = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class generics: + """Namespace for generics types.""" + + TestStructWithNestedGenericStructTwice = ( + ReflectapiDemoTestsGenericsTestStructWithNestedGenericStructTwice + ) + TestStructWithSimpleGeneric = ( + ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric + ) class AsyncInputClient: @@ -57,7 +78,7 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithNestedGenericStructTwice + reflectapi_demo.tests.generics.TestStructWithNestedGenericStructTwice ] = None, ) -> ApiResponse[Any]: """ @@ -102,7 +123,7 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithNestedGenericStructTwice + reflectapi_demo.tests.generics.TestStructWithNestedGenericStructTwice ] = None, ) -> ApiResponse[Any]: """ @@ -146,31 +167,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsGenericsTestStructWithNestedGenericStructTwice.model_rebuild() - ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithNestedGenericStructTwice.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithSimpleGeneric.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsgenericsteststructwithnestedgenericstructtwice_response( - value: ReflectapiDemoTestsGenericsTestStructWithNestedGenericStructTwice, -) -> ApiResponse[ReflectapiDemoTestsGenericsTestStructWithNestedGenericStructTwice]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithNestedGenericStructTwice.""" - return create_api_response(value) - - -def create_reflectapidemotestsgenericsteststructwithsimplegeneric_response( - value: ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric, -) -> ApiResponse[ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_simple_generic-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_simple_generic-3.snap index 91754009..454dc5e9 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_simple_generic-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_simple_generic-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super::into_input_rust_code::>()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestStructWithSimpleGeneric:: > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod generics { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_simple_generic-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_simple_generic-4.snap index 3cb5dd25..ccde25c4 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_simple_generic-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_simple_generic-4.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -36,7 +35,22 @@ class ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric(BaseModel, Generic[ model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: A + f: A = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class generics: + """Namespace for generics types.""" + + TestStructWithSimpleGeneric = ( + ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric + ) class AsyncInputClient: @@ -48,7 +62,7 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric[int] + reflectapi_demo.tests.generics.TestStructWithSimpleGeneric[int] ] = None, ) -> ApiResponse[Any]: """ @@ -93,7 +107,7 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric[int] + reflectapi_demo.tests.generics.TestStructWithSimpleGeneric[int] ] = None, ) -> ApiResponse[Any]: """ @@ -137,23 +151,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithSimpleGeneric.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsgenericsteststructwithsimplegeneric_response( - value: ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric, -) -> ApiResponse[ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic-3.snap index 9ee16585..6dca708c 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super::into_input_rust_code::>()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestStructWithVecGeneric:: > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod generics { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic-4.snap index 056e798f..7ea8d753 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic-4.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -36,7 +35,22 @@ class ReflectapiDemoTestsGenericsTestStructWithVecGeneric(BaseModel, Generic[T]) model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: list[T] + f: list[T] = Field(serialization_alias="_f", validation_alias="_f") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class generics: + """Namespace for generics types.""" + + TestStructWithVecGeneric = ( + ReflectapiDemoTestsGenericsTestStructWithVecGeneric + ) class AsyncInputClient: @@ -47,7 +61,9 @@ class AsyncInputClient: async def test( self, - data: Optional[ReflectapiDemoTestsGenericsTestStructWithVecGeneric[int]] = None, + data: Optional[ + reflectapi_demo.tests.generics.TestStructWithVecGeneric[int] + ] = None, ) -> ApiResponse[Any]: """ @@ -90,7 +106,9 @@ class InputClient: def test( self, - data: Optional[ReflectapiDemoTestsGenericsTestStructWithVecGeneric[int]] = None, + data: Optional[ + reflectapi_demo.tests.generics.TestStructWithVecGeneric[int] + ] = None, ) -> ApiResponse[Any]: """ @@ -133,23 +151,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsGenericsTestStructWithVecGeneric.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithVecGeneric.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsgenericsteststructwithvecgeneric_response( - value: ReflectapiDemoTestsGenericsTestStructWithVecGeneric, -) -> ApiResponse[ReflectapiDemoTestsGenericsTestStructWithVecGeneric]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithVecGeneric.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic-3.snap index 6febf588..70d73284 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super::into_input_rust_code::>()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: < TestStructWithVecGenericGeneric:: > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -54,7 +53,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod generics { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic-4.snap index c0869010..98a157b6 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic-4.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -38,7 +37,7 @@ class ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric(BaseModel, Generic[ model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: A + f: A = Field(serialization_alias="_f", validation_alias="_f") class ReflectapiDemoTestsGenericsTestStructWithVecGenericGeneric(BaseModel, Generic[T]): @@ -46,7 +45,27 @@ class ReflectapiDemoTestsGenericsTestStructWithVecGenericGeneric(BaseModel, Gene model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: list[ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric[T]] + f: list[reflectapi_demo.tests.generics.TestStructWithSimpleGeneric[T]] = Field( + serialization_alias="_f", validation_alias="_f" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class generics: + """Namespace for generics types.""" + + TestStructWithSimpleGeneric = ( + ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric + ) + TestStructWithVecGenericGeneric = ( + ReflectapiDemoTestsGenericsTestStructWithVecGenericGeneric + ) class AsyncInputClient: @@ -58,7 +77,7 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithVecGenericGeneric[int] + reflectapi_demo.tests.generics.TestStructWithVecGenericGeneric[int] ] = None, ) -> ApiResponse[Any]: """ @@ -103,7 +122,7 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithVecGenericGeneric[int] + reflectapi_demo.tests.generics.TestStructWithVecGenericGeneric[int] ] = None, ) -> ApiResponse[Any]: """ @@ -147,31 +166,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric.model_rebuild() - ReflectapiDemoTestsGenericsTestStructWithVecGenericGeneric.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithSimpleGeneric.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithVecGenericGeneric.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsgenericsteststructwithsimplegeneric_response( - value: ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric, -) -> ApiResponse[ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithSimpleGeneric.""" - return create_api_response(value) - - -def create_reflectapidemotestsgenericsteststructwithvecgenericgeneric_response( - value: ReflectapiDemoTestsGenericsTestStructWithVecGenericGeneric, -) -> ApiResponse[ReflectapiDemoTestsGenericsTestStructWithVecGenericGeneric]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithVecGenericGeneric.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic_generic-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic_generic-3.snap index 8195eb55..b5508c5d 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic_generic-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic_generic-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/generics.rs -expression: "super::into_input_rust_code::>>()" -snapshot_kind: text +expression: "super :: into_input_rust_code :: <\nTestStructWithVecGenericGenericGeneric::> > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -52,7 +51,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod generics { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic_generic-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic_generic-4.snap index 950d83af..825b08d2 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic_generic-4.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__generics__struct_with_vec_generic_generic_generic-4.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -36,7 +35,7 @@ class ReflectapiDemoTestsGenericsTestStructWithVecGeneric(BaseModel, Generic[T]) model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: list[T] + f: list[T] = Field(serialization_alias="_f", validation_alias="_f") class ReflectapiDemoTestsGenericsTestStructWithVecGenericGenericGeneric( @@ -46,7 +45,27 @@ class ReflectapiDemoTestsGenericsTestStructWithVecGenericGenericGeneric( model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: list[ReflectapiDemoTestsGenericsTestStructWithVecGeneric[T]] + f: list[reflectapi_demo.tests.generics.TestStructWithVecGeneric[T]] = Field( + serialization_alias="_f", validation_alias="_f" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class generics: + """Namespace for generics types.""" + + TestStructWithVecGeneric = ( + ReflectapiDemoTestsGenericsTestStructWithVecGeneric + ) + TestStructWithVecGenericGenericGeneric = ( + ReflectapiDemoTestsGenericsTestStructWithVecGenericGenericGeneric + ) class AsyncInputClient: @@ -58,7 +77,7 @@ class AsyncInputClient: async def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithVecGenericGenericGeneric[bytes] + reflectapi_demo.tests.generics.TestStructWithVecGenericGenericGeneric[bytes] ] = None, ) -> ApiResponse[Any]: """ @@ -103,7 +122,7 @@ class InputClient: def test( self, data: Optional[ - ReflectapiDemoTestsGenericsTestStructWithVecGenericGenericGeneric[bytes] + reflectapi_demo.tests.generics.TestStructWithVecGenericGenericGeneric[bytes] ] = None, ) -> ApiResponse[Any]: """ @@ -147,31 +166,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsGenericsTestStructWithVecGeneric.model_rebuild() - ReflectapiDemoTestsGenericsTestStructWithVecGenericGenericGeneric.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithVecGeneric.model_rebuild() + reflectapi_demo.tests.generics.TestStructWithVecGenericGenericGeneric.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsgenericsteststructwithvecgeneric_response( - value: ReflectapiDemoTestsGenericsTestStructWithVecGeneric, -) -> ApiResponse[ReflectapiDemoTestsGenericsTestStructWithVecGeneric]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithVecGeneric.""" - return create_api_response(value) - - -def create_reflectapidemotestsgenericsteststructwithvecgenericgenericgeneric_response( - value: ReflectapiDemoTestsGenericsTestStructWithVecGenericGenericGeneric, -) -> ApiResponse[ReflectapiDemoTestsGenericsTestStructWithVecGenericGenericGeneric]: - """Create a mock ApiResponse for ReflectapiDemoTestsGenericsTestStructWithVecGenericGenericGeneric.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__namespace__generic_and_type_conflict-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__namespace__generic_and_type_conflict-3.snap index e625b480..8fce2d95 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__namespace__generic_and_type_conflict-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__namespace__generic_and_type_conflict-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/namespace.rs expression: rust -snapshot_kind: text --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -57,7 +56,6 @@ pub mod interface { pub mod types { pub type T = I; - pub mod reflectapi_demo { pub mod tests { pub mod namespace { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__adj_repr_enum_with_untagged_variant-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__adj_repr_enum_with_untagged_variant-3.snap index fe63bb47..86ca82f8 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__adj_repr_enum_with_untagged_variant-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__adj_repr_enum_with_untagged_variant-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < Test > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__adj_repr_enum_with_untagged_variant-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__adj_repr_enum_with_untagged_variant-5.snap index 6697eaae..dc4aa178 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__adj_repr_enum_with_untagged_variant-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__adj_repr_enum_with_untagged_variant-5.snap @@ -23,7 +23,6 @@ from pydantic import BaseModel, ConfigDict, Field, RootModel from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestVariant1(BaseModel): @@ -31,7 +30,9 @@ class ReflectapiDemoTestsSerdeTestVariant1(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["Variant1"] = "Variant1" + type: Literal["Variant1"] = Field( + default="Variant1", description="Discriminator field" + ) field_name: int @@ -40,8 +41,10 @@ class ReflectapiDemoTestsSerdeTestVariant2(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["Variant2"] = "Variant2" - value: str + type: Literal["Variant2"] = Field( + default="Variant2", description="Discriminator field" + ) + value: str = Field(description="Tuple variant value") class ReflectapiDemoTestsSerdeTest(RootModel): @@ -53,6 +56,21 @@ class ReflectapiDemoTestsSerdeTest(RootModel): ] +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestVariant1 = ReflectapiDemoTestsSerdeTestVariant1 + TestVariant2 = ReflectapiDemoTestsSerdeTestVariant2 + Test = ReflectapiDemoTestsSerdeTest + + class AsyncInoutClient: """Async client for inout operations.""" @@ -61,15 +79,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: + data: Optional[reflectapi_demo.tests.serde.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTest]: Response containing ReflectapiDemoTestsSerdeTest data + ApiResponse[reflectapi_demo.tests.serde.Test]: Response containing reflectapi_demo.tests.serde.Test data """ path = "/inout_test" @@ -79,7 +97,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTest, + response_model=reflectapi_demo.tests.serde.Test, ) @@ -104,15 +122,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: + data: Optional[reflectapi_demo.tests.serde.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTest]: Response containing ReflectapiDemoTestsSerdeTest data + ApiResponse[reflectapi_demo.tests.serde.Test]: Response containing reflectapi_demo.tests.serde.Test data """ path = "/inout_test" @@ -122,7 +140,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTest, + response_model=reflectapi_demo.tests.serde.Test, ) @@ -147,40 +165,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTest.model_rebuild() + reflectapi_demo.tests.serde.Test.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeTestFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTest variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTest variants - """ - - @staticmethod - def variant1(field_name) -> ReflectapiDemoTestsSerdeTestVariant1: - """Creates the 'Variant1' variant of the ReflectapiDemoTestsSerdeTest enum.""" - return ReflectapiDemoTestsSerdeTestVariant1(field_name=field_name) - - @staticmethod - def variant2(field_0) -> ReflectapiDemoTestsSerdeTestVariant2: - """Creates the 'Variant2' variant of the ReflectapiDemoTestsSerdeTest enum.""" - return ReflectapiDemoTestsSerdeTestVariant2(field_0=field_0) - - -# Testing utilities - - -def create_reflectapidemotestsserdetest_response( - value: ReflectapiDemoTestsSerdeTest, -) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTest.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__box_field_unwrapping-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__box_field_unwrapping-2.snap new file mode 100644 index 00000000..cfd8ad92 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__box_field_unwrapping-2.snap @@ -0,0 +1,62 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < TreeNode > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.TreeNode, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export interface TreeNode { + label: string; + child: reflectapi_demo.tests.serde.TreeNode | null; + } + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.TreeNode, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.TreeNode, + {}, + reflectapi_demo.tests.serde.TreeNode, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__box_field_unwrapping-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__box_field_unwrapping-3.snap new file mode 100644 index 00000000..f95796e8 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__box_field_unwrapping-3.snap @@ -0,0 +1,73 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < TreeNode > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::TreeNode, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::TreeNode, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct TreeNode { + pub label: std::string::String, + pub child: std::option::Option< + std::boxed::Box< + super::super::super::reflectapi_demo::tests::serde::TreeNode, + >, + >, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__box_field_unwrapping-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__box_field_unwrapping-4.snap new file mode 100644 index 00000000..1b74af71 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__box_field_unwrapping-4.snap @@ -0,0 +1,74 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.TreeNode" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.TreeNode" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.TreeNode": { + "type": "object", + "title": "reflectapi_demo.tests.serde.TreeNode", + "required": [ + "child", + "label" + ], + "properties": { + "child": { + "oneOf": [ + { + "description": "Null", + "type": "null" + }, + { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.TreeNode" + } + ] + }, + "label": { + "$ref": "#/components/schemas/std.string.String" + } + } + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__box_field_unwrapping-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__box_field_unwrapping-5.snap new file mode 100644 index 00000000..22649dcc --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__box_field_unwrapping-5.snap @@ -0,0 +1,147 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < TreeNode > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeTreeNode(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + label: str + child: reflectapi_demo.tests.serde.TreeNode | None = None + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TreeNode = ReflectapiDemoTestsSerdeTreeNode + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.TreeNode] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TreeNode]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.TreeNode]: Response containing reflectapi_demo.tests.serde.TreeNode data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.TreeNode, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.TreeNode] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TreeNode]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.TreeNode]: Response containing reflectapi_demo.tests.serde.TreeNode data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.TreeNode, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.TreeNode.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__box_field_unwrapping.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__box_field_unwrapping.snap new file mode 100644 index 00000000..7ec9eb7f --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__box_field_unwrapping.snap @@ -0,0 +1,207 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::TreeNode" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::TreeNode" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::TreeNode", + "fields": { + "named": [ + { + "name": "label", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "child", + "type": { + "name": "std::option::Option", + "arguments": [ + { + "name": "std::boxed::Box", + "arguments": [ + { + "name": "reflectapi_demo::tests::serde::TreeNode" + } + ] + } + ] + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::boxed::Box", + "description": "std::boxed::Box pointer type", + "parameters": [ + { + "name": "T" + } + ], + "fallback": { + "name": "T" + } + }, + { + "kind": "enum", + "name": "std::option::Option", + "description": "Optional nullable type", + "parameters": [ + { + "name": "T" + } + ], + "representation": "none", + "variants": [ + { + "name": "None", + "description": "The value is not provided, i.e. null", + "fields": "none" + }, + { + "name": "Some", + "description": "The value is provided and set to some value", + "fields": { + "unnamed": [ + { + "name": "0", + "type": { + "name": "T" + } + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::TreeNode", + "fields": { + "named": [ + { + "name": "label", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "child", + "type": { + "name": "std::option::Option", + "arguments": [ + { + "name": "std::boxed::Box", + "arguments": [ + { + "name": "reflectapi_demo::tests::serde::TreeNode" + } + ] + } + ] + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::boxed::Box", + "description": "std::boxed::Box pointer type", + "parameters": [ + { + "name": "T" + } + ], + "fallback": { + "name": "T" + } + }, + { + "kind": "enum", + "name": "std::option::Option", + "description": "Optional nullable type", + "parameters": [ + { + "name": "T" + } + ], + "representation": "none", + "variants": [ + { + "name": "None", + "description": "The value is not provided, i.e. null", + "fields": "none" + }, + { + "name": "Some", + "description": "The value is provided and set to some value", + "fields": { + "unnamed": [ + { + "name": "0", + "type": { + "name": "T" + } + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__datetime-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__datetime-3.snap index 82b32b5f..6514a9e9 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__datetime-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__datetime-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStruct > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__datetime-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__datetime-5.snap index 6bb6c3e6..d19bb870 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__datetime-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__datetime-5.snap @@ -17,22 +17,12 @@ from datetime import datetime, date, timedelta from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response - - -class StdTimeDuration(BaseModel): - """Time duration type""" - - model_config = ConfigDict(extra="ignore", populate_by_name=True) - - secs: int - nanos: int class ReflectapiDemoTestsSerdeTestStruct(BaseModel): @@ -49,6 +39,37 @@ class ReflectapiDemoTestsSerdeTestStruct(BaseModel): date_time_local: datetime +class StdTimeDuration(BaseModel): + """Time duration type""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + secs: int + nanos: int + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestStruct = ReflectapiDemoTestsSerdeTestStruct + + +class std: + """Namespace for std types.""" + + class time: + """Namespace for time types.""" + + Duration = StdTimeDuration + + class AsyncInoutClient: """Async client for inout operations.""" @@ -57,15 +78,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStruct] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStruct]: + data: Optional[reflectapi_demo.tests.serde.TestStruct] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStruct]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStruct]: Response containing ReflectapiDemoTestsSerdeTestStruct data + ApiResponse[reflectapi_demo.tests.serde.TestStruct]: Response containing reflectapi_demo.tests.serde.TestStruct data """ path = "/inout_test" @@ -75,7 +96,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStruct, + response_model=reflectapi_demo.tests.serde.TestStruct, ) @@ -100,15 +121,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStruct] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStruct]: + data: Optional[reflectapi_demo.tests.serde.TestStruct] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStruct]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStruct]: Response containing ReflectapiDemoTestsSerdeTestStruct data + ApiResponse[reflectapi_demo.tests.serde.TestStruct]: Response containing reflectapi_demo.tests.serde.TestStruct data """ path = "/inout_test" @@ -118,7 +139,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStruct, + response_model=reflectapi_demo.tests.serde.TestStruct, ) @@ -143,31 +164,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestStruct.model_rebuild() - StdTimeDuration.model_rebuild() + reflectapi_demo.tests.serde.TestStruct.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeteststruct_response( - value: ReflectapiDemoTestsSerdeTestStruct, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStruct]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStruct.""" - return create_api_response(value) - - -def create_stdtimeduration_response( - value: StdTimeDuration, -) -> ApiResponse[StdTimeDuration]: - """Create a mock ApiResponse for StdTimeDuration.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_enum-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_enum-2.snap new file mode 100644 index 00000000..22d5f7d2 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_enum-2.snap @@ -0,0 +1,59 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Never > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Never, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export type Never = never; + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Never, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Never, + {}, + reflectapi_demo.tests.serde.Never, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_enum-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_enum-3.snap new file mode 100644 index 00000000..10044cef --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_enum-3.snap @@ -0,0 +1,66 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Never > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Never, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Never, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub enum Never {} + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_enum-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_enum-4.snap new file mode 100644 index 00000000..64b40249 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_enum-4.snap @@ -0,0 +1,49 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Never" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Never" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.Never": { + "oneOf": [] + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_enum-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_enum-5.snap new file mode 100644 index 00000000..f7dbbbf4 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_enum-5.snap @@ -0,0 +1,144 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Never > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeNever(str, Enum): + """Generated enum.""" + + pass + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Never = ReflectapiDemoTestsSerdeNever + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Never] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Never]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Never]: Response containing reflectapi_demo.tests.serde.Never data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Never, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Never] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Never]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Never]: Response containing reflectapi_demo.tests.serde.Never data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Never, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Never.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_enum.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_enum.snap new file mode 100644 index 00000000..786321cf --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_enum.snap @@ -0,0 +1,51 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Never" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Never" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Never" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Never" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_adjacently_tagged-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_adjacently_tagged-3.snap index 296aa5b7..489cd44d 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_adjacently_tagged-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_adjacently_tagged-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEmptyVariantsAdjacentlyTagged > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_adjacently_tagged-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_adjacently_tagged-5.snap index b406ff45..28d9c6f2 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_adjacently_tagged-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_adjacently_tagged-5.snap @@ -17,13 +17,20 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import ( + BaseModel, + ConfigDict, + Field, + PrivateAttr, + RootModel, + model_serializer, + model_validator, +) # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTaggedEmptyUnitVariant( @@ -105,12 +112,29 @@ class ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged( self.root, ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTaggedEmptyStructVariant, ): - return {"t": "EmptyStruct", "c": self.root.model_dump(exclude_none=True)} + return {"t": "EmptyStruct", "c": self.root.model_dump()} raise ValueError( f"Cannot serialize ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged variant: {type(self.root)}" ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestEmptyVariantsAdjacentlyTaggedEmptyUnitVariant = ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTaggedEmptyUnitVariant + TestEmptyVariantsAdjacentlyTaggedEmptyStructVariant = ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTaggedEmptyStructVariant + TestEmptyVariantsAdjacentlyTagged = ( + ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -120,16 +144,16 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged + reflectapi_demo.tests.serde.TestEmptyVariantsAdjacentlyTagged ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged]: + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsAdjacentlyTagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged]: Response containing ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged data + ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsAdjacentlyTagged]: Response containing reflectapi_demo.tests.serde.TestEmptyVariantsAdjacentlyTagged data """ path = "/inout_test" @@ -139,7 +163,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged, + response_model=reflectapi_demo.tests.serde.TestEmptyVariantsAdjacentlyTagged, ) @@ -165,16 +189,16 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged + reflectapi_demo.tests.serde.TestEmptyVariantsAdjacentlyTagged ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged]: + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsAdjacentlyTagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged]: Response containing ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged data + ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsAdjacentlyTagged]: Response containing reflectapi_demo.tests.serde.TestEmptyVariantsAdjacentlyTagged data """ path = "/inout_test" @@ -184,7 +208,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged, + response_model=reflectapi_demo.tests.serde.TestEmptyVariantsAdjacentlyTagged, ) @@ -209,51 +233,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged.model_rebuild() + reflectapi_demo.tests.serde.TestEmptyVariantsAdjacentlyTagged.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTaggedFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged variants - """ - - @staticmethod - def empty() -> ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged: - """Creates the 'Empty' variant of the ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged enum.""" - return ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged.model_validate( - {"t": "Empty"} - ) - - @staticmethod - def empty_unit() -> ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged: - """Creates the 'EmptyUnit' variant of the ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged enum.""" - return ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged( - ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTaggedEmptyUnitVariant() - ) - - @staticmethod - def empty_struct() -> ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged: - """Creates the 'EmptyStruct' variant of the ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged enum.""" - return ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged( - ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTaggedEmptyStructVariant() - ) - - -# Testing utilities - - -def create_reflectapidemotestsserdetestemptyvariantsadjacentlytagged_response( - value: ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestEmptyVariantsAdjacentlyTagged.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_externally_tagged-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_externally_tagged-3.snap index 59301b26..49ec8cec 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_externally_tagged-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_externally_tagged-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEmptyVariantsExternallyTagged > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_externally_tagged-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_externally_tagged-5.snap index 1dcc8db4..2d41c6ee 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_externally_tagged-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_externally_tagged-5.snap @@ -20,6 +20,7 @@ from typing import Annotated, Any, Generic, Optional, TypeVar, Union from pydantic import ( BaseModel, ConfigDict, + Field, PrivateAttr, RootModel, model_serializer, @@ -30,7 +31,6 @@ from pydantic import ( from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTaggedEmptyUnitVariant( @@ -113,13 +113,30 @@ class ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged( self.root, ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTaggedEmptyStructVariant, ): - return {"EmptyStruct": self.root.model_dump(exclude_none=True)} + return {"EmptyStruct": self.root.model_dump()} raise ValueError( f"Cannot serialize ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged variant: {type(self.root)}" ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestEmptyVariantsExternallyTaggedEmptyUnitVariant = ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTaggedEmptyUnitVariant + TestEmptyVariantsExternallyTaggedEmptyStructVariant = ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTaggedEmptyStructVariant + TestEmptyVariantsExternallyTagged = ( + ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -129,16 +146,16 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged + reflectapi_demo.tests.serde.TestEmptyVariantsExternallyTagged ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged]: + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsExternallyTagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged]: Response containing ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged data + ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsExternallyTagged]: Response containing reflectapi_demo.tests.serde.TestEmptyVariantsExternallyTagged data """ path = "/inout_test" @@ -148,7 +165,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged, + response_model=reflectapi_demo.tests.serde.TestEmptyVariantsExternallyTagged, ) @@ -174,16 +191,16 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged + reflectapi_demo.tests.serde.TestEmptyVariantsExternallyTagged ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged]: + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsExternallyTagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged]: Response containing ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged data + ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsExternallyTagged]: Response containing reflectapi_demo.tests.serde.TestEmptyVariantsExternallyTagged data """ path = "/inout_test" @@ -193,7 +210,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged, + response_model=reflectapi_demo.tests.serde.TestEmptyVariantsExternallyTagged, ) @@ -218,49 +235,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged.model_rebuild() + reflectapi_demo.tests.serde.TestEmptyVariantsExternallyTagged.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTaggedFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged variants - """ - - @staticmethod - def empty() -> ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged: - """Creates the 'Empty' variant of the ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged enum.""" - return ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged("Empty") - - @staticmethod - def empty_unit() -> ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged: - """Creates the 'EmptyUnit' variant of the ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged enum.""" - return ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged( - ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTaggedEmptyUnitVariant() - ) - - @staticmethod - def empty_struct() -> ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged: - """Creates the 'EmptyStruct' variant of the ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged enum.""" - return ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged( - ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTaggedEmptyStructVariant() - ) - - -# Testing utilities - - -def create_reflectapidemotestsserdetestemptyvariantsexternallytagged_response( - value: ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestEmptyVariantsExternallyTagged.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_internally_tagged-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_internally_tagged-3.snap index 76e6ac71..b5b78055 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_internally_tagged-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_internally_tagged-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEmptyVariantsInterallyTagged > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_internally_tagged-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_internally_tagged-5.snap index 864dcc6d..f19658fb 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_internally_tagged-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_internally_tagged-5.snap @@ -23,7 +23,6 @@ from pydantic import BaseModel, ConfigDict, Field, RootModel from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTaggedEmpty(BaseModel): @@ -31,7 +30,7 @@ class ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTaggedEmpty(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["Empty"] = "Empty" + type: Literal["Empty"] = Field(default="Empty", description="Discriminator field") class ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTaggedEmptyStruct(BaseModel): @@ -39,7 +38,9 @@ class ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTaggedEmptyStruct(BaseMo model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["EmptyStruct"] = "EmptyStruct" + type: Literal["EmptyStruct"] = Field( + default="EmptyStruct", description="Discriminator field" + ) class ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged(RootModel): @@ -52,6 +53,27 @@ class ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged(RootModel): ] +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestEmptyVariantsInterallyTaggedEmpty = ( + ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTaggedEmpty + ) + TestEmptyVariantsInterallyTaggedEmptyStruct = ( + ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTaggedEmptyStruct + ) + TestEmptyVariantsInterallyTagged = ( + ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -60,15 +82,17 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged]: + data: Optional[ + reflectapi_demo.tests.serde.TestEmptyVariantsInterallyTagged + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsInterallyTagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged]: Response containing ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged data + ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsInterallyTagged]: Response containing reflectapi_demo.tests.serde.TestEmptyVariantsInterallyTagged data """ path = "/inout_test" @@ -78,7 +102,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged, + response_model=reflectapi_demo.tests.serde.TestEmptyVariantsInterallyTagged, ) @@ -103,15 +127,17 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged]: + data: Optional[ + reflectapi_demo.tests.serde.TestEmptyVariantsInterallyTagged + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsInterallyTagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged]: Response containing ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged data + ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsInterallyTagged]: Response containing reflectapi_demo.tests.serde.TestEmptyVariantsInterallyTagged data """ path = "/inout_test" @@ -121,7 +147,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged, + response_model=reflectapi_demo.tests.serde.TestEmptyVariantsInterallyTagged, ) @@ -146,39 +172,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged.model_rebuild() + reflectapi_demo.tests.serde.TestEmptyVariantsInterallyTagged.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTaggedFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged variants - """ - - EMPTY = ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTaggedEmpty() - - @staticmethod - def empty_struct() -> ( - ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTaggedEmptyStruct - ): - """Creates the 'EmptyStruct' variant of the ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged enum.""" - return ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTaggedEmptyStruct() - - -# Testing utilities - - -def create_reflectapidemotestsserdetestemptyvariantsinterallytagged_response( - value: ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestEmptyVariantsInterallyTagged.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_untagged-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_untagged-3.snap index f43bd6c7..e3d4431a 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_untagged-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_untagged-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEmptyVariantsUntagged > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_untagged-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_untagged-5.snap index 067e6635..e3bcbec8 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_untagged-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__empty_variants_untagged-5.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestEmptyVariantsUntaggedEmpty(BaseModel): @@ -51,6 +50,30 @@ ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged = Union[ ] +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestEmptyVariantsUntaggedEmpty = ( + ReflectapiDemoTestsSerdeTestEmptyVariantsUntaggedEmpty + ) + TestEmptyVariantsUntaggedEmptyUnit = ( + ReflectapiDemoTestsSerdeTestEmptyVariantsUntaggedEmptyUnit + ) + TestEmptyVariantsUntaggedEmptyStruct = ( + ReflectapiDemoTestsSerdeTestEmptyVariantsUntaggedEmptyStruct + ) + TestEmptyVariantsUntagged = ( + ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -59,15 +82,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged]: + data: Optional[reflectapi_demo.tests.serde.TestEmptyVariantsUntagged] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsUntagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged]: Response containing ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged data + ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsUntagged]: Response containing reflectapi_demo.tests.serde.TestEmptyVariantsUntagged data """ path = "/inout_test" @@ -77,7 +100,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged, + response_model=reflectapi_demo.tests.serde.TestEmptyVariantsUntagged, ) @@ -102,15 +125,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged]: + data: Optional[reflectapi_demo.tests.serde.TestEmptyVariantsUntagged] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsUntagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged]: Response containing ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged data + ApiResponse[reflectapi_demo.tests.serde.TestEmptyVariantsUntagged]: Response containing reflectapi_demo.tests.serde.TestEmptyVariantsUntagged data """ path = "/inout_test" @@ -120,7 +143,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged, + response_model=reflectapi_demo.tests.serde.TestEmptyVariantsUntagged, ) @@ -145,23 +168,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged.model_rebuild() + reflectapi_demo.tests.serde.TestEmptyVariantsUntagged.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdetestemptyvariantsuntagged_response( - value: ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestEmptyVariantsUntagged.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_mixed_variant_types_internally_tagged-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_mixed_variant_types_internally_tagged-2.snap new file mode 100644 index 00000000..7001019d --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_mixed_variant_types_internally_tagged-2.snap @@ -0,0 +1,69 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Mixed > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Mixed, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export type Mixed = + | { type: "Unit" } + | { + type: "Wrap"; + value: string; + } + | { + type: "Full"; + x: number /* i32 */; + y: number /* i32 */; + }; + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Mixed, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Mixed, + {}, + reflectapi_demo.tests.serde.Mixed, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_mixed_variant_types_internally_tagged-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_mixed_variant_types_internally_tagged-3.snap new file mode 100644 index 00000000..b0aa4aa3 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_mixed_variant_types_internally_tagged-3.snap @@ -0,0 +1,71 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Mixed > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Mixed, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Mixed, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + #[serde(tag = "type")] + pub enum Mixed { + Unit, + Wrap { value: std::string::String }, + Full { x: i32, y: i32 }, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_mixed_variant_types_internally_tagged-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_mixed_variant_types_internally_tagged-4.snap new file mode 100644 index 00000000..25567eb1 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_mixed_variant_types_internally_tagged-4.snap @@ -0,0 +1,106 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Mixed" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Mixed" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "i32": { + "description": "32-bit signed integer", + "type": "integer" + }, + "reflectapi_demo.tests.serde.Mixed": { + "oneOf": [ + { + "type": "object", + "title": "Unit", + "required": [ + "type" + ], + "properties": { + "type": { + "const": "Unit" + } + } + }, + { + "type": "object", + "title": "Wrap", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "const": "Wrap" + }, + "value": { + "$ref": "#/components/schemas/std.string.String" + } + } + }, + { + "type": "object", + "title": "Full", + "required": [ + "type", + "x", + "y" + ], + "properties": { + "type": { + "const": "Full" + }, + "x": { + "$ref": "#/components/schemas/i32" + }, + "y": { + "$ref": "#/components/schemas/i32" + } + } + } + ] + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_mixed_variant_types_internally_tagged-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_mixed_variant_types_internally_tagged-5.snap new file mode 100644 index 00000000..e1208878 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_mixed_variant_types_internally_tagged-5.snap @@ -0,0 +1,179 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Mixed > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Literal, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field, RootModel + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeMixedUnit(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Unit"] = Field(default="Unit", description="Discriminator field") + + +class ReflectapiDemoTestsSerdeMixedWrap(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Wrap"] = Field(default="Wrap", description="Discriminator field") + value: str + + +class ReflectapiDemoTestsSerdeMixedFull(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Full"] = Field(default="Full", description="Discriminator field") + x: int + y: int + + +class ReflectapiDemoTestsSerdeMixed(RootModel): + root: Annotated[ + Union[ + ReflectapiDemoTestsSerdeMixedUnit, + ReflectapiDemoTestsSerdeMixedWrap, + ReflectapiDemoTestsSerdeMixedFull, + ], + Field(discriminator="type"), + ] + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + MixedUnit = ReflectapiDemoTestsSerdeMixedUnit + MixedWrap = ReflectapiDemoTestsSerdeMixedWrap + MixedFull = ReflectapiDemoTestsSerdeMixedFull + Mixed = ReflectapiDemoTestsSerdeMixed + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Mixed] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Mixed]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Mixed]: Response containing reflectapi_demo.tests.serde.Mixed data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Mixed, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Mixed] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Mixed]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Mixed]: Response containing reflectapi_demo.tests.serde.Mixed data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Mixed, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Mixed.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_mixed_variant_types_internally_tagged.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_mixed_variant_types_internally_tagged.snap new file mode 100644 index 00000000..09f134a5 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_mixed_variant_types_internally_tagged.snap @@ -0,0 +1,163 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Mixed" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Mixed" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "primitive", + "name": "i32", + "description": "32-bit signed integer" + }, + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Mixed", + "representation": { + "internal": { + "tag": "type" + } + }, + "variants": [ + { + "name": "Unit", + "fields": "none" + }, + { + "name": "Wrap", + "fields": { + "named": [ + { + "name": "value", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "name": "Full", + "fields": { + "named": [ + { + "name": "x", + "type": { + "name": "i32" + }, + "required": true + }, + { + "name": "y", + "type": { + "name": "i32" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "primitive", + "name": "i32", + "description": "32-bit signed integer" + }, + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Mixed", + "representation": { + "internal": { + "tag": "type" + } + }, + "variants": [ + { + "name": "Unit", + "fields": "none" + }, + { + "name": "Wrap", + "fields": { + "named": [ + { + "name": "value", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "name": "Full", + "fields": { + "named": [ + { + "name": "x", + "type": { + "name": "i32" + }, + "required": true + }, + { + "name": "y", + "type": { + "name": "i32" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename-3.snap index 0bdbcb12..6afd3963 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumRename > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename-5.snap index f74b0041..355a5235 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename-5.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeMyEnum(str, Enum): @@ -33,6 +32,19 @@ class ReflectapiDemoTestsSerdeMyEnum(str, Enum): V2 = "V2" +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + MyEnum = ReflectapiDemoTestsSerdeMyEnum + + class AsyncInoutClient: """Async client for inout operations.""" @@ -41,15 +53,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeMyEnum] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeMyEnum]: + data: Optional[reflectapi_demo.tests.serde.MyEnum] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.MyEnum]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeMyEnum]: Response containing ReflectapiDemoTestsSerdeMyEnum data + ApiResponse[reflectapi_demo.tests.serde.MyEnum]: Response containing reflectapi_demo.tests.serde.MyEnum data """ path = "/inout_test" @@ -59,7 +71,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeMyEnum, + response_model=reflectapi_demo.tests.serde.MyEnum, ) @@ -84,15 +96,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeMyEnum] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeMyEnum]: + data: Optional[reflectapi_demo.tests.serde.MyEnum] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.MyEnum]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeMyEnum]: Response containing ReflectapiDemoTestsSerdeMyEnum data + ApiResponse[reflectapi_demo.tests.serde.MyEnum]: Response containing reflectapi_demo.tests.serde.MyEnum data """ path = "/inout_test" @@ -102,7 +114,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeMyEnum, + response_model=reflectapi_demo.tests.serde.MyEnum, ) @@ -127,23 +139,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeMyEnum.model_rebuild() + reflectapi_demo.tests.serde.MyEnum.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdemyenum_response( - value: ReflectapiDemoTestsSerdeMyEnum, -) -> ApiResponse[ReflectapiDemoTestsSerdeMyEnum]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeMyEnum.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all-3.snap index cbb1ebce..8123131a 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumRenameAll > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all-5.snap index ae8da3b3..98fef325 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all-5.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestEnumRenameAll(str, Enum): @@ -32,6 +31,19 @@ class ReflectapiDemoTestsSerdeTestEnumRenameAll(str, Enum): FIELD_NAME = "fieldName" +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestEnumRenameAll = ReflectapiDemoTestsSerdeTestEnumRenameAll + + class AsyncInoutClient: """Async client for inout operations.""" @@ -40,15 +52,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumRenameAll] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumRenameAll]: + data: Optional[reflectapi_demo.tests.serde.TestEnumRenameAll] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumRenameAll]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumRenameAll]: Response containing ReflectapiDemoTestsSerdeTestEnumRenameAll data + ApiResponse[reflectapi_demo.tests.serde.TestEnumRenameAll]: Response containing reflectapi_demo.tests.serde.TestEnumRenameAll data """ path = "/inout_test" @@ -58,7 +70,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumRenameAll, + response_model=reflectapi_demo.tests.serde.TestEnumRenameAll, ) @@ -83,15 +95,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumRenameAll] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumRenameAll]: + data: Optional[reflectapi_demo.tests.serde.TestEnumRenameAll] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumRenameAll]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumRenameAll]: Response containing ReflectapiDemoTestsSerdeTestEnumRenameAll data + ApiResponse[reflectapi_demo.tests.serde.TestEnumRenameAll]: Response containing reflectapi_demo.tests.serde.TestEnumRenameAll data """ path = "/inout_test" @@ -101,7 +113,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumRenameAll, + response_model=reflectapi_demo.tests.serde.TestEnumRenameAll, ) @@ -126,23 +138,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestEnumRenameAll.model_rebuild() + reflectapi_demo.tests.serde.TestEnumRenameAll.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdetestenumrenameall_response( - value: ReflectapiDemoTestsSerdeTestEnumRenameAll, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumRenameAll]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestEnumRenameAll.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all_on_variant-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all_on_variant-3.snap index ee1e66c0..9da2b437 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all_on_variant-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all_on_variant-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumRenameAllOnVariant > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all_on_variant-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all_on_variant-5.snap index bfc48690..0eeb72e5 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all_on_variant-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_all_on_variant-5.snap @@ -20,6 +20,7 @@ from typing import Annotated, Any, Generic, Optional, TypeVar, Union from pydantic import ( BaseModel, ConfigDict, + Field, PrivateAttr, RootModel, model_serializer, @@ -30,7 +31,6 @@ from pydantic import ( from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariantVariant1Variant(BaseModel): @@ -38,7 +38,9 @@ class ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariantVariant1Variant(BaseMode model_config = ConfigDict(extra="ignore", populate_by_name=True) - field_name: int + field_name: int = Field( + serialization_alias="fieldName", validation_alias="fieldName" + ) class ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariantVariant2Variant(BaseModel): @@ -103,7 +105,7 @@ class ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant( if isinstance( self.root, ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariantVariant1Variant ): - return {"Variant1": self.root.model_dump(exclude_none=True)} + return {"Variant1": self.root.model_dump()} if isinstance( self.root, ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariantVariant2Variant ): @@ -114,6 +116,27 @@ class ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant( ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestEnumRenameAllOnVariantVariant1Variant = ( + ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariantVariant1Variant + ) + TestEnumRenameAllOnVariantVariant2Variant = ( + ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariantVariant2Variant + ) + TestEnumRenameAllOnVariant = ( + ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -122,15 +145,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant]: + data: Optional[reflectapi_demo.tests.serde.TestEnumRenameAllOnVariant] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumRenameAllOnVariant]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant]: Response containing ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant data + ApiResponse[reflectapi_demo.tests.serde.TestEnumRenameAllOnVariant]: Response containing reflectapi_demo.tests.serde.TestEnumRenameAllOnVariant data """ path = "/inout_test" @@ -140,7 +163,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant, + response_model=reflectapi_demo.tests.serde.TestEnumRenameAllOnVariant, ) @@ -165,15 +188,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant]: + data: Optional[reflectapi_demo.tests.serde.TestEnumRenameAllOnVariant] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumRenameAllOnVariant]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant]: Response containing ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant data + ApiResponse[reflectapi_demo.tests.serde.TestEnumRenameAllOnVariant]: Response containing reflectapi_demo.tests.serde.TestEnumRenameAllOnVariant data """ path = "/inout_test" @@ -183,7 +206,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant, + response_model=reflectapi_demo.tests.serde.TestEnumRenameAllOnVariant, ) @@ -208,48 +231,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant.model_rebuild() + reflectapi_demo.tests.serde.TestEnumRenameAllOnVariant.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariantFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant variants - """ - - @staticmethod - def variant1(field_name) -> ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant: - """Creates the 'Variant1' variant of the ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant enum.""" - return ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant( - ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariantVariant1Variant( - field_name=field_name - ) - ) - - @staticmethod - def variant2(field_0) -> ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant: - """Creates the 'Variant2' variant of the ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant enum.""" - return ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant( - ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariantVariant2Variant( - field_0=field_0 - ) - ) - - -# Testing utilities - - -def create_reflectapidemotestsserdetestenumrenameallonvariant_response( - value: ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestEnumRenameAllOnVariant.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_variant_field-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_variant_field-3.snap index 129dea87..49f20850 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_variant_field-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_variant_field-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumRenameVariantField > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_variant_field-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_variant_field-5.snap index 5c7cc6a6..533d4182 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_variant_field-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_rename_variant_field-5.snap @@ -20,6 +20,7 @@ from typing import Annotated, Any, Generic, Optional, TypeVar, Union from pydantic import ( BaseModel, ConfigDict, + Field, PrivateAttr, RootModel, model_serializer, @@ -30,7 +31,6 @@ from pydantic import ( from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestEnumRenameVariantFieldVariant2Variant(BaseModel): @@ -84,13 +84,31 @@ class ReflectapiDemoTestsSerdeTestEnumRenameVariantField( if isinstance( self.root, ReflectapiDemoTestsSerdeTestEnumRenameVariantFieldVariant2Variant ): - return {"Variant2": self.root.model_dump(exclude_none=True)} + return {"Variant2": self.root.model_dump()} raise ValueError( f"Cannot serialize ReflectapiDemoTestsSerdeTestEnumRenameVariantField variant: {type(self.root)}" ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestEnumRenameVariantFieldVariant2Variant = ( + ReflectapiDemoTestsSerdeTestEnumRenameVariantFieldVariant2Variant + ) + TestEnumRenameVariantField = ( + ReflectapiDemoTestsSerdeTestEnumRenameVariantField + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -99,15 +117,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumRenameVariantField] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumRenameVariantField]: + data: Optional[reflectapi_demo.tests.serde.TestEnumRenameVariantField] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumRenameVariantField]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumRenameVariantField]: Response containing ReflectapiDemoTestsSerdeTestEnumRenameVariantField data + ApiResponse[reflectapi_demo.tests.serde.TestEnumRenameVariantField]: Response containing reflectapi_demo.tests.serde.TestEnumRenameVariantField data """ path = "/inout_test" @@ -117,7 +135,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumRenameVariantField, + response_model=reflectapi_demo.tests.serde.TestEnumRenameVariantField, ) @@ -142,15 +160,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumRenameVariantField] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumRenameVariantField]: + data: Optional[reflectapi_demo.tests.serde.TestEnumRenameVariantField] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumRenameVariantField]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumRenameVariantField]: Response containing ReflectapiDemoTestsSerdeTestEnumRenameVariantField data + ApiResponse[reflectapi_demo.tests.serde.TestEnumRenameVariantField]: Response containing reflectapi_demo.tests.serde.TestEnumRenameVariantField data """ path = "/inout_test" @@ -160,7 +178,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumRenameVariantField, + response_model=reflectapi_demo.tests.serde.TestEnumRenameVariantField, ) @@ -185,41 +203,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestEnumRenameVariantField.model_rebuild() + reflectapi_demo.tests.serde.TestEnumRenameVariantField.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeTestEnumRenameVariantFieldFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTestEnumRenameVariantField variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTestEnumRenameVariantField variants - """ - - @staticmethod - def variant2( - variant2_field_name, - ) -> ReflectapiDemoTestsSerdeTestEnumRenameVariantField: - """Creates the 'Variant2' variant of the ReflectapiDemoTestsSerdeTestEnumRenameVariantField enum.""" - return ReflectapiDemoTestsSerdeTestEnumRenameVariantField( - ReflectapiDemoTestsSerdeTestEnumRenameVariantFieldVariant2Variant( - variant2_field_name=variant2_field_name - ) - ) - - -# Testing utilities - - -def create_reflectapidemotestsserdetestenumrenamevariantfield_response( - value: ReflectapiDemoTestsSerdeTestEnumRenameVariantField, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumRenameVariantField]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestEnumRenameVariantField.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag-3.snap index d1867c65..8a1047e0 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumTag > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag-5.snap index ebf9d34d..233b7903 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag-5.snap @@ -23,7 +23,6 @@ from pydantic import BaseModel, ConfigDict, Field, RootModel from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestEnumTagVariant1(BaseModel): @@ -31,7 +30,9 @@ class ReflectapiDemoTestsSerdeTestEnumTagVariant1(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["Variant1"] = "Variant1" + type: Literal["Variant1"] = Field( + default="Variant1", description="Discriminator field" + ) field_name: int @@ -40,7 +41,9 @@ class ReflectapiDemoTestsSerdeTestEnumTagVariant2(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["Variant2"] = "Variant2" + type: Literal["Variant2"] = Field( + default="Variant2", description="Discriminator field" + ) field_name: int @@ -54,6 +57,21 @@ class ReflectapiDemoTestsSerdeTestEnumTag(RootModel): ] +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestEnumTagVariant1 = ReflectapiDemoTestsSerdeTestEnumTagVariant1 + TestEnumTagVariant2 = ReflectapiDemoTestsSerdeTestEnumTagVariant2 + TestEnumTag = ReflectapiDemoTestsSerdeTestEnumTag + + class AsyncInoutClient: """Async client for inout operations.""" @@ -62,15 +80,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumTag] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumTag]: + data: Optional[reflectapi_demo.tests.serde.TestEnumTag] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumTag]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumTag]: Response containing ReflectapiDemoTestsSerdeTestEnumTag data + ApiResponse[reflectapi_demo.tests.serde.TestEnumTag]: Response containing reflectapi_demo.tests.serde.TestEnumTag data """ path = "/inout_test" @@ -80,7 +98,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumTag, + response_model=reflectapi_demo.tests.serde.TestEnumTag, ) @@ -105,15 +123,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumTag] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumTag]: + data: Optional[reflectapi_demo.tests.serde.TestEnumTag] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumTag]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumTag]: Response containing ReflectapiDemoTestsSerdeTestEnumTag data + ApiResponse[reflectapi_demo.tests.serde.TestEnumTag]: Response containing reflectapi_demo.tests.serde.TestEnumTag data """ path = "/inout_test" @@ -123,7 +141,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumTag, + response_model=reflectapi_demo.tests.serde.TestEnumTag, ) @@ -148,40 +166,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestEnumTag.model_rebuild() + reflectapi_demo.tests.serde.TestEnumTag.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeTestEnumTagFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTestEnumTag variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTestEnumTag variants - """ - - @staticmethod - def variant1(field_name) -> ReflectapiDemoTestsSerdeTestEnumTagVariant1: - """Creates the 'Variant1' variant of the ReflectapiDemoTestsSerdeTestEnumTag enum.""" - return ReflectapiDemoTestsSerdeTestEnumTagVariant1(field_name=field_name) - - @staticmethod - def variant2(field_name) -> ReflectapiDemoTestsSerdeTestEnumTagVariant2: - """Creates the 'Variant2' variant of the ReflectapiDemoTestsSerdeTestEnumTag enum.""" - return ReflectapiDemoTestsSerdeTestEnumTagVariant2(field_name=field_name) - - -# Testing utilities - - -def create_reflectapidemotestsserdetestenumtag_response( - value: ReflectapiDemoTestsSerdeTestEnumTag, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumTag]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestEnumTag.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content-3.snap index 4ab107bc..d16877a1 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumTagContent > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content-5.snap index fa7c6f92..7aa08bfe 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content-5.snap @@ -17,13 +17,20 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import ( + BaseModel, + ConfigDict, + Field, + PrivateAttr, + RootModel, + model_serializer, + model_validator, +) # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestEnumTagContentVariant1Variant(BaseModel): @@ -95,10 +102,7 @@ class ReflectapiDemoTestsSerdeTestEnumTagContent( if isinstance( self.root, ReflectapiDemoTestsSerdeTestEnumTagContentVariant1Variant ): - return { - "type": "Variant1", - "content": self.root.model_dump(exclude_none=True), - } + return {"type": "Variant1", "content": self.root.model_dump()} if isinstance( self.root, ReflectapiDemoTestsSerdeTestEnumTagContentVariant2Variant ): @@ -108,6 +112,25 @@ class ReflectapiDemoTestsSerdeTestEnumTagContent( ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestEnumTagContentVariant1Variant = ( + ReflectapiDemoTestsSerdeTestEnumTagContentVariant1Variant + ) + TestEnumTagContentVariant2Variant = ( + ReflectapiDemoTestsSerdeTestEnumTagContentVariant2Variant + ) + TestEnumTagContent = ReflectapiDemoTestsSerdeTestEnumTagContent + + class AsyncInoutClient: """Async client for inout operations.""" @@ -116,15 +139,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumTagContent] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumTagContent]: + data: Optional[reflectapi_demo.tests.serde.TestEnumTagContent] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumTagContent]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumTagContent]: Response containing ReflectapiDemoTestsSerdeTestEnumTagContent data + ApiResponse[reflectapi_demo.tests.serde.TestEnumTagContent]: Response containing reflectapi_demo.tests.serde.TestEnumTagContent data """ path = "/inout_test" @@ -134,7 +157,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumTagContent, + response_model=reflectapi_demo.tests.serde.TestEnumTagContent, ) @@ -159,15 +182,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumTagContent] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumTagContent]: + data: Optional[reflectapi_demo.tests.serde.TestEnumTagContent] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumTagContent]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumTagContent]: Response containing ReflectapiDemoTestsSerdeTestEnumTagContent data + ApiResponse[reflectapi_demo.tests.serde.TestEnumTagContent]: Response containing reflectapi_demo.tests.serde.TestEnumTagContent data """ path = "/inout_test" @@ -177,7 +200,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumTagContent, + response_model=reflectapi_demo.tests.serde.TestEnumTagContent, ) @@ -202,46 +225,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestEnumTagContent.model_rebuild() + reflectapi_demo.tests.serde.TestEnumTagContent.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeTestEnumTagContentFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTestEnumTagContent variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTestEnumTagContent variants - """ - - @staticmethod - def variant1(field_name) -> ReflectapiDemoTestsSerdeTestEnumTagContent: - """Creates the 'Variant1' variant of the ReflectapiDemoTestsSerdeTestEnumTagContent enum.""" - return ReflectapiDemoTestsSerdeTestEnumTagContent( - ReflectapiDemoTestsSerdeTestEnumTagContentVariant1Variant( - field_name=field_name - ) - ) - - @staticmethod - def variant2(field_0) -> ReflectapiDemoTestsSerdeTestEnumTagContent: - """Creates the 'Variant2' variant of the ReflectapiDemoTestsSerdeTestEnumTagContent enum.""" - return ReflectapiDemoTestsSerdeTestEnumTagContent( - ReflectapiDemoTestsSerdeTestEnumTagContentVariant2Variant(field_0=field_0) - ) - - -# Testing utilities - - -def create_reflectapidemotestsserdetestenumtagcontent_response( - value: ReflectapiDemoTestsSerdeTestEnumTagContent, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumTagContent]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestEnumTagContent.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content_rename_all-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content_rename_all-3.snap index b24c6049..363146b4 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content_rename_all-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content_rename_all-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumTagContentRenameAll > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content_rename_all-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content_rename_all-5.snap index 71215d3b..226b586d 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content_rename_all-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_tag_content_rename_all-5.snap @@ -17,13 +17,20 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import ( + BaseModel, + ConfigDict, + Field, + PrivateAttr, + RootModel, + model_serializer, + model_validator, +) # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestEnumTagContentRenameAllVariant1Variant(BaseModel): @@ -100,10 +107,7 @@ class ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll( self.root, ReflectapiDemoTestsSerdeTestEnumTagContentRenameAllVariant1Variant, ): - return { - "type": "variant1", - "content": self.root.model_dump(exclude_none=True), - } + return {"type": "variant1", "content": self.root.model_dump()} if isinstance( self.root, ReflectapiDemoTestsSerdeTestEnumTagContentRenameAllVariant2Variant, @@ -114,6 +118,27 @@ class ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll( ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestEnumTagContentRenameAllVariant1Variant = ( + ReflectapiDemoTestsSerdeTestEnumTagContentRenameAllVariant1Variant + ) + TestEnumTagContentRenameAllVariant2Variant = ( + ReflectapiDemoTestsSerdeTestEnumTagContentRenameAllVariant2Variant + ) + TestEnumTagContentRenameAll = ( + ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -122,15 +147,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll]: + data: Optional[reflectapi_demo.tests.serde.TestEnumTagContentRenameAll] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumTagContentRenameAll]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll]: Response containing ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll data + ApiResponse[reflectapi_demo.tests.serde.TestEnumTagContentRenameAll]: Response containing reflectapi_demo.tests.serde.TestEnumTagContentRenameAll data """ path = "/inout_test" @@ -140,7 +165,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll, + response_model=reflectapi_demo.tests.serde.TestEnumTagContentRenameAll, ) @@ -165,15 +190,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll]: + data: Optional[reflectapi_demo.tests.serde.TestEnumTagContentRenameAll] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumTagContentRenameAll]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll]: Response containing ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll data + ApiResponse[reflectapi_demo.tests.serde.TestEnumTagContentRenameAll]: Response containing reflectapi_demo.tests.serde.TestEnumTagContentRenameAll data """ path = "/inout_test" @@ -183,7 +208,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll, + response_model=reflectapi_demo.tests.serde.TestEnumTagContentRenameAll, ) @@ -208,48 +233,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll.model_rebuild() + reflectapi_demo.tests.serde.TestEnumTagContentRenameAll.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeTestEnumTagContentRenameAllFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll variants - """ - - @staticmethod - def variant1(field_name) -> ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll: - """Creates the 'variant1' variant of the ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll enum.""" - return ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll( - ReflectapiDemoTestsSerdeTestEnumTagContentRenameAllVariant1Variant( - field_name=field_name - ) - ) - - @staticmethod - def variant2(field_0) -> ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll: - """Creates the 'variant2' variant of the ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll enum.""" - return ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll( - ReflectapiDemoTestsSerdeTestEnumTagContentRenameAllVariant2Variant( - field_0=field_0 - ) - ) - - -# Testing utilities - - -def create_reflectapidemotestsserdetestenumtagcontentrenameall_response( - value: ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestEnumTagContentRenameAll.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_untagged-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_untagged-3.snap index 4f6f5be0..690bb48f 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_untagged-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_untagged-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumUntagged > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_untagged-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_untagged-5.snap index a6946806..ca331871 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_untagged-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_untagged-5.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestEnumUntaggedVariant1(BaseModel): @@ -48,6 +47,21 @@ ReflectapiDemoTestsSerdeTestEnumUntagged = Union[ ] +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestEnumUntaggedVariant1 = ReflectapiDemoTestsSerdeTestEnumUntaggedVariant1 + TestEnumUntaggedVariant2 = ReflectapiDemoTestsSerdeTestEnumUntaggedVariant2 + TestEnumUntagged = ReflectapiDemoTestsSerdeTestEnumUntagged + + class AsyncInoutClient: """Async client for inout operations.""" @@ -56,15 +70,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumUntagged] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumUntagged]: + data: Optional[reflectapi_demo.tests.serde.TestEnumUntagged] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumUntagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumUntagged]: Response containing ReflectapiDemoTestsSerdeTestEnumUntagged data + ApiResponse[reflectapi_demo.tests.serde.TestEnumUntagged]: Response containing reflectapi_demo.tests.serde.TestEnumUntagged data """ path = "/inout_test" @@ -74,7 +88,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumUntagged, + response_model=reflectapi_demo.tests.serde.TestEnumUntagged, ) @@ -99,15 +113,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumUntagged] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumUntagged]: + data: Optional[reflectapi_demo.tests.serde.TestEnumUntagged] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumUntagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumUntagged]: Response containing ReflectapiDemoTestsSerdeTestEnumUntagged data + ApiResponse[reflectapi_demo.tests.serde.TestEnumUntagged]: Response containing reflectapi_demo.tests.serde.TestEnumUntagged data """ path = "/inout_test" @@ -117,7 +131,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumUntagged, + response_model=reflectapi_demo.tests.serde.TestEnumUntagged, ) @@ -142,23 +156,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestEnumUntagged.model_rebuild() + reflectapi_demo.tests.serde.TestEnumUntagged.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdetestenumuntagged_response( - value: ReflectapiDemoTestsSerdeTestEnumUntagged, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumUntagged]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestEnumUntagged.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_field_skip-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_field_skip-3.snap index cbff5f70..8b2f9a9e 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_field_skip-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_field_skip-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumWithFieldSkip > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_field_skip-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_field_skip-5.snap index 895f41f5..4a820178 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_field_skip-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_field_skip-5.snap @@ -20,6 +20,7 @@ from typing import Annotated, Any, Generic, Optional, TypeVar, Union from pydantic import ( BaseModel, ConfigDict, + Field, PrivateAttr, RootModel, model_serializer, @@ -30,7 +31,6 @@ from pydantic import ( from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestEnumWithFieldSkipVariant1Variant(BaseModel): @@ -80,13 +80,29 @@ class ReflectapiDemoTestsSerdeTestEnumWithFieldSkip( if isinstance( self.root, ReflectapiDemoTestsSerdeTestEnumWithFieldSkipVariant1Variant ): - return {"Variant1": self.root.model_dump(exclude_none=True)} + return {"Variant1": self.root.model_dump()} raise ValueError( f"Cannot serialize ReflectapiDemoTestsSerdeTestEnumWithFieldSkip variant: {type(self.root)}" ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestEnumWithFieldSkipVariant1Variant = ( + ReflectapiDemoTestsSerdeTestEnumWithFieldSkipVariant1Variant + ) + TestEnumWithFieldSkip = ReflectapiDemoTestsSerdeTestEnumWithFieldSkip + + class AsyncInoutClient: """Async client for inout operations.""" @@ -95,15 +111,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumWithFieldSkip] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithFieldSkip]: + data: Optional[reflectapi_demo.tests.serde.TestEnumWithFieldSkip] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumWithFieldSkip]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithFieldSkip]: Response containing ReflectapiDemoTestsSerdeTestEnumWithFieldSkip data + ApiResponse[reflectapi_demo.tests.serde.TestEnumWithFieldSkip]: Response containing reflectapi_demo.tests.serde.TestEnumWithFieldSkip data """ path = "/inout_test" @@ -113,7 +129,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumWithFieldSkip, + response_model=reflectapi_demo.tests.serde.TestEnumWithFieldSkip, ) @@ -138,15 +154,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumWithFieldSkip] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithFieldSkip]: + data: Optional[reflectapi_demo.tests.serde.TestEnumWithFieldSkip] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumWithFieldSkip]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithFieldSkip]: Response containing ReflectapiDemoTestsSerdeTestEnumWithFieldSkip data + ApiResponse[reflectapi_demo.tests.serde.TestEnumWithFieldSkip]: Response containing reflectapi_demo.tests.serde.TestEnumWithFieldSkip data """ path = "/inout_test" @@ -156,7 +172,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumWithFieldSkip, + response_model=reflectapi_demo.tests.serde.TestEnumWithFieldSkip, ) @@ -181,37 +197,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestEnumWithFieldSkip.model_rebuild() + reflectapi_demo.tests.serde.TestEnumWithFieldSkip.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeTestEnumWithFieldSkipFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTestEnumWithFieldSkip variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTestEnumWithFieldSkip variants - """ - - @staticmethod - def variant1() -> ReflectapiDemoTestsSerdeTestEnumWithFieldSkip: - """Creates the 'Variant1' variant of the ReflectapiDemoTestsSerdeTestEnumWithFieldSkip enum.""" - return ReflectapiDemoTestsSerdeTestEnumWithFieldSkip( - ReflectapiDemoTestsSerdeTestEnumWithFieldSkipVariant1Variant() - ) - - -# Testing utilities - - -def create_reflectapidemotestsserdetestenumwithfieldskip_response( - value: ReflectapiDemoTestsSerdeTestEnumWithFieldSkip, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithFieldSkip]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestEnumWithFieldSkip.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_many_variants-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_many_variants-2.snap new file mode 100644 index 00000000..9e855ecb --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_many_variants-2.snap @@ -0,0 +1,90 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < LargeEnum > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.LargeEnum, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export type LargeEnum = + | { type: "Alpha" } + | { type: "Beta" } + | { + type: "Gamma"; + x: number /* i32 */; + } + | { + type: "Delta"; + value: string; + } + | { type: "Epsilon" } + | { + type: "Zeta"; + y: boolean; + } + | { type: "Eta" } + | { + type: "Theta"; + value: number /* u32 */; + } + | { type: "Iota" } + | { + type: "Kappa"; + z: number /* f64 */; + } + | { type: "Lambda" } + | { + type: "Mu"; + w: string; + v: number /* i32 */; + }; + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.LargeEnum, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.LargeEnum, + {}, + reflectapi_demo.tests.serde.LargeEnum, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_many_variants-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_many_variants-3.snap new file mode 100644 index 00000000..a5ffe5e0 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_many_variants-3.snap @@ -0,0 +1,80 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < LargeEnum > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::LargeEnum, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::LargeEnum, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + #[serde(tag = "type")] + pub enum LargeEnum { + Alpha, + Beta, + Gamma { x: i32 }, + Delta { value: std::string::String }, + Epsilon, + Zeta { y: bool }, + Eta, + Theta { value: u32 }, + Iota, + Kappa { z: f64 }, + Lambda, + Mu { w: std::string::String, v: i32 }, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_many_variants-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_many_variants-4.snap new file mode 100644 index 00000000..aebf4f89 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_many_variants-4.snap @@ -0,0 +1,242 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.LargeEnum" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.LargeEnum" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "bool": { + "description": "Boolean value", + "type": "boolean" + }, + "f64": { + "description": "64-bit floating point number", + "type": "number" + }, + "i32": { + "description": "32-bit signed integer", + "type": "integer" + }, + "reflectapi_demo.tests.serde.LargeEnum": { + "oneOf": [ + { + "type": "object", + "title": "Alpha", + "required": [ + "type" + ], + "properties": { + "type": { + "const": "Alpha" + } + } + }, + { + "type": "object", + "title": "Beta", + "required": [ + "type" + ], + "properties": { + "type": { + "const": "Beta" + } + } + }, + { + "type": "object", + "title": "Gamma", + "required": [ + "type", + "x" + ], + "properties": { + "type": { + "const": "Gamma" + }, + "x": { + "$ref": "#/components/schemas/i32" + } + } + }, + { + "type": "object", + "title": "Delta", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "const": "Delta" + }, + "value": { + "$ref": "#/components/schemas/std.string.String" + } + } + }, + { + "type": "object", + "title": "Epsilon", + "required": [ + "type" + ], + "properties": { + "type": { + "const": "Epsilon" + } + } + }, + { + "type": "object", + "title": "Zeta", + "required": [ + "type", + "y" + ], + "properties": { + "type": { + "const": "Zeta" + }, + "y": { + "$ref": "#/components/schemas/bool" + } + } + }, + { + "type": "object", + "title": "Eta", + "required": [ + "type" + ], + "properties": { + "type": { + "const": "Eta" + } + } + }, + { + "type": "object", + "title": "Theta", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "const": "Theta" + }, + "value": { + "$ref": "#/components/schemas/u32" + } + } + }, + { + "type": "object", + "title": "Iota", + "required": [ + "type" + ], + "properties": { + "type": { + "const": "Iota" + } + } + }, + { + "type": "object", + "title": "Kappa", + "required": [ + "type", + "z" + ], + "properties": { + "type": { + "const": "Kappa" + }, + "z": { + "$ref": "#/components/schemas/f64" + } + } + }, + { + "type": "object", + "title": "Lambda", + "required": [ + "type" + ], + "properties": { + "type": { + "const": "Lambda" + } + } + }, + { + "type": "object", + "title": "Mu", + "required": [ + "type", + "v", + "w" + ], + "properties": { + "type": { + "const": "Mu" + }, + "v": { + "$ref": "#/components/schemas/i32" + }, + "w": { + "$ref": "#/components/schemas/std.string.String" + } + } + } + ] + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + }, + "u32": { + "description": "32-bit unsigned integer", + "type": "integer" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_many_variants-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_many_variants-5.snap new file mode 100644 index 00000000..7563f4d0 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_many_variants-5.snap @@ -0,0 +1,275 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < LargeEnum > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Literal, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field, RootModel + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeLargeEnumAlpha(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Alpha"] = Field(default="Alpha", description="Discriminator field") + + +class ReflectapiDemoTestsSerdeLargeEnumBeta(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Beta"] = Field(default="Beta", description="Discriminator field") + + +class ReflectapiDemoTestsSerdeLargeEnumGamma(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Gamma"] = Field(default="Gamma", description="Discriminator field") + x: int + + +class ReflectapiDemoTestsSerdeLargeEnumDelta(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Delta"] = Field(default="Delta", description="Discriminator field") + value: str + + +class ReflectapiDemoTestsSerdeLargeEnumEpsilon(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Epsilon"] = Field( + default="Epsilon", description="Discriminator field" + ) + + +class ReflectapiDemoTestsSerdeLargeEnumZeta(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Zeta"] = Field(default="Zeta", description="Discriminator field") + y: bool + + +class ReflectapiDemoTestsSerdeLargeEnumEta(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Eta"] = Field(default="Eta", description="Discriminator field") + + +class ReflectapiDemoTestsSerdeLargeEnumTheta(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Theta"] = Field(default="Theta", description="Discriminator field") + value: int + + +class ReflectapiDemoTestsSerdeLargeEnumIota(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Iota"] = Field(default="Iota", description="Discriminator field") + + +class ReflectapiDemoTestsSerdeLargeEnumKappa(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Kappa"] = Field(default="Kappa", description="Discriminator field") + z: float + + +class ReflectapiDemoTestsSerdeLargeEnumLambda(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Lambda"] = Field(default="Lambda", description="Discriminator field") + + +class ReflectapiDemoTestsSerdeLargeEnumMu(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Mu"] = Field(default="Mu", description="Discriminator field") + w: str + v: int + + +class ReflectapiDemoTestsSerdeLargeEnum(RootModel): + root: Annotated[ + Union[ + ReflectapiDemoTestsSerdeLargeEnumAlpha, + ReflectapiDemoTestsSerdeLargeEnumBeta, + ReflectapiDemoTestsSerdeLargeEnumGamma, + ReflectapiDemoTestsSerdeLargeEnumDelta, + ReflectapiDemoTestsSerdeLargeEnumEpsilon, + ReflectapiDemoTestsSerdeLargeEnumZeta, + ReflectapiDemoTestsSerdeLargeEnumEta, + ReflectapiDemoTestsSerdeLargeEnumTheta, + ReflectapiDemoTestsSerdeLargeEnumIota, + ReflectapiDemoTestsSerdeLargeEnumKappa, + ReflectapiDemoTestsSerdeLargeEnumLambda, + ReflectapiDemoTestsSerdeLargeEnumMu, + ], + Field(discriminator="type"), + ] + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + LargeEnumAlpha = ReflectapiDemoTestsSerdeLargeEnumAlpha + LargeEnumBeta = ReflectapiDemoTestsSerdeLargeEnumBeta + LargeEnumGamma = ReflectapiDemoTestsSerdeLargeEnumGamma + LargeEnumDelta = ReflectapiDemoTestsSerdeLargeEnumDelta + LargeEnumEpsilon = ReflectapiDemoTestsSerdeLargeEnumEpsilon + LargeEnumZeta = ReflectapiDemoTestsSerdeLargeEnumZeta + LargeEnumEta = ReflectapiDemoTestsSerdeLargeEnumEta + LargeEnumTheta = ReflectapiDemoTestsSerdeLargeEnumTheta + LargeEnumIota = ReflectapiDemoTestsSerdeLargeEnumIota + LargeEnumKappa = ReflectapiDemoTestsSerdeLargeEnumKappa + LargeEnumLambda = ReflectapiDemoTestsSerdeLargeEnumLambda + LargeEnumMu = ReflectapiDemoTestsSerdeLargeEnumMu + LargeEnum = ReflectapiDemoTestsSerdeLargeEnum + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.LargeEnum] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.LargeEnum]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.LargeEnum]: Response containing reflectapi_demo.tests.serde.LargeEnum data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.LargeEnum, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.LargeEnum] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.LargeEnum]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.LargeEnum]: Response containing reflectapi_demo.tests.serde.LargeEnum data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.LargeEnum, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.LargeEnum.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_many_variants.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_many_variants.snap new file mode 100644 index 00000000..06c3a9da --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_many_variants.snap @@ -0,0 +1,345 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::LargeEnum" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::LargeEnum" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "primitive", + "name": "bool", + "description": "Boolean value" + }, + { + "kind": "primitive", + "name": "f64", + "description": "64-bit floating point number" + }, + { + "kind": "primitive", + "name": "i32", + "description": "32-bit signed integer" + }, + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::LargeEnum", + "representation": { + "internal": { + "tag": "type" + } + }, + "variants": [ + { + "name": "Alpha", + "fields": "none" + }, + { + "name": "Beta", + "fields": "none" + }, + { + "name": "Gamma", + "fields": { + "named": [ + { + "name": "x", + "type": { + "name": "i32" + }, + "required": true + } + ] + } + }, + { + "name": "Delta", + "fields": { + "named": [ + { + "name": "value", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "name": "Epsilon", + "fields": "none" + }, + { + "name": "Zeta", + "fields": { + "named": [ + { + "name": "y", + "type": { + "name": "bool" + }, + "required": true + } + ] + } + }, + { + "name": "Eta", + "fields": "none" + }, + { + "name": "Theta", + "fields": { + "named": [ + { + "name": "value", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + }, + { + "name": "Iota", + "fields": "none" + }, + { + "name": "Kappa", + "fields": { + "named": [ + { + "name": "z", + "type": { + "name": "f64" + }, + "required": true + } + ] + } + }, + { + "name": "Lambda", + "fields": "none" + }, + { + "name": "Mu", + "fields": { + "named": [ + { + "name": "w", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "v", + "type": { + "name": "i32" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "primitive", + "name": "bool", + "description": "Boolean value" + }, + { + "kind": "primitive", + "name": "f64", + "description": "64-bit floating point number" + }, + { + "kind": "primitive", + "name": "i32", + "description": "32-bit signed integer" + }, + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::LargeEnum", + "representation": { + "internal": { + "tag": "type" + } + }, + "variants": [ + { + "name": "Alpha", + "fields": "none" + }, + { + "name": "Beta", + "fields": "none" + }, + { + "name": "Gamma", + "fields": { + "named": [ + { + "name": "x", + "type": { + "name": "i32" + }, + "required": true + } + ] + } + }, + { + "name": "Delta", + "fields": { + "named": [ + { + "name": "value", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "name": "Epsilon", + "fields": "none" + }, + { + "name": "Zeta", + "fields": { + "named": [ + { + "name": "y", + "type": { + "name": "bool" + }, + "required": true + } + ] + } + }, + { + "name": "Eta", + "fields": "none" + }, + { + "name": "Theta", + "fields": { + "named": [ + { + "name": "value", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + }, + { + "name": "Iota", + "fields": "none" + }, + { + "name": "Kappa", + "fields": { + "named": [ + { + "name": "z", + "type": { + "name": "f64" + }, + "required": true + } + ] + } + }, + { + "name": "Lambda", + "fields": "none" + }, + { + "name": "Mu", + "fields": { + "named": [ + { + "name": "w", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "v", + "type": { + "name": "i32" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_rename_to_invalid_chars-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_rename_to_invalid_chars-3.snap index 7aaa3d15..e8ec43ab 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_rename_to_invalid_chars-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_rename_to_invalid_chars-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumWithRenameToInvalidChars > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_rename_to_invalid_chars-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_rename_to_invalid_chars-5.snap index 508eb129..5f7a2237 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_rename_to_invalid_chars-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_rename_to_invalid_chars-5.snap @@ -2,12 +2,12 @@ source: reflectapi-demo/src/tests/serde.rs expression: "super :: into_python_code :: < TestEnumWithRenameToInvalidChars > ()" --- -''' +""" Generated Python client for api_client. DO NOT MODIFY THIS FILE MANUALLY. This file is automatically generated by ReflectAPI. -''' +""" from __future__ import annotations @@ -17,56 +17,98 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict, PrivateAttr, RootModel, model_serializer, model_validator +from pydantic import ( + BaseModel, + ConfigDict, + Field, + PrivateAttr, + RootModel, + model_serializer, + model_validator, +) # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response -class ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariant1Variant(BaseModel): +class ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariant1Variant( + BaseModel +): """Variant1 variant""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - f: int + f: int = Field(serialization_alias="field-name&&", validation_alias="field-name&&") # Externally tagged enum using RootModel -ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariants = ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariant1Variant +ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariants = ( + ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariant1Variant +) -class ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars(RootModel[ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariants]): - """Externally tagged enum""" +class ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars( + RootModel[ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariants] +): + """Externally tagged enum""" - @model_validator(mode='before') + @model_validator(mode="before") @classmethod def _validate_externally_tagged(cls, data): # Handle direct variant instances (for programmatic creation) - if isinstance(data, ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariant1Variant): + if isinstance( + data, + ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariant1Variant, + ): return data # Handle JSON data (for deserialization) - if isinstance(data, dict): if len(data) != 1: raise ValueError("Externally tagged enum must have exactly one key") key, value = next(iter(data.items())) if key == "Variant1": - return ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariant1Variant(**value) + return ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariant1Variant( + **value + ) - raise ValueError(f"Unknown variant for ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars: {data}") + raise ValueError( + f"Unknown variant for ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars: {data}" + ) @model_serializer def _serialize_externally_tagged(self): - if isinstance(self.root, ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariant1Variant): - return {"Variant1": self.root.model_dump(exclude_none=True)} + if isinstance( + self.root, + ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariant1Variant, + ): + return {"Variant1": self.root.model_dump()} + + raise ValueError( + f"Cannot serialize ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars variant: {type(self.root)}" + ) - raise ValueError(f"Cannot serialize ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars variant: {type(self.root)}") + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestEnumWithRenameToInvalidCharsVariant1Variant = ( + ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariant1Variant + ) + TestEnumWithRenameToInvalidChars = ( + ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars + ) class AsyncInoutClient: @@ -75,18 +117,19 @@ class AsyncInoutClient: def __init__(self, client: AsyncClientBase) -> None: self._client = client - async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars]: + data: Optional[ + reflectapi_demo.tests.serde.TestEnumWithRenameToInvalidChars + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumWithRenameToInvalidChars]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars]: Response containing ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars data + ApiResponse[reflectapi_demo.tests.serde.TestEnumWithRenameToInvalidChars]: Response containing reflectapi_demo.tests.serde.TestEnumWithRenameToInvalidChars data """ path = "/inout_test" @@ -96,8 +139,8 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars, -) + response_model=reflectapi_demo.tests.serde.TestEnumWithRenameToInvalidChars, + ) class AsyncClient(AsyncClientBase): @@ -119,18 +162,19 @@ class InoutClient: def __init__(self, client: ClientBase) -> None: self._client = client - def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars]: + data: Optional[ + reflectapi_demo.tests.serde.TestEnumWithRenameToInvalidChars + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumWithRenameToInvalidChars]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars]: Response containing ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars data + ApiResponse[reflectapi_demo.tests.serde.TestEnumWithRenameToInvalidChars]: Response containing reflectapi_demo.tests.serde.TestEnumWithRenameToInvalidChars data """ path = "/inout_test" @@ -140,8 +184,8 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars, -) + response_model=reflectapi_demo.tests.serde.TestEnumWithRenameToInvalidChars, + ) class Client(ClientBase): @@ -165,32 +209,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars.model_rebuild() + reflectapi_demo.tests.serde.TestEnumWithRenameToInvalidChars.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsFactory: - '''Factory class for creating ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars variants - ''' - - @staticmethod - def variant1(field_name&&) -> ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars: - '''Creates the 'Variant1' variant of the ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars enum.''' - return ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars(ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidCharsVariant1Variant(f=field_name&&)) - - -# Testing utilities - - -def create_reflectapidemotestsserdetestenumwithrenametoinvalidchars_response(value: ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestEnumWithRenameToInvalidChars.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_serde_rename_on_variants-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_serde_rename_on_variants-2.snap new file mode 100644 index 00000000..50efd6d9 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_serde_rename_on_variants-2.snap @@ -0,0 +1,71 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Action > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Action, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export type Action = + | { + kind: "create_item"; + data: { + name: string; + }; + } + | { + kind: "delete_item"; + data: { + id: number /* u32 */; + }; + }; + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Action, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Action, + {}, + reflectapi_demo.tests.serde.Action, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_serde_rename_on_variants-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_serde_rename_on_variants-3.snap new file mode 100644 index 00000000..34b8e251 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_serde_rename_on_variants-3.snap @@ -0,0 +1,72 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Action > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Action, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Action, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + #[serde(tag = "kind", content = "data")] + pub enum Action { + #[serde(rename = "create_item")] + CreateItem { name: std::string::String }, + #[serde(rename = "delete_item")] + DeleteItem { id: u32 }, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_serde_rename_on_variants-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_serde_rename_on_variants-4.snap new file mode 100644 index 00000000..bb7425b6 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_serde_rename_on_variants-4.snap @@ -0,0 +1,108 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Action" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Action" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.Action": { + "oneOf": [ + { + "type": "object", + "title": "create_item", + "required": [ + "data", + "kind" + ], + "properties": { + "data": { + "type": "object", + "title": "create_item", + "required": [ + "name" + ], + "properties": { + "name": { + "$ref": "#/components/schemas/std.string.String" + } + } + }, + "kind": { + "const": "create_item" + } + } + }, + { + "type": "object", + "title": "delete_item", + "required": [ + "data", + "kind" + ], + "properties": { + "data": { + "type": "object", + "title": "delete_item", + "required": [ + "id" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/u32" + } + } + }, + "kind": { + "const": "delete_item" + } + } + } + ] + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + }, + "u32": { + "description": "32-bit unsigned integer", + "type": "integer" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_serde_rename_on_variants-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_serde_rename_on_variants-5.snap new file mode 100644 index 00000000..d0b2408a --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_serde_rename_on_variants-5.snap @@ -0,0 +1,213 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Action > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import ( + BaseModel, + ConfigDict, + Field, + PrivateAttr, + RootModel, + model_serializer, + model_validator, +) + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeActionCreateItemVariant(BaseModel): + """create_item variant""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + name: str + + +class ReflectapiDemoTestsSerdeActionDeleteItemVariant(BaseModel): + """delete_item variant""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + id: int + + +# Adjacently tagged enum using RootModel +ReflectapiDemoTestsSerdeActionVariants = Union[ + ReflectapiDemoTestsSerdeActionCreateItemVariant, + ReflectapiDemoTestsSerdeActionDeleteItemVariant, +] + + +class ReflectapiDemoTestsSerdeAction(RootModel[ReflectapiDemoTestsSerdeActionVariants]): + """Adjacently tagged enum""" + + @model_validator(mode="before") + @classmethod + def _validate_adjacently_tagged(cls, data): + # Handle direct variant instances + if isinstance( + data, + ( + ReflectapiDemoTestsSerdeActionCreateItemVariant, + ReflectapiDemoTestsSerdeActionDeleteItemVariant, + ), + ): + return data + if isinstance(data, dict): + tag = data.get("kind") + content = data.get("data") + if tag is None: + raise ValueError("Missing tag field 'kind'") + if content is None and tag not in (): + raise ValueError("Missing content field 'data' for tag: {}".format(tag)) + # Dispatch based on tag + if tag == "create_item": + return ReflectapiDemoTestsSerdeActionCreateItemVariant(**content) + if tag == "delete_item": + return ReflectapiDemoTestsSerdeActionDeleteItemVariant(**content) + raise ValueError( + "Unknown variant for ReflectapiDemoTestsSerdeAction: {}".format(data) + ) + + @model_serializer + def _serialize_adjacently_tagged(self): + if isinstance(self.root, ReflectapiDemoTestsSerdeActionCreateItemVariant): + return {"kind": "create_item", "data": self.root.model_dump()} + if isinstance(self.root, ReflectapiDemoTestsSerdeActionDeleteItemVariant): + return {"kind": "delete_item", "data": self.root.model_dump()} + raise ValueError( + f"Cannot serialize ReflectapiDemoTestsSerdeAction variant: {type(self.root)}" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + ActionCreateItemVariant = ReflectapiDemoTestsSerdeActionCreateItemVariant + ActionDeleteItemVariant = ReflectapiDemoTestsSerdeActionDeleteItemVariant + Action = ReflectapiDemoTestsSerdeAction + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Action] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Action]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Action]: Response containing reflectapi_demo.tests.serde.Action data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Action, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Action] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Action]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Action]: Response containing reflectapi_demo.tests.serde.Action data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Action, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Action.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_serde_rename_on_variants.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_serde_rename_on_variants.snap new file mode 100644 index 00000000..7e7e7ca6 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_serde_rename_on_variants.snap @@ -0,0 +1,143 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Action" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Action" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Action", + "representation": { + "adjacent": { + "tag": "kind", + "content": "data" + } + }, + "variants": [ + { + "name": "create_item", + "fields": { + "named": [ + { + "name": "name", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "name": "delete_item", + "fields": { + "named": [ + { + "name": "id", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Action", + "representation": { + "adjacent": { + "tag": "kind", + "content": "data" + } + }, + "variants": [ + { + "name": "create_item", + "fields": { + "named": [ + { + "name": "name", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "name": "delete_item", + "fields": { + "named": [ + { + "name": "id", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_other-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_other-3.snap index c98749d8..2800190c 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_other-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_other-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumWithVariantOther > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_other-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_other-5.snap index 6c944ce4..a9ad367b 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_other-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_other-5.snap @@ -23,7 +23,6 @@ from pydantic import BaseModel, ConfigDict, Field, RootModel from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeInputTestEnumWithVariantOtherV0(BaseModel): @@ -31,7 +30,7 @@ class ReflectapiDemoTestsSerdeInputTestEnumWithVariantOtherV0(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["V0"] = "V0" + type: Literal["V0"] = Field(default="V0", description="Discriminator field") class ReflectapiDemoTestsSerdeInputTestEnumWithVariantOther(RootModel): @@ -46,7 +45,7 @@ class ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOtherV0(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["V0"] = "V0" + type: Literal["V0"] = Field(default="V0", description="Discriminator field") class ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOtherVariant1(BaseModel): @@ -54,7 +53,9 @@ class ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOtherVariant1(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["Variant1"] = "Variant1" + type: Literal["Variant1"] = Field( + default="Variant1", description="Discriminator field" + ) class ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther(RootModel): @@ -67,6 +68,40 @@ class ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther(RootModel): ] +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + class input: + """Namespace for input types.""" + + TestEnumWithVariantOtherV0 = ( + ReflectapiDemoTestsSerdeInputTestEnumWithVariantOtherV0 + ) + TestEnumWithVariantOther = ( + ReflectapiDemoTestsSerdeInputTestEnumWithVariantOther + ) + + class output: + """Namespace for output types.""" + + TestEnumWithVariantOtherV0 = ( + ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOtherV0 + ) + TestEnumWithVariantOtherVariant1 = ( + ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOtherVariant1 + ) + TestEnumWithVariantOther = ( + ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -75,15 +110,17 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeInputTestEnumWithVariantOther] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther]: + data: Optional[ + reflectapi_demo.tests.serde.input.TestEnumWithVariantOther + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.output.TestEnumWithVariantOther]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther]: Response containing ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther data + ApiResponse[reflectapi_demo.tests.serde.output.TestEnumWithVariantOther]: Response containing reflectapi_demo.tests.serde.output.TestEnumWithVariantOther data """ path = "/inout_test" @@ -93,7 +130,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther, + response_model=reflectapi_demo.tests.serde.output.TestEnumWithVariantOther, ) @@ -118,15 +155,17 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeInputTestEnumWithVariantOther] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther]: + data: Optional[ + reflectapi_demo.tests.serde.input.TestEnumWithVariantOther + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.output.TestEnumWithVariantOther]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther]: Response containing ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther data + ApiResponse[reflectapi_demo.tests.serde.output.TestEnumWithVariantOther]: Response containing reflectapi_demo.tests.serde.output.TestEnumWithVariantOther data """ path = "/inout_test" @@ -136,7 +175,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther, + response_model=reflectapi_demo.tests.serde.output.TestEnumWithVariantOther, ) @@ -161,50 +200,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeInputTestEnumWithVariantOther.model_rebuild() - ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther.model_rebuild() + reflectapi_demo.tests.serde.input.TestEnumWithVariantOther.model_rebuild() + reflectapi_demo.tests.serde.output.TestEnumWithVariantOther.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeInputTestEnumWithVariantOtherFactory: - """Factory class for creating ReflectapiDemoTestsSerdeInputTestEnumWithVariantOther variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeInputTestEnumWithVariantOther variants - """ - - V0 = ReflectapiDemoTestsSerdeInputTestEnumWithVariantOtherV0() - - -class ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOtherFactory: - """Factory class for creating ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther variants - """ - - V0 = ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOtherV0() - VARIANT1 = ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOtherVariant1() - - -# Testing utilities - - -def create_reflectapidemotestsserdeinputtestenumwithvariantother_response( - value: ReflectapiDemoTestsSerdeInputTestEnumWithVariantOther, -) -> ApiResponse[ReflectapiDemoTestsSerdeInputTestEnumWithVariantOther]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeInputTestEnumWithVariantOther.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeoutputtestenumwithvariantother_response( - value: ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther, -) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeOutputTestEnumWithVariantOther.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip-3.snap index 002c425e..8d146e1d 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumWithVariantSkip > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip-5.snap index da671e1c..9ad62d20 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip-5.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestEnumWithVariantSkip(str, Enum): @@ -32,6 +31,19 @@ class ReflectapiDemoTestsSerdeTestEnumWithVariantSkip(str, Enum): pass +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestEnumWithVariantSkip = ReflectapiDemoTestsSerdeTestEnumWithVariantSkip + + class AsyncInoutClient: """Async client for inout operations.""" @@ -40,15 +52,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumWithVariantSkip] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithVariantSkip]: + data: Optional[reflectapi_demo.tests.serde.TestEnumWithVariantSkip] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumWithVariantSkip]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithVariantSkip]: Response containing ReflectapiDemoTestsSerdeTestEnumWithVariantSkip data + ApiResponse[reflectapi_demo.tests.serde.TestEnumWithVariantSkip]: Response containing reflectapi_demo.tests.serde.TestEnumWithVariantSkip data """ path = "/inout_test" @@ -58,7 +70,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumWithVariantSkip, + response_model=reflectapi_demo.tests.serde.TestEnumWithVariantSkip, ) @@ -83,15 +95,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumWithVariantSkip] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithVariantSkip]: + data: Optional[reflectapi_demo.tests.serde.TestEnumWithVariantSkip] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumWithVariantSkip]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithVariantSkip]: Response containing ReflectapiDemoTestsSerdeTestEnumWithVariantSkip data + ApiResponse[reflectapi_demo.tests.serde.TestEnumWithVariantSkip]: Response containing reflectapi_demo.tests.serde.TestEnumWithVariantSkip data """ path = "/inout_test" @@ -101,7 +113,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumWithVariantSkip, + response_model=reflectapi_demo.tests.serde.TestEnumWithVariantSkip, ) @@ -126,23 +138,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestEnumWithVariantSkip.model_rebuild() + reflectapi_demo.tests.serde.TestEnumWithVariantSkip.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdetestenumwithvariantskip_response( - value: ReflectapiDemoTestsSerdeTestEnumWithVariantSkip, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithVariantSkip]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestEnumWithVariantSkip.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_deserialize-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_deserialize-3.snap index ec6a214b..6094be35 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_deserialize-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_deserialize-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumWithVariantSkipDeserialize > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_deserialize-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_deserialize-5.snap index 7d1af585..6817e991 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_deserialize-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_deserialize-5.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipDeserialize(str, Enum): @@ -38,6 +37,31 @@ class ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipDeserialize(str, Enum _VARIANT1 = "_Variant1" +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + class input: + """Namespace for input types.""" + + TestEnumWithVariantSkipDeserialize = ( + ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipDeserialize + ) + + class output: + """Namespace for output types.""" + + TestEnumWithVariantSkipDeserialize = ( + ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipDeserialize + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -47,16 +71,18 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipDeserialize + reflectapi_demo.tests.serde.input.TestEnumWithVariantSkipDeserialize ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipDeserialize]: + ) -> ApiResponse[ + reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipDeserialize + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipDeserialize]: Response containing ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipDeserialize data + ApiResponse[reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipDeserialize]: Response containing reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipDeserialize data """ path = "/inout_test" @@ -66,7 +92,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipDeserialize, + response_model=reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipDeserialize, ) @@ -92,16 +118,18 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipDeserialize + reflectapi_demo.tests.serde.input.TestEnumWithVariantSkipDeserialize ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipDeserialize]: + ) -> ApiResponse[ + reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipDeserialize + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipDeserialize]: Response containing ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipDeserialize data + ApiResponse[reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipDeserialize]: Response containing reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipDeserialize data """ path = "/inout_test" @@ -111,7 +139,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipDeserialize, + response_model=reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipDeserialize, ) @@ -136,31 +164,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipDeserialize.model_rebuild() - ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipDeserialize.model_rebuild() + reflectapi_demo.tests.serde.input.TestEnumWithVariantSkipDeserialize.model_rebuild() + reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipDeserialize.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeinputtestenumwithvariantskipdeserialize_response( - value: ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipDeserialize, -) -> ApiResponse[ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipDeserialize]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipDeserialize.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeoutputtestenumwithvariantskipdeserialize_response( - value: ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipDeserialize, -) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipDeserialize]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipDeserialize.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_serialize-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_serialize-3.snap index 8507ce01..226325b3 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_serialize-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_serialize-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumWithVariantSkipSerialize > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_serialize-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_serialize-5.snap index ffbf3302..a6522535 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_serialize-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_skip_serialize-5.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipSerialize(str, Enum): @@ -38,6 +37,31 @@ class ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipSerialize(str, Enum): pass +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + class input: + """Namespace for input types.""" + + TestEnumWithVariantSkipSerialize = ( + ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipSerialize + ) + + class output: + """Namespace for output types.""" + + TestEnumWithVariantSkipSerialize = ( + ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipSerialize + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -47,16 +71,18 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipSerialize + reflectapi_demo.tests.serde.input.TestEnumWithVariantSkipSerialize ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipSerialize]: + ) -> ApiResponse[ + reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipSerialize + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipSerialize]: Response containing ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipSerialize data + ApiResponse[reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipSerialize]: Response containing reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipSerialize data """ path = "/inout_test" @@ -66,7 +92,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipSerialize, + response_model=reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipSerialize, ) @@ -92,16 +118,18 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipSerialize + reflectapi_demo.tests.serde.input.TestEnumWithVariantSkipSerialize ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipSerialize]: + ) -> ApiResponse[ + reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipSerialize + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipSerialize]: Response containing ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipSerialize data + ApiResponse[reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipSerialize]: Response containing reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipSerialize data """ path = "/inout_test" @@ -111,7 +139,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipSerialize, + response_model=reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipSerialize, ) @@ -136,31 +164,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipSerialize.model_rebuild() - ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipSerialize.model_rebuild() + reflectapi_demo.tests.serde.input.TestEnumWithVariantSkipSerialize.model_rebuild() + reflectapi_demo.tests.serde.output.TestEnumWithVariantSkipSerialize.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeinputtestenumwithvariantskipserialize_response( - value: ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipSerialize, -) -> ApiResponse[ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipSerialize]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeInputTestEnumWithVariantSkipSerialize.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeoutputtestenumwithvariantskipserialize_response( - value: ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipSerialize, -) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipSerialize]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeOutputTestEnumWithVariantSkipSerialize.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_untagged-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_untagged-3.snap index 88a7721b..59340730 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_untagged-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_untagged-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestEnumWithVariantUntagged > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_untagged-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_untagged-5.snap index 200d8e53..38cc0bf6 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_untagged-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__enum_with_variant_untagged-5.snap @@ -20,6 +20,7 @@ from typing import Annotated, Any, Generic, Optional, TypeVar, Union from pydantic import ( BaseModel, ConfigDict, + Field, PrivateAttr, RootModel, model_serializer, @@ -30,7 +31,6 @@ from pydantic import ( from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestEnumWithVariantUntaggedVariant1Variant(BaseModel): @@ -92,6 +92,24 @@ class ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged( ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestEnumWithVariantUntaggedVariant1Variant = ( + ReflectapiDemoTestsSerdeTestEnumWithVariantUntaggedVariant1Variant + ) + TestEnumWithVariantUntagged = ( + ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -100,15 +118,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged]: + data: Optional[reflectapi_demo.tests.serde.TestEnumWithVariantUntagged] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumWithVariantUntagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged]: Response containing ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged data + ApiResponse[reflectapi_demo.tests.serde.TestEnumWithVariantUntagged]: Response containing reflectapi_demo.tests.serde.TestEnumWithVariantUntagged data """ path = "/inout_test" @@ -118,7 +136,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged, + response_model=reflectapi_demo.tests.serde.TestEnumWithVariantUntagged, ) @@ -143,15 +161,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged]: + data: Optional[reflectapi_demo.tests.serde.TestEnumWithVariantUntagged] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestEnumWithVariantUntagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged]: Response containing ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged data + ApiResponse[reflectapi_demo.tests.serde.TestEnumWithVariantUntagged]: Response containing reflectapi_demo.tests.serde.TestEnumWithVariantUntagged data """ path = "/inout_test" @@ -161,7 +179,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged, + response_model=reflectapi_demo.tests.serde.TestEnumWithVariantUntagged, ) @@ -186,39 +204,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged.model_rebuild() + reflectapi_demo.tests.serde.TestEnumWithVariantUntagged.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeTestEnumWithVariantUntaggedFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged variants - """ - - @staticmethod - def variant1(field_0) -> ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged: - """Creates the 'Variant1' variant of the ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged enum.""" - return ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged( - ReflectapiDemoTestsSerdeTestEnumWithVariantUntaggedVariant1Variant( - field_0=field_0 - ) - ) - - -# Testing utilities - - -def create_reflectapidemotestsserdetestenumwithvariantuntagged_response( - value: ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestEnumWithVariantUntagged.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__external_impls-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__external_impls-3.snap index 7c0eb279..85466a22 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__external_impls-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__external_impls-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < Test > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__external_impls-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__external_impls-5.snap index 0a057090..170d9e2b 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__external_impls-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__external_impls-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTest(BaseModel): @@ -36,6 +35,19 @@ class ReflectapiDemoTestsSerdeTest(BaseModel): json: Any +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Test = ReflectapiDemoTestsSerdeTest + + class AsyncInoutClient: """Async client for inout operations.""" @@ -44,15 +56,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: + data: Optional[reflectapi_demo.tests.serde.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTest]: Response containing ReflectapiDemoTestsSerdeTest data + ApiResponse[reflectapi_demo.tests.serde.Test]: Response containing reflectapi_demo.tests.serde.Test data """ path = "/inout_test" @@ -62,7 +74,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTest, + response_model=reflectapi_demo.tests.serde.Test, ) @@ -87,15 +99,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: + data: Optional[reflectapi_demo.tests.serde.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTest]: Response containing ReflectapiDemoTestsSerdeTest data + ApiResponse[reflectapi_demo.tests.serde.Test]: Response containing reflectapi_demo.tests.serde.Test data """ path = "/inout_test" @@ -105,7 +117,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTest, + response_model=reflectapi_demo.tests.serde.Test, ) @@ -130,23 +142,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTest.model_rebuild() + reflectapi_demo.tests.serde.Test.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdetest_response( - value: ReflectapiDemoTestsSerdeTest, -) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTest.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_all_python_keywords-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_all_python_keywords-2.snap new file mode 100644 index 00000000..c542aa43 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_all_python_keywords-2.snap @@ -0,0 +1,64 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Keywords > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Keywords, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export interface Keywords { + type: string; + class: string; + from: string; + import: string; + } + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Keywords, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Keywords, + {}, + reflectapi_demo.tests.serde.Keywords, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_all_python_keywords-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_all_python_keywords-3.snap new file mode 100644 index 00000000..574c49da --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_all_python_keywords-3.snap @@ -0,0 +1,72 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Keywords > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Keywords, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Keywords, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Keywords { + #[serde(rename = "type")] + pub type_: std::string::String, + pub class: std::string::String, + pub from: std::string::String, + pub import: std::string::String, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_all_python_keywords-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_all_python_keywords-4.snap new file mode 100644 index 00000000..c43d499b --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_all_python_keywords-4.snap @@ -0,0 +1,74 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Keywords" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Keywords" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.Keywords": { + "type": "object", + "title": "reflectapi_demo.tests.serde.Keywords", + "required": [ + "class", + "from", + "import", + "type" + ], + "properties": { + "class": { + "$ref": "#/components/schemas/std.string.String" + }, + "from": { + "$ref": "#/components/schemas/std.string.String" + }, + "import": { + "$ref": "#/components/schemas/std.string.String" + }, + "type": { + "$ref": "#/components/schemas/std.string.String" + } + } + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_all_python_keywords-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_all_python_keywords-5.snap new file mode 100644 index 00000000..6e5141a2 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_all_python_keywords-5.snap @@ -0,0 +1,148 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Keywords > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeKeywords(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type_: str = Field(serialization_alias="type", validation_alias="type") + class_: str = Field(serialization_alias="class", validation_alias="class") + from_: str = Field(serialization_alias="from", validation_alias="from") + import_: str = Field(serialization_alias="import", validation_alias="import") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Keywords = ReflectapiDemoTestsSerdeKeywords + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Keywords] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Keywords]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Keywords]: Response containing reflectapi_demo.tests.serde.Keywords data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Keywords, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Keywords] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Keywords]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Keywords]: Response containing reflectapi_demo.tests.serde.Keywords data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Keywords, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Keywords.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_all_python_keywords.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_all_python_keywords.snap new file mode 100644 index 00000000..c1317400 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_all_python_keywords.snap @@ -0,0 +1,125 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Keywords" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Keywords" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Keywords", + "fields": { + "named": [ + { + "name": "type", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "class", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "from", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "import", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Keywords", + "fields": { + "named": [ + { + "name": "type", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "class", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "from", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "import", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_names_with_special_chars-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_names_with_special_chars-2.snap new file mode 100644 index 00000000..8211417e --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_names_with_special_chars-2.snap @@ -0,0 +1,63 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < SpecialNames > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.SpecialNames, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export interface SpecialNames { + "Content-Type": string; + "x.nested.key": string; + "has spaces": number /* u32 */; + } + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.SpecialNames, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.SpecialNames, + {}, + reflectapi_demo.tests.serde.SpecialNames, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_names_with_special_chars-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_names_with_special_chars-3.snap new file mode 100644 index 00000000..bf7828a3 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_names_with_special_chars-3.snap @@ -0,0 +1,73 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < SpecialNames > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::SpecialNames, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::SpecialNames, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct SpecialNames { + #[serde(rename = "Content-Type")] + pub content__type: std::string::String, + #[serde(rename = "x.nested.key")] + pub nested_key: std::string::String, + #[serde(rename = "has spaces")] + pub has_spaces: u32, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_names_with_special_chars-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_names_with_special_chars-4.snap new file mode 100644 index 00000000..fb55328d --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_names_with_special_chars-4.snap @@ -0,0 +1,74 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.SpecialNames" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.SpecialNames" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.SpecialNames": { + "type": "object", + "title": "reflectapi_demo.tests.serde.SpecialNames", + "required": [ + "Content-Type", + "has spaces", + "x.nested.key" + ], + "properties": { + "Content-Type": { + "$ref": "#/components/schemas/std.string.String" + }, + "has spaces": { + "$ref": "#/components/schemas/u32" + }, + "x.nested.key": { + "$ref": "#/components/schemas/std.string.String" + } + } + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + }, + "u32": { + "description": "32-bit unsigned integer", + "type": "integer" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_names_with_special_chars-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_names_with_special_chars-5.snap new file mode 100644 index 00000000..58e8f934 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_names_with_special_chars-5.snap @@ -0,0 +1,153 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < SpecialNames > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeSpecialNames(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + content_type: str = Field( + serialization_alias="Content-Type", validation_alias="Content-Type" + ) + nested_key: str = Field( + serialization_alias="x.nested.key", validation_alias="x.nested.key" + ) + has_spaces: int = Field( + serialization_alias="has spaces", validation_alias="has spaces" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + SpecialNames = ReflectapiDemoTestsSerdeSpecialNames + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.SpecialNames] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.SpecialNames]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.SpecialNames]: Response containing reflectapi_demo.tests.serde.SpecialNames data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.SpecialNames, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.SpecialNames] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.SpecialNames]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.SpecialNames]: Response containing reflectapi_demo.tests.serde.SpecialNames data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.SpecialNames, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.SpecialNames.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_names_with_special_chars.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_names_with_special_chars.snap new file mode 100644 index 00000000..729799a8 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__field_names_with_special_chars.snap @@ -0,0 +1,127 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::SpecialNames" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::SpecialNames" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::SpecialNames", + "fields": { + "named": [ + { + "name": "Content_Type", + "serde_name": "Content-Type", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "nested_key", + "serde_name": "x.nested.key", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "has_spaces", + "serde_name": "has spaces", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::SpecialNames", + "fields": { + "named": [ + { + "name": "Content_Type", + "serde_name": "Content-Type", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "nested_key", + "serde_name": "x.nested.key", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "has_spaces", + "serde_name": "has spaces", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_adjacently_tagged_enum_field-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_adjacently_tagged_enum_field-2.snap new file mode 100644 index 00000000..21408207 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_adjacently_tagged_enum_field-2.snap @@ -0,0 +1,75 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Message > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Message, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export type Message = { + id: string; + } & NullToEmptyObject; + + export type Payload = + | { + kind: "Text"; + data: { + body: string; + }; + } + | { + kind: "Binary"; + data: { + size: number /* u32 */; + }; + }; + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Message, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Message, + {}, + reflectapi_demo.tests.serde.Message, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_adjacently_tagged_enum_field-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_adjacently_tagged_enum_field-3.snap new file mode 100644 index 00000000..108e3901 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_adjacently_tagged_enum_field-3.snap @@ -0,0 +1,77 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Message > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Message, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Message, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Message { + pub id: std::string::String, + #[serde(flatten)] + pub payload: super::super::super::reflectapi_demo::tests::serde::Payload, + } + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + #[serde(tag = "kind", content = "data")] + pub enum Payload { + Text { body: std::string::String }, + Binary { size: u32 }, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_adjacently_tagged_enum_field-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_adjacently_tagged_enum_field-4.snap new file mode 100644 index 00000000..fc1e338c --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_adjacently_tagged_enum_field-4.snap @@ -0,0 +1,127 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Message" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Message" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.Message": { + "allOf": [ + { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Payload" + }, + { + "type": "object", + "title": "reflectapi_demo.tests.serde.Message", + "required": [ + "id" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/std.string.String" + } + } + } + ] + }, + "reflectapi_demo.tests.serde.Payload": { + "oneOf": [ + { + "type": "object", + "title": "Text", + "required": [ + "data", + "kind" + ], + "properties": { + "data": { + "type": "object", + "title": "Text", + "required": [ + "body" + ], + "properties": { + "body": { + "$ref": "#/components/schemas/std.string.String" + } + } + }, + "kind": { + "const": "Text" + } + } + }, + { + "type": "object", + "title": "Binary", + "required": [ + "data", + "kind" + ], + "properties": { + "data": { + "type": "object", + "title": "Binary", + "required": [ + "size" + ], + "properties": { + "size": { + "$ref": "#/components/schemas/u32" + } + } + }, + "kind": { + "const": "Binary" + } + } + } + ] + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + }, + "u32": { + "description": "32-bit unsigned integer", + "type": "integer" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_adjacently_tagged_enum_field-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_adjacently_tagged_enum_field-5.snap new file mode 100644 index 00000000..2563f520 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_adjacently_tagged_enum_field-5.snap @@ -0,0 +1,226 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Message > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import ( + BaseModel, + ConfigDict, + Field, + PrivateAttr, + RootModel, + model_serializer, + model_validator, +) + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeMessage(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + id: str + payload: reflectapi_demo.tests.serde.Payload + + +class ReflectapiDemoTestsSerdePayloadTextVariant(BaseModel): + """Text variant""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + body: str + + +class ReflectapiDemoTestsSerdePayloadBinaryVariant(BaseModel): + """Binary variant""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + size: int + + +# Adjacently tagged enum using RootModel +ReflectapiDemoTestsSerdePayloadVariants = Union[ + ReflectapiDemoTestsSerdePayloadTextVariant, + ReflectapiDemoTestsSerdePayloadBinaryVariant, +] + + +class ReflectapiDemoTestsSerdePayload( + RootModel[ReflectapiDemoTestsSerdePayloadVariants] +): + """Adjacently tagged enum""" + + @model_validator(mode="before") + @classmethod + def _validate_adjacently_tagged(cls, data): + # Handle direct variant instances + if isinstance( + data, + ( + ReflectapiDemoTestsSerdePayloadTextVariant, + ReflectapiDemoTestsSerdePayloadBinaryVariant, + ), + ): + return data + if isinstance(data, dict): + tag = data.get("kind") + content = data.get("data") + if tag is None: + raise ValueError("Missing tag field 'kind'") + if content is None and tag not in (): + raise ValueError("Missing content field 'data' for tag: {}".format(tag)) + # Dispatch based on tag + if tag == "Text": + return ReflectapiDemoTestsSerdePayloadTextVariant(**content) + if tag == "Binary": + return ReflectapiDemoTestsSerdePayloadBinaryVariant(**content) + raise ValueError( + "Unknown variant for ReflectapiDemoTestsSerdePayload: {}".format(data) + ) + + @model_serializer + def _serialize_adjacently_tagged(self): + if isinstance(self.root, ReflectapiDemoTestsSerdePayloadTextVariant): + return {"kind": "Text", "data": self.root.model_dump()} + if isinstance(self.root, ReflectapiDemoTestsSerdePayloadBinaryVariant): + return {"kind": "Binary", "data": self.root.model_dump()} + raise ValueError( + f"Cannot serialize ReflectapiDemoTestsSerdePayload variant: {type(self.root)}" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Message = ReflectapiDemoTestsSerdeMessage + PayloadTextVariant = ReflectapiDemoTestsSerdePayloadTextVariant + PayloadBinaryVariant = ReflectapiDemoTestsSerdePayloadBinaryVariant + Payload = ReflectapiDemoTestsSerdePayload + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Message] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Message]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Message]: Response containing reflectapi_demo.tests.serde.Message data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Message, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Message] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Message]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Message]: Response containing reflectapi_demo.tests.serde.Message data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Message, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Message.model_rebuild() + reflectapi_demo.tests.serde.Payload.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_adjacently_tagged_enum_field.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_adjacently_tagged_enum_field.snap new file mode 100644 index 00000000..21bafe2f --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_adjacently_tagged_enum_field.snap @@ -0,0 +1,189 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Message" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Message" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Message", + "fields": { + "named": [ + { + "name": "id", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "payload", + "type": { + "name": "reflectapi_demo::tests::serde::Payload" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Payload", + "representation": { + "adjacent": { + "tag": "kind", + "content": "data" + } + }, + "variants": [ + { + "name": "Text", + "fields": { + "named": [ + { + "name": "body", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "name": "Binary", + "fields": { + "named": [ + { + "name": "size", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Message", + "fields": { + "named": [ + { + "name": "id", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "payload", + "type": { + "name": "reflectapi_demo::tests::serde::Payload" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Payload", + "representation": { + "adjacent": { + "tag": "kind", + "content": "data" + } + }, + "variants": [ + { + "name": "Text", + "fields": { + "named": [ + { + "name": "body", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "name": "Binary", + "fields": { + "named": [ + { + "name": "size", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_enum_with_unit_variants_only-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_enum_with_unit_variants_only-2.snap new file mode 100644 index 00000000..4f5275ad --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_enum_with_unit_variants_only-2.snap @@ -0,0 +1,66 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Item > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Item, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export type Item = { + name: string; + } & NullToEmptyObject; + + export type Status = + | { status: "Active" } + | { status: "Inactive" } + | { status: "Pending" }; + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Item, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Item, + {}, + reflectapi_demo.tests.serde.Item, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_enum_with_unit_variants_only-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_enum_with_unit_variants_only-3.snap new file mode 100644 index 00000000..450c9930 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_enum_with_unit_variants_only-3.snap @@ -0,0 +1,78 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Item > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Item, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Item, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Item { + pub name: std::string::String, + #[serde(flatten)] + pub status: super::super::super::reflectapi_demo::tests::serde::Status, + } + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + #[serde(tag = "status")] + pub enum Status { + Active, + Inactive, + Pending, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_enum_with_unit_variants_only-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_enum_with_unit_variants_only-4.snap new file mode 100644 index 00000000..102d8ac2 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_enum_with_unit_variants_only-4.snap @@ -0,0 +1,109 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Item" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Item" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.Item": { + "allOf": [ + { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Status" + }, + { + "type": "object", + "title": "reflectapi_demo.tests.serde.Item", + "required": [ + "name" + ], + "properties": { + "name": { + "$ref": "#/components/schemas/std.string.String" + } + } + } + ] + }, + "reflectapi_demo.tests.serde.Status": { + "oneOf": [ + { + "type": "object", + "title": "Active", + "required": [ + "status" + ], + "properties": { + "status": { + "const": "Active" + } + } + }, + { + "type": "object", + "title": "Inactive", + "required": [ + "status" + ], + "properties": { + "status": { + "const": "Inactive" + } + } + }, + { + "type": "object", + "title": "Pending", + "required": [ + "status" + ], + "properties": { + "status": { + "const": "Pending" + } + } + } + ] + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_enum_with_unit_variants_only-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_enum_with_unit_variants_only-5.snap new file mode 100644 index 00000000..a6c0949a --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_enum_with_unit_variants_only-5.snap @@ -0,0 +1,231 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Item > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Literal, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field, RootModel + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeItemActive(BaseModel): + """'Active' variant of ReflectapiDemoTestsSerdeItem""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + name: str + status: Literal["Active"] = Field( + default="Active", description="Discriminator field" + ) + + +class ReflectapiDemoTestsSerdeItemInactive(BaseModel): + """'Inactive' variant of ReflectapiDemoTestsSerdeItem""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + name: str + status: Literal["Inactive"] = Field( + default="Inactive", description="Discriminator field" + ) + + +class ReflectapiDemoTestsSerdeItemPending(BaseModel): + """'Pending' variant of ReflectapiDemoTestsSerdeItem""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + name: str + status: Literal["Pending"] = Field( + default="Pending", description="Discriminator field" + ) + + +class ReflectapiDemoTestsSerdeItem(RootModel): + root: Annotated[ + Union[ + ReflectapiDemoTestsSerdeItemActive, + ReflectapiDemoTestsSerdeItemInactive, + ReflectapiDemoTestsSerdeItemPending, + ], + Field(discriminator="status"), + ] + + +class ReflectapiDemoTestsSerdeStatusActive(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + status: Literal["Active"] = Field( + default="Active", description="Discriminator field" + ) + + +class ReflectapiDemoTestsSerdeStatusInactive(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + status: Literal["Inactive"] = Field( + default="Inactive", description="Discriminator field" + ) + + +class ReflectapiDemoTestsSerdeStatusPending(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + status: Literal["Pending"] = Field( + default="Pending", description="Discriminator field" + ) + + +class ReflectapiDemoTestsSerdeStatus(RootModel): + root: Annotated[ + Union[ + ReflectapiDemoTestsSerdeStatusActive, + ReflectapiDemoTestsSerdeStatusInactive, + ReflectapiDemoTestsSerdeStatusPending, + ], + Field(discriminator="status"), + ] + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + ItemActive = ReflectapiDemoTestsSerdeItemActive + ItemInactive = ReflectapiDemoTestsSerdeItemInactive + ItemPending = ReflectapiDemoTestsSerdeItemPending + Item = ReflectapiDemoTestsSerdeItem + StatusActive = ReflectapiDemoTestsSerdeStatusActive + StatusInactive = ReflectapiDemoTestsSerdeStatusInactive + StatusPending = ReflectapiDemoTestsSerdeStatusPending + Status = ReflectapiDemoTestsSerdeStatus + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Item] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Item]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Item]: Response containing reflectapi_demo.tests.serde.Item data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Item, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Item] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Item]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Item]: Response containing reflectapi_demo.tests.serde.Item data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Item, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Item.model_rebuild() + reflectapi_demo.tests.serde.Status.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_enum_with_unit_variants_only.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_enum_with_unit_variants_only.snap new file mode 100644 index 00000000..ce79d688 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_enum_with_unit_variants_only.snap @@ -0,0 +1,145 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Item" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Item" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Item", + "fields": { + "named": [ + { + "name": "name", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "status", + "type": { + "name": "reflectapi_demo::tests::serde::Status" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Status", + "representation": { + "internal": { + "tag": "status" + } + }, + "variants": [ + { + "name": "Active", + "fields": "none" + }, + { + "name": "Inactive", + "fields": "none" + }, + { + "name": "Pending", + "fields": "none" + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Item", + "fields": { + "named": [ + { + "name": "name", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "status", + "type": { + "name": "reflectapi_demo::tests::serde::Status" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Status", + "representation": { + "internal": { + "tag": "status" + } + }, + "variants": [ + { + "name": "Active", + "fields": "none" + }, + { + "name": "Inactive", + "fields": "none" + }, + { + "name": "Pending", + "fields": "none" + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_externally_tagged_enum_field-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_externally_tagged_enum_field-2.snap new file mode 100644 index 00000000..bee20758 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_externally_tagged_enum_field-2.snap @@ -0,0 +1,74 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Drawing > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Drawing, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export type Drawing = { + name: string; + } & NullToEmptyObject; + + export type Shape = + | { + Circle: { + radius: number /* f64 */; + }; + } + | { + Rect: { + width: number /* f64 */; + height: number /* f64 */; + }; + }; + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Drawing, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Drawing, + {}, + reflectapi_demo.tests.serde.Drawing, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_externally_tagged_enum_field-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_externally_tagged_enum_field-3.snap new file mode 100644 index 00000000..73c45fef --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_externally_tagged_enum_field-3.snap @@ -0,0 +1,76 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Drawing > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Drawing, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Drawing, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Drawing { + pub name: std::string::String, + #[serde(flatten)] + pub shape: super::super::super::reflectapi_demo::tests::serde::Shape, + } + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub enum Shape { + Circle { radius: f64 }, + Rect { width: f64, height: f64 }, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_externally_tagged_enum_field-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_externally_tagged_enum_field-4.snap new file mode 100644 index 00000000..b6051693 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_externally_tagged_enum_field-4.snap @@ -0,0 +1,123 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Drawing" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Drawing" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "f64": { + "description": "64-bit floating point number", + "type": "number" + }, + "reflectapi_demo.tests.serde.Drawing": { + "allOf": [ + { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Shape" + }, + { + "type": "object", + "title": "reflectapi_demo.tests.serde.Drawing", + "required": [ + "name" + ], + "properties": { + "name": { + "$ref": "#/components/schemas/std.string.String" + } + } + } + ] + }, + "reflectapi_demo.tests.serde.Shape": { + "oneOf": [ + { + "type": "object", + "title": "Circle", + "required": [ + "Circle" + ], + "properties": { + "Circle": { + "type": "object", + "title": "Circle", + "required": [ + "radius" + ], + "properties": { + "radius": { + "$ref": "#/components/schemas/f64" + } + } + } + } + }, + { + "type": "object", + "title": "Rect", + "required": [ + "Rect" + ], + "properties": { + "Rect": { + "type": "object", + "title": "Rect", + "required": [ + "height", + "width" + ], + "properties": { + "height": { + "$ref": "#/components/schemas/f64" + }, + "width": { + "$ref": "#/components/schemas/f64" + } + } + } + } + } + ] + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_externally_tagged_enum_field-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_externally_tagged_enum_field-5.snap new file mode 100644 index 00000000..1e7c313d --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_externally_tagged_enum_field-5.snap @@ -0,0 +1,220 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Drawing > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import ( + BaseModel, + ConfigDict, + Field, + PrivateAttr, + RootModel, + model_serializer, + model_validator, +) + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeDrawing(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + name: str + shape: reflectapi_demo.tests.serde.Shape + + +class ReflectapiDemoTestsSerdeShapeCircleVariant(BaseModel): + """Circle variant""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + radius: float + + +class ReflectapiDemoTestsSerdeShapeRectVariant(BaseModel): + """Rect variant""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + width: float + height: float + + +# Externally tagged enum using RootModel +ReflectapiDemoTestsSerdeShapeVariants = Union[ + ReflectapiDemoTestsSerdeShapeCircleVariant, ReflectapiDemoTestsSerdeShapeRectVariant +] + + +class ReflectapiDemoTestsSerdeShape(RootModel[ReflectapiDemoTestsSerdeShapeVariants]): + """Externally tagged enum""" + + @model_validator(mode="before") + @classmethod + def _validate_externally_tagged(cls, data): + # Handle direct variant instances (for programmatic creation) + if isinstance(data, ReflectapiDemoTestsSerdeShapeCircleVariant): + return data + if isinstance(data, ReflectapiDemoTestsSerdeShapeRectVariant): + return data + + # Handle JSON data (for deserialization) + + if isinstance(data, dict): + if len(data) != 1: + raise ValueError("Externally tagged enum must have exactly one key") + + key, value = next(iter(data.items())) + if key == "Circle": + return ReflectapiDemoTestsSerdeShapeCircleVariant(**value) + if key == "Rect": + return ReflectapiDemoTestsSerdeShapeRectVariant(**value) + + raise ValueError(f"Unknown variant for ReflectapiDemoTestsSerdeShape: {data}") + + @model_serializer + def _serialize_externally_tagged(self): + if isinstance(self.root, ReflectapiDemoTestsSerdeShapeCircleVariant): + return {"Circle": self.root.model_dump()} + if isinstance(self.root, ReflectapiDemoTestsSerdeShapeRectVariant): + return {"Rect": self.root.model_dump()} + + raise ValueError( + f"Cannot serialize ReflectapiDemoTestsSerdeShape variant: {type(self.root)}" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Drawing = ReflectapiDemoTestsSerdeDrawing + ShapeCircleVariant = ReflectapiDemoTestsSerdeShapeCircleVariant + ShapeRectVariant = ReflectapiDemoTestsSerdeShapeRectVariant + Shape = ReflectapiDemoTestsSerdeShape + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Drawing] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Drawing]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Drawing]: Response containing reflectapi_demo.tests.serde.Drawing data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Drawing, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Drawing] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Drawing]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Drawing]: Response containing reflectapi_demo.tests.serde.Drawing data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Drawing, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Drawing.model_rebuild() + reflectapi_demo.tests.serde.Shape.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_externally_tagged_enum_field.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_externally_tagged_enum_field.snap new file mode 100644 index 00000000..99c64359 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_externally_tagged_enum_field.snap @@ -0,0 +1,191 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Drawing" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Drawing" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "primitive", + "name": "f64", + "description": "64-bit floating point number" + }, + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Drawing", + "fields": { + "named": [ + { + "name": "name", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "shape", + "type": { + "name": "reflectapi_demo::tests::serde::Shape" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Shape", + "variants": [ + { + "name": "Circle", + "fields": { + "named": [ + { + "name": "radius", + "type": { + "name": "f64" + }, + "required": true + } + ] + } + }, + { + "name": "Rect", + "fields": { + "named": [ + { + "name": "width", + "type": { + "name": "f64" + }, + "required": true + }, + { + "name": "height", + "type": { + "name": "f64" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "primitive", + "name": "f64", + "description": "64-bit floating point number" + }, + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Drawing", + "fields": { + "named": [ + { + "name": "name", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "shape", + "type": { + "name": "reflectapi_demo::tests::serde::Shape" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Shape", + "variants": [ + { + "name": "Circle", + "fields": { + "named": [ + { + "name": "radius", + "type": { + "name": "f64" + }, + "required": true + } + ] + } + }, + { + "name": "Rect", + "fields": { + "named": [ + { + "name": "width", + "type": { + "name": "f64" + }, + "required": true + }, + { + "name": "height", + "type": { + "name": "f64" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged-3.snap index d455b97d..cf1cd467 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < Test > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged-5.snap index 5de18095..95d3d2cc 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged-5.snap @@ -23,7 +23,6 @@ from pydantic import BaseModel, ConfigDict, Field, RootModel from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -34,12 +33,6 @@ Additional = TypeVar("Additional") Payload = TypeVar("Payload") -class ReflectapiDemoTestsSerdeS(BaseModel, Generic[Payload, Additional]): - """Generated data model.""" - - model_config = ConfigDict(extra="ignore", populate_by_name=True) - - class ReflectapiDemoTestsSerdeA(BaseModel): """Generated data model.""" @@ -56,12 +49,18 @@ class ReflectapiDemoTestsSerdeB(BaseModel): b: int +class ReflectapiDemoTestsSerdeS(BaseModel, Generic[Payload, Additional]): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + class ReflectapiDemoTestsSerdeTestS(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["S"] = "S" + type: Literal["S"] = Field(default="S", description="Discriminator field") payload: Annotated[Any, "External type: Payload"] additional: Annotated[Any, "External type: Additional"] @@ -70,6 +69,23 @@ class ReflectapiDemoTestsSerdeTest(RootModel): root: Annotated[Union[ReflectapiDemoTestsSerdeTestS], Field(discriminator="type")] +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + A = ReflectapiDemoTestsSerdeA + B = ReflectapiDemoTestsSerdeB + S = ReflectapiDemoTestsSerdeS + TestS = ReflectapiDemoTestsSerdeTestS + Test = ReflectapiDemoTestsSerdeTest + + class AsyncInoutClient: """Async client for inout operations.""" @@ -78,15 +94,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: + data: Optional[reflectapi_demo.tests.serde.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTest]: Response containing ReflectapiDemoTestsSerdeTest data + ApiResponse[reflectapi_demo.tests.serde.Test]: Response containing reflectapi_demo.tests.serde.Test data """ path = "/inout_test" @@ -96,7 +112,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTest, + response_model=reflectapi_demo.tests.serde.Test, ) @@ -121,15 +137,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: + data: Optional[reflectapi_demo.tests.serde.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTest]: Response containing ReflectapiDemoTestsSerdeTest data + ApiResponse[reflectapi_demo.tests.serde.Test]: Response containing reflectapi_demo.tests.serde.Test data """ path = "/inout_test" @@ -139,7 +155,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTest, + response_model=reflectapi_demo.tests.serde.Test, ) @@ -164,59 +180,10 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeA.model_rebuild() - ReflectapiDemoTestsSerdeB.model_rebuild() - ReflectapiDemoTestsSerdeS.model_rebuild() - ReflectapiDemoTestsSerdeTest.model_rebuild() + reflectapi_demo.tests.serde.A.model_rebuild() + reflectapi_demo.tests.serde.B.model_rebuild() + reflectapi_demo.tests.serde.S.model_rebuild() + reflectapi_demo.tests.serde.Test.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeTestFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTest variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTest variants - """ - - @staticmethod - def s(field_0) -> ReflectapiDemoTestsSerdeTestS: - """Creates the 'S' variant of the ReflectapiDemoTestsSerdeTest enum.""" - return ReflectapiDemoTestsSerdeTestS(field_0=field_0) - - -# Testing utilities - - -def create_reflectapidemotestsserdea_response( - value: ReflectapiDemoTestsSerdeA, -) -> ApiResponse[ReflectapiDemoTestsSerdeA]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeA.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeb_response( - value: ReflectapiDemoTestsSerdeB, -) -> ApiResponse[ReflectapiDemoTestsSerdeB]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeB.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdes_response( - value: ReflectapiDemoTestsSerdeS, -) -> ApiResponse[ReflectapiDemoTestsSerdeS]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeS.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdetest_response( - value: ReflectapiDemoTestsSerdeTest, -) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTest.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged_enum_field-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged_enum_field-2.snap new file mode 100644 index 00000000..cfa878b4 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged_enum_field-2.snap @@ -0,0 +1,71 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Offer > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Offer, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export type Offer = { + id: string; + } & NullToEmptyObject; + + export type OfferKind = + | { + type: "Single"; + business: string; + } + | { + type: "Group"; + count: number /* u32 */; + }; + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Offer, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Offer, + {}, + reflectapi_demo.tests.serde.Offer, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged_enum_field-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged_enum_field-3.snap new file mode 100644 index 00000000..33d8a042 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged_enum_field-3.snap @@ -0,0 +1,77 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Offer > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Offer, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Offer, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Offer { + pub id: std::string::String, + #[serde(flatten)] + pub payload: super::super::super::reflectapi_demo::tests::serde::OfferKind, + } + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + #[serde(tag = "type")] + pub enum OfferKind { + Single { business: std::string::String }, + Group { count: u32 }, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged_enum_field-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged_enum_field-4.snap new file mode 100644 index 00000000..5c15b9fa --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged_enum_field-4.snap @@ -0,0 +1,109 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Offer" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Offer" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.Offer": { + "allOf": [ + { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.OfferKind" + }, + { + "type": "object", + "title": "reflectapi_demo.tests.serde.Offer", + "required": [ + "id" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/std.string.String" + } + } + } + ] + }, + "reflectapi_demo.tests.serde.OfferKind": { + "oneOf": [ + { + "type": "object", + "title": "Single", + "required": [ + "business", + "type" + ], + "properties": { + "business": { + "$ref": "#/components/schemas/std.string.String" + }, + "type": { + "const": "Single" + } + } + }, + { + "type": "object", + "title": "Group", + "required": [ + "count", + "type" + ], + "properties": { + "count": { + "$ref": "#/components/schemas/u32" + }, + "type": { + "const": "Group" + } + } + } + ] + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + }, + "u32": { + "description": "32-bit unsigned integer", + "type": "integer" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged_enum_field-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged_enum_field-5.snap new file mode 100644 index 00000000..8e87a143 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged_enum_field-5.snap @@ -0,0 +1,212 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Offer > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Literal, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field, RootModel + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeOfferSingle(BaseModel): + """'Single' variant of ReflectapiDemoTestsSerdeOffer""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + id: str + type_: Literal["Single"] = Field( + default="Single", + serialization_alias="type", + validation_alias="type", + description="Discriminator field", + ) + business: str + + +class ReflectapiDemoTestsSerdeOfferGroup(BaseModel): + """'Group' variant of ReflectapiDemoTestsSerdeOffer""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + id: str + type_: Literal["Group"] = Field( + default="Group", + serialization_alias="type", + validation_alias="type", + description="Discriminator field", + ) + count: int + + +class ReflectapiDemoTestsSerdeOffer(RootModel): + root: Annotated[ + Union[ + ReflectapiDemoTestsSerdeOfferSingle, + ReflectapiDemoTestsSerdeOfferGroup, + ], + Field(discriminator="type_"), + ] + + +class ReflectapiDemoTestsSerdeOfferKindSingle(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Single"] = Field(default="Single", description="Discriminator field") + business: str + + +class ReflectapiDemoTestsSerdeOfferKindGroup(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Group"] = Field(default="Group", description="Discriminator field") + count: int + + +class ReflectapiDemoTestsSerdeOfferKind(RootModel): + root: Annotated[ + Union[ + ReflectapiDemoTestsSerdeOfferKindSingle, + ReflectapiDemoTestsSerdeOfferKindGroup, + ], + Field(discriminator="type"), + ] + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + OfferSingle = ReflectapiDemoTestsSerdeOfferSingle + OfferGroup = ReflectapiDemoTestsSerdeOfferGroup + Offer = ReflectapiDemoTestsSerdeOffer + OfferKindSingle = ReflectapiDemoTestsSerdeOfferKindSingle + OfferKindGroup = ReflectapiDemoTestsSerdeOfferKindGroup + OfferKind = ReflectapiDemoTestsSerdeOfferKind + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Offer] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Offer]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Offer]: Response containing reflectapi_demo.tests.serde.Offer data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Offer, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Offer] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Offer]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Offer]: Response containing reflectapi_demo.tests.serde.Offer data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Offer, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Offer.model_rebuild() + reflectapi_demo.tests.serde.OfferKind.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged_enum_field.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged_enum_field.snap new file mode 100644 index 00000000..03c458f7 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_internally_tagged_enum_field.snap @@ -0,0 +1,187 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Offer" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Offer" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Offer", + "fields": { + "named": [ + { + "name": "id", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "payload", + "type": { + "name": "reflectapi_demo::tests::serde::OfferKind" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::OfferKind", + "representation": { + "internal": { + "tag": "type" + } + }, + "variants": [ + { + "name": "Single", + "fields": { + "named": [ + { + "name": "business", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "name": "Group", + "fields": { + "named": [ + { + "name": "count", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Offer", + "fields": { + "named": [ + { + "name": "id", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "payload", + "type": { + "name": "reflectapi_demo::tests::serde::OfferKind" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::OfferKind", + "representation": { + "internal": { + "tag": "type" + } + }, + "variants": [ + { + "name": "Single", + "fields": { + "named": [ + { + "name": "business", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "name": "Group", + "fields": { + "named": [ + { + "name": "count", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_multiple_structs-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_multiple_structs-2.snap new file mode 100644 index 00000000..6e128c1e --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_multiple_structs-2.snap @@ -0,0 +1,72 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Document > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Document, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export type Document = { + title: string; + } & NullToEmptyObject & + NullToEmptyObject; + + export interface Metadata { + author: string; + version: number /* u32 */; + } + + export interface Timestamps { + created_at: string; + updated_at: string; + } + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Document, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Document, + {}, + reflectapi_demo.tests.serde.Document, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_multiple_structs-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_multiple_structs-3.snap new file mode 100644 index 00000000..f5774e43 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_multiple_structs-3.snap @@ -0,0 +1,84 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Document > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Document, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Document, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Document { + pub title: std::string::String, + #[serde(flatten)] + pub timestamps: super::super::super::reflectapi_demo::tests::serde::Timestamps, + #[serde(flatten)] + pub meta: super::super::super::reflectapi_demo::tests::serde::Metadata, + } + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Metadata { + pub author: std::string::String, + pub version: u32, + } + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Timestamps { + pub created_at: std::string::String, + pub updated_at: std::string::String, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_multiple_structs-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_multiple_structs-4.snap new file mode 100644 index 00000000..56d47fdf --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_multiple_structs-4.snap @@ -0,0 +1,108 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Document" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Document" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.Document": { + "allOf": [ + { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Timestamps" + }, + { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Metadata" + }, + { + "type": "object", + "title": "reflectapi_demo.tests.serde.Document", + "required": [ + "title" + ], + "properties": { + "title": { + "$ref": "#/components/schemas/std.string.String" + } + } + } + ] + }, + "reflectapi_demo.tests.serde.Metadata": { + "type": "object", + "title": "reflectapi_demo.tests.serde.Metadata", + "required": [ + "author", + "version" + ], + "properties": { + "author": { + "$ref": "#/components/schemas/std.string.String" + }, + "version": { + "$ref": "#/components/schemas/u32" + } + } + }, + "reflectapi_demo.tests.serde.Timestamps": { + "type": "object", + "title": "reflectapi_demo.tests.serde.Timestamps", + "required": [ + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "$ref": "#/components/schemas/std.string.String" + }, + "updated_at": { + "$ref": "#/components/schemas/std.string.String" + } + } + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + }, + "u32": { + "description": "32-bit unsigned integer", + "type": "integer" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_multiple_structs-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_multiple_structs-5.snap new file mode 100644 index 00000000..57a00356 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_multiple_structs-5.snap @@ -0,0 +1,171 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Document > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeDocument(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + title: str + created_at: str + updated_at: str + author: str + version: int + + +class ReflectapiDemoTestsSerdeMetadata(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + author: str + version: int + + +class ReflectapiDemoTestsSerdeTimestamps(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + created_at: str + updated_at: str + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Document = ReflectapiDemoTestsSerdeDocument + Metadata = ReflectapiDemoTestsSerdeMetadata + Timestamps = ReflectapiDemoTestsSerdeTimestamps + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Document] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Document]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Document]: Response containing reflectapi_demo.tests.serde.Document data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Document, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Document] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Document]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Document]: Response containing reflectapi_demo.tests.serde.Document data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Document, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Document.model_rebuild() + reflectapi_demo.tests.serde.Metadata.model_rebuild() + reflectapi_demo.tests.serde.Timestamps.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_multiple_structs.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_multiple_structs.snap new file mode 100644 index 00000000..f5d4dda4 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_multiple_structs.snap @@ -0,0 +1,213 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Document" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Document" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Document", + "fields": { + "named": [ + { + "name": "title", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "timestamps", + "type": { + "name": "reflectapi_demo::tests::serde::Timestamps" + }, + "required": true, + "flattened": true + }, + { + "name": "meta", + "type": { + "name": "reflectapi_demo::tests::serde::Metadata" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Metadata", + "fields": { + "named": [ + { + "name": "author", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "version", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Timestamps", + "fields": { + "named": [ + { + "name": "created_at", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "updated_at", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Document", + "fields": { + "named": [ + { + "name": "title", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "timestamps", + "type": { + "name": "reflectapi_demo::tests::serde::Timestamps" + }, + "required": true, + "flattened": true + }, + { + "name": "meta", + "type": { + "name": "reflectapi_demo::tests::serde::Metadata" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Metadata", + "fields": { + "named": [ + { + "name": "author", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "version", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Timestamps", + "fields": { + "named": [ + { + "name": "created_at", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "updated_at", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_optional_internally_tagged_enum-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_optional_internally_tagged_enum-2.snap new file mode 100644 index 00000000..a3b00636 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_optional_internally_tagged_enum-2.snap @@ -0,0 +1,68 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Task > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Task, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export type Priority = + | { + kind: "High"; + deadline: string; + } + | { kind: "Low" }; + + export type Task = { + title: string; + } & NullToEmptyObject; + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Task, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Task, + {}, + reflectapi_demo.tests.serde.Task, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_optional_internally_tagged_enum-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_optional_internally_tagged_enum-3.snap new file mode 100644 index 00000000..08f18b11 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_optional_internally_tagged_enum-3.snap @@ -0,0 +1,79 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Task > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Task, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Task, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + #[serde(tag = "kind")] + pub enum Priority { + High { deadline: std::string::String }, + Low, + } + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Task { + pub title: std::string::String, + #[serde(flatten)] + pub priority: std::option::Option< + super::super::super::reflectapi_demo::tests::serde::Priority, + >, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_optional_internally_tagged_enum-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_optional_internally_tagged_enum-4.snap new file mode 100644 index 00000000..e512fad1 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_optional_internally_tagged_enum-4.snap @@ -0,0 +1,109 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Task" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Task" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.Priority": { + "oneOf": [ + { + "type": "object", + "title": "High", + "required": [ + "deadline", + "kind" + ], + "properties": { + "deadline": { + "$ref": "#/components/schemas/std.string.String" + }, + "kind": { + "const": "High" + } + } + }, + { + "type": "object", + "title": "Low", + "required": [ + "kind" + ], + "properties": { + "kind": { + "const": "Low" + } + } + } + ] + }, + "reflectapi_demo.tests.serde.Task": { + "allOf": [ + { + "oneOf": [ + { + "description": "Null", + "type": "null" + }, + { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Priority" + } + ] + }, + { + "type": "object", + "title": "reflectapi_demo.tests.serde.Task", + "required": [ + "title" + ], + "properties": { + "title": { + "$ref": "#/components/schemas/std.string.String" + } + } + } + ] + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_optional_internally_tagged_enum-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_optional_internally_tagged_enum-5.snap new file mode 100644 index 00000000..2897c29b --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_optional_internally_tagged_enum-5.snap @@ -0,0 +1,199 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Task > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Literal, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field, RootModel + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeTaskHigh(BaseModel): + """'High' variant of ReflectapiDemoTestsSerdeTask""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + title: str + kind: Literal["High"] = Field(default="High", description="Discriminator field") + deadline: str + + +class ReflectapiDemoTestsSerdeTaskLow(BaseModel): + """'Low' variant of ReflectapiDemoTestsSerdeTask""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + title: str + kind: Literal["Low"] = Field(default="Low", description="Discriminator field") + + +class ReflectapiDemoTestsSerdeTask(RootModel): + root: Annotated[ + Union[ + ReflectapiDemoTestsSerdeTaskHigh, + ReflectapiDemoTestsSerdeTaskLow, + ], + Field(discriminator="kind"), + ] + + +class ReflectapiDemoTestsSerdePriorityHigh(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + kind: Literal["High"] = Field(default="High", description="Discriminator field") + deadline: str + + +class ReflectapiDemoTestsSerdePriorityLow(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + kind: Literal["Low"] = Field(default="Low", description="Discriminator field") + + +class ReflectapiDemoTestsSerdePriority(RootModel): + root: Annotated[ + Union[ + ReflectapiDemoTestsSerdePriorityHigh, ReflectapiDemoTestsSerdePriorityLow + ], + Field(discriminator="kind"), + ] + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TaskHigh = ReflectapiDemoTestsSerdeTaskHigh + TaskLow = ReflectapiDemoTestsSerdeTaskLow + Task = ReflectapiDemoTestsSerdeTask + PriorityHigh = ReflectapiDemoTestsSerdePriorityHigh + PriorityLow = ReflectapiDemoTestsSerdePriorityLow + Priority = ReflectapiDemoTestsSerdePriority + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Task] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Task]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Task]: Response containing reflectapi_demo.tests.serde.Task data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Task, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Task] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Task]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Task]: Response containing reflectapi_demo.tests.serde.Task data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Task, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Priority.model_rebuild() + reflectapi_demo.tests.serde.Task.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_optional_internally_tagged_enum.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_optional_internally_tagged_enum.snap new file mode 100644 index 00000000..bfc043b8 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_optional_internally_tagged_enum.snap @@ -0,0 +1,231 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Task" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Task" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Priority", + "representation": { + "internal": { + "tag": "kind" + } + }, + "variants": [ + { + "name": "High", + "fields": { + "named": [ + { + "name": "deadline", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "name": "Low", + "fields": "none" + } + ] + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Task", + "fields": { + "named": [ + { + "name": "title", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "priority", + "type": { + "name": "std::option::Option", + "arguments": [ + { + "name": "reflectapi_demo::tests::serde::Priority" + } + ] + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "enum", + "name": "std::option::Option", + "description": "Optional nullable type", + "parameters": [ + { + "name": "T" + } + ], + "representation": "none", + "variants": [ + { + "name": "None", + "description": "The value is not provided, i.e. null", + "fields": "none" + }, + { + "name": "Some", + "description": "The value is provided and set to some value", + "fields": { + "unnamed": [ + { + "name": "0", + "type": { + "name": "T" + } + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Priority", + "representation": { + "internal": { + "tag": "kind" + } + }, + "variants": [ + { + "name": "High", + "fields": { + "named": [ + { + "name": "deadline", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "name": "Low", + "fields": "none" + } + ] + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Task", + "fields": { + "named": [ + { + "name": "title", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "priority", + "type": { + "name": "std::option::Option", + "arguments": [ + { + "name": "reflectapi_demo::tests::serde::Priority" + } + ] + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "enum", + "name": "std::option::Option", + "description": "Optional nullable type", + "parameters": [ + { + "name": "T" + } + ], + "representation": "none", + "variants": [ + { + "name": "None", + "description": "The value is not provided, i.e. null", + "fields": "none" + }, + { + "name": "Some", + "description": "The value is provided and set to some value", + "fields": { + "unnamed": [ + { + "name": "0", + "type": { + "name": "T" + } + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_and_internal_enum_combined-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_and_internal_enum_combined-2.snap new file mode 100644 index 00000000..2c85608a --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_and_internal_enum_combined-2.snap @@ -0,0 +1,77 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Post > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Post, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export interface Audit { + modified_by: string; + } + + export type Content = + | { + type: "Text"; + body: string; + } + | { + type: "Image"; + url: string; + width: number /* u32 */; + }; + + export type Post = { + id: string; + } & NullToEmptyObject & + NullToEmptyObject; + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Post, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Post, + {}, + reflectapi_demo.tests.serde.Post, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_and_internal_enum_combined-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_and_internal_enum_combined-3.snap new file mode 100644 index 00000000..bfa321e6 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_and_internal_enum_combined-3.snap @@ -0,0 +1,89 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Post > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Post, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Post, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Audit { + pub modified_by: std::string::String, + } + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + #[serde(tag = "type")] + pub enum Content { + Text { + body: std::string::String, + }, + Image { + url: std::string::String, + width: u32, + }, + } + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Post { + pub id: std::string::String, + #[serde(flatten)] + pub audit: super::super::super::reflectapi_demo::tests::serde::Audit, + #[serde(flatten)] + pub content: super::super::super::reflectapi_demo::tests::serde::Content, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_and_internal_enum_combined-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_and_internal_enum_combined-4.snap new file mode 100644 index 00000000..53a1b92d --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_and_internal_enum_combined-4.snap @@ -0,0 +1,128 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Post" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Post" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.Audit": { + "type": "object", + "title": "reflectapi_demo.tests.serde.Audit", + "required": [ + "modified_by" + ], + "properties": { + "modified_by": { + "$ref": "#/components/schemas/std.string.String" + } + } + }, + "reflectapi_demo.tests.serde.Content": { + "oneOf": [ + { + "type": "object", + "title": "Text", + "required": [ + "body", + "type" + ], + "properties": { + "body": { + "$ref": "#/components/schemas/std.string.String" + }, + "type": { + "const": "Text" + } + } + }, + { + "type": "object", + "title": "Image", + "required": [ + "type", + "url", + "width" + ], + "properties": { + "type": { + "const": "Image" + }, + "url": { + "$ref": "#/components/schemas/std.string.String" + }, + "width": { + "$ref": "#/components/schemas/u32" + } + } + } + ] + }, + "reflectapi_demo.tests.serde.Post": { + "allOf": [ + { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Audit" + }, + { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Content" + }, + { + "type": "object", + "title": "reflectapi_demo.tests.serde.Post", + "required": [ + "id" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/std.string.String" + } + } + } + ] + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + }, + "u32": { + "description": "32-bit unsigned integer", + "type": "integer" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_and_internal_enum_combined-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_and_internal_enum_combined-5.snap new file mode 100644 index 00000000..daf93012 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_and_internal_enum_combined-5.snap @@ -0,0 +1,225 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Post > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Literal, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field, RootModel + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeAudit(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + modified_by: str + + +class ReflectapiDemoTestsSerdePostText(BaseModel): + """'Text' variant of ReflectapiDemoTestsSerdePost""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + id: str + modified_by: str + type_: Literal["Text"] = Field( + default="Text", + serialization_alias="type", + validation_alias="type", + description="Discriminator field", + ) + body: str + + +class ReflectapiDemoTestsSerdePostImage(BaseModel): + """'Image' variant of ReflectapiDemoTestsSerdePost""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + id: str + modified_by: str + type_: Literal["Image"] = Field( + default="Image", + serialization_alias="type", + validation_alias="type", + description="Discriminator field", + ) + url: str + width: int + + +class ReflectapiDemoTestsSerdePost(RootModel): + root: Annotated[ + Union[ + ReflectapiDemoTestsSerdePostText, + ReflectapiDemoTestsSerdePostImage, + ], + Field(discriminator="type_"), + ] + + +class ReflectapiDemoTestsSerdeContentText(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Text"] = Field(default="Text", description="Discriminator field") + body: str + + +class ReflectapiDemoTestsSerdeContentImage(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + type: Literal["Image"] = Field(default="Image", description="Discriminator field") + url: str + width: int + + +class ReflectapiDemoTestsSerdeContent(RootModel): + root: Annotated[ + Union[ + ReflectapiDemoTestsSerdeContentText, ReflectapiDemoTestsSerdeContentImage + ], + Field(discriminator="type"), + ] + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Audit = ReflectapiDemoTestsSerdeAudit + PostText = ReflectapiDemoTestsSerdePostText + PostImage = ReflectapiDemoTestsSerdePostImage + Post = ReflectapiDemoTestsSerdePost + ContentText = ReflectapiDemoTestsSerdeContentText + ContentImage = ReflectapiDemoTestsSerdeContentImage + Content = ReflectapiDemoTestsSerdeContent + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Post] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Post]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Post]: Response containing reflectapi_demo.tests.serde.Post data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Post, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Post] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Post]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Post]: Response containing reflectapi_demo.tests.serde.Post data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Post, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Audit.model_rebuild() + reflectapi_demo.tests.serde.Content.model_rebuild() + reflectapi_demo.tests.serde.Post.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_and_internal_enum_combined.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_and_internal_enum_combined.snap new file mode 100644 index 00000000..3d76d0b7 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_and_internal_enum_combined.snap @@ -0,0 +1,247 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Post" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Post" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Audit", + "fields": { + "named": [ + { + "name": "modified_by", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Content", + "representation": { + "internal": { + "tag": "type" + } + }, + "variants": [ + { + "name": "Text", + "fields": { + "named": [ + { + "name": "body", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "name": "Image", + "fields": { + "named": [ + { + "name": "url", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "width", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Post", + "fields": { + "named": [ + { + "name": "id", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "audit", + "type": { + "name": "reflectapi_demo::tests::serde::Audit" + }, + "required": true, + "flattened": true + }, + { + "name": "content", + "type": { + "name": "reflectapi_demo::tests::serde::Content" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Audit", + "fields": { + "named": [ + { + "name": "modified_by", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Content", + "representation": { + "internal": { + "tag": "type" + } + }, + "variants": [ + { + "name": "Text", + "fields": { + "named": [ + { + "name": "body", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "name": "Image", + "fields": { + "named": [ + { + "name": "url", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "width", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Post", + "fields": { + "named": [ + { + "name": "id", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "audit", + "type": { + "name": "reflectapi_demo::tests::serde::Audit" + }, + "required": true, + "flattened": true + }, + { + "name": "content", + "type": { + "name": "reflectapi_demo::tests::serde::Content" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_with_nested_flatten-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_with_nested_flatten-2.snap new file mode 100644 index 00000000..104ae1cd --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_with_nested_flatten-2.snap @@ -0,0 +1,69 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Outer > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Outer, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export interface Inner { + z: string; + } + + export type Middle = { + y: number /* u32 */; + } & NullToEmptyObject; + + export type Outer = { + x: string; + } & NullToEmptyObject; + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Outer, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Outer, + {}, + reflectapi_demo.tests.serde.Outer, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_with_nested_flatten-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_with_nested_flatten-3.snap new file mode 100644 index 00000000..92969993 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_with_nested_flatten-3.snap @@ -0,0 +1,82 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Outer > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Outer, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Outer, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Inner { + pub z: std::string::String, + } + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Middle { + pub y: u32, + #[serde(flatten)] + pub inner: super::super::super::reflectapi_demo::tests::serde::Inner, + } + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Outer { + pub x: std::string::String, + #[serde(flatten)] + pub nested: super::super::super::reflectapi_demo::tests::serde::Middle, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_with_nested_flatten-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_with_nested_flatten-4.snap new file mode 100644 index 00000000..e358c7d6 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_with_nested_flatten-4.snap @@ -0,0 +1,104 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Outer" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Outer" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.Inner": { + "type": "object", + "title": "reflectapi_demo.tests.serde.Inner", + "required": [ + "z" + ], + "properties": { + "z": { + "$ref": "#/components/schemas/std.string.String" + } + } + }, + "reflectapi_demo.tests.serde.Middle": { + "allOf": [ + { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Inner" + }, + { + "type": "object", + "title": "reflectapi_demo.tests.serde.Middle", + "required": [ + "y" + ], + "properties": { + "y": { + "$ref": "#/components/schemas/u32" + } + } + } + ] + }, + "reflectapi_demo.tests.serde.Outer": { + "allOf": [ + { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Middle" + }, + { + "type": "object", + "title": "reflectapi_demo.tests.serde.Outer", + "required": [ + "x" + ], + "properties": { + "x": { + "$ref": "#/components/schemas/std.string.String" + } + } + } + ] + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + }, + "u32": { + "description": "32-bit unsigned integer", + "type": "integer" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_with_nested_flatten-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_with_nested_flatten-5.snap new file mode 100644 index 00000000..0104634a --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_with_nested_flatten-5.snap @@ -0,0 +1,168 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Outer > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeInner(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + z: str + + +class ReflectapiDemoTestsSerdeMiddle(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + y: int + z: str + + +class ReflectapiDemoTestsSerdeOuter(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + x: str + y: int + z: str + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Inner = ReflectapiDemoTestsSerdeInner + Middle = ReflectapiDemoTestsSerdeMiddle + Outer = ReflectapiDemoTestsSerdeOuter + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Outer] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Outer]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Outer]: Response containing reflectapi_demo.tests.serde.Outer data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Outer, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Outer] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Outer]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Outer]: Response containing reflectapi_demo.tests.serde.Outer data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Outer, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Inner.model_rebuild() + reflectapi_demo.tests.serde.Middle.model_rebuild() + reflectapi_demo.tests.serde.Outer.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_with_nested_flatten.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_with_nested_flatten.snap new file mode 100644 index 00000000..b4f5c31e --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_struct_with_nested_flatten.snap @@ -0,0 +1,185 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Outer" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Outer" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Inner", + "fields": { + "named": [ + { + "name": "z", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Middle", + "fields": { + "named": [ + { + "name": "y", + "type": { + "name": "u32" + }, + "required": true + }, + { + "name": "inner", + "type": { + "name": "reflectapi_demo::tests::serde::Inner" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Outer", + "fields": { + "named": [ + { + "name": "x", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "nested", + "type": { + "name": "reflectapi_demo::tests::serde::Middle" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Inner", + "fields": { + "named": [ + { + "name": "z", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Middle", + "fields": { + "named": [ + { + "name": "y", + "type": { + "name": "u32" + }, + "required": true + }, + { + "name": "inner", + "type": { + "name": "reflectapi_demo::tests::serde::Inner" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Outer", + "fields": { + "named": [ + { + "name": "x", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "nested", + "type": { + "name": "reflectapi_demo::tests::serde::Middle" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_unit-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_unit-3.snap index ededeca1..c6337f31 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_unit-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_unit-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::>()" -snapshot_kind: text +expression: "super :: into_rust_code :: < S > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -61,7 +60,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_unit-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_unit-5.snap index 4144ec6d..e33271b4 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_unit-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_unit-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response # Type variables for generic types @@ -33,18 +32,32 @@ Additional = TypeVar("Additional") Payload = TypeVar("Payload") -class ReflectapiDemoTestsSerdeS(BaseModel, Generic[Payload, Additional]): +class ReflectapiDemoTestsSerdeK(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) + a: int -class ReflectapiDemoTestsSerdeK(BaseModel): + +class ReflectapiDemoTestsSerdeS(BaseModel, Generic[Payload, Additional]): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - a: int + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + K = ReflectapiDemoTestsSerdeK + S = ReflectapiDemoTestsSerdeS class AsyncInoutClient: @@ -56,16 +69,18 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsSerdeS[ReflectapiDemoTestsSerdeK, None] + reflectapi_demo.tests.serde.S[reflectapi_demo.tests.serde.K, None] ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeS[ReflectapiDemoTestsSerdeK, None]]: + ) -> ApiResponse[ + reflectapi_demo.tests.serde.S[reflectapi_demo.tests.serde.K, None] + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeS[ReflectapiDemoTestsSerdeK, None]]: Response containing ReflectapiDemoTestsSerdeS[ReflectapiDemoTestsSerdeK, None] data + ApiResponse[reflectapi_demo.tests.serde.S[reflectapi_demo.tests.serde.K, None]]: Response containing reflectapi_demo.tests.serde.S[reflectapi_demo.tests.serde.K, None] data """ path = "/inout_test" @@ -75,7 +90,9 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeS[ReflectapiDemoTestsSerdeK, None], + response_model=reflectapi_demo.tests.serde.S[ + reflectapi_demo.tests.serde.K, None + ], ) @@ -101,16 +118,18 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsSerdeS[ReflectapiDemoTestsSerdeK, None] + reflectapi_demo.tests.serde.S[reflectapi_demo.tests.serde.K, None] ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeS[ReflectapiDemoTestsSerdeK, None]]: + ) -> ApiResponse[ + reflectapi_demo.tests.serde.S[reflectapi_demo.tests.serde.K, None] + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeS[ReflectapiDemoTestsSerdeK, None]]: Response containing ReflectapiDemoTestsSerdeS[ReflectapiDemoTestsSerdeK, None] data + ApiResponse[reflectapi_demo.tests.serde.S[reflectapi_demo.tests.serde.K, None]]: Response containing reflectapi_demo.tests.serde.S[reflectapi_demo.tests.serde.K, None] data """ path = "/inout_test" @@ -120,7 +139,9 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeS[ReflectapiDemoTestsSerdeK, None], + response_model=reflectapi_demo.tests.serde.S[ + reflectapi_demo.tests.serde.K, None + ], ) @@ -145,31 +166,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeK.model_rebuild() - ReflectapiDemoTestsSerdeS.model_rebuild() + reflectapi_demo.tests.serde.K.model_rebuild() + reflectapi_demo.tests.serde.S.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdek_response( - value: ReflectapiDemoTestsSerdeK, -) -> ApiResponse[ReflectapiDemoTestsSerdeK]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeK.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdes_response( - value: ReflectapiDemoTestsSerdeS, -) -> ApiResponse[ReflectapiDemoTestsSerdeS]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeS.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_untagged_enum_field-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_untagged_enum_field-2.snap new file mode 100644 index 00000000..7d8d6ffc --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_untagged_enum_field-2.snap @@ -0,0 +1,69 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Cell > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Cell, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export type Cell = { + label: string; + } & NullToEmptyObject; + + export type Value = + | { + value: number /* f64 */; + } + | { + text: string; + }; + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Cell, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Cell, + {}, + reflectapi_demo.tests.serde.Cell, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_untagged_enum_field-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_untagged_enum_field-3.snap new file mode 100644 index 00000000..49b44b7f --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_untagged_enum_field-3.snap @@ -0,0 +1,77 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Cell > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Cell, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Cell, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Cell { + pub label: std::string::String, + #[serde(flatten)] + pub content: super::super::super::reflectapi_demo::tests::serde::Value, + } + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + #[serde(untagged)] + pub enum Value { + Num { value: f64 }, + Text { text: std::string::String }, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_untagged_enum_field-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_untagged_enum_field-4.snap new file mode 100644 index 00000000..9c1e2503 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_untagged_enum_field-4.snap @@ -0,0 +1,101 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Cell" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Cell" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "f64": { + "description": "64-bit floating point number", + "type": "number" + }, + "reflectapi_demo.tests.serde.Cell": { + "allOf": [ + { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Value" + }, + { + "type": "object", + "title": "reflectapi_demo.tests.serde.Cell", + "required": [ + "label" + ], + "properties": { + "label": { + "$ref": "#/components/schemas/std.string.String" + } + } + } + ] + }, + "reflectapi_demo.tests.serde.Value": { + "oneOf": [ + { + "type": "object", + "title": "Num", + "required": [ + "value" + ], + "properties": { + "value": { + "$ref": "#/components/schemas/f64" + } + } + }, + { + "type": "object", + "title": "Text", + "required": [ + "text" + ], + "properties": { + "text": { + "$ref": "#/components/schemas/std.string.String" + } + } + } + ] + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_untagged_enum_field-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_untagged_enum_field-5.snap new file mode 100644 index 00000000..45df6567 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_untagged_enum_field-5.snap @@ -0,0 +1,172 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Cell > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeCell(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + label: str + content: reflectapi_demo.tests.serde.Value + + +class ReflectapiDemoTestsSerdeValueNum(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + value: float + + +class ReflectapiDemoTestsSerdeValueText(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + text: str + + +ReflectapiDemoTestsSerdeValue = Union[ + ReflectapiDemoTestsSerdeValueNum, ReflectapiDemoTestsSerdeValueText +] + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Cell = ReflectapiDemoTestsSerdeCell + ValueNum = ReflectapiDemoTestsSerdeValueNum + ValueText = ReflectapiDemoTestsSerdeValueText + Value = ReflectapiDemoTestsSerdeValue + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Cell] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Cell]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Cell]: Response containing reflectapi_demo.tests.serde.Cell data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Cell, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Cell] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Cell]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Cell]: Response containing reflectapi_demo.tests.serde.Cell data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Cell, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Cell.model_rebuild() + reflectapi_demo.tests.serde.Value.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_untagged_enum_field.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_untagged_enum_field.snap new file mode 100644 index 00000000..d3fed83a --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__flatten_untagged_enum_field.snap @@ -0,0 +1,179 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Cell" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Cell" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "primitive", + "name": "f64", + "description": "64-bit floating point number" + }, + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Cell", + "fields": { + "named": [ + { + "name": "label", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "content", + "type": { + "name": "reflectapi_demo::tests::serde::Value" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Value", + "representation": "none", + "variants": [ + { + "name": "Num", + "fields": { + "named": [ + { + "name": "value", + "type": { + "name": "f64" + }, + "required": true + } + ] + } + }, + { + "name": "Text", + "fields": { + "named": [ + { + "name": "text", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "primitive", + "name": "f64", + "description": "64-bit floating point number" + }, + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Cell", + "fields": { + "named": [ + { + "name": "label", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "content", + "type": { + "name": "reflectapi_demo::tests::serde::Value" + }, + "required": true, + "flattened": true + } + ] + } + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Value", + "representation": "none", + "variants": [ + { + "name": "Num", + "fields": { + "named": [ + { + "name": "value", + "type": { + "name": "f64" + }, + "required": true + } + ] + } + }, + { + "name": "Text", + "fields": { + "named": [ + { + "name": "text", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_adjacently_tagged_enum-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_adjacently_tagged_enum-2.snap new file mode 100644 index 00000000..ba6f6301 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_adjacently_tagged_enum-2.snap @@ -0,0 +1,59 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Tagged > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Tagged, + headers: {}, + options?: RequestOptions, + ) => AsyncResult, {}>; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export type Tagged = { t: "Item"; c: T } | { t: "Nothing"; c: {} }; + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Tagged, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Tagged, + {}, + reflectapi_demo.tests.serde.Tagged, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_adjacently_tagged_enum-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_adjacently_tagged_enum-3.snap new file mode 100644 index 00000000..e8ab1b85 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_adjacently_tagged_enum-3.snap @@ -0,0 +1,70 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Tagged > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Tagged, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Tagged, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + #[serde(tag = "t", content = "c")] + pub enum Tagged { + Item(T), + Nothing, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_adjacently_tagged_enum-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_adjacently_tagged_enum-4.snap new file mode 100644 index 00000000..977c9e86 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_adjacently_tagged_enum-4.snap @@ -0,0 +1,120 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "title": "Item", + "required": [ + "c", + "t" + ], + "properties": { + "c": { + "$ref": "#/components/schemas/u32" + }, + "t": { + "const": "Item" + } + } + }, + { + "type": "object", + "title": "Nothing", + "required": [ + "c", + "t" + ], + "properties": { + "c": { + "type": "object", + "title": "Nothing", + "properties": {} + }, + "t": { + "const": "Nothing" + } + } + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "title": "Item", + "required": [ + "c", + "t" + ], + "properties": { + "c": { + "$ref": "#/components/schemas/u32" + }, + "t": { + "const": "Item" + } + } + }, + { + "type": "object", + "title": "Nothing", + "required": [ + "c", + "t" + ], + "properties": { + "c": { + "type": "object", + "title": "Nothing", + "properties": {} + }, + "t": { + "const": "Nothing" + } + } + } + ] + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "u32": { + "description": "32-bit unsigned integer", + "type": "integer" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_adjacently_tagged_enum-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_adjacently_tagged_enum-5.snap new file mode 100644 index 00000000..064c4073 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_adjacently_tagged_enum-5.snap @@ -0,0 +1,208 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Tagged > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import ( + BaseModel, + ConfigDict, + Field, + PrivateAttr, + RootModel, + model_serializer, + model_validator, +) + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +# Type variables for generic types + + +T = TypeVar("T") + + +class ReflectapiDemoTestsSerdeTaggedItemVariant(BaseModel, Generic[T]): + """Item variant""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + field_0: T + + +# Adjacently tagged enum using RootModel +ReflectapiDemoTestsSerdeTaggedVariants = Union[ + ReflectapiDemoTestsSerdeTaggedItemVariant, Literal["Nothing"] +] + + +class ReflectapiDemoTestsSerdeTagged( + RootModel[ReflectapiDemoTestsSerdeTaggedVariants], Generic[T] +): + """Adjacently tagged enum""" + + @model_validator(mode="before") + @classmethod + def _validate_adjacently_tagged(cls, data): + # Handle direct variant instances + if isinstance(data, (ReflectapiDemoTestsSerdeTaggedItemVariant)): + return data + if isinstance(data, dict): + tag = data.get("t") + content = data.get("c") + if tag is None: + raise ValueError("Missing tag field 't'") + if content is None and tag not in ("Nothing"): + raise ValueError("Missing content field 'c' for tag: {}".format(tag)) + # Dispatch based on tag + if tag == "Item": + return ReflectapiDemoTestsSerdeTaggedItemVariant(field_0=content) + if tag == "Nothing": + return "Nothing" + raise ValueError( + "Unknown variant for ReflectapiDemoTestsSerdeTagged: {}".format(data) + ) + + @model_serializer + def _serialize_adjacently_tagged(self): + if isinstance(self.root, ReflectapiDemoTestsSerdeTaggedItemVariant): + return {"t": "Item", "c": self.root.field_0} + if self.root == "Nothing": + return {"t": "Nothing"} + raise ValueError( + f"Cannot serialize ReflectapiDemoTestsSerdeTagged variant: {type(self.root)}" + ) + + def __class_getitem__(cls, params): + return cls + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TaggedItemVariant = ReflectapiDemoTestsSerdeTaggedItemVariant + Tagged = ReflectapiDemoTestsSerdeTagged + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Tagged[int]] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Tagged[int]]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Tagged[int]]: Response containing reflectapi_demo.tests.serde.Tagged[int] data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Tagged[int], + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Tagged[int]] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Tagged[int]]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Tagged[int]]: Response containing reflectapi_demo.tests.serde.Tagged[int] data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Tagged[int], + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Tagged.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_adjacently_tagged_enum.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_adjacently_tagged_enum.snap new file mode 100644 index 00000000..8f4ca1b9 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_adjacently_tagged_enum.snap @@ -0,0 +1,133 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Tagged", + "arguments": [ + { + "name": "u32" + } + ] + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Tagged", + "arguments": [ + { + "name": "u32" + } + ] + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Tagged", + "parameters": [ + { + "name": "T" + } + ], + "representation": { + "adjacent": { + "tag": "t", + "content": "c" + } + }, + "variants": [ + { + "name": "Item", + "fields": { + "unnamed": [ + { + "name": "0", + "type": { + "name": "T" + }, + "required": true + } + ] + } + }, + { + "name": "Nothing", + "fields": "none" + } + ] + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Tagged", + "parameters": [ + { + "name": "T" + } + ], + "representation": { + "adjacent": { + "tag": "t", + "content": "c" + } + }, + "variants": [ + { + "name": "Item", + "fields": { + "unnamed": [ + { + "name": "0", + "type": { + "name": "T" + }, + "required": true + } + ] + } + }, + { + "name": "Nothing", + "fields": "none" + } + ] + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_externally_tagged_enum-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_externally_tagged_enum-2.snap new file mode 100644 index 00000000..6430fbcb --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_externally_tagged_enum-2.snap @@ -0,0 +1,63 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Wrapper > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Wrapper, + headers: {}, + options?: RequestOptions, + ) => AsyncResult, {}>; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export type Wrapper = + | { + Value: T; + } + | "Empty"; + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Wrapper, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Wrapper, + {}, + reflectapi_demo.tests.serde.Wrapper, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_externally_tagged_enum-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_externally_tagged_enum-3.snap new file mode 100644 index 00000000..6f55afde --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_externally_tagged_enum-3.snap @@ -0,0 +1,69 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Wrapper > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Wrapper, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Wrapper, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub enum Wrapper { + Value(T), + Empty, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_externally_tagged_enum-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_externally_tagged_enum-4.snap new file mode 100644 index 00000000..9f7a1c85 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_externally_tagged_enum-4.snap @@ -0,0 +1,82 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "title": "Value", + "required": [ + "Value" + ], + "properties": { + "Value": { + "$ref": "#/components/schemas/std.string.String" + } + } + }, + { + "const": "Empty" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "title": "Value", + "required": [ + "Value" + ], + "properties": { + "Value": { + "$ref": "#/components/schemas/std.string.String" + } + } + }, + { + "const": "Empty" + } + ] + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_externally_tagged_enum-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_externally_tagged_enum-5.snap new file mode 100644 index 00000000..acb3e9f9 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_externally_tagged_enum-5.snap @@ -0,0 +1,209 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Wrapper > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import ( + BaseModel, + ConfigDict, + Field, + PrivateAttr, + RootModel, + model_serializer, + model_validator, +) + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +# Type variables for generic types + + +T = TypeVar("T") + + +class ReflectapiDemoTestsSerdeWrapperValueVariant(BaseModel, Generic[T]): + """Value variant""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + field_0: T + + +# Externally tagged enum using RootModel +ReflectapiDemoTestsSerdeWrapperVariants = Union[ + ReflectapiDemoTestsSerdeWrapperValueVariant[T], Literal["Empty"] +] + + +class ReflectapiDemoTestsSerdeWrapper( + RootModel[ReflectapiDemoTestsSerdeWrapperVariants], Generic[T] +): + """Externally tagged enum""" + + @classmethod + def __class_getitem__(cls, params): + return cls + + @model_validator(mode="before") + @classmethod + def _validate_externally_tagged(cls, data): + # Handle direct variant instances (for programmatic creation) + if isinstance(data, ReflectapiDemoTestsSerdeWrapperValueVariant): + return data + + # Handle JSON data (for deserialization) + if isinstance(data, str) and data == "Empty": + return data + + if isinstance(data, dict): + if len(data) != 1: + raise ValueError("Externally tagged enum must have exactly one key") + + key, value = next(iter(data.items())) + if key == "Value": + return ReflectapiDemoTestsSerdeWrapperValueVariant(field_0=value) + + raise ValueError(f"Unknown variant for ReflectapiDemoTestsSerdeWrapper: {data}") + + @model_serializer + def _serialize_externally_tagged(self): + if isinstance(self.root, ReflectapiDemoTestsSerdeWrapperValueVariant): + return {"Value": self.root.field_0} + if self.root == "Empty": + return "Empty" + + raise ValueError( + f"Cannot serialize ReflectapiDemoTestsSerdeWrapper variant: {type(self.root)}" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + WrapperValueVariant = ReflectapiDemoTestsSerdeWrapperValueVariant + Wrapper = ReflectapiDemoTestsSerdeWrapper + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Wrapper[str]] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Wrapper[str]]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Wrapper[str]]: Response containing reflectapi_demo.tests.serde.Wrapper[str] data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Wrapper[str], + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Wrapper[str]] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Wrapper[str]]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Wrapper[str]]: Response containing reflectapi_demo.tests.serde.Wrapper[str] data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Wrapper[str], + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Wrapper.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_externally_tagged_enum.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_externally_tagged_enum.snap new file mode 100644 index 00000000..354efb91 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_externally_tagged_enum.snap @@ -0,0 +1,121 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Wrapper", + "arguments": [ + { + "name": "std::string::String" + } + ] + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Wrapper", + "arguments": [ + { + "name": "std::string::String" + } + ] + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Wrapper", + "parameters": [ + { + "name": "T" + } + ], + "variants": [ + { + "name": "Value", + "fields": { + "unnamed": [ + { + "name": "0", + "type": { + "name": "T" + }, + "required": true + } + ] + } + }, + { + "name": "Empty", + "fields": "none" + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "enum", + "name": "reflectapi_demo::tests::serde::Wrapper", + "parameters": [ + { + "name": "T" + } + ], + "variants": [ + { + "name": "Value", + "fields": { + "unnamed": [ + { + "name": "0", + "type": { + "name": "T" + }, + "required": true + } + ] + } + }, + { + "name": "Empty", + "fields": "none" + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_struct_repr_transparent-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_struct_repr_transparent-5.snap index 65dbac3a..d47d9065 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_struct_repr_transparent-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_struct_repr_transparent-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class AsyncInoutClient: @@ -31,7 +30,6 @@ class AsyncInoutClient: def __init__(self, client: AsyncClientBase) -> None: self._client = client - async def test( self, data: Optional[bytes] = None, @@ -53,7 +51,7 @@ class AsyncInoutClient: params=params if params else None, json_model=data, response_model=bytes, -) + ) class AsyncClient(AsyncClientBase): @@ -66,6 +64,7 @@ class AsyncClient(AsyncClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = AsyncInoutClient(self) @@ -75,7 +74,6 @@ class InoutClient: def __init__(self, client: ClientBase) -> None: self._client = client - def test( self, data: Optional[bytes] = None, @@ -97,7 +95,7 @@ class InoutClient: params=params if params else None, json_model=data, response_model=bytes, -) + ) class Client(ClientBase): @@ -110,6 +108,7 @@ class Client(ClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = InoutClient(self) @@ -124,12 +123,3 @@ try: except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_struct_repr_transparent_partially_generic-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_struct_repr_transparent_partially_generic-5.snap index eb868688..31b84a7e 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_struct_repr_transparent_partially_generic-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__generic_struct_repr_transparent_partially_generic-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class AsyncInoutClient: @@ -31,7 +30,6 @@ class AsyncInoutClient: def __init__(self, client: AsyncClientBase) -> None: self._client = client - async def test( self, data: Optional[dict[str, int]] = None, @@ -53,7 +51,7 @@ class AsyncInoutClient: params=params if params else None, json_model=data, response_model=dict[str, int], -) + ) class AsyncClient(AsyncClientBase): @@ -66,6 +64,7 @@ class AsyncClient(AsyncClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = AsyncInoutClient(self) @@ -75,7 +74,6 @@ class InoutClient: def __init__(self, client: ClientBase) -> None: self._client = client - def test( self, data: Optional[dict[str, int]] = None, @@ -97,7 +95,7 @@ class InoutClient: params=params if params else None, json_model=data, response_model=dict[str, int], -) + ) class Client(ClientBase): @@ -110,6 +108,7 @@ class Client(ClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = InoutClient(self) @@ -124,12 +123,3 @@ try: except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__kebab_case-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__kebab_case-3.snap index 9b6689b5..285e0493 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__kebab_case-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__kebab_case-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < Test > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__kebab_case-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__kebab_case-5.snap index 1fa93697..c74060b7 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__kebab_case-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__kebab_case-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTest(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsSerdeTest(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - field_name: int + field_name: int = Field( + serialization_alias="field-name", validation_alias="field-name" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Test = ReflectapiDemoTestsSerdeTest class AsyncInoutClient: @@ -41,15 +55,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: + data: Optional[reflectapi_demo.tests.serde.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTest]: Response containing ReflectapiDemoTestsSerdeTest data + ApiResponse[reflectapi_demo.tests.serde.Test]: Response containing reflectapi_demo.tests.serde.Test data """ path = "/inout_test" @@ -59,7 +73,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTest, + response_model=reflectapi_demo.tests.serde.Test, ) @@ -84,15 +98,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: + data: Optional[reflectapi_demo.tests.serde.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTest]: Response containing ReflectapiDemoTestsSerdeTest data + ApiResponse[reflectapi_demo.tests.serde.Test]: Response containing reflectapi_demo.tests.serde.Test data """ path = "/inout_test" @@ -102,7 +116,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTest, + response_model=reflectapi_demo.tests.serde.Test, ) @@ -127,23 +141,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTest.model_rebuild() + reflectapi_demo.tests.serde.Test.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdetest_response( - value: ReflectapiDemoTestsSerdeTest, -) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTest.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__multiple_underscore_prefix_fields-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__multiple_underscore_prefix_fields-2.snap new file mode 100644 index 00000000..2a57ffb1 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__multiple_underscore_prefix_fields-2.snap @@ -0,0 +1,63 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Underscored > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Underscored, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export interface Underscored { + _single: number /* u32 */; + __double: string; + ___triple: boolean; + } + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Underscored, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Underscored, + {}, + reflectapi_demo.tests.serde.Underscored, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__multiple_underscore_prefix_fields-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__multiple_underscore_prefix_fields-3.snap new file mode 100644 index 00000000..08cbfd79 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__multiple_underscore_prefix_fields-3.snap @@ -0,0 +1,70 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Underscored > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Underscored, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Underscored, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Underscored { + pub _single: u32, + pub __double: std::string::String, + pub ___triple: bool, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__multiple_underscore_prefix_fields-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__multiple_underscore_prefix_fields-4.snap new file mode 100644 index 00000000..6b15ae2a --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__multiple_underscore_prefix_fields-4.snap @@ -0,0 +1,78 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Underscored" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Underscored" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "bool": { + "description": "Boolean value", + "type": "boolean" + }, + "reflectapi_demo.tests.serde.Underscored": { + "type": "object", + "title": "reflectapi_demo.tests.serde.Underscored", + "required": [ + "___triple", + "__double", + "_single" + ], + "properties": { + "___triple": { + "$ref": "#/components/schemas/bool" + }, + "__double": { + "$ref": "#/components/schemas/std.string.String" + }, + "_single": { + "$ref": "#/components/schemas/u32" + } + } + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + }, + "u32": { + "description": "32-bit unsigned integer", + "type": "integer" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__multiple_underscore_prefix_fields-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__multiple_underscore_prefix_fields-5.snap new file mode 100644 index 00000000..4d4f295b --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__multiple_underscore_prefix_fields-5.snap @@ -0,0 +1,147 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Underscored > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeUnderscored(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + single: int = Field(serialization_alias="_single", validation_alias="_single") + double: str = Field(serialization_alias="__double", validation_alias="__double") + triple: bool = Field(serialization_alias="___triple", validation_alias="___triple") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Underscored = ReflectapiDemoTestsSerdeUnderscored + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Underscored] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Underscored]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Underscored]: Response containing reflectapi_demo.tests.serde.Underscored data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Underscored, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Underscored] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Underscored]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Underscored]: Response containing reflectapi_demo.tests.serde.Underscored data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Underscored, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Underscored.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__multiple_underscore_prefix_fields.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__multiple_underscore_prefix_fields.snap new file mode 100644 index 00000000..707e8b5a --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__multiple_underscore_prefix_fields.snap @@ -0,0 +1,131 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Underscored" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Underscored" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "primitive", + "name": "bool", + "description": "Boolean value" + }, + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Underscored", + "fields": { + "named": [ + { + "name": "_single", + "type": { + "name": "u32" + }, + "required": true + }, + { + "name": "__double", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "___triple", + "type": { + "name": "bool" + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "primitive", + "name": "bool", + "description": "Boolean value" + }, + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Underscored", + "fields": { + "named": [ + { + "name": "_single", + "type": { + "name": "u32" + }, + "required": true + }, + { + "name": "__double", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "___triple", + "type": { + "name": "bool" + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_deeply_nested_modules-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_deeply_nested_modules-2.snap new file mode 100644 index 00000000..05d7935f --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_deeply_nested_modules-2.snap @@ -0,0 +1,70 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < deep::nested::inner::DeepType > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.deep.nested.inner.DeepType, + headers: {}, + options?: RequestOptions, + ) => AsyncResult< + reflectapi_demo.tests.serde.deep.nested.inner.DeepType, + {} + >; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export namespace deep { + export namespace nested { + export namespace inner { + export interface DeepType { + data: string; + } + } + } + } + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.deep.nested.inner.DeepType, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.deep.nested.inner.DeepType, + {}, + reflectapi_demo.tests.serde.deep.nested.inner.DeepType, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_deeply_nested_modules-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_deeply_nested_modules-3.snap new file mode 100644 index 00000000..49e58dd4 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_deeply_nested_modules-3.snap @@ -0,0 +1,74 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < deep::nested::inner::DeepType > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::deep::nested::inner::DeepType, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::deep::nested::inner::DeepType, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + pub mod deep { + pub mod nested { + pub mod inner { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct DeepType { + pub data: std::string::String, + } + } + } + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_deeply_nested_modules-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_deeply_nested_modules-4.snap new file mode 100644 index 00000000..1514a865 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_deeply_nested_modules-4.snap @@ -0,0 +1,62 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.deep.nested.inner.DeepType" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.deep.nested.inner.DeepType" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.deep.nested.inner.DeepType": { + "type": "object", + "title": "reflectapi_demo.tests.serde.deep.nested.inner.DeepType", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/std.string.String" + } + } + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_deeply_nested_modules-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_deeply_nested_modules-5.snap new file mode 100644 index 00000000..f49bcd70 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_deeply_nested_modules-5.snap @@ -0,0 +1,154 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < deep::nested::inner::DeepType > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeDeepNestedInnerDeepType(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + data: str + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + class deep: + """Namespace for deep types.""" + + class nested: + """Namespace for nested types.""" + + class inner: + """Namespace for inner types.""" + + DeepType = ReflectapiDemoTestsSerdeDeepNestedInnerDeepType + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.deep.nested.inner.DeepType] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.deep.nested.inner.DeepType]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.deep.nested.inner.DeepType]: Response containing reflectapi_demo.tests.serde.deep.nested.inner.DeepType data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.deep.nested.inner.DeepType, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.deep.nested.inner.DeepType] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.deep.nested.inner.DeepType]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.deep.nested.inner.DeepType]: Response containing reflectapi_demo.tests.serde.deep.nested.inner.DeepType data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.deep.nested.inner.DeepType, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.deep.nested.inner.DeepType.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_deeply_nested_modules.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_deeply_nested_modules.snap new file mode 100644 index 00000000..3756b6fe --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_deeply_nested_modules.snap @@ -0,0 +1,83 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::deep::nested::inner::DeepType" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::deep::nested::inner::DeepType" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::deep::nested::inner::DeepType", + "fields": { + "named": [ + { + "name": "data", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::deep::nested::inner::DeepType", + "fields": { + "named": [ + { + "name": "data", + "type": { + "name": "std::string::String" + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_single_segment_type-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_single_segment_type-2.snap new file mode 100644 index 00000000..1168e2bc --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_single_segment_type-2.snap @@ -0,0 +1,61 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < SimpleTopLevel > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.SimpleTopLevel, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export interface SimpleTopLevel { + value: number /* u32 */; + } + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.SimpleTopLevel, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.SimpleTopLevel, + {}, + reflectapi_demo.tests.serde.SimpleTopLevel, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_single_segment_type-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_single_segment_type-3.snap new file mode 100644 index 00000000..700c3183 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_single_segment_type-3.snap @@ -0,0 +1,68 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < SimpleTopLevel > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::SimpleTopLevel, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::SimpleTopLevel, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct SimpleTopLevel { + pub value: u32, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_single_segment_type-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_single_segment_type-4.snap new file mode 100644 index 00000000..bd50055e --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_single_segment_type-4.snap @@ -0,0 +1,62 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.SimpleTopLevel" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.SimpleTopLevel" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.SimpleTopLevel": { + "type": "object", + "title": "reflectapi_demo.tests.serde.SimpleTopLevel", + "required": [ + "value" + ], + "properties": { + "value": { + "$ref": "#/components/schemas/u32" + } + } + }, + "u32": { + "description": "32-bit unsigned integer", + "type": "integer" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_single_segment_type-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_single_segment_type-5.snap new file mode 100644 index 00000000..ab97e063 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_single_segment_type-5.snap @@ -0,0 +1,145 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < SimpleTopLevel > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeSimpleTopLevel(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + value: int + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + SimpleTopLevel = ReflectapiDemoTestsSerdeSimpleTopLevel + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.SimpleTopLevel] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.SimpleTopLevel]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.SimpleTopLevel]: Response containing reflectapi_demo.tests.serde.SimpleTopLevel data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.SimpleTopLevel, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.SimpleTopLevel] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.SimpleTopLevel]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.SimpleTopLevel]: Response containing reflectapi_demo.tests.serde.SimpleTopLevel data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.SimpleTopLevel, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.SimpleTopLevel.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_single_segment_type.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_single_segment_type.snap new file mode 100644 index 00000000..d99668ca --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_single_segment_type.snap @@ -0,0 +1,83 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::SimpleTopLevel" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::SimpleTopLevel" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::SimpleTopLevel", + "fields": { + "named": [ + { + "name": "value", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::SimpleTopLevel", + "fields": { + "named": [ + { + "name": "value", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_with_numeric_start-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_with_numeric_start-2.snap new file mode 100644 index 00000000..c55dcb24 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_with_numeric_start-2.snap @@ -0,0 +1,62 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < TypeWithNumbers > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.TypeWithNumbers, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export interface TypeWithNumbers { + "123start": string; + "kebab-field": number /* u32 */; + } + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.TypeWithNumbers, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.TypeWithNumbers, + {}, + reflectapi_demo.tests.serde.TypeWithNumbers, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_with_numeric_start-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_with_numeric_start-3.snap new file mode 100644 index 00000000..525664c2 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_with_numeric_start-3.snap @@ -0,0 +1,71 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < TypeWithNumbers > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::TypeWithNumbers, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::TypeWithNumbers, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct TypeWithNumbers { + #[serde(rename = "123start")] + pub field_123: std::string::String, + #[serde(rename = "kebab-field")] + pub kebab_field: u32, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_with_numeric_start-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_with_numeric_start-4.snap new file mode 100644 index 00000000..3aecf9e9 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_with_numeric_start-4.snap @@ -0,0 +1,70 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.TypeWithNumbers" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.TypeWithNumbers" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.TypeWithNumbers": { + "type": "object", + "title": "reflectapi_demo.tests.serde.TypeWithNumbers", + "required": [ + "123start", + "kebab-field" + ], + "properties": { + "123start": { + "$ref": "#/components/schemas/std.string.String" + }, + "kebab-field": { + "$ref": "#/components/schemas/u32" + } + } + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + }, + "u32": { + "description": "32-bit unsigned integer", + "type": "integer" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_with_numeric_start-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_with_numeric_start-5.snap new file mode 100644 index 00000000..7c9c3e4f --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_with_numeric_start-5.snap @@ -0,0 +1,148 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < TypeWithNumbers > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeTypeWithNumbers(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + field_123: str = Field(serialization_alias="123start", validation_alias="123start") + kebab_field: int = Field( + serialization_alias="kebab-field", validation_alias="kebab-field" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TypeWithNumbers = ReflectapiDemoTestsSerdeTypeWithNumbers + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.TypeWithNumbers] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TypeWithNumbers]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.TypeWithNumbers]: Response containing reflectapi_demo.tests.serde.TypeWithNumbers data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.TypeWithNumbers, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.TypeWithNumbers] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TypeWithNumbers]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.TypeWithNumbers]: Response containing reflectapi_demo.tests.serde.TypeWithNumbers data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.TypeWithNumbers, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.TypeWithNumbers.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_with_numeric_start.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_with_numeric_start.snap new file mode 100644 index 00000000..77082242 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__namespace_with_numeric_start.snap @@ -0,0 +1,111 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::TypeWithNumbers" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::TypeWithNumbers" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::TypeWithNumbers", + "fields": { + "named": [ + { + "name": "field_123", + "serde_name": "123start", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "kebab_field", + "serde_name": "kebab-field", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::TypeWithNumbers", + "fields": { + "named": [ + { + "name": "field_123", + "serde_name": "123start", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "kebab_field", + "serde_name": "kebab-field", + "type": { + "name": "u32" + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_generic_containers-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_generic_containers-2.snap new file mode 100644 index 00000000..3a2c435c --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_generic_containers-2.snap @@ -0,0 +1,62 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Complex > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Complex, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export interface Complex { + matrix: Array>; + lookup: Record>; + } + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Complex, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Complex, + {}, + reflectapi_demo.tests.serde.Complex, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_generic_containers-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_generic_containers-3.snap new file mode 100644 index 00000000..89f050f5 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_generic_containers-3.snap @@ -0,0 +1,72 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Complex > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Complex, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Complex, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Complex { + pub matrix: std::vec::Vec>, + pub lookup: std::collections::HashMap< + std::string::String, + std::vec::Vec>, + >, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_generic_containers-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_generic_containers-4.snap new file mode 100644 index 00000000..93902e14 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_generic_containers-4.snap @@ -0,0 +1,94 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Complex" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Complex" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "i32": { + "description": "32-bit signed integer", + "type": "integer" + }, + "reflectapi_demo.tests.serde.Complex": { + "type": "object", + "title": "reflectapi_demo.tests.serde.Complex", + "required": [ + "lookup", + "matrix" + ], + "properties": { + "lookup": { + "description": "Key-value map type", + "type": "object", + "additionalProperties": { + "description": "Expandable array type", + "type": "array", + "items": { + "oneOf": [ + { + "description": "Null", + "type": "null" + }, + { + "$ref": "#/components/schemas/i32" + } + ] + } + } + }, + "matrix": { + "description": "Expandable array type", + "type": "array", + "items": { + "description": "Expandable array type", + "type": "array", + "items": { + "$ref": "#/components/schemas/u32" + } + } + } + } + }, + "u32": { + "description": "32-bit unsigned integer", + "type": "integer" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_generic_containers-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_generic_containers-5.snap new file mode 100644 index 00000000..53ac8c41 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_generic_containers-5.snap @@ -0,0 +1,147 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Complex > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeComplex(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + matrix: list[list[int]] + lookup: dict[str, list[int | None]] + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Complex = ReflectapiDemoTestsSerdeComplex + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Complex] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Complex]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Complex]: Response containing reflectapi_demo.tests.serde.Complex data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Complex, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Complex] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Complex]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Complex]: Response containing reflectapi_demo.tests.serde.Complex data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Complex, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Complex.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_generic_containers.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_generic_containers.snap new file mode 100644 index 00000000..11b31863 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_generic_containers.snap @@ -0,0 +1,283 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Complex" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Complex" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "primitive", + "name": "i32", + "description": "32-bit signed integer" + }, + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Complex", + "fields": { + "named": [ + { + "name": "matrix", + "type": { + "name": "std::vec::Vec", + "arguments": [ + { + "name": "std::vec::Vec", + "arguments": [ + { + "name": "u32" + } + ] + } + ] + }, + "required": true + }, + { + "name": "lookup", + "type": { + "name": "std::collections::HashMap", + "arguments": [ + { + "name": "std::string::String" + }, + { + "name": "std::vec::Vec", + "arguments": [ + { + "name": "std::option::Option", + "arguments": [ + { + "name": "i32" + } + ] + } + ] + } + ] + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::collections::HashMap", + "description": "Key-value map type", + "parameters": [ + { + "name": "K" + }, + { + "name": "V" + } + ] + }, + { + "kind": "enum", + "name": "std::option::Option", + "description": "Optional nullable type", + "parameters": [ + { + "name": "T" + } + ], + "representation": "none", + "variants": [ + { + "name": "None", + "description": "The value is not provided, i.e. null", + "fields": "none" + }, + { + "name": "Some", + "description": "The value is provided and set to some value", + "fields": { + "unnamed": [ + { + "name": "0", + "type": { + "name": "T" + } + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "std::vec::Vec", + "description": "Expandable array type", + "parameters": [ + { + "name": "T" + } + ] + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "primitive", + "name": "i32", + "description": "32-bit signed integer" + }, + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Complex", + "fields": { + "named": [ + { + "name": "matrix", + "type": { + "name": "std::vec::Vec", + "arguments": [ + { + "name": "std::vec::Vec", + "arguments": [ + { + "name": "u32" + } + ] + } + ] + }, + "required": true + }, + { + "name": "lookup", + "type": { + "name": "std::collections::HashMap", + "arguments": [ + { + "name": "std::string::String" + }, + { + "name": "std::vec::Vec", + "arguments": [ + { + "name": "std::option::Option", + "arguments": [ + { + "name": "i32" + } + ] + } + ] + } + ] + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::collections::HashMap", + "description": "Key-value map type", + "parameters": [ + { + "name": "K" + }, + { + "name": "V" + } + ] + }, + { + "kind": "enum", + "name": "std::option::Option", + "description": "Optional nullable type", + "parameters": [ + { + "name": "T" + } + ], + "representation": "none", + "variants": [ + { + "name": "None", + "description": "The value is not provided, i.e. null", + "fields": "none" + }, + { + "name": "Some", + "description": "The value is provided and set to some value", + "fields": { + "unnamed": [ + { + "name": "0", + "type": { + "name": "T" + } + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "std::vec::Vec", + "description": "Expandable array type", + "parameters": [ + { + "name": "T" + } + ] + }, + { + "kind": "primitive", + "name": "u32", + "description": "32-bit unsigned integer" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums-3.snap index eec41c11..71582322 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < Test > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums-5.snap index 2cb88f80..c4b88175 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums-5.snap @@ -23,31 +23,30 @@ from pydantic import BaseModel, ConfigDict, Field, RootModel from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response -class ReflectapiDemoTestsSerdeV2C(BaseModel): +class ReflectapiDemoTestsSerdeTestV1(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["C"] = "C" - c: int + version: Literal["v1"] = Field(default="v1", description="Discriminator field") + value: reflectapi_demo.tests.serde.V1 = Field(description="Tuple variant value") -class ReflectapiDemoTestsSerdeV2D(BaseModel): +class ReflectapiDemoTestsSerdeTestV2(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["D"] = "D" - d: int + version: Literal["v2"] = Field(default="v2", description="Discriminator field") + value: reflectapi_demo.tests.serde.V2 = Field(description="Tuple variant value") -class ReflectapiDemoTestsSerdeV2(RootModel): +class ReflectapiDemoTestsSerdeTest(RootModel): root: Annotated[ - Union[ReflectapiDemoTestsSerdeV2C, ReflectapiDemoTestsSerdeV2D], - Field(discriminator="type"), + Union[ReflectapiDemoTestsSerdeTestV1, ReflectapiDemoTestsSerdeTestV2], + Field(discriminator="version"), ] @@ -56,7 +55,7 @@ class ReflectapiDemoTestsSerdeV1A(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["A"] = "A" + type: Literal["A"] = Field(default="A", description="Discriminator field") a: int @@ -65,7 +64,7 @@ class ReflectapiDemoTestsSerdeV1B(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["B"] = "B" + type: Literal["B"] = Field(default="B", description="Discriminator field") b: int @@ -76,31 +75,52 @@ class ReflectapiDemoTestsSerdeV1(RootModel): ] -class ReflectapiDemoTestsSerdeTestV1(BaseModel): +class ReflectapiDemoTestsSerdeV2C(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - version: Literal["v1"] = "v1" - value: ReflectapiDemoTestsSerdeV1 + type: Literal["C"] = Field(default="C", description="Discriminator field") + c: int -class ReflectapiDemoTestsSerdeTestV2(BaseModel): +class ReflectapiDemoTestsSerdeV2D(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - version: Literal["v2"] = "v2" - value: ReflectapiDemoTestsSerdeV2 + type: Literal["D"] = Field(default="D", description="Discriminator field") + d: int -class ReflectapiDemoTestsSerdeTest(RootModel): +class ReflectapiDemoTestsSerdeV2(RootModel): root: Annotated[ - Union[ReflectapiDemoTestsSerdeTestV1, ReflectapiDemoTestsSerdeTestV2], - Field(discriminator="version"), + Union[ReflectapiDemoTestsSerdeV2C, ReflectapiDemoTestsSerdeV2D], + Field(discriminator="type"), ] +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestV1 = ReflectapiDemoTestsSerdeTestV1 + TestV2 = ReflectapiDemoTestsSerdeTestV2 + Test = ReflectapiDemoTestsSerdeTest + V1A = ReflectapiDemoTestsSerdeV1A + V1B = ReflectapiDemoTestsSerdeV1B + V1 = ReflectapiDemoTestsSerdeV1 + V2C = ReflectapiDemoTestsSerdeV2C + V2D = ReflectapiDemoTestsSerdeV2D + V2 = ReflectapiDemoTestsSerdeV2 + + class AsyncInoutClient: """Async client for inout operations.""" @@ -109,15 +129,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: + data: Optional[reflectapi_demo.tests.serde.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTest]: Response containing ReflectapiDemoTestsSerdeTest data + ApiResponse[reflectapi_demo.tests.serde.Test]: Response containing reflectapi_demo.tests.serde.Test data """ path = "/inout_test" @@ -127,7 +147,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTest, + response_model=reflectapi_demo.tests.serde.Test, ) @@ -152,15 +172,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: + data: Optional[reflectapi_demo.tests.serde.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTest]: Response containing ReflectapiDemoTestsSerdeTest data + ApiResponse[reflectapi_demo.tests.serde.Test]: Response containing reflectapi_demo.tests.serde.Test data """ path = "/inout_test" @@ -170,7 +190,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTest, + response_model=reflectapi_demo.tests.serde.Test, ) @@ -195,90 +215,9 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTest.model_rebuild() - ReflectapiDemoTestsSerdeV1.model_rebuild() - ReflectapiDemoTestsSerdeV2.model_rebuild() + reflectapi_demo.tests.serde.Test.model_rebuild() + reflectapi_demo.tests.serde.V1.model_rebuild() + reflectapi_demo.tests.serde.V2.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeV2Factory: - """Factory class for creating ReflectapiDemoTestsSerdeV2 variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeV2 variants - """ - - @staticmethod - def c(c) -> ReflectapiDemoTestsSerdeV2C: - """Creates the 'C' variant of the ReflectapiDemoTestsSerdeV2 enum.""" - return ReflectapiDemoTestsSerdeV2C(c=c) - - @staticmethod - def d(d) -> ReflectapiDemoTestsSerdeV2D: - """Creates the 'D' variant of the ReflectapiDemoTestsSerdeV2 enum.""" - return ReflectapiDemoTestsSerdeV2D(d=d) - - -class ReflectapiDemoTestsSerdeV1Factory: - """Factory class for creating ReflectapiDemoTestsSerdeV1 variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeV1 variants - """ - - @staticmethod - def a(a) -> ReflectapiDemoTestsSerdeV1A: - """Creates the 'A' variant of the ReflectapiDemoTestsSerdeV1 enum.""" - return ReflectapiDemoTestsSerdeV1A(a=a) - - @staticmethod - def b(b) -> ReflectapiDemoTestsSerdeV1B: - """Creates the 'B' variant of the ReflectapiDemoTestsSerdeV1 enum.""" - return ReflectapiDemoTestsSerdeV1B(b=b) - - -class ReflectapiDemoTestsSerdeTestFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTest variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTest variants - """ - - @staticmethod - def v1(field_0) -> ReflectapiDemoTestsSerdeTestV1: - """Creates the 'v1' variant of the ReflectapiDemoTestsSerdeTest enum.""" - return ReflectapiDemoTestsSerdeTestV1(field_0=field_0) - - @staticmethod - def v2(field_0) -> ReflectapiDemoTestsSerdeTestV2: - """Creates the 'v2' variant of the ReflectapiDemoTestsSerdeTest enum.""" - return ReflectapiDemoTestsSerdeTestV2(field_0=field_0) - - -# Testing utilities - - -def create_reflectapidemotestsserdetest_response( - value: ReflectapiDemoTestsSerdeTest, -) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTest.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdev1_response( - value: ReflectapiDemoTestsSerdeV1, -) -> ApiResponse[ReflectapiDemoTestsSerdeV1]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeV1.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdev2_response( - value: ReflectapiDemoTestsSerdeV2, -) -> ApiResponse[ReflectapiDemoTestsSerdeV2]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeV2.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums_minimal-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums_minimal-3.snap index 1af7dcb3..4236e107 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums_minimal-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums_minimal-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < Test > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums_minimal-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums_minimal-5.snap index 9240d30e..33e39df6 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums_minimal-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__nested_internally_tagged_enums_minimal-5.snap @@ -23,7 +23,21 @@ from pydantic import BaseModel, ConfigDict, Field, RootModel from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response + + +class ReflectapiDemoTestsSerdeTestV1(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + version: Literal["v1"] = Field(default="v1", description="Discriminator field") + value: reflectapi_demo.tests.serde.V1 = Field(description="Tuple variant value") + + +class ReflectapiDemoTestsSerdeTest(RootModel): + root: Annotated[ + Union[ReflectapiDemoTestsSerdeTestV1], Field(discriminator="version") + ] class ReflectapiDemoTestsSerdeV1A(BaseModel): @@ -31,7 +45,7 @@ class ReflectapiDemoTestsSerdeV1A(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["A"] = "A" + type: Literal["A"] = Field(default="A", description="Discriminator field") a: int @@ -39,19 +53,20 @@ class ReflectapiDemoTestsSerdeV1(RootModel): root: Annotated[Union[ReflectapiDemoTestsSerdeV1A], Field(discriminator="type")] -class ReflectapiDemoTestsSerdeTestV1(BaseModel): - """Generated data model.""" +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" - model_config = ConfigDict(extra="ignore", populate_by_name=True) + class tests: + """Namespace for tests types.""" - version: Literal["v1"] = "v1" - value: ReflectapiDemoTestsSerdeV1 + class serde: + """Namespace for serde types.""" - -class ReflectapiDemoTestsSerdeTest(RootModel): - root: Annotated[ - Union[ReflectapiDemoTestsSerdeTestV1], Field(discriminator="version") - ] + TestV1 = ReflectapiDemoTestsSerdeTestV1 + Test = ReflectapiDemoTestsSerdeTest + V1A = ReflectapiDemoTestsSerdeV1A + V1 = ReflectapiDemoTestsSerdeV1 class AsyncInoutClient: @@ -62,15 +77,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: + data: Optional[reflectapi_demo.tests.serde.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTest]: Response containing ReflectapiDemoTestsSerdeTest data + ApiResponse[reflectapi_demo.tests.serde.Test]: Response containing reflectapi_demo.tests.serde.Test data """ path = "/inout_test" @@ -80,7 +95,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTest, + response_model=reflectapi_demo.tests.serde.Test, ) @@ -105,15 +120,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: + data: Optional[reflectapi_demo.tests.serde.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTest]: Response containing ReflectapiDemoTestsSerdeTest data + ApiResponse[reflectapi_demo.tests.serde.Test]: Response containing reflectapi_demo.tests.serde.Test data """ path = "/inout_test" @@ -123,7 +138,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTest, + response_model=reflectapi_demo.tests.serde.Test, ) @@ -148,55 +163,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTest.model_rebuild() - ReflectapiDemoTestsSerdeV1.model_rebuild() + reflectapi_demo.tests.serde.Test.model_rebuild() + reflectapi_demo.tests.serde.V1.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeV1Factory: - """Factory class for creating ReflectapiDemoTestsSerdeV1 variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeV1 variants - """ - - @staticmethod - def a(a) -> ReflectapiDemoTestsSerdeV1A: - """Creates the 'A' variant of the ReflectapiDemoTestsSerdeV1 enum.""" - return ReflectapiDemoTestsSerdeV1A(a=a) - - -class ReflectapiDemoTestsSerdeTestFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTest variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTest variants - """ - - @staticmethod - def v1(field_0) -> ReflectapiDemoTestsSerdeTestV1: - """Creates the 'v1' variant of the ReflectapiDemoTestsSerdeTest enum.""" - return ReflectapiDemoTestsSerdeTestV1(field_0=field_0) - - -# Testing utilities - - -def create_reflectapidemotestsserdetest_response( - value: ReflectapiDemoTestsSerdeTest, -) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTest.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdev1_response( - value: ReflectapiDemoTestsSerdeV1, -) -> ApiResponse[ReflectapiDemoTestsSerdeV1]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeV1.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_adjacently_tagged-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_adjacently_tagged-3.snap index 2c081e62..27f114d5 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_adjacently_tagged-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_adjacently_tagged-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestNewtypeVariantsAdjacentlyTagged > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_adjacently_tagged-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_adjacently_tagged-5.snap index ad50f9d9..fc347cb7 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_adjacently_tagged-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_adjacently_tagged-5.snap @@ -17,13 +17,20 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import ( + BaseModel, + ConfigDict, + Field, + PrivateAttr, + RootModel, + model_serializer, + model_validator, +) # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTaggedIntVariant(BaseModel): @@ -131,6 +138,30 @@ class ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged( ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestNewtypeVariantsAdjacentlyTaggedIntVariant = ( + ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTaggedIntVariant + ) + TestNewtypeVariantsAdjacentlyTaggedStringVariant = ( + ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTaggedStringVariant + ) + TestNewtypeVariantsAdjacentlyTaggedBoolVariant = ( + ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTaggedBoolVariant + ) + TestNewtypeVariantsAdjacentlyTagged = ( + ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -140,16 +171,16 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged + reflectapi_demo.tests.serde.TestNewtypeVariantsAdjacentlyTagged ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged]: + ) -> ApiResponse[reflectapi_demo.tests.serde.TestNewtypeVariantsAdjacentlyTagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged]: Response containing ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged data + ApiResponse[reflectapi_demo.tests.serde.TestNewtypeVariantsAdjacentlyTagged]: Response containing reflectapi_demo.tests.serde.TestNewtypeVariantsAdjacentlyTagged data """ path = "/inout_test" @@ -159,7 +190,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged, + response_model=reflectapi_demo.tests.serde.TestNewtypeVariantsAdjacentlyTagged, ) @@ -185,16 +216,16 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged + reflectapi_demo.tests.serde.TestNewtypeVariantsAdjacentlyTagged ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged]: + ) -> ApiResponse[reflectapi_demo.tests.serde.TestNewtypeVariantsAdjacentlyTagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged]: Response containing ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged data + ApiResponse[reflectapi_demo.tests.serde.TestNewtypeVariantsAdjacentlyTagged]: Response containing reflectapi_demo.tests.serde.TestNewtypeVariantsAdjacentlyTagged data """ path = "/inout_test" @@ -204,7 +235,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged, + response_model=reflectapi_demo.tests.serde.TestNewtypeVariantsAdjacentlyTagged, ) @@ -229,66 +260,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged.model_rebuild() + reflectapi_demo.tests.serde.TestNewtypeVariantsAdjacentlyTagged.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTaggedFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged variants - """ - - @staticmethod - def int(field_0) -> ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged: - """Creates the 'int' variant of the ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged enum.""" - return ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged( - ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTaggedIntVariant( - field_0=field_0 - ) - ) - - @staticmethod - def string(field_0) -> ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged: - """Creates the 'string' variant of the ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged enum.""" - return ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged( - ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTaggedStringVariant( - field_0=field_0 - ) - ) - - @staticmethod - def bool(field_0) -> ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged: - """Creates the 'bool' variant of the ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged enum.""" - return ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged( - ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTaggedBoolVariant( - field_0=field_0 - ) - ) - - @staticmethod - def unit() -> ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged: - """Creates the 'unit' variant of the ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged enum.""" - return ( - ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged.model_validate( - {"t": "unit"} - ) - ) - - -# Testing utilities - - -def create_reflectapidemotestsserdetestnewtypevariantsadjacentlytagged_response( - value: ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestNewtypeVariantsAdjacentlyTagged.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_externally_tagged-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_externally_tagged-3.snap index 60928008..d2d52b1b 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_externally_tagged-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_externally_tagged-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestNewtypeVariantsExternallyTagged > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_externally_tagged-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_externally_tagged-5.snap index 3e171b8c..b4c7ea68 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_externally_tagged-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_externally_tagged-5.snap @@ -20,6 +20,7 @@ from typing import Annotated, Any, Generic, Optional, TypeVar, Union from pydantic import ( BaseModel, ConfigDict, + Field, PrivateAttr, RootModel, model_serializer, @@ -30,7 +31,6 @@ from pydantic import ( from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTaggedIntVariant(BaseModel): @@ -142,6 +142,30 @@ class ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged( ) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestNewtypeVariantsExternallyTaggedIntVariant = ( + ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTaggedIntVariant + ) + TestNewtypeVariantsExternallyTaggedStringVariant = ( + ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTaggedStringVariant + ) + TestNewtypeVariantsExternallyTaggedBoolVariant = ( + ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTaggedBoolVariant + ) + TestNewtypeVariantsExternallyTagged = ( + ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -151,16 +175,16 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged + reflectapi_demo.tests.serde.TestNewtypeVariantsExternallyTagged ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged]: + ) -> ApiResponse[reflectapi_demo.tests.serde.TestNewtypeVariantsExternallyTagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged]: Response containing ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged data + ApiResponse[reflectapi_demo.tests.serde.TestNewtypeVariantsExternallyTagged]: Response containing reflectapi_demo.tests.serde.TestNewtypeVariantsExternallyTagged data """ path = "/inout_test" @@ -170,7 +194,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged, + response_model=reflectapi_demo.tests.serde.TestNewtypeVariantsExternallyTagged, ) @@ -196,16 +220,16 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged + reflectapi_demo.tests.serde.TestNewtypeVariantsExternallyTagged ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged]: + ) -> ApiResponse[reflectapi_demo.tests.serde.TestNewtypeVariantsExternallyTagged]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged]: Response containing ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged data + ApiResponse[reflectapi_demo.tests.serde.TestNewtypeVariantsExternallyTagged]: Response containing reflectapi_demo.tests.serde.TestNewtypeVariantsExternallyTagged data """ path = "/inout_test" @@ -215,7 +239,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged, + response_model=reflectapi_demo.tests.serde.TestNewtypeVariantsExternallyTagged, ) @@ -240,62 +264,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged.model_rebuild() + reflectapi_demo.tests.serde.TestNewtypeVariantsExternallyTagged.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTaggedFactory: - """Factory class for creating ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged variants - """ - - @staticmethod - def int(field_0) -> ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged: - """Creates the 'int' variant of the ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged enum.""" - return ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged( - ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTaggedIntVariant( - field_0=field_0 - ) - ) - - @staticmethod - def string(field_0) -> ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged: - """Creates the 'string' variant of the ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged enum.""" - return ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged( - ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTaggedStringVariant( - field_0=field_0 - ) - ) - - @staticmethod - def bool(field_0) -> ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged: - """Creates the 'bool' variant of the ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged enum.""" - return ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged( - ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTaggedBoolVariant( - field_0=field_0 - ) - ) - - @staticmethod - def unit() -> ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged: - """Creates the 'unit' variant of the ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged enum.""" - return ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged("unit") - - -# Testing utilities - - -def create_reflectapidemotestsserdetestnewtypevariantsexternallytagged_response( - value: ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestNewtypeVariantsExternallyTagged.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_internally_tagged-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_internally_tagged-3.snap index b0b4da84..d2875d4a 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_internally_tagged-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_internally_tagged-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < Enum > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_internally_tagged-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_internally_tagged-5.snap index 53304f7f..4f2eb66a 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_internally_tagged-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__newtype_variants_internally_tagged-5.snap @@ -23,25 +23,24 @@ from pydantic import BaseModel, ConfigDict, Field, RootModel from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response -class ReflectapiDemoTestsSerdeStrukt2(BaseModel): +class ReflectapiDemoTestsSerdeStrukt1(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - c: int - d: int + a: int + b: int -class ReflectapiDemoTestsSerdeStrukt1(BaseModel): +class ReflectapiDemoTestsSerdeStrukt2(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - a: int - b: int + c: int + d: int class ReflectapiDemoTestsSerdeEnumA(BaseModel): @@ -49,7 +48,7 @@ class ReflectapiDemoTestsSerdeEnumA(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["a"] = "a" + type: Literal["a"] = Field(default="a", description="Discriminator field") a: int b: int @@ -59,7 +58,7 @@ class ReflectapiDemoTestsSerdeEnumB(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - type: Literal["b"] = "b" + type: Literal["b"] = Field(default="b", description="Discriminator field") c: int d: int @@ -71,6 +70,23 @@ class ReflectapiDemoTestsSerdeEnum(RootModel): ] +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Strukt1 = ReflectapiDemoTestsSerdeStrukt1 + Strukt2 = ReflectapiDemoTestsSerdeStrukt2 + EnumA = ReflectapiDemoTestsSerdeEnumA + EnumB = ReflectapiDemoTestsSerdeEnumB + Enum = ReflectapiDemoTestsSerdeEnum + + class AsyncInoutClient: """Async client for inout operations.""" @@ -79,15 +95,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeEnum] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeEnum]: + data: Optional[reflectapi_demo.tests.serde.Enum] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Enum]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeEnum]: Response containing ReflectapiDemoTestsSerdeEnum data + ApiResponse[reflectapi_demo.tests.serde.Enum]: Response containing reflectapi_demo.tests.serde.Enum data """ path = "/inout_test" @@ -97,7 +113,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeEnum, + response_model=reflectapi_demo.tests.serde.Enum, ) @@ -122,15 +138,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeEnum] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeEnum]: + data: Optional[reflectapi_demo.tests.serde.Enum] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Enum]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeEnum]: Response containing ReflectapiDemoTestsSerdeEnum data + ApiResponse[reflectapi_demo.tests.serde.Enum]: Response containing reflectapi_demo.tests.serde.Enum data """ path = "/inout_test" @@ -140,7 +156,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeEnum, + response_model=reflectapi_demo.tests.serde.Enum, ) @@ -165,56 +181,9 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeEnum.model_rebuild() - ReflectapiDemoTestsSerdeStrukt1.model_rebuild() - ReflectapiDemoTestsSerdeStrukt2.model_rebuild() + reflectapi_demo.tests.serde.Enum.model_rebuild() + reflectapi_demo.tests.serde.Strukt1.model_rebuild() + reflectapi_demo.tests.serde.Strukt2.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - - -# Factory classes (generated after model rebuild to avoid forward references) -class ReflectapiDemoTestsSerdeEnumFactory: - """Factory class for creating ReflectapiDemoTestsSerdeEnum variants with ergonomic syntax. - - ReflectapiDemoTestsSerdeEnum variants - """ - - @staticmethod - def a(field_0) -> ReflectapiDemoTestsSerdeEnumA: - """Creates the 'a' variant of the ReflectapiDemoTestsSerdeEnum enum.""" - return ReflectapiDemoTestsSerdeEnumA(field_0=field_0) - - @staticmethod - def b(field_0) -> ReflectapiDemoTestsSerdeEnumB: - """Creates the 'b' variant of the ReflectapiDemoTestsSerdeEnum enum.""" - return ReflectapiDemoTestsSerdeEnumB(field_0=field_0) - - -# Testing utilities - - -def create_reflectapidemotestsserdeenum_response( - value: ReflectapiDemoTestsSerdeEnum, -) -> ApiResponse[ReflectapiDemoTestsSerdeEnum]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeEnum.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdestrukt1_response( - value: ReflectapiDemoTestsSerdeStrukt1, -) -> ApiResponse[ReflectapiDemoTestsSerdeStrukt1]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeStrukt1.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdestrukt2_response( - value: ReflectapiDemoTestsSerdeStrukt2, -) -> ApiResponse[ReflectapiDemoTestsSerdeStrukt2]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeStrukt2.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__option_of_option-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__option_of_option-2.snap new file mode 100644 index 00000000..9368a30b --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__option_of_option-2.snap @@ -0,0 +1,61 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Nested > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Nested, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export interface Nested { + value: (string | null) | null; + } + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Nested, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Nested, + {}, + reflectapi_demo.tests.serde.Nested, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__option_of_option-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__option_of_option-3.snap new file mode 100644 index 00000000..d0b3c31c --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__option_of_option-3.snap @@ -0,0 +1,68 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Nested > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Nested, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Nested, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Nested { + pub value: std::option::Option>, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__option_of_option-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__option_of_option-4.snap new file mode 100644 index 00000000..77c11857 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__option_of_option-4.snap @@ -0,0 +1,78 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Nested" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Nested" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.Nested": { + "type": "object", + "title": "reflectapi_demo.tests.serde.Nested", + "required": [ + "value" + ], + "properties": { + "value": { + "oneOf": [ + { + "description": "Null", + "type": "null" + }, + { + "oneOf": [ + { + "description": "Null", + "type": "null" + }, + { + "$ref": "#/components/schemas/std.string.String" + } + ] + } + ] + } + } + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__option_of_option-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__option_of_option-5.snap new file mode 100644 index 00000000..d64ef1b7 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__option_of_option-5.snap @@ -0,0 +1,146 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Nested > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from enum import Enum +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeNested(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + value: str | None | None = None + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Nested = ReflectapiDemoTestsSerdeNested + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Nested] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Nested]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Nested]: Response containing reflectapi_demo.tests.serde.Nested data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Nested, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Nested] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Nested]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Nested]: Response containing reflectapi_demo.tests.serde.Nested data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Nested, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Nested.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__option_of_option.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__option_of_option.snap new file mode 100644 index 00000000..a523a9fb --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__option_of_option.snap @@ -0,0 +1,167 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Nested" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Nested" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Nested", + "fields": { + "named": [ + { + "name": "value", + "type": { + "name": "std::option::Option", + "arguments": [ + { + "name": "std::option::Option", + "arguments": [ + { + "name": "std::string::String" + } + ] + } + ] + }, + "required": true + } + ] + } + }, + { + "kind": "enum", + "name": "std::option::Option", + "description": "Optional nullable type", + "parameters": [ + { + "name": "T" + } + ], + "representation": "none", + "variants": [ + { + "name": "None", + "description": "The value is not provided, i.e. null", + "fields": "none" + }, + { + "name": "Some", + "description": "The value is provided and set to some value", + "fields": { + "unnamed": [ + { + "name": "0", + "type": { + "name": "T" + } + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Nested", + "fields": { + "named": [ + { + "name": "value", + "type": { + "name": "std::option::Option", + "arguments": [ + { + "name": "std::option::Option", + "arguments": [ + { + "name": "std::string::String" + } + ] + } + ] + }, + "required": true + } + ] + } + }, + { + "kind": "enum", + "name": "std::option::Option", + "description": "Optional nullable type", + "parameters": [ + { + "name": "T" + } + ], + "representation": "none", + "variants": [ + { + "name": "None", + "description": "The value is not provided, i.e. null", + "fields": "none" + }, + { + "name": "Some", + "description": "The value is provided and set to some value", + "fields": { + "unnamed": [ + { + "name": "0", + "type": { + "name": "T" + } + } + ] + } + } + ] + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__self_referential_struct-2.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__self_referential_struct-2.snap new file mode 100644 index 00000000..c422df9c --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__self_referential_struct-2.snap @@ -0,0 +1,62 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_typescript_code :: < Category > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +export function client(base: string | Client): __definition.Interface { + return __implementation.__client(base); +} + +export namespace __definition { + export interface Interface { + inout_test: ( + input: reflectapi_demo.tests.serde.Category, + headers: {}, + options?: RequestOptions, + ) => AsyncResult; + } +} +export namespace reflectapi { + /** + * Struct object with no fields + */ + export interface Empty {} + + /** + * Error object which is expected to be never returned + */ + export interface Infallible {} +} + +export namespace reflectapi_demo { + export namespace tests { + export namespace serde { + export interface Category { + name: string; + subcategories: Array; + } + } + } +} + +namespace __implementation { + + function inout_test(client: Client) { + return ( + input: reflectapi_demo.tests.serde.Category, + headers: {}, + options?: RequestOptions, + ) => + __request< + reflectapi_demo.tests.serde.Category, + {}, + reflectapi_demo.tests.serde.Category, + {} + >(client, "/inout_test", input, headers, options); + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__self_referential_struct-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__self_referential_struct-3.snap new file mode 100644 index 00000000..f280e0cf --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__self_referential_struct-3.snap @@ -0,0 +1,70 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_rust_code :: < Category > ()" +--- +// DO NOT MODIFY THIS FILE MANUALLY +// This file was generated by reflectapi-cli +// +// Schema name: +// + +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +pub use interface::Interface; +pub use reflectapi::rt::*; + +pub mod interface { + + #[derive(Debug)] + pub struct Interface { + client: C, + base_url: reflectapi::rt::Url, + } + + impl Interface { + pub fn try_new( + client: C, + base_url: reflectapi::rt::Url, + ) -> std::result::Result { + if base_url.cannot_be_a_base() { + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + } + + Ok(Self { client, base_url }) + } + pub async fn inout_test( + &self, + input: super::types::reflectapi_demo::tests::serde::Category, + headers: reflectapi::Empty, + ) -> Result< + super::types::reflectapi_demo::tests::serde::Category, + reflectapi::rt::Error, + > { + reflectapi::rt::__request_impl( + &self.client, + self.base_url + .join("/inout_test") + .expect("checked base_url already and path is valid"), + input, + headers, + ) + .await + } + } +} +pub mod types { + pub mod reflectapi_demo { + pub mod tests { + pub mod serde { + + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct Category { + pub name: std::string::String, + pub subcategories: + std::vec::Vec, + } + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__self_referential_struct-4.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__self_referential_struct-4.snap new file mode 100644 index 00000000..0764fdfa --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__self_referential_struct-4.snap @@ -0,0 +1,70 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "reflectapi :: codegen :: openapi :: Spec :: from(& schema)" +--- +{ + "openapi": "3.1.0", + "info": { + "title": "", + "description": "", + "version": "1.0.0" + }, + "paths": { + "/inout_test": { + "description": "", + "post": { + "operationId": "inout_test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Category" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "200 OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Category" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "reflectapi_demo.tests.serde.Category": { + "type": "object", + "title": "reflectapi_demo.tests.serde.Category", + "required": [ + "name", + "subcategories" + ], + "properties": { + "name": { + "$ref": "#/components/schemas/std.string.String" + }, + "subcategories": { + "description": "Expandable array type", + "type": "array", + "items": { + "$ref": "#/components/schemas/reflectapi_demo.tests.serde.Category" + } + } + } + }, + "std.string.String": { + "description": "UTF-8 encoded string", + "type": "string" + } + } + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__self_referential_struct-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__self_referential_struct-5.snap new file mode 100644 index 00000000..61120080 --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__self_referential_struct-5.snap @@ -0,0 +1,146 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: "super :: into_python_code :: < Category > ()" +--- +""" +Generated Python client for api_client. + +DO NOT MODIFY THIS FILE MANUALLY. +This file is automatically generated by ReflectAPI. +""" + +from __future__ import annotations + + +# Standard library imports +from typing import Annotated, Any, Generic, Optional, TypeVar, Union + +# Third-party imports +from pydantic import BaseModel, ConfigDict, Field + +# Runtime imports +from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse +from reflectapi_runtime import ReflectapiEmpty +from reflectapi_runtime import ReflectapiInfallible + + +class ReflectapiDemoTestsSerdeCategory(BaseModel): + """Generated data model.""" + + model_config = ConfigDict(extra="ignore", populate_by_name=True) + + name: str + subcategories: list[reflectapi_demo.tests.serde.Category] + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Category = ReflectapiDemoTestsSerdeCategory + + +class AsyncInoutClient: + """Async client for inout operations.""" + + def __init__(self, client: AsyncClientBase) -> None: + self._client = client + + async def test( + self, + data: Optional[reflectapi_demo.tests.serde.Category] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Category]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Category]: Response containing reflectapi_demo.tests.serde.Category data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return await self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Category, + ) + + +class AsyncClient(AsyncClientBase): + """Async client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = AsyncInoutClient(self) + + +class InoutClient: + """Synchronous client for inout operations.""" + + def __init__(self, client: ClientBase) -> None: + self._client = client + + def test( + self, + data: Optional[reflectapi_demo.tests.serde.Category] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Category]: + """ + + Args: + data: Request data for the test operation. + + Returns: + ApiResponse[reflectapi_demo.tests.serde.Category]: Response containing reflectapi_demo.tests.serde.Category data + """ + path = "/inout_test" + + params: dict[str, Any] = {} + return self._client._make_request( + "POST", + path, + params=params if params else None, + json_model=data, + response_model=reflectapi_demo.tests.serde.Category, + ) + + +class Client(ClientBase): + """Synchronous client for the API.""" + + def __init__( + self, + base_url: str, + **kwargs: Any, + ) -> None: + super().__init__(base_url, **kwargs) + + self.inout = InoutClient(self) + + +# External type definitions +StdNumNonZeroU32 = Annotated[int, "Rust NonZero u32 type"] +StdNumNonZeroU64 = Annotated[int, "Rust NonZero u64 type"] +StdNumNonZeroI32 = Annotated[int, "Rust NonZero i32 type"] +StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] + +# Rebuild models to resolve forward references +try: + reflectapi_demo.tests.serde.Category.model_rebuild() +except AttributeError: + # Some types may not have model_rebuild method + pass diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__self_referential_struct.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__self_referential_struct.snap new file mode 100644 index 00000000..781a1e0b --- /dev/null +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__self_referential_struct.snap @@ -0,0 +1,127 @@ +--- +source: reflectapi-demo/src/tests/serde.rs +expression: schema +--- +{ + "name": "", + "functions": [ + { + "name": "inout_test", + "path": "", + "input_type": { + "name": "reflectapi_demo::tests::serde::Category" + }, + "output_type": { + "name": "reflectapi_demo::tests::serde::Category" + }, + "serialization": [ + "json", + "msgpack" + ] + } + ], + "input_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Empty", + "description": "Struct object with no fields", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Category", + "fields": { + "named": [ + { + "name": "name", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "subcategories", + "type": { + "name": "std::vec::Vec", + "arguments": [ + { + "name": "reflectapi_demo::tests::serde::Category" + } + ] + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "std::vec::Vec", + "description": "Expandable array type", + "parameters": [ + { + "name": "T" + } + ] + } + ] + }, + "output_types": { + "types": [ + { + "kind": "struct", + "name": "reflectapi::Infallible", + "description": "Error object which is expected to be never returned", + "fields": "none" + }, + { + "kind": "struct", + "name": "reflectapi_demo::tests::serde::Category", + "fields": { + "named": [ + { + "name": "name", + "type": { + "name": "std::string::String" + }, + "required": true + }, + { + "name": "subcategories", + "type": { + "name": "std::vec::Vec", + "arguments": [ + { + "name": "reflectapi_demo::tests::serde::Category" + } + ] + }, + "required": true + } + ] + } + }, + { + "kind": "primitive", + "name": "std::string::String", + "description": "UTF-8 encoded string" + }, + { + "kind": "primitive", + "name": "std::vec::Vec", + "description": "Expandable array type", + "parameters": [ + { + "name": "T" + } + ] + } + ] + } +} diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_from-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_from-3.snap index cf1fc631..04b39467 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_from-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_from-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructFromProxy > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_from-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_from-5.snap index 15a113de..a09ea2e9 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_from-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_from-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestStructFrom(BaseModel): @@ -41,6 +40,20 @@ class ReflectapiDemoTestsSerdeTestStructFromProxy(BaseModel): f: int +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestStructFrom = ReflectapiDemoTestsSerdeTestStructFrom + TestStructFromProxy = ReflectapiDemoTestsSerdeTestStructFromProxy + + class AsyncInoutClient: """Async client for inout operations.""" @@ -49,15 +62,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructFrom] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructFromProxy]: + data: Optional[reflectapi_demo.tests.serde.TestStructFrom] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructFromProxy]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructFromProxy]: Response containing ReflectapiDemoTestsSerdeTestStructFromProxy data + ApiResponse[reflectapi_demo.tests.serde.TestStructFromProxy]: Response containing reflectapi_demo.tests.serde.TestStructFromProxy data """ path = "/inout_test" @@ -67,7 +80,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructFromProxy, + response_model=reflectapi_demo.tests.serde.TestStructFromProxy, ) @@ -92,15 +105,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructFrom] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructFromProxy]: + data: Optional[reflectapi_demo.tests.serde.TestStructFrom] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructFromProxy]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructFromProxy]: Response containing ReflectapiDemoTestsSerdeTestStructFromProxy data + ApiResponse[reflectapi_demo.tests.serde.TestStructFromProxy]: Response containing reflectapi_demo.tests.serde.TestStructFromProxy data """ path = "/inout_test" @@ -110,7 +123,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructFromProxy, + response_model=reflectapi_demo.tests.serde.TestStructFromProxy, ) @@ -135,31 +148,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestStructFrom.model_rebuild() - ReflectapiDemoTestsSerdeTestStructFromProxy.model_rebuild() + reflectapi_demo.tests.serde.TestStructFrom.model_rebuild() + reflectapi_demo.tests.serde.TestStructFromProxy.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeteststructfrom_response( - value: ReflectapiDemoTestsSerdeTestStructFrom, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructFrom]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructFrom.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeteststructfromproxy_response( - value: ReflectapiDemoTestsSerdeTestStructFromProxy, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructFromProxy]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructFromProxy.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_into-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_into-3.snap index 64fd50ba..30d3eab4 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_into-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_into-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructIntoProxy > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_into-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_into-5.snap index aaa68672..662f54ac 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_into-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_into-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestStructInto(BaseModel): @@ -41,6 +40,20 @@ class ReflectapiDemoTestsSerdeTestStructIntoProxy(BaseModel): f: int +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestStructInto = ReflectapiDemoTestsSerdeTestStructInto + TestStructIntoProxy = ReflectapiDemoTestsSerdeTestStructIntoProxy + + class AsyncInoutClient: """Async client for inout operations.""" @@ -49,15 +62,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructIntoProxy] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructInto]: + data: Optional[reflectapi_demo.tests.serde.TestStructIntoProxy] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructInto]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructInto]: Response containing ReflectapiDemoTestsSerdeTestStructInto data + ApiResponse[reflectapi_demo.tests.serde.TestStructInto]: Response containing reflectapi_demo.tests.serde.TestStructInto data """ path = "/inout_test" @@ -67,7 +80,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructInto, + response_model=reflectapi_demo.tests.serde.TestStructInto, ) @@ -92,15 +105,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructIntoProxy] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructInto]: + data: Optional[reflectapi_demo.tests.serde.TestStructIntoProxy] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructInto]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructInto]: Response containing ReflectapiDemoTestsSerdeTestStructInto data + ApiResponse[reflectapi_demo.tests.serde.TestStructInto]: Response containing reflectapi_demo.tests.serde.TestStructInto data """ path = "/inout_test" @@ -110,7 +123,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructInto, + response_model=reflectapi_demo.tests.serde.TestStructInto, ) @@ -135,31 +148,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestStructInto.model_rebuild() - ReflectapiDemoTestsSerdeTestStructIntoProxy.model_rebuild() + reflectapi_demo.tests.serde.TestStructInto.model_rebuild() + reflectapi_demo.tests.serde.TestStructIntoProxy.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeteststructinto_response( - value: ReflectapiDemoTestsSerdeTestStructInto, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructInto]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructInto.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeteststructintoproxy_response( - value: ReflectapiDemoTestsSerdeTestStructIntoProxy, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructIntoProxy]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructIntoProxy.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename-3.snap index 33a55555..bf84bdb5 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructRename > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename-5.snap index 10887da7..cbc43008 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeMyStruct(BaseModel): @@ -31,6 +30,19 @@ class ReflectapiDemoTestsSerdeMyStruct(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + MyStruct = ReflectapiDemoTestsSerdeMyStruct + + class AsyncInoutClient: """Async client for inout operations.""" @@ -39,15 +51,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeMyStruct] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeMyStruct]: + data: Optional[reflectapi_demo.tests.serde.MyStruct] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.MyStruct]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeMyStruct]: Response containing ReflectapiDemoTestsSerdeMyStruct data + ApiResponse[reflectapi_demo.tests.serde.MyStruct]: Response containing reflectapi_demo.tests.serde.MyStruct data """ path = "/inout_test" @@ -57,7 +69,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeMyStruct, + response_model=reflectapi_demo.tests.serde.MyStruct, ) @@ -82,15 +94,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeMyStruct] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeMyStruct]: + data: Optional[reflectapi_demo.tests.serde.MyStruct] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.MyStruct]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeMyStruct]: Response containing ReflectapiDemoTestsSerdeMyStruct data + ApiResponse[reflectapi_demo.tests.serde.MyStruct]: Response containing reflectapi_demo.tests.serde.MyStruct data """ path = "/inout_test" @@ -100,7 +112,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeMyStruct, + response_model=reflectapi_demo.tests.serde.MyStruct, ) @@ -125,23 +137,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeMyStruct.model_rebuild() + reflectapi_demo.tests.serde.MyStruct.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdemystruct_response( - value: ReflectapiDemoTestsSerdeMyStruct, -) -> ApiResponse[ReflectapiDemoTestsSerdeMyStruct]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeMyStruct.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all-3.snap index 24146efe..9629ca0a 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructRenameAll > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all-5.snap index 93a1ea13..f6c0a618 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestStructRenameAll(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsSerdeTestStructRenameAll(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - field_name: int + field_name: int = Field( + serialization_alias="fieldName", validation_alias="fieldName" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestStructRenameAll = ReflectapiDemoTestsSerdeTestStructRenameAll class AsyncInoutClient: @@ -41,15 +55,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructRenameAll] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructRenameAll]: + data: Optional[reflectapi_demo.tests.serde.TestStructRenameAll] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructRenameAll]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructRenameAll]: Response containing ReflectapiDemoTestsSerdeTestStructRenameAll data + ApiResponse[reflectapi_demo.tests.serde.TestStructRenameAll]: Response containing reflectapi_demo.tests.serde.TestStructRenameAll data """ path = "/inout_test" @@ -59,7 +73,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructRenameAll, + response_model=reflectapi_demo.tests.serde.TestStructRenameAll, ) @@ -84,15 +98,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructRenameAll] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructRenameAll]: + data: Optional[reflectapi_demo.tests.serde.TestStructRenameAll] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructRenameAll]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructRenameAll]: Response containing ReflectapiDemoTestsSerdeTestStructRenameAll data + ApiResponse[reflectapi_demo.tests.serde.TestStructRenameAll]: Response containing reflectapi_demo.tests.serde.TestStructRenameAll data """ path = "/inout_test" @@ -102,7 +116,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructRenameAll, + response_model=reflectapi_demo.tests.serde.TestStructRenameAll, ) @@ -127,23 +141,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestStructRenameAll.model_rebuild() + reflectapi_demo.tests.serde.TestStructRenameAll.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeteststructrenameall_response( - value: ReflectapiDemoTestsSerdeTestStructRenameAll, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructRenameAll]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructRenameAll.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_differently-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_differently-3.snap index c8b79b27..b675e3d5 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_differently-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_differently-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructRenameAllDifferently > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_differently-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_differently-5.snap index a6f28260..8f0a3619 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_differently-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_differently-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeInputTestStructRenameAllDifferently(BaseModel): @@ -38,7 +37,34 @@ class ReflectapiDemoTestsSerdeOutputTestStructRenameAllDifferently(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - field_name: int + field_name: int = Field( + serialization_alias="fieldName", validation_alias="fieldName" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + class input: + """Namespace for input types.""" + + TestStructRenameAllDifferently = ( + ReflectapiDemoTestsSerdeInputTestStructRenameAllDifferently + ) + + class output: + """Namespace for output types.""" + + TestStructRenameAllDifferently = ( + ReflectapiDemoTestsSerdeOutputTestStructRenameAllDifferently + ) class AsyncInoutClient: @@ -50,16 +76,16 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsSerdeInputTestStructRenameAllDifferently + reflectapi_demo.tests.serde.input.TestStructRenameAllDifferently ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructRenameAllDifferently]: + ) -> ApiResponse[reflectapi_demo.tests.serde.output.TestStructRenameAllDifferently]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructRenameAllDifferently]: Response containing ReflectapiDemoTestsSerdeOutputTestStructRenameAllDifferently data + ApiResponse[reflectapi_demo.tests.serde.output.TestStructRenameAllDifferently]: Response containing reflectapi_demo.tests.serde.output.TestStructRenameAllDifferently data """ path = "/inout_test" @@ -69,7 +95,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestStructRenameAllDifferently, + response_model=reflectapi_demo.tests.serde.output.TestStructRenameAllDifferently, ) @@ -95,16 +121,16 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsSerdeInputTestStructRenameAllDifferently + reflectapi_demo.tests.serde.input.TestStructRenameAllDifferently ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructRenameAllDifferently]: + ) -> ApiResponse[reflectapi_demo.tests.serde.output.TestStructRenameAllDifferently]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructRenameAllDifferently]: Response containing ReflectapiDemoTestsSerdeOutputTestStructRenameAllDifferently data + ApiResponse[reflectapi_demo.tests.serde.output.TestStructRenameAllDifferently]: Response containing reflectapi_demo.tests.serde.output.TestStructRenameAllDifferently data """ path = "/inout_test" @@ -114,7 +140,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestStructRenameAllDifferently, + response_model=reflectapi_demo.tests.serde.output.TestStructRenameAllDifferently, ) @@ -139,31 +165,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeInputTestStructRenameAllDifferently.model_rebuild() - ReflectapiDemoTestsSerdeOutputTestStructRenameAllDifferently.model_rebuild() + reflectapi_demo.tests.serde.input.TestStructRenameAllDifferently.model_rebuild() + reflectapi_demo.tests.serde.output.TestStructRenameAllDifferently.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeinputteststructrenamealldifferently_response( - value: ReflectapiDemoTestsSerdeInputTestStructRenameAllDifferently, -) -> ApiResponse[ReflectapiDemoTestsSerdeInputTestStructRenameAllDifferently]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeInputTestStructRenameAllDifferently.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeoutputteststructrenamealldifferently_response( - value: ReflectapiDemoTestsSerdeOutputTestStructRenameAllDifferently, -) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructRenameAllDifferently]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeOutputTestStructRenameAllDifferently.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_pascal_case-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_pascal_case-3.snap index e1026faa..23146eb9 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_pascal_case-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_pascal_case-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructRenameAllPascalCase > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_pascal_case-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_pascal_case-5.snap index 3aba983e..a4cd3aa8 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_pascal_case-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_all_pascal_case-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase(BaseModel): @@ -30,7 +29,24 @@ class ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - field_name: int + field_name: int = Field( + serialization_alias="FieldName", validation_alias="FieldName" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestStructRenameAllPascalCase = ( + ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase + ) class AsyncInoutClient: @@ -41,15 +57,17 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase]: + data: Optional[ + reflectapi_demo.tests.serde.TestStructRenameAllPascalCase + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructRenameAllPascalCase]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase]: Response containing ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase data + ApiResponse[reflectapi_demo.tests.serde.TestStructRenameAllPascalCase]: Response containing reflectapi_demo.tests.serde.TestStructRenameAllPascalCase data """ path = "/inout_test" @@ -59,7 +77,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase, + response_model=reflectapi_demo.tests.serde.TestStructRenameAllPascalCase, ) @@ -84,15 +102,17 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase]: + data: Optional[ + reflectapi_demo.tests.serde.TestStructRenameAllPascalCase + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructRenameAllPascalCase]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase]: Response containing ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase data + ApiResponse[reflectapi_demo.tests.serde.TestStructRenameAllPascalCase]: Response containing reflectapi_demo.tests.serde.TestStructRenameAllPascalCase data """ path = "/inout_test" @@ -102,7 +122,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase, + response_model=reflectapi_demo.tests.serde.TestStructRenameAllPascalCase, ) @@ -127,23 +147,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase.model_rebuild() + reflectapi_demo.tests.serde.TestStructRenameAllPascalCase.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeteststructrenameallpascalcase_response( - value: ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructRenameAllPascalCase.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_differently-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_differently-3.snap index a2bb77ce..a3093137 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_differently-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_differently-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructRenameDifferently > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_differently-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_differently-5.snap index 4011c0f4..73e2d3bd 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_differently-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_differently-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeMyStructInput(BaseModel): @@ -37,6 +36,20 @@ class ReflectapiDemoTestsSerdeMyStructOutput(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + MyStructInput = ReflectapiDemoTestsSerdeMyStructInput + MyStructOutput = ReflectapiDemoTestsSerdeMyStructOutput + + class AsyncInoutClient: """Async client for inout operations.""" @@ -45,15 +58,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeMyStructInput] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeMyStructOutput]: + data: Optional[reflectapi_demo.tests.serde.MyStructInput] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.MyStructOutput]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeMyStructOutput]: Response containing ReflectapiDemoTestsSerdeMyStructOutput data + ApiResponse[reflectapi_demo.tests.serde.MyStructOutput]: Response containing reflectapi_demo.tests.serde.MyStructOutput data """ path = "/inout_test" @@ -63,7 +76,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeMyStructOutput, + response_model=reflectapi_demo.tests.serde.MyStructOutput, ) @@ -88,15 +101,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeMyStructInput] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeMyStructOutput]: + data: Optional[reflectapi_demo.tests.serde.MyStructInput] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.MyStructOutput]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeMyStructOutput]: Response containing ReflectapiDemoTestsSerdeMyStructOutput data + ApiResponse[reflectapi_demo.tests.serde.MyStructOutput]: Response containing reflectapi_demo.tests.serde.MyStructOutput data """ path = "/inout_test" @@ -106,7 +119,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeMyStructOutput, + response_model=reflectapi_demo.tests.serde.MyStructOutput, ) @@ -131,31 +144,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeMyStructInput.model_rebuild() - ReflectapiDemoTestsSerdeMyStructOutput.model_rebuild() + reflectapi_demo.tests.serde.MyStructInput.model_rebuild() + reflectapi_demo.tests.serde.MyStructOutput.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdemystructinput_response( - value: ReflectapiDemoTestsSerdeMyStructInput, -) -> ApiResponse[ReflectapiDemoTestsSerdeMyStructInput]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeMyStructInput.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdemystructoutput_response( - value: ReflectapiDemoTestsSerdeMyStructOutput, -) -> ApiResponse[ReflectapiDemoTestsSerdeMyStructOutput]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeMyStructOutput.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_field-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_field-3.snap index 8d974921..04baa8d8 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_field-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_field-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructRenameField > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_field-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_field-5.snap index b54d1823..eaa742ed 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_field-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_rename_field-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeInputTestStructRenameField(BaseModel): @@ -30,7 +29,9 @@ class ReflectapiDemoTestsSerdeInputTestStructRenameField(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - field_name: int + field_name: int = Field( + serialization_alias="fieldName", validation_alias="fieldName" + ) class ReflectapiDemoTestsSerdeOutputTestStructRenameField(BaseModel): @@ -41,6 +42,31 @@ class ReflectapiDemoTestsSerdeOutputTestStructRenameField(BaseModel): field_name: int +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + class input: + """Namespace for input types.""" + + TestStructRenameField = ( + ReflectapiDemoTestsSerdeInputTestStructRenameField + ) + + class output: + """Namespace for output types.""" + + TestStructRenameField = ( + ReflectapiDemoTestsSerdeOutputTestStructRenameField + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -49,15 +75,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeInputTestStructRenameField] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructRenameField]: + data: Optional[reflectapi_demo.tests.serde.input.TestStructRenameField] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.output.TestStructRenameField]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructRenameField]: Response containing ReflectapiDemoTestsSerdeOutputTestStructRenameField data + ApiResponse[reflectapi_demo.tests.serde.output.TestStructRenameField]: Response containing reflectapi_demo.tests.serde.output.TestStructRenameField data """ path = "/inout_test" @@ -67,7 +93,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestStructRenameField, + response_model=reflectapi_demo.tests.serde.output.TestStructRenameField, ) @@ -92,15 +118,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeInputTestStructRenameField] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructRenameField]: + data: Optional[reflectapi_demo.tests.serde.input.TestStructRenameField] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.output.TestStructRenameField]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructRenameField]: Response containing ReflectapiDemoTestsSerdeOutputTestStructRenameField data + ApiResponse[reflectapi_demo.tests.serde.output.TestStructRenameField]: Response containing reflectapi_demo.tests.serde.output.TestStructRenameField data """ path = "/inout_test" @@ -110,7 +136,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestStructRenameField, + response_model=reflectapi_demo.tests.serde.output.TestStructRenameField, ) @@ -135,31 +161,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeInputTestStructRenameField.model_rebuild() - ReflectapiDemoTestsSerdeOutputTestStructRenameField.model_rebuild() + reflectapi_demo.tests.serde.input.TestStructRenameField.model_rebuild() + reflectapi_demo.tests.serde.output.TestStructRenameField.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeinputteststructrenamefield_response( - value: ReflectapiDemoTestsSerdeInputTestStructRenameField, -) -> ApiResponse[ReflectapiDemoTestsSerdeInputTestStructRenameField]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeInputTestStructRenameField.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeoutputteststructrenamefield_response( - value: ReflectapiDemoTestsSerdeOutputTestStructRenameField, -) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructRenameField]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeOutputTestStructRenameField.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_repr_transparent_generic_inner_type-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_repr_transparent_generic_inner_type-3.snap index 360cfdd5..8ee04f83 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_repr_transparent_generic_inner_type-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_repr_transparent_generic_inner_type-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < Test > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_repr_transparent_generic_inner_type-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_repr_transparent_generic_inner_type-5.snap index cf21d9c1..e54e0b3b 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_repr_transparent_generic_inner_type-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_repr_transparent_generic_inner_type-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTest(BaseModel): @@ -33,6 +32,19 @@ class ReflectapiDemoTestsSerdeTest(BaseModel): inner: bytes +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + Test = ReflectapiDemoTestsSerdeTest + + class AsyncInoutClient: """Async client for inout operations.""" @@ -41,15 +53,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: + data: Optional[reflectapi_demo.tests.serde.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTest]: Response containing ReflectapiDemoTestsSerdeTest data + ApiResponse[reflectapi_demo.tests.serde.Test]: Response containing reflectapi_demo.tests.serde.Test data """ path = "/inout_test" @@ -59,7 +71,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTest, + response_model=reflectapi_demo.tests.serde.Test, ) @@ -84,15 +96,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTest] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: + data: Optional[reflectapi_demo.tests.serde.Test] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.Test]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTest]: Response containing ReflectapiDemoTestsSerdeTest data + ApiResponse[reflectapi_demo.tests.serde.Test]: Response containing reflectapi_demo.tests.serde.Test data """ path = "/inout_test" @@ -102,7 +114,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTest, + response_model=reflectapi_demo.tests.serde.Test, ) @@ -127,23 +139,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTest.model_rebuild() + reflectapi_demo.tests.serde.Test.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdetest_response( - value: ReflectapiDemoTestsSerdeTest, -) -> ApiResponse[ReflectapiDemoTestsSerdeTest]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTest.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_try_from-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_try_from-3.snap index d16fcb1f..a917b455 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_try_from-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_try_from-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructTryFormProxy > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_try_from-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_try_from-5.snap index 5d6d20fd..91a92da7 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_try_from-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_try_from-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestStructTryFormProxy(BaseModel): @@ -41,6 +40,20 @@ class ReflectapiDemoTestsSerdeTestStructTryFrom(BaseModel): f: int +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestStructTryFormProxy = ReflectapiDemoTestsSerdeTestStructTryFormProxy + TestStructTryFrom = ReflectapiDemoTestsSerdeTestStructTryFrom + + class AsyncInoutClient: """Async client for inout operations.""" @@ -49,15 +62,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructTryFrom] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructTryFormProxy]: + data: Optional[reflectapi_demo.tests.serde.TestStructTryFrom] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructTryFormProxy]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructTryFormProxy]: Response containing ReflectapiDemoTestsSerdeTestStructTryFormProxy data + ApiResponse[reflectapi_demo.tests.serde.TestStructTryFormProxy]: Response containing reflectapi_demo.tests.serde.TestStructTryFormProxy data """ path = "/inout_test" @@ -67,7 +80,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructTryFormProxy, + response_model=reflectapi_demo.tests.serde.TestStructTryFormProxy, ) @@ -92,15 +105,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructTryFrom] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructTryFormProxy]: + data: Optional[reflectapi_demo.tests.serde.TestStructTryFrom] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructTryFormProxy]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructTryFormProxy]: Response containing ReflectapiDemoTestsSerdeTestStructTryFormProxy data + ApiResponse[reflectapi_demo.tests.serde.TestStructTryFormProxy]: Response containing reflectapi_demo.tests.serde.TestStructTryFormProxy data """ path = "/inout_test" @@ -110,7 +123,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructTryFormProxy, + response_model=reflectapi_demo.tests.serde.TestStructTryFormProxy, ) @@ -135,31 +148,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestStructTryFormProxy.model_rebuild() - ReflectapiDemoTestsSerdeTestStructTryFrom.model_rebuild() + reflectapi_demo.tests.serde.TestStructTryFormProxy.model_rebuild() + reflectapi_demo.tests.serde.TestStructTryFrom.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeteststructtryformproxy_response( - value: ReflectapiDemoTestsSerdeTestStructTryFormProxy, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructTryFormProxy]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructTryFormProxy.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeteststructtryfrom_response( - value: ReflectapiDemoTestsSerdeTestStructTryFrom, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructTryFrom]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructTryFrom.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten-3.snap index 91ad8d80..e67ff456 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithFlatten > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten-5.snap index 56b3044c..30423229 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten-5.snap @@ -16,16 +16,15 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response -class ReflectapiDemoTestsSerdeTestStructWithFlattenNested(BaseModel): +class ReflectapiDemoTestsSerdeTestStructWithFlatten(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) @@ -33,7 +32,7 @@ class ReflectapiDemoTestsSerdeTestStructWithFlattenNested(BaseModel): f: int -class ReflectapiDemoTestsSerdeTestStructWithFlatten(BaseModel): +class ReflectapiDemoTestsSerdeTestStructWithFlattenNested(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) @@ -41,6 +40,22 @@ class ReflectapiDemoTestsSerdeTestStructWithFlatten(BaseModel): f: int +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestStructWithFlatten = ReflectapiDemoTestsSerdeTestStructWithFlatten + TestStructWithFlattenNested = ( + ReflectapiDemoTestsSerdeTestStructWithFlattenNested + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -49,15 +64,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructWithFlatten] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlatten]: + data: Optional[reflectapi_demo.tests.serde.TestStructWithFlatten] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructWithFlatten]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlatten]: Response containing ReflectapiDemoTestsSerdeTestStructWithFlatten data + ApiResponse[reflectapi_demo.tests.serde.TestStructWithFlatten]: Response containing reflectapi_demo.tests.serde.TestStructWithFlatten data """ path = "/inout_test" @@ -67,7 +82,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructWithFlatten, + response_model=reflectapi_demo.tests.serde.TestStructWithFlatten, ) @@ -92,15 +107,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructWithFlatten] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlatten]: + data: Optional[reflectapi_demo.tests.serde.TestStructWithFlatten] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructWithFlatten]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlatten]: Response containing ReflectapiDemoTestsSerdeTestStructWithFlatten data + ApiResponse[reflectapi_demo.tests.serde.TestStructWithFlatten]: Response containing reflectapi_demo.tests.serde.TestStructWithFlatten data """ path = "/inout_test" @@ -110,7 +125,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructWithFlatten, + response_model=reflectapi_demo.tests.serde.TestStructWithFlatten, ) @@ -135,31 +150,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestStructWithFlatten.model_rebuild() - ReflectapiDemoTestsSerdeTestStructWithFlattenNested.model_rebuild() + reflectapi_demo.tests.serde.TestStructWithFlatten.model_rebuild() + reflectapi_demo.tests.serde.TestStructWithFlattenNested.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeteststructwithflatten_response( - value: ReflectapiDemoTestsSerdeTestStructWithFlatten, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlatten]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructWithFlatten.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeteststructwithflattennested_response( - value: ReflectapiDemoTestsSerdeTestStructWithFlattenNested, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlattenNested]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructWithFlattenNested.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional-3.snap index a2752955..2cdf9bf3 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithFlattenOptional > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional-5.snap index df21728f..d97d1c86 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional-5.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestStructWithFlattenNested(BaseModel): @@ -42,6 +41,24 @@ class ReflectapiDemoTestsSerdeTestStructWithFlattenOptional(BaseModel): f: int | None = None +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestStructWithFlattenNested = ( + ReflectapiDemoTestsSerdeTestStructWithFlattenNested + ) + TestStructWithFlattenOptional = ( + ReflectapiDemoTestsSerdeTestStructWithFlattenOptional + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -50,15 +67,17 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructWithFlattenOptional] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlattenOptional]: + data: Optional[ + reflectapi_demo.tests.serde.TestStructWithFlattenOptional + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructWithFlattenOptional]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlattenOptional]: Response containing ReflectapiDemoTestsSerdeTestStructWithFlattenOptional data + ApiResponse[reflectapi_demo.tests.serde.TestStructWithFlattenOptional]: Response containing reflectapi_demo.tests.serde.TestStructWithFlattenOptional data """ path = "/inout_test" @@ -68,7 +87,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructWithFlattenOptional, + response_model=reflectapi_demo.tests.serde.TestStructWithFlattenOptional, ) @@ -93,15 +112,17 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructWithFlattenOptional] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlattenOptional]: + data: Optional[ + reflectapi_demo.tests.serde.TestStructWithFlattenOptional + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructWithFlattenOptional]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlattenOptional]: Response containing ReflectapiDemoTestsSerdeTestStructWithFlattenOptional data + ApiResponse[reflectapi_demo.tests.serde.TestStructWithFlattenOptional]: Response containing reflectapi_demo.tests.serde.TestStructWithFlattenOptional data """ path = "/inout_test" @@ -111,7 +132,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructWithFlattenOptional, + response_model=reflectapi_demo.tests.serde.TestStructWithFlattenOptional, ) @@ -136,31 +157,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestStructWithFlattenNested.model_rebuild() - ReflectapiDemoTestsSerdeTestStructWithFlattenOptional.model_rebuild() + reflectapi_demo.tests.serde.TestStructWithFlattenNested.model_rebuild() + reflectapi_demo.tests.serde.TestStructWithFlattenOptional.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeteststructwithflattennested_response( - value: ReflectapiDemoTestsSerdeTestStructWithFlattenNested, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlattenNested]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructWithFlattenNested.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeteststructwithflattenoptional_response( - value: ReflectapiDemoTestsSerdeTestStructWithFlattenOptional, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlattenOptional]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructWithFlattenOptional.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional_and_required-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional_and_required-3.snap index 2590e27f..106deb7a 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional_and_required-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional_and_required-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithFlattenOptionalAndRequired > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional_and_required-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional_and_required-5.snap index 1113a59f..a9b72a75 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional_and_required-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_flatten_optional_and_required-5.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestStructRenameAll(BaseModel): @@ -31,7 +30,9 @@ class ReflectapiDemoTestsSerdeTestStructRenameAll(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - field_name: int + field_name: int = Field( + serialization_alias="fieldName", validation_alias="fieldName" + ) class ReflectapiDemoTestsSerdeTestStructWithFlattenNested(BaseModel): @@ -48,7 +49,28 @@ class ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired(BaseModel model_config = ConfigDict(extra="ignore", populate_by_name=True) f: int | None = None - field_name: int + field_name: int = Field( + serialization_alias="fieldName", validation_alias="fieldName" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestStructRenameAll = ReflectapiDemoTestsSerdeTestStructRenameAll + TestStructWithFlattenNested = ( + ReflectapiDemoTestsSerdeTestStructWithFlattenNested + ) + TestStructWithFlattenOptionalAndRequired = ( + ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired + ) class AsyncInoutClient: @@ -60,16 +82,18 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired + reflectapi_demo.tests.serde.TestStructWithFlattenOptionalAndRequired ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired]: + ) -> ApiResponse[ + reflectapi_demo.tests.serde.TestStructWithFlattenOptionalAndRequired + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired]: Response containing ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired data + ApiResponse[reflectapi_demo.tests.serde.TestStructWithFlattenOptionalAndRequired]: Response containing reflectapi_demo.tests.serde.TestStructWithFlattenOptionalAndRequired data """ path = "/inout_test" @@ -79,7 +103,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired, + response_model=reflectapi_demo.tests.serde.TestStructWithFlattenOptionalAndRequired, ) @@ -105,16 +129,18 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired + reflectapi_demo.tests.serde.TestStructWithFlattenOptionalAndRequired ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired]: + ) -> ApiResponse[ + reflectapi_demo.tests.serde.TestStructWithFlattenOptionalAndRequired + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired]: Response containing ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired data + ApiResponse[reflectapi_demo.tests.serde.TestStructWithFlattenOptionalAndRequired]: Response containing reflectapi_demo.tests.serde.TestStructWithFlattenOptionalAndRequired data """ path = "/inout_test" @@ -124,7 +150,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired, + response_model=reflectapi_demo.tests.serde.TestStructWithFlattenOptionalAndRequired, ) @@ -149,39 +175,9 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestStructRenameAll.model_rebuild() - ReflectapiDemoTestsSerdeTestStructWithFlattenNested.model_rebuild() - ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired.model_rebuild() + reflectapi_demo.tests.serde.TestStructRenameAll.model_rebuild() + reflectapi_demo.tests.serde.TestStructWithFlattenNested.model_rebuild() + reflectapi_demo.tests.serde.TestStructWithFlattenOptionalAndRequired.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeteststructrenameall_response( - value: ReflectapiDemoTestsSerdeTestStructRenameAll, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructRenameAll]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructRenameAll.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeteststructwithflattennested_response( - value: ReflectapiDemoTestsSerdeTestStructWithFlattenNested, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlattenNested]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructWithFlattenNested.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeteststructwithflattenoptionalandrequired_response( - value: ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructWithFlattenOptionalAndRequired.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_invalid_chars-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_invalid_chars-3.snap index 2c20efb7..20885b56 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_invalid_chars-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_invalid_chars-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithRenameToInvalidChars > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_invalid_chars-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_invalid_chars-5.snap index ad3a0975..19ac1fd3 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_invalid_chars-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_invalid_chars-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - f: int + f: int = Field(serialization_alias="field-name&&", validation_alias="field-name&&") + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestStructWithRenameToInvalidChars = ( + ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars + ) class AsyncInoutClient: @@ -42,16 +56,16 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars + reflectapi_demo.tests.serde.TestStructWithRenameToInvalidChars ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars]: + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructWithRenameToInvalidChars]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars]: Response containing ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars data + ApiResponse[reflectapi_demo.tests.serde.TestStructWithRenameToInvalidChars]: Response containing reflectapi_demo.tests.serde.TestStructWithRenameToInvalidChars data """ path = "/inout_test" @@ -61,7 +75,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars, + response_model=reflectapi_demo.tests.serde.TestStructWithRenameToInvalidChars, ) @@ -87,16 +101,16 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars + reflectapi_demo.tests.serde.TestStructWithRenameToInvalidChars ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars]: + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructWithRenameToInvalidChars]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars]: Response containing ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars data + ApiResponse[reflectapi_demo.tests.serde.TestStructWithRenameToInvalidChars]: Response containing reflectapi_demo.tests.serde.TestStructWithRenameToInvalidChars data """ path = "/inout_test" @@ -106,7 +120,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars, + response_model=reflectapi_demo.tests.serde.TestStructWithRenameToInvalidChars, ) @@ -131,23 +145,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars.model_rebuild() + reflectapi_demo.tests.serde.TestStructWithRenameToInvalidChars.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeteststructwithrenametoinvalidchars_response( - value: ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructWithRenameToInvalidChars.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_kebab_case-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_kebab_case-3.snap index ff22224a..a165d910 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_kebab_case-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_kebab_case-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithRenameToKebabCase > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_kebab_case-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_kebab_case-5.snap index dbc98cbf..fed2460f 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_kebab_case-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_rename_to_kebab_case-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeStructName(BaseModel): @@ -30,7 +29,22 @@ class ReflectapiDemoTestsSerdeStructName(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - field_name: int + field_name: int = Field( + serialization_alias="field-name", validation_alias="field-name" + ) + + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + StructName = ReflectapiDemoTestsSerdeStructName class AsyncInoutClient: @@ -41,15 +55,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeStructName] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeStructName]: + data: Optional[reflectapi_demo.tests.serde.StructName] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.StructName]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeStructName]: Response containing ReflectapiDemoTestsSerdeStructName data + ApiResponse[reflectapi_demo.tests.serde.StructName]: Response containing reflectapi_demo.tests.serde.StructName data """ path = "/inout_test" @@ -59,7 +73,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeStructName, + response_model=reflectapi_demo.tests.serde.StructName, ) @@ -84,15 +98,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeStructName] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeStructName]: + data: Optional[reflectapi_demo.tests.serde.StructName] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.StructName]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeStructName]: Response containing ReflectapiDemoTestsSerdeStructName data + ApiResponse[reflectapi_demo.tests.serde.StructName]: Response containing reflectapi_demo.tests.serde.StructName data """ path = "/inout_test" @@ -102,7 +116,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeStructName, + response_model=reflectapi_demo.tests.serde.StructName, ) @@ -127,23 +141,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeStructName.model_rebuild() + reflectapi_demo.tests.serde.StructName.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdestructname_response( - value: ReflectapiDemoTestsSerdeStructName, -) -> ApiResponse[ReflectapiDemoTestsSerdeStructName]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeStructName.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_default-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_default-3.snap index debb962c..8dfa7b8d 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_default-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_default-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithSerdeDefault > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_default-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_default-5.snap index 1f18aa25..1eb93882 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_default-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_default-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeInputTestStructWithSerdeDefault(BaseModel): @@ -41,6 +40,31 @@ class ReflectapiDemoTestsSerdeOutputTestStructWithSerdeDefault(BaseModel): f: int +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + class input: + """Namespace for input types.""" + + TestStructWithSerdeDefault = ( + ReflectapiDemoTestsSerdeInputTestStructWithSerdeDefault + ) + + class output: + """Namespace for output types.""" + + TestStructWithSerdeDefault = ( + ReflectapiDemoTestsSerdeOutputTestStructWithSerdeDefault + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -49,15 +73,17 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeInputTestStructWithSerdeDefault] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeDefault]: + data: Optional[ + reflectapi_demo.tests.serde.input.TestStructWithSerdeDefault + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.output.TestStructWithSerdeDefault]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeDefault]: Response containing ReflectapiDemoTestsSerdeOutputTestStructWithSerdeDefault data + ApiResponse[reflectapi_demo.tests.serde.output.TestStructWithSerdeDefault]: Response containing reflectapi_demo.tests.serde.output.TestStructWithSerdeDefault data """ path = "/inout_test" @@ -67,7 +93,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestStructWithSerdeDefault, + response_model=reflectapi_demo.tests.serde.output.TestStructWithSerdeDefault, ) @@ -92,15 +118,17 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeInputTestStructWithSerdeDefault] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeDefault]: + data: Optional[ + reflectapi_demo.tests.serde.input.TestStructWithSerdeDefault + ] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.output.TestStructWithSerdeDefault]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeDefault]: Response containing ReflectapiDemoTestsSerdeOutputTestStructWithSerdeDefault data + ApiResponse[reflectapi_demo.tests.serde.output.TestStructWithSerdeDefault]: Response containing reflectapi_demo.tests.serde.output.TestStructWithSerdeDefault data """ path = "/inout_test" @@ -110,7 +138,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestStructWithSerdeDefault, + response_model=reflectapi_demo.tests.serde.output.TestStructWithSerdeDefault, ) @@ -135,31 +163,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeInputTestStructWithSerdeDefault.model_rebuild() - ReflectapiDemoTestsSerdeOutputTestStructWithSerdeDefault.model_rebuild() + reflectapi_demo.tests.serde.input.TestStructWithSerdeDefault.model_rebuild() + reflectapi_demo.tests.serde.output.TestStructWithSerdeDefault.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeinputteststructwithserdedefault_response( - value: ReflectapiDemoTestsSerdeInputTestStructWithSerdeDefault, -) -> ApiResponse[ReflectapiDemoTestsSerdeInputTestStructWithSerdeDefault]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeInputTestStructWithSerdeDefault.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeoutputteststructwithserdedefault_response( - value: ReflectapiDemoTestsSerdeOutputTestStructWithSerdeDefault, -) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeDefault]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeOutputTestStructWithSerdeDefault.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip-3.snap index 973dfc79..ad7e27d8 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithSerdeSkip > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip-5.snap index ba99b884..63f230c6 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestStructWithSerdeSkip(BaseModel): @@ -31,6 +30,19 @@ class ReflectapiDemoTestsSerdeTestStructWithSerdeSkip(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestStructWithSerdeSkip = ReflectapiDemoTestsSerdeTestStructWithSerdeSkip + + class AsyncInoutClient: """Async client for inout operations.""" @@ -39,15 +51,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructWithSerdeSkip] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithSerdeSkip]: + data: Optional[reflectapi_demo.tests.serde.TestStructWithSerdeSkip] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructWithSerdeSkip]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructWithSerdeSkip]: Response containing ReflectapiDemoTestsSerdeTestStructWithSerdeSkip data + ApiResponse[reflectapi_demo.tests.serde.TestStructWithSerdeSkip]: Response containing reflectapi_demo.tests.serde.TestStructWithSerdeSkip data """ path = "/inout_test" @@ -57,7 +69,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructWithSerdeSkip, + response_model=reflectapi_demo.tests.serde.TestStructWithSerdeSkip, ) @@ -82,15 +94,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStructWithSerdeSkip] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithSerdeSkip]: + data: Optional[reflectapi_demo.tests.serde.TestStructWithSerdeSkip] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStructWithSerdeSkip]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStructWithSerdeSkip]: Response containing ReflectapiDemoTestsSerdeTestStructWithSerdeSkip data + ApiResponse[reflectapi_demo.tests.serde.TestStructWithSerdeSkip]: Response containing reflectapi_demo.tests.serde.TestStructWithSerdeSkip data """ path = "/inout_test" @@ -100,7 +112,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStructWithSerdeSkip, + response_model=reflectapi_demo.tests.serde.TestStructWithSerdeSkip, ) @@ -125,23 +137,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestStructWithSerdeSkip.model_rebuild() + reflectapi_demo.tests.serde.TestStructWithSerdeSkip.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeteststructwithserdeskip_response( - value: ReflectapiDemoTestsSerdeTestStructWithSerdeSkip, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStructWithSerdeSkip]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStructWithSerdeSkip.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_deserialize-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_deserialize-3.snap index 53a4b9ef..4c582160 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_deserialize-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_deserialize-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithSerdeSkipDeserialize > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_deserialize-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_deserialize-5.snap index 62647334..52a915da 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_deserialize-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_deserialize-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipDeserialize(BaseModel): @@ -39,6 +38,31 @@ class ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipDeserialize(BaseModel f: int +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + class input: + """Namespace for input types.""" + + TestStructWithSerdeSkipDeserialize = ( + ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipDeserialize + ) + + class output: + """Namespace for output types.""" + + TestStructWithSerdeSkipDeserialize = ( + ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipDeserialize + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -48,16 +72,18 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipDeserialize + reflectapi_demo.tests.serde.input.TestStructWithSerdeSkipDeserialize ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipDeserialize]: + ) -> ApiResponse[ + reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipDeserialize + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipDeserialize]: Response containing ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipDeserialize data + ApiResponse[reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipDeserialize]: Response containing reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipDeserialize data """ path = "/inout_test" @@ -67,7 +93,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipDeserialize, + response_model=reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipDeserialize, ) @@ -93,16 +119,18 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipDeserialize + reflectapi_demo.tests.serde.input.TestStructWithSerdeSkipDeserialize ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipDeserialize]: + ) -> ApiResponse[ + reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipDeserialize + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipDeserialize]: Response containing ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipDeserialize data + ApiResponse[reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipDeserialize]: Response containing reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipDeserialize data """ path = "/inout_test" @@ -112,7 +140,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipDeserialize, + response_model=reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipDeserialize, ) @@ -137,31 +165,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipDeserialize.model_rebuild() - ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipDeserialize.model_rebuild() + reflectapi_demo.tests.serde.input.TestStructWithSerdeSkipDeserialize.model_rebuild() + reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipDeserialize.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeinputteststructwithserdeskipdeserialize_response( - value: ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipDeserialize, -) -> ApiResponse[ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipDeserialize]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipDeserialize.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeoutputteststructwithserdeskipdeserialize_response( - value: ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipDeserialize, -) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipDeserialize]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipDeserialize.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize-3.snap index 13fd8f57..aad6255b 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithSerdeSkipSerialize > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize-5.snap index cee769c3..b8965b63 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize-5.snap @@ -16,27 +16,51 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response -class ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerialize(BaseModel): +class ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerialize(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) + f: int = Field(serialization_alias="_f", validation_alias="_f") -class ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerialize(BaseModel): + +class ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerialize(BaseModel): """Generated data model.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - _f: int + +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + class input: + """Namespace for input types.""" + + TestStructWithSerdeSkipSerialize = ( + ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerialize + ) + + class output: + """Namespace for output types.""" + + TestStructWithSerdeSkipSerialize = ( + ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerialize + ) class AsyncInoutClient: @@ -48,16 +72,18 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerialize + reflectapi_demo.tests.serde.input.TestStructWithSerdeSkipSerialize ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerialize]: + ) -> ApiResponse[ + reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerialize + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerialize]: Response containing ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerialize data + ApiResponse[reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerialize]: Response containing reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerialize data """ path = "/inout_test" @@ -67,7 +93,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerialize, + response_model=reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerialize, ) @@ -93,16 +119,18 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerialize + reflectapi_demo.tests.serde.input.TestStructWithSerdeSkipSerialize ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerialize]: + ) -> ApiResponse[ + reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerialize + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerialize]: Response containing ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerialize data + ApiResponse[reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerialize]: Response containing reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerialize data """ path = "/inout_test" @@ -112,7 +140,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerialize, + response_model=reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerialize, ) @@ -137,31 +165,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerialize.model_rebuild() - ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerialize.model_rebuild() + reflectapi_demo.tests.serde.input.TestStructWithSerdeSkipSerialize.model_rebuild() + reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerialize.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeinputteststructwithserdeskipserialize_response( - value: ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerialize, -) -> ApiResponse[ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerialize]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerialize.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeoutputteststructwithserdeskipserialize_response( - value: ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerialize, -) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerialize]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerialize.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize_if-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize_if-3.snap index a9f25cac..05cf6f34 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize_if-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize_if-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestStructWithSerdeSkipSerializeIf > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize_if-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize_if-5.snap index 48f3c6df..a1a8e240 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize_if-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_skip_serialize_if-5.snap @@ -17,13 +17,12 @@ from enum import Enum from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerializeIf(BaseModel): @@ -42,6 +41,31 @@ class ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerializeIf(BaseModel f: int | None = None +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + class input: + """Namespace for input types.""" + + TestStructWithSerdeSkipSerializeIf = ( + ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerializeIf + ) + + class output: + """Namespace for output types.""" + + TestStructWithSerdeSkipSerializeIf = ( + ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerializeIf + ) + + class AsyncInoutClient: """Async client for inout operations.""" @@ -51,16 +75,18 @@ class AsyncInoutClient: async def test( self, data: Optional[ - ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerializeIf + reflectapi_demo.tests.serde.input.TestStructWithSerdeSkipSerializeIf ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerializeIf]: + ) -> ApiResponse[ + reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerializeIf + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerializeIf]: Response containing ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerializeIf data + ApiResponse[reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerializeIf]: Response containing reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerializeIf data """ path = "/inout_test" @@ -70,7 +96,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerializeIf, + response_model=reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerializeIf, ) @@ -96,16 +122,18 @@ class InoutClient: def test( self, data: Optional[ - ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerializeIf + reflectapi_demo.tests.serde.input.TestStructWithSerdeSkipSerializeIf ] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerializeIf]: + ) -> ApiResponse[ + reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerializeIf + ]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerializeIf]: Response containing ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerializeIf data + ApiResponse[reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerializeIf]: Response containing reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerializeIf data """ path = "/inout_test" @@ -115,7 +143,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerializeIf, + response_model=reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerializeIf, ) @@ -140,31 +168,8 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerializeIf.model_rebuild() - ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerializeIf.model_rebuild() + reflectapi_demo.tests.serde.input.TestStructWithSerdeSkipSerializeIf.model_rebuild() + reflectapi_demo.tests.serde.output.TestStructWithSerdeSkipSerializeIf.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeinputteststructwithserdeskipserializeif_response( - value: ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerializeIf, -) -> ApiResponse[ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerializeIf]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeInputTestStructWithSerdeSkipSerializeIf.""" - return create_api_response(value) - - -def create_reflectapidemotestsserdeoutputteststructwithserdeskipserializeif_response( - value: ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerializeIf, -) -> ApiResponse[ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerializeIf]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeOutputTestStructWithSerdeSkipSerializeIf.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_transparent-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_transparent-5.snap index cc5d66e3..38276207 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_transparent-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__struct_with_serde_transparent-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class AsyncInoutClient: @@ -31,7 +30,6 @@ class AsyncInoutClient: def __init__(self, client: AsyncClientBase) -> None: self._client = client - async def test( self, data: Optional[int] = None, @@ -53,7 +51,7 @@ class AsyncInoutClient: params=params if params else None, json_data=data, response_model=int, -) + ) class AsyncClient(AsyncClientBase): @@ -66,6 +64,7 @@ class AsyncClient(AsyncClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = AsyncInoutClient(self) @@ -75,7 +74,6 @@ class InoutClient: def __init__(self, client: ClientBase) -> None: self._client = client - def test( self, data: Optional[int] = None, @@ -97,7 +95,7 @@ class InoutClient: params=params if params else None, json_data=data, response_model=int, -) + ) class Client(ClientBase): @@ -110,6 +108,7 @@ class Client(ClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = InoutClient(self) @@ -124,12 +123,3 @@ try: except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__timezone-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__timezone-3.snap index ef636176..c893f6a9 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__timezone-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__timezone-3.snap @@ -54,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__timezone-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__timezone-5.snap index 610b4665..ca5f1b59 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__timezone-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__timezone-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class ReflectapiDemoTestsSerdeTestStruct(BaseModel): @@ -33,6 +32,19 @@ class ReflectapiDemoTestsSerdeTestStruct(BaseModel): timezone: str +# Namespace classes for dotted access to types +class reflectapi_demo: + """Namespace for reflectapi_demo types.""" + + class tests: + """Namespace for tests types.""" + + class serde: + """Namespace for serde types.""" + + TestStruct = ReflectapiDemoTestsSerdeTestStruct + + class AsyncInoutClient: """Async client for inout operations.""" @@ -41,15 +53,15 @@ class AsyncInoutClient: async def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStruct] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStruct]: + data: Optional[reflectapi_demo.tests.serde.TestStruct] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStruct]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStruct]: Response containing ReflectapiDemoTestsSerdeTestStruct data + ApiResponse[reflectapi_demo.tests.serde.TestStruct]: Response containing reflectapi_demo.tests.serde.TestStruct data """ path = "/inout_test" @@ -59,7 +71,7 @@ class AsyncInoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStruct, + response_model=reflectapi_demo.tests.serde.TestStruct, ) @@ -84,15 +96,15 @@ class InoutClient: def test( self, - data: Optional[ReflectapiDemoTestsSerdeTestStruct] = None, - ) -> ApiResponse[ReflectapiDemoTestsSerdeTestStruct]: + data: Optional[reflectapi_demo.tests.serde.TestStruct] = None, + ) -> ApiResponse[reflectapi_demo.tests.serde.TestStruct]: """ Args: data: Request data for the test operation. Returns: - ApiResponse[ReflectapiDemoTestsSerdeTestStruct]: Response containing ReflectapiDemoTestsSerdeTestStruct data + ApiResponse[reflectapi_demo.tests.serde.TestStruct]: Response containing reflectapi_demo.tests.serde.TestStruct data """ path = "/inout_test" @@ -102,7 +114,7 @@ class InoutClient: path, params=params if params else None, json_model=data, - response_model=ReflectapiDemoTestsSerdeTestStruct, + response_model=reflectapi_demo.tests.serde.TestStruct, ) @@ -127,23 +139,7 @@ StdNumNonZeroI64 = Annotated[int, "Rust NonZero i64 type"] # Rebuild models to resolve forward references try: - ReflectapiDemoTestsSerdeTestStruct.model_rebuild() + reflectapi_demo.tests.serde.TestStruct.model_rebuild() except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_reflectapidemotestsserdeteststruct_response( - value: ReflectapiDemoTestsSerdeTestStruct, -) -> ApiResponse[ReflectapiDemoTestsSerdeTestStruct]: - """Create a mock ApiResponse for ReflectapiDemoTestsSerdeTestStruct.""" - return create_api_response(value) - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_struct-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_struct-3.snap index e5c48847..e2df29ea 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_struct-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_struct-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestUnitStruct > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_struct-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_struct-5.snap index f9f137ab..4b7497c8 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_struct-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_struct-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class AsyncInoutClient: @@ -31,7 +30,6 @@ class AsyncInoutClient: def __init__(self, client: AsyncClientBase) -> None: self._client = client - async def test( self, data: Optional[None] = None, @@ -53,7 +51,7 @@ class AsyncInoutClient: params=params if params else None, json_model=data, response_model=None, -) + ) class AsyncClient(AsyncClientBase): @@ -66,6 +64,7 @@ class AsyncClient(AsyncClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = AsyncInoutClient(self) @@ -75,7 +74,6 @@ class InoutClient: def __init__(self, client: ClientBase) -> None: self._client = client - def test( self, data: Optional[None] = None, @@ -97,7 +95,7 @@ class InoutClient: params=params if params else None, json_model=data, response_model=None, -) + ) class Client(ClientBase): @@ -110,6 +108,7 @@ class Client(ClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = InoutClient(self) @@ -124,12 +123,3 @@ try: except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_tuple_struct-3.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_tuple_struct-3.snap index 91289318..9b98c3cd 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_tuple_struct-3.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_tuple_struct-3.snap @@ -1,7 +1,6 @@ --- source: reflectapi-demo/src/tests/serde.rs -expression: "super::into_rust_code::()" -snapshot_kind: text +expression: "super :: into_rust_code :: < TestUnitTupleStruct > ()" --- // DO NOT MODIFY THIS FILE MANUALLY // This file was generated by reflectapi-cli @@ -55,7 +54,6 @@ pub mod interface { } } pub mod types { - pub mod reflectapi_demo { pub mod tests { pub mod serde { diff --git a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_tuple_struct-5.snap b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_tuple_struct-5.snap index 48a97ca8..5340e847 100644 --- a/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_tuple_struct-5.snap +++ b/reflectapi-demo/src/tests/snapshots/reflectapi_demo__tests__serde__unit_tuple_struct-5.snap @@ -16,13 +16,12 @@ from __future__ import annotations from typing import Annotated, Any, Generic, Optional, TypeVar, Union # Third-party imports -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field # Runtime imports from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse from reflectapi_runtime import ReflectapiEmpty from reflectapi_runtime import ReflectapiInfallible -from reflectapi_runtime.testing import MockClient, create_api_response class AsyncInoutClient: @@ -31,7 +30,6 @@ class AsyncInoutClient: def __init__(self, client: AsyncClientBase) -> None: self._client = client - async def test( self, data: Optional[None] = None, @@ -53,7 +51,7 @@ class AsyncInoutClient: params=params if params else None, json_model=data, response_model=None, -) + ) class AsyncClient(AsyncClientBase): @@ -66,6 +64,7 @@ class AsyncClient(AsyncClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = AsyncInoutClient(self) @@ -75,7 +74,6 @@ class InoutClient: def __init__(self, client: ClientBase) -> None: self._client = client - def test( self, data: Optional[None] = None, @@ -97,7 +95,7 @@ class InoutClient: params=params if params else None, json_model=data, response_model=None, -) + ) class Client(ClientBase): @@ -110,6 +108,7 @@ class Client(ClientBase): ) -> None: super().__init__(base_url, **kwargs) + self.inout = InoutClient(self) @@ -124,12 +123,3 @@ try: except AttributeError: # Some types may not have model_rebuild method pass - -# Factory classes (generated after model rebuild to avoid forward references) - -# Testing utilities - - -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() diff --git a/reflectapi-derive/src/derive.rs b/reflectapi-derive/src/derive.rs index bace5ff3..9bb83825 100644 --- a/reflectapi-derive/src/derive.rs +++ b/reflectapi-derive/src/derive.rs @@ -170,6 +170,7 @@ fn visit_type(cx: &Context, container: &ast::Container<'_>) -> Type { codegen_config: reflectapi_schema::LanguageSpecificTypeCodegenConfig, ) -> Struct { Struct { + id: Default::default(), name: type_def_name, serde_name, description: type_def_description, @@ -384,6 +385,7 @@ fn visit_variant( }; Variant { + id: Default::default(), name: variant_def_name, serde_name, description: parse_doc_attributes(&variant.original.attrs), diff --git a/reflectapi-derive/src/tokenizable_schema.rs b/reflectapi-derive/src/tokenizable_schema.rs index 69b99ea9..c52674d5 100644 --- a/reflectapi-derive/src/tokenizable_schema.rs +++ b/reflectapi-derive/src/tokenizable_schema.rs @@ -117,6 +117,7 @@ impl ToTokens for TokenizableField<'_> { } tokens.extend(quote::quote! { reflectapi::Field { + id: Default::default(), name: #name.into(), serde_name: #serde_name.into(), description: #description.into(), @@ -168,6 +169,7 @@ impl ToTokens for TokenizableVariant<'_> { let untagged = self.inner.untagged; tokens.extend(quote::quote! { reflectapi::Variant { + id: Default::default(), name: #name.into(), serde_name: #serde_name.into(), description: #description.into(), @@ -239,6 +241,7 @@ impl ToTokens for TokenizableEnum<'_> { TokenizableLanguageSpecificTypeCodegenConfig(&self.inner.codegen_config); tokens.extend(quote::quote! { reflectapi::Enum { + id: Default::default(), name: #name.into(), serde_name: #serde_name.into(), description: #description.into(), @@ -313,6 +316,7 @@ impl ToTokens for TokenizableStruct<'_> { TokenizableLanguageSpecificTypeCodegenConfig(&self.inner.codegen_config); tokens.extend(quote::quote! { reflectapi::Struct { + id: Default::default(), name: #name.into(), serde_name: #serde_name.into(), description: #description.into(), @@ -347,6 +351,7 @@ impl ToTokens for TokenizablePrimitive<'_> { .map(TokenizableTypeReference::new); tokens.extend(quote::quote! { reflectapi::Primitive { + id: Default::default(), name: #name.into(), description: #description.into(), parameters: vec![#(#parameters),*], diff --git a/reflectapi-python-runtime/README.md b/reflectapi-python-runtime/README.md new file mode 100644 index 00000000..e69de29b diff --git a/reflectapi-python-runtime/src/reflectapi_runtime/client.py b/reflectapi-python-runtime/src/reflectapi_runtime/client.py index bee7b756..178011a7 100644 --- a/reflectapi-python-runtime/src/reflectapi_runtime/client.py +++ b/reflectapi-python-runtime/src/reflectapi_runtime/client.py @@ -9,7 +9,7 @@ from typing import Any, TypeVar, overload import httpx -from pydantic import BaseModel +from pydantic import BaseModel, TypeAdapter from pydantic import ValidationError as PydanticValidationError from .auth import AuthHandler @@ -373,17 +373,35 @@ def _execute_request(self, request: httpx.Request) -> httpx.Response: return self._client.send(request) def _handle_error_response( - self, response: httpx.Response, metadata: TransportMetadata + self, + response: httpx.Response, + metadata: TransportMetadata, + error_model: type | None = None, ) -> None: - """Handle HTTP error responses (4xx, 5xx).""" + """Handle HTTP error responses (4xx, 5xx). + + If error_model is provided, attempts to deserialize the error body + into a typed Pydantic model before raising ApplicationError. + """ if response.status_code >= 400: error_data = None + typed_error = None try: error_data = response.json() except Exception: pass - raise ApplicationError.from_response(response, metadata, error_data) + # Try typed error deserialization + if error_model is not None and error_data is not None: + try: + ta = TypeAdapter(error_model) + typed_error = ta.validate_python(error_data) + except Exception: + pass # Fall back to raw error_data + + raise ApplicationError.from_response( + response, metadata, error_data, typed_error=typed_error + ) def _parse_json_response(self, response: httpx.Response) -> dict[str, Any]: """Parse JSON response with error handling.""" @@ -401,67 +419,30 @@ def _validate_response_model( response_model: type[T] | type[Any] | str | _NoValidation, metadata: TransportMetadata, ) -> ApiResponse[T] | ApiResponse[dict[str, Any]]: - """Validate response using Pydantic model.""" + """Validate response using Pydantic model via TypeAdapter. + + TypeAdapter handles all types: plain BaseModel, Generic types + (list[Model], dict[str, Model]), Union types, and primitives. + Uses validate_json for performance when raw bytes are available. + """ # Handle special cases where no validation is needed if response_model == "Any" or response_model is NO_VALIDATION: json_response = self._parse_json_response(response) return ApiResponse(json_response, metadata) - # Handle typing.Any - try: - if response_model is Any: - json_response = self._parse_json_response(response) - return ApiResponse(json_response, metadata) - except Exception: - # If there's any issue with the comparison, continue with validation - pass + if response_model is Any: + json_response = self._parse_json_response(response) + return ApiResponse(json_response, metadata) try: - # Handle Union types (like MyapiModelOutputPet | None) - import types - - if hasattr(types, "UnionType") and isinstance( - response_model, types.UnionType - ): - json_response = self._parse_json_response(response) - # For Union types, try to deserialize with each type in the union - union_args = response_model.__args__ - - # Handle None case first - if json_response is None and type(None) in union_args: - return ApiResponse(None, metadata) - - # Try each non-None type in the union - for arg_type in union_args: - if arg_type is not type(None) and hasattr( - arg_type, "model_validate" - ): - try: - validated_data = arg_type.model_validate(json_response) - return ApiResponse(validated_data, metadata) - except Exception: - continue # Try next type - - # If none of the types worked, return as dict - return ApiResponse(json_response, metadata) - - # Type guard to ensure we have a model with validation methods - if not ( - isinstance(response_model, type) - and hasattr(response_model, "model_validate") - ): - # Shouldn't happen, but fallback to JSON parsing - json_response = self._parse_json_response(response) - return ApiResponse(json_response, metadata) - - # Use model_validate_json for high-performance parsing - if hasattr(response_model, "model_validate_json"): - validated_data = response_model.model_validate_json(response.content) + ta = TypeAdapter(response_model) + # Prefer validate_json for Pydantic's fast Rust-based JSON parsing + content = response.content + if isinstance(content, (bytes, bytearray)): + validated_data = ta.validate_json(content) else: - # Fallback to old method for compatibility json_response = self._parse_json_response(response) - validated_data = response_model.model_validate(json_response) - + validated_data = ta.validate_python(json_response) return ApiResponse(validated_data, metadata) except PydanticValidationError as e: raise ValidationError( @@ -480,6 +461,7 @@ def _make_request( json_model: BaseModel | None = None, headers_model: BaseModel | None = None, response_model: type[T] | type[Any] | str | _NoValidation | None = None, + error_model: type | None = None, ) -> ApiResponse[T] | ApiResponse[dict[str, Any]]: """Make an HTTP request and return an ApiResponse.""" # Validate request parameters @@ -499,7 +481,7 @@ def _make_request( metadata = TransportMetadata.from_response(response, start_time) # Handle error responses - self._handle_error_response(response, metadata) + self._handle_error_response(response, metadata, error_model=error_model) # Validate and return response if response_model is not None: @@ -840,17 +822,30 @@ async def _execute_request(self, request: httpx.Request) -> httpx.Response: return await self._client.send(request) def _handle_error_response( - self, response: httpx.Response, metadata: TransportMetadata + self, + response: httpx.Response, + metadata: TransportMetadata, + error_model: type | None = None, ) -> None: """Handle HTTP error responses (4xx, 5xx).""" if response.status_code >= 400: error_data = None + typed_error = None try: error_data = response.json() except Exception: pass - raise ApplicationError.from_response(response, metadata, error_data) + if error_model is not None and error_data is not None: + try: + ta = TypeAdapter(error_model) + typed_error = ta.validate_python(error_data) + except Exception: + pass + + raise ApplicationError.from_response( + response, metadata, error_data, typed_error=typed_error + ) def _parse_json_response(self, response: httpx.Response) -> dict[str, Any]: """Parse JSON response with error handling.""" @@ -868,73 +863,23 @@ def _validate_response_model( response_model: type[T] | type[Any] | str | _NoValidation, metadata: TransportMetadata, ) -> ApiResponse[T] | ApiResponse[dict[str, Any]]: - """Validate response using Pydantic model.""" - # Handle special cases where no validation is needed + """Validate response using Pydantic model via TypeAdapter.""" if response_model == "Any" or response_model is NO_VALIDATION: json_response = self._parse_json_response(response) return ApiResponse(json_response, metadata) - # Handle typing.Any - try: - if response_model is Any: - json_response = self._parse_json_response(response) - return ApiResponse(json_response, metadata) - except Exception: - # If there's any issue with the comparison, continue with validation - pass + if response_model is Any: + json_response = self._parse_json_response(response) + return ApiResponse(json_response, metadata) try: - # Handle Union types (like MyapiModelOutputPet | None) - import types - - if hasattr(types, "UnionType") and isinstance( - response_model, types.UnionType - ): - json_response = self._parse_json_response(response) - # For Union types, try to deserialize with each type in the union - union_args = response_model.__args__ - - # Handle None case first - if json_response is None and type(None) in union_args: - return ApiResponse(None, metadata) - - # Try each non-None type in the union - for arg_type in union_args: - if arg_type is not type(None) and hasattr( - arg_type, "model_validate" - ): - try: - validated_data = arg_type.model_validate(json_response) - return ApiResponse(validated_data, metadata) - except Exception: - continue # Try next type - - # If none of the types worked, return as dict - return ApiResponse(json_response, metadata) - - # Type guard to ensure we have a model with validation methods - if not ( - isinstance(response_model, type) - and hasattr(response_model, "model_validate") - ): - # Shouldn't happen, but fallback to JSON parsing - json_response = self._parse_json_response(response) - return ApiResponse(json_response, metadata) - - # Use model_validate_json for high-performance parsing - if hasattr(response_model, "model_validate_json"): - content = response.content - # In tests/mocked responses, content may not be bytes/str; fall back to parsed JSON - if not isinstance(content, (bytes, bytearray, str)): - json_response = self._parse_json_response(response) - validated_data = response_model.model_validate(json_response) - else: - validated_data = response_model.model_validate_json(content) + ta = TypeAdapter(response_model) + content = response.content + if isinstance(content, (bytes, bytearray)): + validated_data = ta.validate_json(content) else: - # Fallback to old method for compatibility json_response = self._parse_json_response(response) - validated_data = response_model.model_validate(json_response) - + validated_data = ta.validate_python(json_response) return ApiResponse(validated_data, metadata) except PydanticValidationError as e: raise ValidationError( @@ -953,6 +898,7 @@ async def _make_request( json_model: BaseModel | None = None, headers_model: BaseModel | None = None, response_model: type[T] | type[Any] | str | _NoValidation | None = None, + error_model: type | None = None, ) -> ApiResponse[T] | ApiResponse[dict[str, Any]]: """Make an HTTP request and return an ApiResponse.""" # Validate request parameters @@ -972,13 +918,12 @@ async def _make_request( metadata = TransportMetadata.from_response(response, start_time) # Handle error responses - self._handle_error_response(response, metadata) + self._handle_error_response(response, metadata, error_model=error_model) # Validate and return response if response_model is not None: return self._validate_response_model(response, response_model, metadata) else: - # No response_model provided - parse JSON into dict json_response = self._parse_json_response(response) return ApiResponse(json_response, metadata) diff --git a/reflectapi-python-runtime/src/reflectapi_runtime/exceptions.py b/reflectapi-python-runtime/src/reflectapi_runtime/exceptions.py index bd7aee40..b4e4530c 100644 --- a/reflectapi-python-runtime/src/reflectapi_runtime/exceptions.py +++ b/reflectapi-python-runtime/src/reflectapi_runtime/exceptions.py @@ -78,9 +78,11 @@ def __init__( *, metadata: TransportMetadata, error_data: Any | None = None, + typed_error: Any | None = None, ) -> None: super().__init__(message, metadata=metadata) self.error_data = error_data + self.typed_error = typed_error @property def status_code(self) -> int: @@ -93,8 +95,14 @@ def from_response( response: httpx.Response, metadata: TransportMetadata, error_data: Any | None = None, + typed_error: Any | None = None, ) -> ApplicationError: - """Create an ApplicationError from an HTTP response.""" + """Create an ApplicationError from an HTTP response. + + Args: + typed_error: If provided, the error body deserialized into the + typed error model from the API schema. Access via .typed_error. + """ message = f"API error {response.status_code}: {response.reason_phrase}" if error_data: message += f" - {error_data}" @@ -103,6 +111,7 @@ def from_response( message, metadata=metadata, error_data=error_data, + typed_error=typed_error, ) diff --git a/reflectapi-python-runtime/src/reflectapi_runtime/response.py b/reflectapi-python-runtime/src/reflectapi_runtime/response.py index 9338f5ec..ef3e2b5e 100644 --- a/reflectapi-python-runtime/src/reflectapi_runtime/response.py +++ b/reflectapi-python-runtime/src/reflectapi_runtime/response.py @@ -9,6 +9,7 @@ import httpx # noqa: TC002 T = TypeVar("T") +E = TypeVar("E") @dataclass(frozen=True) @@ -36,11 +37,16 @@ def from_response( ) -class ApiResponse(Generic[T]): - """Wrapper for successful API responses. +class ApiResponse(Generic[T, E]): + """Wrapper for API responses with typed success and error values. + + Type parameters: + T: The success response type. + E: The error response type (defaults to Any when not specified). Provides ergonomic access to both the deserialized value and transport metadata. - The deserialized value can be accessed directly via attribute access. + Supports `ApiResponse[OutputType]` (backward compatible) and + `ApiResponse[OutputType, ErrorType]` (with typed errors). """ def __init__(self, value: T, metadata: TransportMetadata) -> None: diff --git a/reflectapi-schema/src/ids.rs b/reflectapi-schema/src/ids.rs new file mode 100644 index 00000000..79b6eba6 --- /dev/null +++ b/reflectapi-schema/src/ids.rs @@ -0,0 +1,458 @@ +/// ID assignment utilities for ensuring unique, stable SymbolIds before normalization +/// +/// This module fixes the core issue where JSON-deserialized schemas have default +/// SymbolIds that cause conflicts during normalization discovery. +use crate::symbol::STDLIB_TYPES; +use crate::{Enum, Schema, Struct, SymbolId, SymbolKind, Type, Typespace}; +use std::collections::HashMap; + +/// Ensure all symbols in the schema have unique, stable IDs based on their canonical names. +/// +/// Types that share a fully-qualified name across input and output typespaces +/// receive distinct SymbolIds via the disambiguator field. This prevents +/// collisions when types with the same name have different definitions in +/// each typespace (e.g., request vs response variants of the same type). +pub fn ensure_symbol_ids(schema: &mut Schema) { + if schema.id.is_unknown() { + schema.id = SymbolId::new( + SymbolKind::Struct, + vec!["__schema__".to_string(), schema.name.clone()], + ); + } + + let mut seen: HashMap = HashMap::new(); + register_stdlib_types(&mut seen); + + for function in &mut schema.functions { + if function.id.is_unknown() { + function.id = SymbolId::new(SymbolKind::Endpoint, vec![function.name.clone()]); + } + } + + // Use separate seen maps per typespace, sharing stdlib registrations. + // This ensures types with the same FQN in different typespaces get + // distinct SymbolIds (via disambiguator) when they are different types. + let mut input_seen = seen.clone(); + let mut output_seen = seen; + assign_typespace_ids(&mut schema.input_types, &mut input_seen); + assign_typespace_ids(&mut schema.output_types, &mut output_seen); + + // For any FQN that appears in both typespaces with different types, + // disambiguate the output typespace's IDs + for (fqn, input_id) in &input_seen { + if let Some(output_id) = output_seen.get(fqn) { + if input_id == output_id { + // Same ID means same type — check if the actual types differ + let input_ty = schema.input_types.get_type(fqn); + let output_ty = schema.output_types.get_type(fqn); + if let (Some(input_ty), Some(output_ty)) = (input_ty, output_ty) { + if input_ty != output_ty { + // Different types with same name — disambiguate output + let disambiguated = + SymbolId::with_disambiguator(output_id.kind, output_id.path.clone(), 1); + assign_disambiguated_id(&mut schema.output_types, fqn, &disambiguated); + } + } + } + } + } +} + +/// Pre-register well-known stdlib types that might be referenced but not always defined +fn register_stdlib_types(seen: &mut HashMap) { + for &(name, kind) in STDLIB_TYPES { + seen.entry(name.to_string()) + .or_insert_with(|| SymbolId::new(kind, split_path(name))); + } +} + +/// Assign IDs to all types in a typespace +fn assign_typespace_ids(typespace: &mut Typespace, seen: &mut HashMap) { + let mut new_typespace = Typespace::new(); + + for ty in typespace.types() { + let mut updated_type = ty.clone(); + let type_name = updated_type.name().to_string(); + assign_type_id(&type_name, &mut updated_type, seen); + new_typespace.insert_type(updated_type); + } + + *typespace = new_typespace; +} + +/// Assign a unique ID to a type and its nested members +fn assign_type_id(fqn: &str, ty: &mut Type, seen: &mut HashMap) { + let id = seen + .entry(fqn.to_string()) + .or_insert_with(|| { + let kind = match ty { + Type::Primitive(_) => SymbolKind::Primitive, + Type::Struct(_) => SymbolKind::Struct, + Type::Enum(_) => SymbolKind::Enum, + }; + SymbolId::new(kind, split_path(fqn)) + }) + .clone(); + + match ty { + Type::Primitive(p) => { + if p.id.is_unknown() { + p.id = id; + } + } + Type::Struct(s) => { + if s.id.is_unknown() { + s.id = id.clone(); + } + assign_struct_member_ids(s, &s.id.clone()); + } + Type::Enum(e) => { + if e.id.is_unknown() { + e.id = id.clone(); + } + assign_enum_member_ids(e, &e.id.clone()); + } + } +} + +/// Reassign the top-level ID of a type in a typespace (for disambiguation) +fn assign_disambiguated_id(typespace: &mut Typespace, fqn: &str, new_id: &SymbolId) { + let types: Vec<_> = typespace.types().cloned().collect(); + let mut new_typespace = Typespace::new(); + for mut ty in types { + if ty.name() == fqn { + match &mut ty { + Type::Primitive(p) => p.id = new_id.clone(), + Type::Struct(s) => { + s.id = new_id.clone(); + // Clear member IDs so they get re-assigned with the new parent + clear_struct_member_ids(s); + assign_struct_member_ids(s, new_id); + } + Type::Enum(e) => { + e.id = new_id.clone(); + clear_enum_member_ids(e); + assign_enum_member_ids(e, new_id); + } + } + } + new_typespace.insert_type(ty); + } + *typespace = new_typespace; +} + +fn clear_struct_member_ids(s: &mut Struct) { + match &mut s.fields { + crate::Fields::Named(fields) | crate::Fields::Unnamed(fields) => { + for field in fields { + field.id = SymbolId::default(); + } + } + crate::Fields::None => {} + } +} + +fn clear_enum_member_ids(e: &mut Enum) { + for variant in &mut e.variants { + variant.id = SymbolId::default(); + match &mut variant.fields { + crate::Fields::Named(fields) | crate::Fields::Unnamed(fields) => { + for field in fields { + field.id = SymbolId::default(); + } + } + crate::Fields::None => {} + } + } +} + +/// Assign IDs to struct fields +fn assign_struct_member_ids(s: &mut Struct, owner: &SymbolId) { + match &mut s.fields { + crate::Fields::Named(fields) => { + for field in fields { + if field.id.is_unknown() { + let mut path = owner.path.clone(); + path.push(field.name.clone()); + field.id = SymbolId::new(SymbolKind::Field, path); + } + } + } + crate::Fields::Unnamed(fields) => { + for (i, field) in fields.iter_mut().enumerate() { + if field.id.is_unknown() { + let mut path = owner.path.clone(); + path.push(format!("arg{i:02}")); + field.id = SymbolId::new(SymbolKind::Field, path); + } + } + } + crate::Fields::None => {} + } +} + +/// Assign IDs to enum variants and their fields +fn assign_enum_member_ids(e: &mut Enum, owner: &SymbolId) { + for variant in &mut e.variants { + if variant.id.is_unknown() { + let mut path = owner.path.clone(); + path.push(variant.name.clone()); + variant.id = SymbolId::new(SymbolKind::Variant, path); + } + + match &mut variant.fields { + crate::Fields::Named(fields) => { + for field in fields { + if field.id.is_unknown() { + let mut path = variant.id.path.clone(); + path.push(field.name.clone()); + field.id = SymbolId::new(SymbolKind::Field, path); + } + } + } + crate::Fields::Unnamed(fields) => { + for (i, field) in fields.iter_mut().enumerate() { + if field.id.is_unknown() { + let mut path = variant.id.path.clone(); + path.push(format!("arg{i:02}")); + field.id = SymbolId::new(SymbolKind::Field, path); + } + } + } + crate::Fields::None => {} + } + } +} + +/// Split a fully-qualified name into path components +fn split_path(fqn: &str) -> Vec { + fqn.split("::").map(|s| s.to_string()).collect() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_split_path() { + assert_eq!( + split_path("std::option::Option"), + vec!["std", "option", "Option"] + ); + assert_eq!( + split_path("myapi::proto::Headers"), + vec!["myapi", "proto", "Headers"] + ); + assert_eq!(split_path("SimpleType"), vec!["SimpleType"]); + } + + #[test] + fn test_is_unknown() { + let unknown = SymbolId::default(); + assert!(unknown.is_unknown()); + + let known = SymbolId::new(SymbolKind::Struct, vec!["MyType".to_string()]); + assert!(!known.is_unknown()); + } + + #[test] + fn test_pre_assigned_id_member_paths_consistent() { + // Regression: when a struct has a pre-assigned ID (e.g. from Struct::new), + // field IDs must use the struct's actual ID as their parent, not the + // seen-map ID which uses split_path and produces different path segments. + use crate::{Field, Fields}; + + let mut schema = Schema::new(); + schema.name = "Test".to_string(); + + // Struct::new("api::User") sets id.path = ["api::User"] (single unsplit element) + let mut s = crate::Struct::new("api::User"); + s.fields = Fields::Named(vec![Field::new("name".into(), "String".into())]); + schema.input_types.insert_type(s.into()); + + ensure_symbol_ids(&mut schema); + + let s = schema + .input_types + .get_type("api::User") + .unwrap() + .as_struct() + .unwrap(); + + // The struct's ID path should be preserved as-is + let struct_path = &s.id.path; + + // The field's path should start with the struct's actual path + let field = s.fields().next().unwrap(); + let field_path = &field.id.path; + + assert_eq!( + &field_path[..field_path.len() - 1], + struct_path.as_slice(), + "Field path prefix {field_path:?} should match struct path {struct_path:?}" + ); + } + + #[test] + fn test_pre_assigned_id_enum_member_paths_consistent() { + // Same regression test for enums + use crate::Variant; + + let mut schema = Schema::new(); + schema.name = "Test".to_string(); + + let mut e = crate::Enum::new("api::Status".into()); + e.variants = vec![Variant::new("Active".into())]; + schema.input_types.insert_type(e.into()); + + ensure_symbol_ids(&mut schema); + + let e = schema + .input_types + .get_type("api::Status") + .unwrap() + .as_enum() + .unwrap(); + + let enum_path = &e.id.path; + let variant = &e.variants[0]; + let variant_path = &variant.id.path; + + assert_eq!( + &variant_path[..variant_path.len() - 1], + enum_path.as_slice(), + "Variant path prefix {variant_path:?} should match enum path {enum_path:?}" + ); + } + + #[test] + fn test_zero_padded_tuple_field_ordering() { + // Regression: unnamed (tuple) fields with >= 10 elements must use zero-padded + // indices so that lexicographic sorting preserves declaration order. + use crate::{Field, Fields}; + + let mut schema = Schema::new(); + schema.name = "Test".to_string(); + + let mut tuple_struct = crate::Struct::new("BigTuple"); + // Create 12 unnamed fields + let fields: Vec = (0..12) + .map(|i| Field::new(format!("{i}"), format!("u{}", 8 + i).into())) + .collect(); + tuple_struct.fields = Fields::Unnamed(fields); + schema.input_types.insert_type(tuple_struct.into()); + + ensure_symbol_ids(&mut schema); + + let s = schema + .input_types + .get_type("BigTuple") + .unwrap() + .as_struct() + .unwrap(); + + let field_ids: Vec = s + .fields() + .map(|f| f.id.path.last().unwrap().clone()) + .collect(); + + // Verify zero-padded format: arg00, arg01, ..., arg09, arg10, arg11 + assert_eq!(field_ids.len(), 12); + assert_eq!(field_ids[0], "arg00"); + assert_eq!(field_ids[1], "arg01"); + assert_eq!(field_ids[2], "arg02"); + assert_eq!(field_ids[9], "arg09"); + assert_eq!(field_ids[10], "arg10"); + assert_eq!(field_ids[11], "arg11"); + + // Verify lexicographic sort preserves declaration order: + // arg02 < arg10 (not arg10 < arg2 which would happen without padding) + let mut sorted_ids = field_ids.clone(); + sorted_ids.sort(); + assert_eq!( + field_ids, sorted_ids, + "Zero-padded field IDs should sort in declaration order" + ); + } + + #[test] + fn test_disambiguated_id_updates_member_ids() { + // Regression: when a type in the output typespace is disambiguated (because + // a type with the same name but different fields exists in the input typespace), + // the field IDs of the disambiguated type must reflect the new parent ID. + use crate::{Field, Fields}; + + let mut schema = Schema::new(); + schema.name = "Test".to_string(); + + // Input "Foo" has field "a" + let mut input_foo = crate::Struct::new("Foo"); + input_foo.fields = Fields::Named(vec![Field::new("a".into(), "u32".into())]); + schema.input_types.insert_type(input_foo.into()); + + // Output "Foo" has field "b" (different structure triggers disambiguation) + let mut output_foo = crate::Struct::new("Foo"); + output_foo.fields = Fields::Named(vec![Field::new("b".into(), "u64".into())]); + schema.output_types.insert_type(output_foo.into()); + + ensure_symbol_ids(&mut schema); + + // The output Foo should have disambiguator=1 + let output_struct = schema + .output_types + .get_type("Foo") + .unwrap() + .as_struct() + .unwrap(); + assert_eq!( + output_struct.id.disambiguator, 1, + "Output Foo should have disambiguator=1, got {:?}", + output_struct.id + ); + + // The field "b" should have a path consistent with the disambiguated parent + let field_b = output_struct.fields().next().unwrap(); + let field_path_prefix = &field_b.id.path[..field_b.id.path.len() - 1]; + assert_eq!( + field_path_prefix, + output_struct.id.path.as_slice(), + "Field path prefix {:?} should match disambiguated parent path {:?}", + field_b.id.path, + output_struct.id.path + ); + } + + #[test] + fn test_schema_root_id_does_not_collide_with_type() { + // Regression: a schema named "User" with a struct also named "User" + // should not produce colliding IDs. The schema root uses the "__schema__" + // sentinel in its path to avoid this. + let mut schema = Schema::new(); + schema.name = "User".to_string(); + + let user_struct = crate::Struct::new("User"); + schema.input_types.insert_type(user_struct.into()); + + ensure_symbol_ids(&mut schema); + + let struct_type = schema + .input_types + .get_type("User") + .unwrap() + .as_struct() + .unwrap(); + + assert_ne!( + schema.id, struct_type.id, + "Schema root ID {:?} should not collide with struct ID {:?}", + schema.id, struct_type.id + ); + + // Verify the schema root uses the __schema__ sentinel + assert!( + schema.id.path.contains(&"__schema__".to_string()), + "Schema root ID path should contain '__schema__' sentinel, got {:?}", + schema.id.path + ); + } +} diff --git a/reflectapi-schema/src/lib.rs b/reflectapi-schema/src/lib.rs index 63c23749..70f9f4a8 100644 --- a/reflectapi-schema/src/lib.rs +++ b/reflectapi-schema/src/lib.rs @@ -1,11 +1,23 @@ mod codegen; +mod ids; mod internal; +mod normalize; mod rename; +mod semantic; mod subst; +mod symbol; mod visit; pub use self::codegen::*; +pub use self::ids::ensure_symbol_ids; +pub use self::normalize::{ + CircularDependencyResolutionStage, Consolidation, Naming, NamingResolutionStage, + NormalizationError, NormalizationPipeline, NormalizationStage, Normalizer, PipelineBuilder, + ResolutionStrategy, TypeConsolidationStage, +}; +pub use self::semantic::*; pub use self::subst::{mk_subst, Instantiate, Substitute}; +pub use self::symbol::{SymbolId, SymbolKind, STDLIB_TYPES, STDLIB_TYPE_PREFIXES}; pub use self::visit::{VisitMut, Visitor}; #[cfg(feature = "glob")] @@ -24,6 +36,9 @@ use std::{ #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct Schema { + #[serde(skip_serializing, default)] + pub id: SymbolId, + pub name: String, #[serde(skip_serializing_if = "String::is_empty", default)] @@ -48,6 +63,7 @@ impl Default for Schema { impl Schema { pub fn new() -> Self { Schema { + id: SymbolId::default(), name: String::new(), description: String::new(), functions: Vec::new(), @@ -86,6 +102,7 @@ impl Schema { pub fn extend(&mut self, other: Self) { let Self { + id: _, functions, input_types, output_types, @@ -404,6 +421,9 @@ impl Typespace { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct Function { + #[serde(skip_serializing, default)] + pub id: SymbolId, + /// Includes entity and action, for example: users.login pub name: String, /// URL mounting path, for example: /api/v1 @@ -449,7 +469,9 @@ pub struct Function { impl Function { pub fn new(name: String) -> Self { + let id = SymbolId::endpoint_id(vec![name.clone()]); Function { + id, name, deprecation_note: Default::default(), path: Default::default(), @@ -505,7 +527,7 @@ impl Function { } } -#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "snake_case")] pub enum SerializationMode { #[default] @@ -724,8 +746,11 @@ impl Type { } } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq)] pub struct Primitive { + #[serde(skip_serializing, default)] + pub id: SymbolId, + pub name: String, #[serde(skip_serializing_if = "String::is_empty", default)] pub description: String, @@ -746,7 +771,9 @@ impl Primitive { parameters: Vec, fallback: Option, ) -> Self { + let id = SymbolId::new(SymbolKind::Primitive, vec![name.clone()]); Primitive { + id, name, description, parameters, @@ -827,14 +854,35 @@ impl Primitive { } } +impl PartialEq for Primitive { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + && self.description == other.description + && self.parameters == other.parameters + && self.fallback == other.fallback + } +} + +impl std::hash::Hash for Primitive { + fn hash(&self, state: &mut H) { + self.name.hash(state); + self.description.hash(state); + self.parameters.hash(state); + self.fallback.hash(state); + } +} + impl From for Type { fn from(val: Primitive) -> Self { Type::Primitive(val) } } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq)] pub struct Struct { + #[serde(skip_serializing, default)] + pub id: SymbolId, + /// Name of a struct, should be a valid Rust struct name identifier pub name: String, @@ -863,8 +911,11 @@ pub struct Struct { impl Struct { pub fn new(name: impl Into) -> Self { + let name = name.into(); + let id = SymbolId::struct_id(vec![name.clone()]); Struct { - name: name.into(), + id, + name, serde_name: Default::default(), description: Default::default(), parameters: Default::default(), @@ -934,6 +985,18 @@ impl Struct { } } +impl PartialEq for Struct { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + && self.serde_name == other.serde_name + && self.description == other.description + && self.parameters == other.parameters + && self.fields == other.fields + && self.transparent == other.transparent + && self.codegen_config == other.codegen_config + } +} + impl From for Type { fn from(val: Struct) -> Self { Type::Struct(val) @@ -1015,6 +1078,9 @@ impl IntoIterator for Fields { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq)] pub struct Field { + #[serde(skip_serializing, default)] + pub id: SymbolId, + /// Field name, should be a valid Rust field name identifier pub name: String, /// If a serialized name is not a valid Rust field name identifier @@ -1068,6 +1134,7 @@ impl PartialEq for Field { fn eq( &self, Self { + id: _, name, serde_name, description, @@ -1090,9 +1157,23 @@ impl PartialEq for Field { } } +impl std::hash::Hash for Field { + fn hash(&self, state: &mut H) { + self.name.hash(state); + self.serde_name.hash(state); + self.description.hash(state); + self.deprecation_note.hash(state); + self.type_ref.hash(state); + self.required.hash(state); + self.flattened.hash(state); + self.transform_callback.hash(state); + } +} + impl Field { pub fn new(name: String, type_ref: TypeReference) -> Self { Field { + id: SymbolId::default(), name, type_ref, serde_name: Default::default(), @@ -1167,8 +1248,11 @@ fn is_default(t: &T) -> bool { *t == Default::default() } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq)] pub struct Enum { + #[serde(skip_serializing, default)] + pub id: SymbolId, + pub name: String, #[serde(skip_serializing_if = "String::is_empty", default)] pub serde_name: String, @@ -1191,7 +1275,9 @@ pub struct Enum { impl Enum { pub fn new(name: String) -> Self { + let id = SymbolId::enum_id(vec![name.clone()]); Enum { + id, name, serde_name: Default::default(), description: Default::default(), @@ -1231,14 +1317,29 @@ impl Enum { } } +impl PartialEq for Enum { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + && self.serde_name == other.serde_name + && self.description == other.description + && self.parameters == other.parameters + && self.representation == other.representation + && self.variants == other.variants + && self.codegen_config == other.codegen_config + } +} + impl From for Type { fn from(val: Enum) -> Self { Type::Enum(val) } } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq)] pub struct Variant { + #[serde(skip_serializing, default)] + pub id: SymbolId, + pub name: String, #[serde(skip_serializing_if = "String::is_empty", default)] pub serde_name: String, @@ -1257,6 +1358,7 @@ pub struct Variant { impl Variant { pub fn new(name: String) -> Self { Variant { + id: SymbolId::default(), name, serde_name: String::new(), description: String::new(), @@ -1295,6 +1397,17 @@ impl Variant { } } +impl PartialEq for Variant { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + && self.serde_name == other.serde_name + && self.description == other.description + && self.fields == other.fields + && self.discriminant == other.discriminant + && self.untagged == other.untagged + } +} + #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash, Default)] #[serde(rename_all = "snake_case")] pub enum Representation { diff --git a/reflectapi-schema/src/normalize.rs b/reflectapi-schema/src/normalize.rs new file mode 100644 index 00000000..f8ded076 --- /dev/null +++ b/reflectapi-schema/src/normalize.rs @@ -0,0 +1,2166 @@ +/// Normalization pipeline for transforming raw schemas into semantic IRs +/// +/// This module provides the core normalization passes that transform +/// the raw reflectapi_schema types into validated, immutable semantic +/// representations with deterministic ordering and resolved dependencies. +use crate::symbol::{STDLIB_TYPES, STDLIB_TYPE_PREFIXES}; +use crate::{ + Enum, Field, FieldStyle, Fields, Function, Primitive, ResolvedTypeReference, Schema, + SemanticEnum, SemanticField, SemanticFunction, SemanticPrimitive, SemanticSchema, + SemanticStruct, SemanticType, SemanticTypeParameter, SemanticVariant, Struct, SymbolId, + SymbolInfo, SymbolKind, SymbolTable, Type, TypeReference, Variant, +}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; + +/// Trait for individual normalization stages in the pipeline +pub trait NormalizationStage { + fn name(&self) -> &'static str; + fn transform(&self, schema: &mut Schema) -> Result<(), Vec>; +} + +/// Normalization pipeline that applies multiple stages in sequence +#[derive(Default)] +pub struct NormalizationPipeline { + stages: Vec>, +} + +impl NormalizationPipeline { + pub fn new() -> Self { + Self { stages: Vec::new() } + } + + pub fn add_stage(mut self, stage: S) -> Self { + self.stages.push(Box::new(stage)); + self + } + + pub fn run(&self, schema: &mut Schema) -> Result<(), Vec> { + for stage in &self.stages { + stage.transform(schema)?; + } + Ok(()) + } + + /// Create the standard normalization pipeline. + /// + /// Delegates to `PipelineBuilder` with all default settings. + pub fn standard() -> Self { + PipelineBuilder::new().build() + } + + /// Create a codegen-oriented pipeline that only runs CircularDependencyResolution. + /// + /// This is designed for use when the caller has already run + /// `schema.consolidate_types()` and does not want NamingResolution + /// (which would rename types and create a name-domain mismatch + /// between the SemanticSchema and the raw Schema used for rendering). + /// + /// Delegates to `PipelineBuilder` with consolidation and naming skipped. + pub fn for_codegen() -> Self { + PipelineBuilder::new() + .consolidation(Consolidation::Skip) + .naming(Naming::Skip) + .build() + } +} + +// --------------------------------------------------------------------------- +// PipelineBuilder: configurable pipeline construction +// --------------------------------------------------------------------------- + +/// Controls whether and how input/output types are merged. +#[derive(Debug, Clone, Default)] +pub enum Consolidation { + /// Run the standard `TypeConsolidationStage`. + #[default] + Standard, + /// Skip type consolidation entirely. + Skip, +} + +/// Controls how type names are resolved. +#[derive(Default)] +pub enum Naming { + /// Run the standard `NamingResolutionStage`. + #[default] + Standard, + /// Skip naming resolution entirely. + Skip, + /// Use a custom naming stage. + Custom(Box), +} + +impl std::fmt::Debug for Naming { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Naming::Standard => write!(f, "Naming::Standard"), + Naming::Skip => write!(f, "Naming::Skip"), + Naming::Custom(_) => write!(f, "Naming::Custom(...)"), + } + } +} + +/// Builder for configuring a normalization pipeline. +/// +/// Provides fine-grained control over which normalization stages are included +/// and in what order. The default configuration matches `NormalizationPipeline::standard()`. +/// +/// # Examples +/// +/// ```rust,ignore +/// // Standard pipeline (equivalent to NormalizationPipeline::standard()) +/// let pipeline = PipelineBuilder::new().build(); +/// +/// // Codegen pipeline (equivalent to NormalizationPipeline::for_codegen()) +/// let pipeline = PipelineBuilder::new() +/// .consolidation(Consolidation::Skip) +/// .naming(Naming::Skip) +/// .build(); +/// +/// // Custom pipeline with extra stages +/// let pipeline = PipelineBuilder::new() +/// .circular_dependency_strategy(ResolutionStrategy::Boxing) +/// .add_stage(MyCustomStage) +/// .build(); +/// ``` +pub struct PipelineBuilder { + consolidation: Consolidation, + naming: Naming, + circular_dependency_strategy: ResolutionStrategy, + extra_stages: Vec>, +} + +impl Default for PipelineBuilder { + fn default() -> Self { + Self::new() + } +} + +impl PipelineBuilder { + /// Create a new builder with default settings (all stages enabled). + pub fn new() -> Self { + Self { + consolidation: Consolidation::default(), + naming: Naming::default(), + circular_dependency_strategy: ResolutionStrategy::default(), + extra_stages: Vec::new(), + } + } + + /// Set the consolidation strategy. + pub fn consolidation(mut self, consolidation: Consolidation) -> Self { + self.consolidation = consolidation; + self + } + + /// Set the naming resolution strategy. + pub fn naming(mut self, naming: Naming) -> Self { + self.naming = naming; + self + } + + /// Set the circular dependency resolution strategy. + pub fn circular_dependency_strategy(mut self, strategy: ResolutionStrategy) -> Self { + self.circular_dependency_strategy = strategy; + self + } + + /// Append a custom stage that will run after the built-in stages. + pub fn add_stage(mut self, stage: S) -> Self { + self.extra_stages.push(Box::new(stage)); + self + } + + /// Build the configured `NormalizationPipeline`. + /// + /// Stages are added in order: + /// 1. Type consolidation (if not skipped) + /// 2. Naming resolution (if not skipped, or custom stage) + /// 3. Circular dependency resolution (always included) + /// 4. Any extra stages added via `add_stage()` + pub fn build(self) -> NormalizationPipeline { + let mut pipeline = NormalizationPipeline::new(); + + match self.consolidation { + Consolidation::Standard => { + pipeline = pipeline.add_stage(TypeConsolidationStage); + } + Consolidation::Skip => {} + } + + match self.naming { + Naming::Standard => { + pipeline = pipeline.add_stage(NamingResolutionStage); + } + Naming::Skip => {} + Naming::Custom(stage) => { + pipeline.stages.push(stage); + } + } + + pipeline = pipeline.add_stage(CircularDependencyResolutionStage::with_strategy( + self.circular_dependency_strategy, + )); + + for stage in self.extra_stages { + pipeline.stages.push(stage); + } + + pipeline + } +} + +// --------------------------------------------------------------------------- +// Stage 1: Type Consolidation +// --------------------------------------------------------------------------- + +/// Merges input_types and output_types into a single unified types collection. +/// Handles naming conflicts by renaming types with prefixes. +pub struct TypeConsolidationStage; + +impl NormalizationStage for TypeConsolidationStage { + fn name(&self) -> &'static str { + "TypeConsolidation" + } + + fn transform(&self, schema: &mut Schema) -> Result<(), Vec> { + use crate::Typespace; + + let mut consolidated = Typespace::new(); + let mut name_conflicts = HashMap::new(); + // Tracks old_name -> new_name for type reference rewriting + let mut rename_map: HashMap = HashMap::new(); + + let mut input_type_names = HashMap::new(); + let mut output_type_names = HashMap::new(); + + for ty in schema.input_types.types() { + let simple_name = extract_simple_name(ty.name()); + input_type_names.insert(simple_name.clone(), ty.clone()); + + if output_type_names.contains_key(&simple_name) { + name_conflicts.insert(simple_name, true); + } + } + + for ty in schema.output_types.types() { + let simple_name = extract_simple_name(ty.name()); + output_type_names.insert(simple_name.clone(), ty.clone()); + + if input_type_names.contains_key(&simple_name) { + name_conflicts.insert(simple_name, true); + } + } + + for ty in schema.input_types.types() { + let simple_name = extract_simple_name(ty.name()); + let mut new_type = ty.clone(); + + if name_conflicts.contains_key(&simple_name) { + let old_name = ty.name().to_string(); + let new_name = format!("input.{}", ty.name().replace("::", ".")); + rename_type(&mut new_type, &new_name); + rename_map.insert(old_name, new_name); + } + + consolidated.insert_type(new_type); + } + + for ty in schema.output_types.types() { + let simple_name = extract_simple_name(ty.name()); + let mut new_type = ty.clone(); + + if name_conflicts.contains_key(&simple_name) { + let old_name = ty.name().to_string(); + let new_name = format!("output.{}", ty.name().replace("::", ".")); + rename_type(&mut new_type, &new_name); + rename_map.insert(old_name, new_name); + consolidated.insert_type(new_type); + } else if !input_type_names.contains_key(&simple_name) { + consolidated.insert_type(new_type); + } + } + + schema.input_types = consolidated; + schema.output_types = Typespace::new(); + + // Rewrite type references that still point to old names + if !rename_map.is_empty() { + for function in &mut schema.functions { + update_type_reference_in_option(&mut function.input_type, &rename_map); + update_type_reference_in_option(&mut function.input_headers, &rename_map); + update_type_reference_in_option(&mut function.output_type, &rename_map); + update_type_reference_in_option(&mut function.error_type, &rename_map); + } + + let types_to_update: Vec<_> = schema.input_types.types().cloned().collect(); + schema.input_types = Typespace::new(); + for mut ty in types_to_update { + update_type_references_in_type(&mut ty, &rename_map); + schema.input_types.insert_type(ty); + } + } + + Ok(()) + } +} + +fn extract_simple_name(qualified_name: &str) -> String { + qualified_name + .split("::") + .last() + .unwrap_or(qualified_name) + .to_string() +} + +fn rename_type(ty: &mut Type, new_name: &str) { + let new_path: Vec = new_name.split("::").map(|s| s.to_string()).collect(); + match ty { + Type::Struct(s) => { + s.name = new_name.to_string(); + s.id.path = new_path; + } + Type::Enum(e) => { + e.name = new_name.to_string(); + e.id.path = new_path; + } + Type::Primitive(p) => { + p.name = new_name.to_string(); + p.id.path = new_path; + } + } +} + +// --------------------------------------------------------------------------- +// Stage 2: Naming Resolution +// --------------------------------------------------------------------------- + +/// Sanitizes type names by stripping module paths and handling naming conflicts. +pub struct NamingResolutionStage; + +impl NormalizationStage for NamingResolutionStage { + fn name(&self) -> &'static str { + "NamingResolution" + } + + fn transform(&self, schema: &mut Schema) -> Result<(), Vec> { + let mut name_usage: HashMap> = HashMap::new(); + let mut name_conflicts = HashMap::new(); + + for ty in schema.input_types.types() { + let qualified_name = ty.name().to_string(); + let simple_name = extract_simple_name(&qualified_name); + + let entries = name_usage.entry(simple_name.clone()).or_default(); + if !entries.contains(&qualified_name) { + if !entries.is_empty() { + name_conflicts.insert(simple_name.clone(), true); + } + entries.push(qualified_name); + } + } + + let types_to_update: Vec<_> = schema.input_types.types().cloned().collect(); + schema.input_types = crate::Typespace::new(); + + for mut ty in types_to_update { + let qualified_name = ty.name().to_string(); + let simple_name = extract_simple_name(&qualified_name); + + let resolved_name = if name_conflicts.contains_key(&simple_name) { + generate_unique_name(&qualified_name) + } else { + simple_name + }; + + rename_type(&mut ty, &resolved_name); + schema.input_types.insert_type(ty); + } + + update_type_references_in_schema(schema, &name_usage, &name_conflicts); + + Ok(()) + } +} + +fn generate_unique_name(qualified_name: &str) -> String { + let parts: Vec<&str> = qualified_name.split("::").collect(); + if parts.len() < 2 { + return qualified_name.to_string(); + } + + let type_name = parts.last().unwrap(); + let module_parts: Vec<&str> = parts[..parts.len() - 1].to_vec(); + + let non_excluded: Vec<&str> = module_parts + .iter() + .filter(|&&part| part != "model" && part != "proto" && !part.is_empty()) + .copied() + .collect(); + + let prefix = if non_excluded.is_empty() { + module_parts.join("_") + } else { + non_excluded + .iter() + .map(|s| capitalize_first_letter(s)) + .collect::>() + .join("") + }; + format!("{prefix}{type_name}") +} + +fn capitalize_first_letter(s: &str) -> String { + let mut chars = s.chars(); + match chars.next() { + None => String::new(), + Some(first) => first.to_uppercase().collect::() + chars.as_str(), + } +} + +fn update_type_references_in_schema( + schema: &mut Schema, + name_usage: &HashMap>, + name_conflicts: &HashMap, +) { + let mut name_mapping = HashMap::new(); + + for (simple_name, qualified_names) in name_usage { + if name_conflicts.contains_key(simple_name) { + for qualified_name in qualified_names { + let resolved_name = generate_unique_name(qualified_name); + name_mapping.insert(qualified_name.clone(), resolved_name); + } + } else { + for qualified_name in qualified_names { + name_mapping.insert(qualified_name.clone(), simple_name.clone()); + } + } + } + + for function in &mut schema.functions { + update_type_reference_in_option(&mut function.input_type, &name_mapping); + update_type_reference_in_option(&mut function.input_headers, &name_mapping); + update_type_reference_in_option(&mut function.output_type, &name_mapping); + update_type_reference_in_option(&mut function.error_type, &name_mapping); + } + + let types_to_update: Vec<_> = schema.input_types.types().cloned().collect(); + schema.input_types = crate::Typespace::new(); + + for mut ty in types_to_update { + update_type_references_in_type(&mut ty, &name_mapping); + schema.input_types.insert_type(ty); + } +} + +fn update_type_reference( + type_ref: &mut crate::TypeReference, + name_mapping: &HashMap, +) { + if let Some(new_name) = name_mapping.get(&type_ref.name) { + type_ref.name.clone_from(new_name); + } + + for arg in &mut type_ref.arguments { + update_type_reference(arg, name_mapping); + } +} + +fn update_type_reference_in_option( + type_ref_opt: &mut Option, + name_mapping: &HashMap, +) { + if let Some(type_ref) = type_ref_opt { + update_type_reference(type_ref, name_mapping); + } +} + +fn update_type_references_in_type(ty: &mut crate::Type, name_mapping: &HashMap) { + match ty { + crate::Type::Struct(s) => match &mut s.fields { + crate::Fields::Named(fields) | crate::Fields::Unnamed(fields) => { + for field in fields { + update_type_reference(&mut field.type_ref, name_mapping); + } + } + crate::Fields::None => {} + }, + crate::Type::Enum(e) => { + for variant in &mut e.variants { + match &mut variant.fields { + crate::Fields::Named(fields) | crate::Fields::Unnamed(fields) => { + for field in fields { + update_type_reference(&mut field.type_ref, name_mapping); + } + } + crate::Fields::None => {} + } + } + } + crate::Type::Primitive(p) => { + if let Some(fallback) = &mut p.fallback { + update_type_reference(fallback, name_mapping); + } + } + } +} + +// --------------------------------------------------------------------------- +// Stage 3: Circular Dependency Resolution +// --------------------------------------------------------------------------- + +/// Detects and resolves circular dependencies using Tarjan's SCC algorithm +/// and configurable resolution strategies. +pub struct CircularDependencyResolutionStage { + strategy: ResolutionStrategy, +} + +#[derive(Debug, Clone, Default)] +pub enum ResolutionStrategy { + /// Try boxing first, then forward declarations + #[default] + Intelligent, + /// Always use Box for self-references + Boxing, + /// Always use forward declarations + ForwardDeclarations, + /// Make circular references optional + OptionalBreaking, + /// Use reference counting for complex cycles + ReferenceCounted, +} + +impl CircularDependencyResolutionStage { + pub fn new() -> Self { + Self { + strategy: ResolutionStrategy::default(), + } + } + + pub fn with_strategy(strategy: ResolutionStrategy) -> Self { + Self { strategy } + } +} + +impl Default for CircularDependencyResolutionStage { + fn default() -> Self { + Self::new() + } +} + +impl NormalizationStage for CircularDependencyResolutionStage { + fn name(&self) -> &'static str { + "CircularDependencyResolution" + } + + fn transform(&self, schema: &mut Schema) -> Result<(), Vec> { + let cycles = self.detect_circular_dependencies(schema)?; + + if cycles.is_empty() { + return Ok(()); + } + + for cycle in cycles { + self.resolve_cycle(schema, &cycle)?; + } + + Ok(()) + } +} + +impl CircularDependencyResolutionStage { + fn detect_circular_dependencies( + &self, + schema: &Schema, + ) -> Result>, Vec> { + let mut dependencies: HashMap> = HashMap::new(); + + for ty in schema + .input_types + .types() + .chain(schema.output_types.types()) + { + let type_name = ty.name().to_string(); + let mut deps = BTreeSet::new(); + self.collect_type_dependencies(ty, &mut deps); + dependencies.insert(type_name, deps); + } + + let scc_cycles = self.find_strongly_connected_components(&dependencies); + + let mut cycles = Vec::new(); + for component in scc_cycles { + if component.len() > 1 + || (component.len() == 1 + && dependencies + .get(&component[0]) + .is_some_and(|deps| deps.contains(&component[0]))) + { + cycles.push(component); + } + } + + Ok(cycles) + } + + fn collect_type_dependencies(&self, ty: &Type, deps: &mut BTreeSet) { + match ty { + Type::Struct(s) => { + for field in s.fields() { + self.collect_type_ref_dependencies(&field.type_ref, deps); + } + } + Type::Enum(e) => { + for variant in e.variants() { + for field in variant.fields() { + self.collect_type_ref_dependencies(&field.type_ref, deps); + } + } + } + Type::Primitive(p) => { + if let Some(fallback) = &p.fallback { + self.collect_type_ref_dependencies(fallback, deps); + } + } + } + } + + fn collect_type_ref_dependencies(&self, type_ref: &TypeReference, deps: &mut BTreeSet) { + if !self.is_stdlib_type(&type_ref.name) && !self.is_generic_parameter(&type_ref.name) { + deps.insert(type_ref.name.clone()); + } + + for arg in &type_ref.arguments { + self.collect_type_ref_dependencies(arg, deps); + } + } + + fn is_stdlib_type(&self, name: &str) -> bool { + // Check exact matches from the canonical list + if STDLIB_TYPES.iter().any(|&(n, _)| n == name) { + return true; + } + // Fall back to prefix matching for types not explicitly listed + STDLIB_TYPE_PREFIXES + .iter() + .any(|prefix| name.starts_with(prefix)) + } + + fn is_generic_parameter(&self, name: &str) -> bool { + name.len() <= 2 && name.chars().all(|c| c.is_ascii_uppercase()) + } + + fn find_strongly_connected_components( + &self, + dependencies: &HashMap>, + ) -> Vec> { + let mut index = 0; + let mut stack = Vec::new(); + let mut indices: HashMap = HashMap::new(); + let mut lowlinks: HashMap = HashMap::new(); + let mut on_stack: HashMap = HashMap::new(); + let mut components = Vec::new(); + + for node in dependencies.keys() { + if !indices.contains_key(node) { + self.strongconnect( + node, + dependencies, + &mut index, + &mut stack, + &mut indices, + &mut lowlinks, + &mut on_stack, + &mut components, + ); + } + } + + components + } + + #[allow(clippy::too_many_arguments, clippy::only_used_in_recursion)] + fn strongconnect( + &self, + node: &str, + dependencies: &HashMap>, + index: &mut usize, + stack: &mut Vec, + indices: &mut HashMap, + lowlinks: &mut HashMap, + on_stack: &mut HashMap, + components: &mut Vec>, + ) { + indices.insert(node.to_string(), *index); + lowlinks.insert(node.to_string(), *index); + *index += 1; + stack.push(node.to_string()); + on_stack.insert(node.to_string(), true); + + if let Some(deps) = dependencies.get(node) { + for neighbor in deps { + if !indices.contains_key(neighbor) { + self.strongconnect( + neighbor, + dependencies, + index, + stack, + indices, + lowlinks, + on_stack, + components, + ); + lowlinks.insert(node.to_string(), lowlinks[node].min(lowlinks[neighbor])); + } else if *on_stack.get(neighbor).unwrap_or(&false) { + lowlinks.insert(node.to_string(), lowlinks[node].min(indices[neighbor])); + } + } + } + + if lowlinks[node] == indices[node] { + let mut component = Vec::new(); + loop { + let w = stack.pop().unwrap(); + on_stack.insert(w.clone(), false); + component.push(w.clone()); + if w == node { + break; + } + } + if !component.is_empty() { + components.push(component); + } + } + } + + fn resolve_cycle( + &self, + schema: &mut Schema, + cycle: &[String], + ) -> Result<(), Vec> { + match self.strategy { + ResolutionStrategy::Intelligent => { + if cycle.len() == 1 { + self.apply_boxing_strategy(schema, cycle) + } else { + self.apply_forward_declaration_strategy(schema, cycle) + } + } + ResolutionStrategy::Boxing => self.apply_boxing_strategy(schema, cycle), + ResolutionStrategy::ForwardDeclarations => { + self.apply_forward_declaration_strategy(schema, cycle) + } + ResolutionStrategy::OptionalBreaking => { + self.apply_optional_breaking_strategy(schema, cycle) + } + ResolutionStrategy::ReferenceCounted => { + self.apply_reference_counting_strategy(schema, cycle) + } + } + } + + /// No-op: Rust schemas already encode `Box` in the type references, so + /// self-referential types (cycle length 1) and multi-type cycles (A → B → A) + /// are already representable. The cycle detection performed by the + /// `CircularDependencyResolutionStage` is still valuable — downstream codegen + /// backends (e.g. Python, TypeScript) can query the detected cycles to emit + /// forward-reference annotations or similar language-specific constructs. + fn apply_boxing_strategy( + &self, + _schema: &mut Schema, + _cycle: &[String], + ) -> Result<(), Vec> { + Ok(()) + } + + fn apply_forward_declaration_strategy( + &self, + _schema: &mut Schema, + _cycle: &[String], + ) -> Result<(), Vec> { + // TODO: Implement forward declarations by creating type aliases + Ok(()) + } + + fn apply_optional_breaking_strategy( + &self, + _schema: &mut Schema, + _cycle: &[String], + ) -> Result<(), Vec> { + // TODO: Make certain fields optional to break cycles + Ok(()) + } + + fn apply_reference_counting_strategy( + &self, + _schema: &mut Schema, + _cycle: &[String], + ) -> Result<(), Vec> { + // TODO: Wrap cycle references in Rc> + Ok(()) + } +} + +// --------------------------------------------------------------------------- +// Error types +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum NormalizationError { + UnresolvedReference { + name: String, + referrer: SymbolId, + }, + CircularDependency { + cycle: Vec, + }, + ConflictingDefinition { + symbol: SymbolId, + existing: String, + new: String, + }, + InvalidGenericParameter { + type_name: String, + parameter: String, + reason: String, + }, + ValidationError { + symbol: SymbolId, + message: String, + }, +} + +impl std::fmt::Display for NormalizationError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + NormalizationError::UnresolvedReference { name, referrer } => { + write!( + f, + "Unresolved type reference '{name}' in symbol {referrer:?}" + ) + } + NormalizationError::CircularDependency { cycle } => { + write!(f, "Circular dependency detected: {cycle:?}") + } + NormalizationError::ConflictingDefinition { + symbol, + existing, + new, + } => { + write!( + f, + "Conflicting definition for symbol {symbol:?}: existing '{existing}', new '{new}'" + ) + } + NormalizationError::InvalidGenericParameter { + type_name, + parameter, + reason, + } => { + write!( + f, + "Invalid generic parameter '{parameter}' in type '{type_name}': {reason}" + ) + } + NormalizationError::ValidationError { symbol, message } => { + write!(f, "Validation error for symbol {symbol:?}: {message}") + } + } + } +} + +impl std::error::Error for NormalizationError {} + +// --------------------------------------------------------------------------- +// Normalizer: main pipeline converting Schema -> SemanticSchema +// --------------------------------------------------------------------------- + +#[derive(Debug)] +struct NormalizationContext { + symbol_table: SymbolTable, + raw_types: HashMap, + raw_functions: HashMap, + resolution_cache: HashMap, + generic_scope: BTreeSet, + errors: Vec, +} + +impl Default for NormalizationContext { + fn default() -> Self { + Self::new() + } +} + +impl NormalizationContext { + fn new() -> Self { + Self { + symbol_table: SymbolTable::new(), + raw_types: HashMap::new(), + raw_functions: HashMap::new(), + resolution_cache: HashMap::new(), + generic_scope: BTreeSet::new(), + errors: Vec::new(), + } + } + + fn has_errors(&self) -> bool { + !self.errors.is_empty() + } + + fn take_errors(&mut self) -> Vec { + std::mem::take(&mut self.errors) + } +} + +/// Main normalizer that converts a raw Schema into a SemanticSchema +pub struct Normalizer { + context: NormalizationContext, +} + +impl Normalizer { + pub fn new() -> Self { + Self { + context: NormalizationContext::new(), + } + } + + /// Normalize a raw schema into a semantic schema using the standard pipeline. + pub fn normalize(self, schema: &Schema) -> Result> { + self.normalize_with_pipeline(schema, NormalizationPipeline::standard()) + } + + /// Normalize a raw schema into a semantic schema using a custom pipeline. + /// + /// Use `PipelineBuilder` to configure which stages run, or the convenience + /// methods `NormalizationPipeline::standard()` / `NormalizationPipeline::for_codegen()`. + pub fn normalize_with_pipeline( + mut self, + schema: &Schema, + pipeline: NormalizationPipeline, + ) -> Result> { + // Clone so that pipeline stages can mutate without affecting the caller + let mut schema = schema.clone(); + + // Phase 0: Ensure all symbols have unique, stable IDs + crate::ids::ensure_symbol_ids(&mut schema); + + // Capture original type names BEFORE the pipeline transforms them. + // NamingResolution (if present in the pipeline) will strip module + // paths, so we need to map short names back to qualified names. + let pre_norm_names: Vec = schema + .input_types + .types() + .chain(schema.output_types.types()) + .map(|t| t.name().to_string()) + .collect(); + + // Run the caller-provided pipeline + pipeline.run(&mut schema)?; + + // Build the original_names reverse mapping. + // When NamingResolution runs, it strips module paths (e.g. + // "my_module::MyType" -> "MyType"). We map the short name back + // to the pre-pipeline qualified name. + // When NamingResolution is NOT in the pipeline, names are unchanged + // and the mapping is identity — the unwrap_or fallback handles this. + let mut original_names: HashMap = HashMap::new(); + for pre_name in &pre_norm_names { + let short = pre_name.split("::").last().unwrap_or(pre_name); + original_names + .entry(short.to_string()) + .or_insert_with(|| pre_name.clone()); + } + + // Phase 1: Symbol Discovery + self.discover_symbols(&schema)?; + + // Phase 2: Type Resolution + self.resolve_types()?; + + // Phase 3: Dependency Analysis + self.analyze_dependencies()?; + + // Phase 4: Semantic Validation + self.validate_semantics()?; + + // Phase 5: IR Construction + self.build_semantic_ir(&schema, &original_names) + } + + fn discover_symbols(&mut self, schema: &Schema) -> Result<(), Vec> { + let schema_info = SymbolInfo { + id: schema.id.clone(), + name: schema.name.clone(), + path: schema.id.path.clone(), + kind: SymbolKind::Struct, + resolved: false, + dependencies: BTreeSet::new(), + }; + self.context.symbol_table.register(schema_info); + + for function in &schema.functions { + let function_info = SymbolInfo { + id: function.id.clone(), + name: function.name.clone(), + path: function.id.path.clone(), + kind: SymbolKind::Endpoint, + resolved: false, + dependencies: BTreeSet::new(), + }; + self.context.symbol_table.register(function_info); + self.context + .raw_functions + .insert(function.id.clone(), function.clone()); + } + + self.discover_types_from_typespace(&schema.input_types); + self.discover_types_from_typespace(&schema.output_types); + + if self.context.has_errors() { + return Err(self.context.take_errors()); + } + + Ok(()) + } + + fn discover_types_from_typespace(&mut self, typespace: &crate::Typespace) { + for ty in typespace.types() { + self.discover_type_symbols(ty); + } + } + + fn discover_type_symbols(&mut self, ty: &Type) { + let (id, name, kind) = match ty { + Type::Primitive(p) => (p.id.clone(), p.name.clone(), SymbolKind::Primitive), + Type::Struct(s) => (s.id.clone(), s.name.clone(), SymbolKind::Struct), + Type::Enum(e) => (e.id.clone(), e.name.clone(), SymbolKind::Enum), + }; + + let path = id.path.clone(); + + let symbol_info = SymbolInfo { + id: id.clone(), + name, + path, + kind, + resolved: false, + dependencies: BTreeSet::new(), + }; + + self.context.symbol_table.register(symbol_info); + self.context.raw_types.insert(id, ty.clone()); + + match ty { + Type::Struct(s) => self.discover_struct_symbols(s), + Type::Enum(e) => self.discover_enum_symbols(e), + Type::Primitive(_) => {} + } + } + + fn discover_struct_symbols(&mut self, strukt: &Struct) { + for field in strukt.fields() { + let field_info = SymbolInfo { + id: field.id.clone(), + name: field.name.clone(), + path: field.id.path.clone(), + kind: SymbolKind::Field, + resolved: false, + dependencies: BTreeSet::new(), + }; + self.context.symbol_table.register(field_info); + } + } + + fn discover_enum_symbols(&mut self, enm: &Enum) { + for variant in enm.variants() { + let variant_info = SymbolInfo { + id: variant.id.clone(), + name: variant.name.clone(), + path: variant.id.path.clone(), + kind: SymbolKind::Variant, + resolved: false, + dependencies: BTreeSet::new(), + }; + self.context.symbol_table.register(variant_info); + + for field in variant.fields() { + let field_info = SymbolInfo { + id: field.id.clone(), + name: field.name.clone(), + path: field.id.path.clone(), + kind: SymbolKind::Field, + resolved: false, + dependencies: BTreeSet::new(), + }; + self.context.symbol_table.register(field_info); + } + } + } + + fn resolve_types(&mut self) -> Result<(), Vec> { + for symbol_info in self.context.symbol_table.symbols.values() { + if !matches!( + symbol_info.kind, + SymbolKind::Struct + | SymbolKind::Enum + | SymbolKind::Primitive + | SymbolKind::TypeAlias + ) { + continue; + } + self.context + .resolution_cache + .insert(symbol_info.name.clone(), symbol_info.id.clone()); + + let qualified_name = symbol_info.id.qualified_name(); + if qualified_name != symbol_info.name { + self.context + .resolution_cache + .insert(qualified_name, symbol_info.id.clone()); + } + } + + self.add_stdlib_types_to_cache(); + + for (function_id, function) in &self.context.raw_functions.clone() { + self.resolve_function_references(function_id, function); + } + + for (type_id, ty) in &self.context.raw_types.clone() { + self.resolve_type_references(type_id, ty); + } + + if self.context.has_errors() { + return Err(self.context.take_errors()); + } + + Ok(()) + } + + fn resolve_function_references(&mut self, function_id: &SymbolId, function: &Function) { + if let Some(input_type) = &function.input_type { + self.resolve_single_reference(function_id, input_type); + } + if let Some(input_headers) = &function.input_headers { + self.resolve_single_reference(function_id, input_headers); + } + if let Some(output_type) = &function.output_type { + self.resolve_single_reference(function_id, output_type); + } + if let Some(error_type) = &function.error_type { + self.resolve_single_reference(function_id, error_type); + } + } + + fn resolve_type_references(&mut self, type_id: &SymbolId, ty: &Type) { + let generic_params: BTreeSet = ty.parameters().map(|p| p.name.clone()).collect(); + self.context.generic_scope.extend(generic_params.clone()); + + match ty { + Type::Struct(s) => { + for field in s.fields() { + self.resolve_field_references(type_id, field); + } + } + Type::Enum(e) => { + for variant in e.variants() { + for field in variant.fields() { + self.resolve_field_references(type_id, field); + } + } + } + Type::Primitive(p) => { + if let Some(fallback) = &p.fallback { + self.resolve_single_reference(type_id, fallback); + } + } + } + + for param in generic_params { + self.context.generic_scope.remove(¶m); + } + } + + fn resolve_field_references(&mut self, owner_id: &SymbolId, field: &Field) { + self.resolve_single_reference(owner_id, &field.type_ref); + } + + fn add_stdlib_types_to_cache(&mut self) { + for &(name, kind) in STDLIB_TYPES { + let path = name.split("::").map(|s| s.to_string()).collect(); + let symbol_id = SymbolId::new(kind, path); + self.context + .resolution_cache + .insert(name.to_string(), symbol_id); + } + } + + fn resolve_single_reference(&mut self, referrer: &SymbolId, type_ref: &TypeReference) { + if self.context.generic_scope.contains(&type_ref.name) { + for arg in &type_ref.arguments { + self.resolve_single_reference(referrer, arg); + } + return; + } + + if let Some(target_id) = self.resolve_global_type_reference(&type_ref.name) { + self.context + .symbol_table + .add_dependency(referrer.clone(), target_id); + } + // Unresolved references are silently ignored for now - + // they'll be handled as placeholders in IR building + + for arg in &type_ref.arguments { + self.resolve_single_reference(referrer, arg); + } + } + + fn resolve_global_type_reference(&self, name: &str) -> Option { + self.context.resolution_cache.get(name).cloned() + } + + fn analyze_dependencies(&mut self) -> Result<(), Vec> { + match self.context.symbol_table.topological_sort() { + Ok(_) => Ok(()), + Err(_cycle) => { + // Cycles may be expected after CircularDependencyResolutionStage + Ok(()) + } + } + } + + fn validate_semantics(&mut self) -> Result<(), Vec> { + // TODO: Add semantic validation passes + if self.context.has_errors() { + return Err(self.context.take_errors()); + } + Ok(()) + } + + fn build_semantic_ir( + self, + schema: &Schema, + original_names: &HashMap, + ) -> Result> { + let mut semantic_types = BTreeMap::new(); + let mut semantic_functions = BTreeMap::new(); + + let sorted_symbols = match self.context.symbol_table.topological_sort() { + Ok(sorted) => sorted, + Err(_cycle) => self.context.symbol_table.symbols.keys().cloned().collect(), + }; + + for symbol_id in sorted_symbols { + if let Some(raw_type) = self.context.raw_types.get(&symbol_id) { + let semantic_type = self.build_semantic_type(raw_type, original_names)?; + semantic_types.insert(symbol_id, semantic_type); + } + } + + for (function_id, raw_function) in &self.context.raw_functions { + let semantic_function = self.build_semantic_function(raw_function)?; + semantic_functions.insert(function_id.clone(), semantic_function); + } + + Ok(SemanticSchema { + id: schema.id.clone(), + name: schema.name.clone(), + description: schema.description.clone(), + functions: semantic_functions, + types: semantic_types, + symbol_table: self.context.symbol_table, + }) + } + + fn build_semantic_type( + &self, + raw_type: &Type, + original_names: &HashMap, + ) -> Result> { + match raw_type { + Type::Primitive(p) => Ok(SemanticType::Primitive( + self.build_semantic_primitive(p, original_names)?, + )), + Type::Struct(s) => Ok(SemanticType::Struct( + self.build_semantic_struct(s, original_names)?, + )), + Type::Enum(e) => Ok(SemanticType::Enum( + self.build_semantic_enum(e, original_names)?, + )), + } + } + + fn build_semantic_primitive( + &self, + primitive: &Primitive, + original_names: &HashMap, + ) -> Result> { + let fallback = primitive + .fallback + .as_ref() + .and_then(|tr| self.resolve_global_type_reference(&tr.name)); + + let original_name = original_names + .get(&primitive.name) + .cloned() + .unwrap_or_else(|| primitive.name.clone()); + + Ok(SemanticPrimitive { + id: primitive.id.clone(), + name: primitive.name.clone(), + original_name, + description: primitive.description.clone(), + parameters: primitive + .parameters + .iter() + .map(|p| SemanticTypeParameter { + name: p.name.clone(), + description: p.description.clone(), + bounds: vec![], + default: None, + }) + .collect(), + fallback, + }) + } + + fn build_semantic_struct( + &self, + strukt: &Struct, + original_names: &HashMap, + ) -> Result> { + let mut fields = BTreeMap::new(); + + for field in strukt.fields() { + let semantic_field = self.build_semantic_field(field)?; + fields.insert(field.id.clone(), semantic_field); + } + + let original_name = original_names + .get(&strukt.name) + .cloned() + .unwrap_or_else(|| strukt.name.clone()); + + Ok(SemanticStruct { + id: strukt.id.clone(), + name: strukt.name.clone(), + original_name, + serde_name: strukt.serde_name.clone(), + description: strukt.description.clone(), + parameters: strukt + .parameters + .iter() + .map(|p| SemanticTypeParameter { + name: p.name.clone(), + description: p.description.clone(), + bounds: vec![], + default: None, + }) + .collect(), + fields, + transparent: strukt.transparent, + is_tuple: strukt.is_tuple(), + is_unit: strukt.is_unit(), + codegen_config: strukt.codegen_config.clone(), + }) + } + + fn build_semantic_enum( + &self, + enm: &Enum, + original_names: &HashMap, + ) -> Result> { + let mut variants = BTreeMap::new(); + + for variant in enm.variants() { + let semantic_variant = self.build_semantic_variant(variant)?; + variants.insert(variant.id.clone(), semantic_variant); + } + + let original_name = original_names + .get(&enm.name) + .cloned() + .unwrap_or_else(|| enm.name.clone()); + + Ok(SemanticEnum { + id: enm.id.clone(), + name: enm.name.clone(), + original_name, + serde_name: enm.serde_name.clone(), + description: enm.description.clone(), + parameters: enm + .parameters + .iter() + .map(|p| SemanticTypeParameter { + name: p.name.clone(), + description: p.description.clone(), + bounds: vec![], + default: None, + }) + .collect(), + variants, + representation: enm.representation.clone(), + codegen_config: enm.codegen_config.clone(), + }) + } + + fn build_semantic_field( + &self, + field: &Field, + ) -> Result> { + let resolved_type_ref = self.build_resolved_type_reference(&field.type_ref)?; + + Ok(SemanticField { + id: field.id.clone(), + name: field.name.clone(), + serde_name: field.serde_name.clone(), + description: field.description.clone(), + deprecation_note: field.deprecation_note.clone(), + type_ref: resolved_type_ref, + required: field.required, + flattened: field.flattened, + transform_callback: field.transform_callback.clone(), + }) + } + + fn build_semantic_variant( + &self, + variant: &Variant, + ) -> Result> { + let mut fields = BTreeMap::new(); + + for field in variant.fields() { + let semantic_field = self.build_semantic_field(field)?; + fields.insert(field.id.clone(), semantic_field); + } + + let field_style = match &variant.fields { + Fields::Named(_) => FieldStyle::Named, + Fields::Unnamed(_) => FieldStyle::Unnamed, + Fields::None => FieldStyle::Unit, + }; + + Ok(SemanticVariant { + id: variant.id.clone(), + name: variant.name.clone(), + serde_name: variant.serde_name.clone(), + description: variant.description.clone(), + fields, + discriminant: variant.discriminant, + untagged: variant.untagged, + field_style, + }) + } + + fn build_semantic_function( + &self, + function: &Function, + ) -> Result> { + let input_type = function + .input_type + .as_ref() + .and_then(|tr| self.resolve_global_type_reference(&tr.name)); + let input_headers = function + .input_headers + .as_ref() + .and_then(|tr| self.resolve_global_type_reference(&tr.name)); + let output_type = function + .output_type + .as_ref() + .and_then(|tr| self.resolve_global_type_reference(&tr.name)); + let error_type = function + .error_type + .as_ref() + .and_then(|tr| self.resolve_global_type_reference(&tr.name)); + + Ok(SemanticFunction { + id: function.id.clone(), + name: function.name.clone(), + path: function.path.clone(), + description: function.description.clone(), + deprecation_note: function.deprecation_note.clone(), + input_type, + input_headers, + output_type, + error_type, + serialization: function.serialization.clone(), + readonly: function.readonly, + tags: function.tags.clone(), + }) + } + + fn build_resolved_type_reference( + &self, + type_ref: &TypeReference, + ) -> Result> { + let is_likely_generic = !type_ref.name.contains("::"); + + let target = if let Some(target) = self.resolve_global_type_reference(&type_ref.name) { + target + } else if is_likely_generic { + SymbolId::new(SymbolKind::TypeAlias, vec![type_ref.name.clone()]) + } else { + SymbolId::new(SymbolKind::Struct, vec![type_ref.name.replace("::", "_")]) + }; + + let mut resolved_args = Vec::new(); + for arg in &type_ref.arguments { + resolved_args.push(self.build_resolved_type_reference(arg)?); + } + + Ok(ResolvedTypeReference::new( + target, + resolved_args, + type_ref.name.clone(), + )) + } +} + +impl Default for Normalizer { + fn default() -> Self { + Self::new() + } +} + +// --------------------------------------------------------------------------- +// Tests +// --------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use crate::{Fields, Function, Representation, Schema, Struct, TypeReference, Typespace}; + + #[test] + fn test_basic_normalization() { + let mut schema = Schema::new(); + schema.name = "TestSchema".to_string(); + + let user_struct = Struct::new("User"); + let user_type = Type::Struct(user_struct); + + let mut input_types = Typespace::new(); + input_types.insert_type(user_type); + schema.input_types = input_types; + + let normalizer = Normalizer::new(); + let result = normalizer.normalize(&schema); + + assert!( + result.is_ok(), + "Normalization should succeed for simple schema" + ); + + let semantic_schema = result.unwrap(); + assert_eq!(semantic_schema.name, "TestSchema"); + assert_eq!(semantic_schema.types.len(), 1); + } + + #[test] + fn test_unresolved_reference_handled_gracefully() { + let mut schema = Schema::new(); + schema.name = "TestSchema".to_string(); + + let mut function = Function::new("test_function".to_string()); + function.input_type = Some(TypeReference::new("NonExistentType", vec![])); + schema.functions.push(function); + + let normalizer = Normalizer::new(); + let result = normalizer.normalize(&schema); + + assert!( + result.is_ok(), + "Normalization should handle unresolved references gracefully" + ); + + let semantic_schema = result.unwrap(); + assert!(!semantic_schema.functions.is_empty()); + } + + #[test] + fn test_normalize_with_functions_and_types() { + let mut schema = Schema::new(); + schema.name = "API".to_string(); + + // Add types + let mut user_struct = Struct::new("api::User"); + user_struct.fields = Fields::Named(vec![ + Field::new("name".into(), "std::string::String".into()), + Field::new("age".into(), "u32".into()), + ]); + schema.input_types.insert_type(user_struct.into()); + + let mut error_enum = Enum::new("api::Error".into()); + error_enum.representation = Representation::Internal { tag: "type".into() }; + error_enum.variants = vec![ + Variant::new("NotFound".into()), + Variant::new("Forbidden".into()), + ]; + schema.output_types.insert_type(error_enum.into()); + + // Add a function referencing both types + let mut function = Function::new("get_user".into()); + function.input_type = Some(TypeReference::new("api::User", vec![])); + function.error_type = Some(TypeReference::new("api::Error", vec![])); + schema.functions.push(function); + + let normalizer = Normalizer::new(); + let result = normalizer.normalize(&schema); + assert!(result.is_ok(), "Normalization failed: {:?}", result.err()); + + let semantic = result.unwrap(); + assert_eq!(semantic.types.len(), 2); + assert_eq!(semantic.functions.len(), 1); + + // Verify the function has resolved type references + let func = semantic.functions.values().next().unwrap(); + assert!(func.input_type.is_some()); + assert!(func.error_type.is_some()); + } + + #[test] + fn test_normalize_function_with_input_headers() { + let mut schema = Schema::new(); + schema.name = "API".to_string(); + + let headers_struct = Struct::new("Headers"); + schema.input_types.insert_type(headers_struct.into()); + + let body_struct = Struct::new("Body"); + schema.input_types.insert_type(body_struct.into()); + + let mut function = Function::new("do_thing".into()); + function.input_type = Some(TypeReference::new("Body", vec![])); + function.input_headers = Some(TypeReference::new("Headers", vec![])); + schema.functions.push(function); + + let normalizer = Normalizer::new(); + let semantic = normalizer.normalize(&schema).unwrap(); + + let func = semantic.functions.values().next().unwrap(); + assert!(func.input_type.is_some()); + assert!(func.input_headers.is_some()); + } + + #[test] + fn test_type_consolidation_shared_name() { + let mut schema = Schema::new(); + schema.name = "Test".to_string(); + + // Same simple name in both typespaces triggers conflict renaming + let input_struct = Struct::new("Shared"); + let output_struct = Struct::new("Shared"); + schema.input_types.insert_type(input_struct.into()); + schema.output_types.insert_type(output_struct.into()); + + let stage = TypeConsolidationStage; + stage.transform(&mut schema).unwrap(); + + // Both get prefixed since they share a simple name + let type_names: Vec<_> = schema + .input_types + .types() + .map(|t| t.name().to_string()) + .collect(); + assert!( + type_names.contains(&"input.Shared".to_string()), + "Expected input.Shared, got: {type_names:?}" + ); + assert!( + type_names.contains(&"output.Shared".to_string()), + "Expected output.Shared, got: {type_names:?}" + ); + assert!(schema.output_types.is_empty()); + } + + #[test] + fn test_type_consolidation_conflict_renaming() { + let mut schema = Schema::new(); + schema.name = "Test".to_string(); + + // Different types sharing simple name get renamed + let mut input_struct = Struct::new("Foo"); + input_struct.description = "input version".into(); + let mut output_struct = Struct::new("Foo"); + output_struct.description = "output version".into(); + // Make them different so they're not deduplicated + output_struct.fields = Fields::Named(vec![Field::new("x".into(), "u32".into())]); + + schema.input_types.insert_type(input_struct.into()); + schema.output_types.insert_type(output_struct.into()); + + let stage = TypeConsolidationStage; + stage.transform(&mut schema).unwrap(); + + let type_names: Vec<_> = schema + .input_types + .types() + .map(|t| t.name().to_string()) + .collect(); + assert!( + type_names.contains(&"input.Foo".to_string()) + || type_names.contains(&"output.Foo".to_string()), + "Expected conflict renaming, got: {type_names:?}" + ); + } + + #[test] + fn test_ensure_symbol_ids_idempotent() { + let mut schema = Schema::new(); + schema.name = "Test".to_string(); + + let mut user_struct = Struct::new("User"); + user_struct.fields = Fields::Named(vec![Field::new("id".into(), "u64".into())]); + schema.input_types.insert_type(user_struct.into()); + + // Run twice + crate::ensure_symbol_ids(&mut schema); + let ids_first: Vec<_> = schema + .input_types + .types() + .map(|t| match t { + Type::Struct(s) => s.id.clone(), + _ => unreachable!(), + }) + .collect(); + + crate::ensure_symbol_ids(&mut schema); + let ids_second: Vec<_> = schema + .input_types + .types() + .map(|t| match t { + Type::Struct(s) => s.id.clone(), + _ => unreachable!(), + }) + .collect(); + + assert_eq!( + ids_first, ids_second, + "ensure_symbol_ids should be idempotent" + ); + } + + #[test] + fn test_ensure_symbol_ids_enum_variants_and_fields() { + let mut schema = Schema::new(); + schema.name = "Test".to_string(); + + let mut enm = Enum::new("Status".into()); + let mut variant = Variant::new("Active".into()); + variant.fields = Fields::Named(vec![Field::new( + "since".into(), + "std::string::String".into(), + )]); + enm.variants = vec![variant, Variant::new("Inactive".into())]; + schema.input_types.insert_type(enm.into()); + + crate::ensure_symbol_ids(&mut schema); + + let enm = schema + .input_types + .get_type("Status") + .unwrap() + .as_enum() + .unwrap(); + assert!(!enm.id.is_unknown(), "Enum should have a non-unknown id"); + + for variant in &enm.variants { + assert!( + !variant.id.is_unknown(), + "Variant '{}' should have a non-unknown id", + variant.name + ); + for field in variant.fields() { + assert!( + !field.id.is_unknown(), + "Field '{}' in variant '{}' should have a non-unknown id", + field.name, + variant.name + ); + } + } + + // Check paths are structured correctly + let active = &enm.variants[0]; + assert_eq!(active.id.path.last().unwrap(), "Active"); + let since_field = active.fields().next().unwrap(); + assert!( + since_field.id.path.contains(&"Active".to_string()), + "Field path should include parent variant: {:?}", + since_field.id.path + ); + } + + #[test] + fn test_circular_dependency_detection() { + let mut schema = Schema::new(); + schema.name = "Test".to_string(); + + // Node { children: Vec } - self-referential + let mut node_struct = Struct::new("Node"); + node_struct.fields = Fields::Named(vec![Field::new( + "children".into(), + TypeReference::new("std::vec::Vec", vec![TypeReference::new("Node", vec![])]), + )]); + schema.input_types.insert_type(node_struct.into()); + + let stage = CircularDependencyResolutionStage::new(); + // Should detect the cycle but not fail (strategies are stubs) + let result = stage.transform(&mut schema); + assert!(result.is_ok()); + } + + #[test] + fn test_empty_schema_normalization() { + let schema = Schema::new(); + let normalizer = Normalizer::new(); + let result = normalizer.normalize(&schema); + assert!(result.is_ok()); + + let semantic = result.unwrap(); + assert!(semantic.types.is_empty()); + assert!(semantic.functions.is_empty()); + } + + #[test] + fn test_naming_resolution_all_conflicting_types_have_references_rewritten() { + // Regression: NamingResolutionStage only tracked the first qualified name + // per simple name in name_usage, leaving references to the second conflicting + // type dangling after rename. + let mut schema = Schema::new(); + schema.name = "Test".to_string(); + + // Two types sharing simple name "Foo" in different modules + let a_foo = Struct::new("a::Foo"); + let b_foo = Struct::new("b::Foo"); + schema.input_types.insert_type(a_foo.into()); + schema.input_types.insert_type(b_foo.into()); + + // Function referencing BOTH types + let mut func1 = Function::new("use_a_foo".into()); + func1.input_type = Some(TypeReference::new("a::Foo", vec![])); + schema.functions.push(func1); + + let mut func2 = Function::new("use_b_foo".into()); + func2.input_type = Some(TypeReference::new("b::Foo", vec![])); + schema.functions.push(func2); + + let stage = NamingResolutionStage; + stage.transform(&mut schema).unwrap(); + + // Collect all type names defined in the schema + let type_names: std::collections::HashSet = schema + .input_types + .types() + .map(|t| t.name().to_string()) + .collect(); + + // Both function references must point to names that exist in the schema + for func in &schema.functions { + if let Some(ref input_type) = func.input_type { + assert!( + type_names.contains(&input_type.name), + "Function '{}' references type '{}' which doesn't exist in schema. Available: {:?}", + func.name, input_type.name, type_names + ); + } + } + } + + #[test] + fn test_generate_unique_name_excluded_modules_no_collision() { + // Regression: when all module parts are in the exclusion list ("model", "proto"), + // the fallback was module_parts[0], causing "model::Foo" and "model::proto::Foo" + // to both become "ModelFoo". Now uses joined fallback to avoid collisions. + let name1 = generate_unique_name("model::Foo"); + let name2 = generate_unique_name("model::proto::Foo"); + + assert_ne!( + name1, name2, + "model::Foo and model::proto::Foo must produce different names, got '{name1}' and '{name2}'" + ); + } + + #[test] + fn test_generate_unique_name_with_non_excluded_module() { + // Normal case: module part not in exclusion list is used as prefix + let name = generate_unique_name("billing::Invoice"); + assert_eq!(name, "BillingInvoice"); + } + + #[test] + fn test_self_referential_type_normalizes_successfully() { + // A self-referential type (cycle of length 1) should pass through the + // full Normalizer pipeline without error. In Rust the schema already + // records Box wrappers, so the boxing strategy is intentionally a + // no-op — the cycle is detected but does not block normalization. + let mut schema = Schema::new(); + schema.name = "TreeSchema".to_string(); + + // TreeNode has a field `children` of type Vec (indirect + // self-reference via a container — already broken by Vec) and a field + // `parent` that directly references TreeNode (direct self-reference, + // which in real Rust code would be Box). + let mut tree_node = Struct::new("TreeNode"); + tree_node.fields = Fields::Named(vec![ + Field::new("label".into(), "std::string::String".into()), + Field::new( + "children".into(), + TypeReference::new( + "std::vec::Vec", + vec![TypeReference::new("TreeNode", vec![])], + ), + ), + Field::new( + "parent".into(), + TypeReference::new( + "std::boxed::Box", + vec![TypeReference::new("TreeNode", vec![])], + ), + ), + ]); + schema.input_types.insert_type(tree_node.into()); + + let normalizer = Normalizer::new(); + let result = normalizer.normalize(&schema); + + assert!( + result.is_ok(), + "Self-referential type should not prevent normalization: {:?}", + result.err() + ); + + let semantic = result.unwrap(); + assert_eq!(semantic.types.len(), 1, "TreeNode type should be present"); + + // Verify the type round-tripped with the expected name + let tree_node_type = semantic.types.values().next().unwrap(); + match tree_node_type { + SemanticType::Struct(s) => { + assert_eq!(s.name, "TreeNode"); + assert_eq!(s.fields.len(), 3, "All three fields should survive"); + } + other => panic!("Expected Struct, got {:?}", std::mem::discriminant(other)), + } + } + + #[test] + fn test_multi_type_cycle_normalizes_successfully() { + // A → B → A cycle (length 2) should also pass through normalization + // without error. The forward-declaration strategy is likewise a no-op + // for Rust schemas. + let mut schema = Schema::new(); + schema.name = "CycleSchema".to_string(); + + // Department references Employee, Employee references Department + let mut department = Struct::new("Department"); + department.fields = Fields::Named(vec![ + Field::new("name".into(), "std::string::String".into()), + Field::new("manager".into(), TypeReference::new("Employee", vec![])), + ]); + + let mut employee = Struct::new("Employee"); + employee.fields = Fields::Named(vec![ + Field::new("name".into(), "std::string::String".into()), + Field::new( + "department".into(), + TypeReference::new("Department", vec![]), + ), + ]); + + schema.input_types.insert_type(department.into()); + schema.input_types.insert_type(employee.into()); + + let normalizer = Normalizer::new(); + let result = normalizer.normalize(&schema); + + assert!( + result.is_ok(), + "Multi-type cycle should not prevent normalization: {:?}", + result.err() + ); + + let semantic = result.unwrap(); + assert_eq!( + semantic.types.len(), + 2, + "Both Department and Employee types should be present" + ); + } + + #[test] + fn test_type_consolidation_qualified_name_uniqueness() { + // Regression: when input types `a::Foo` and `b::Foo` both conflict with + // an output type `c::Foo`, all three must receive distinct names after + // consolidation — no silent drops. + let mut schema = Schema::new(); + schema.name = "Test".to_string(); + + let a_foo = Struct::new("a::Foo"); + let b_foo = Struct::new("b::Foo"); + let c_foo = Struct::new("c::Foo"); + + schema.input_types.insert_type(a_foo.into()); + schema.input_types.insert_type(b_foo.into()); + schema.output_types.insert_type(c_foo.into()); + + let stage = TypeConsolidationStage; + stage.transform(&mut schema).unwrap(); + + let type_names: Vec = schema + .input_types + .types() + .map(|t| t.name().to_string()) + .collect(); + + // All three should be present with distinct names + assert_eq!( + type_names.len(), + 3, + "All three Foo types should survive consolidation, got: {type_names:?}" + ); + + // Verify uniqueness — no two names are the same + let unique_names: std::collections::HashSet<&String> = type_names.iter().collect(); + assert_eq!( + unique_names.len(), + 3, + "All three names should be distinct, got: {type_names:?}" + ); + + // Verify the naming convention: input types get "input." prefix, + // output types get "output." prefix + let has_input_a = type_names + .iter() + .any(|n| n.contains("input") && n.contains("a")); + let has_input_b = type_names + .iter() + .any(|n| n.contains("input") && n.contains("b")); + let has_output_c = type_names + .iter() + .any(|n| n.contains("output") && n.contains("c")); + assert!( + has_input_a, + "Expected an input.a.Foo variant, got: {type_names:?}" + ); + assert!( + has_input_b, + "Expected an input.b.Foo variant, got: {type_names:?}" + ); + assert!( + has_output_c, + "Expected an output.c.Foo variant, got: {type_names:?}" + ); + } + + #[test] + fn test_resolve_types_does_not_confuse_variant_with_type() { + // Regression: the resolve_types phase should resolve a function's type + // reference "Status" to the Struct named "Status", not to an enum variant + // that happens to also be named "Status". + let mut schema = Schema::new(); + schema.name = "Test".to_string(); + + // A struct named "Status" + let status_struct = Struct::new("Status"); + schema.input_types.insert_type(status_struct.into()); + + // An enum with a variant named "Status" + let mut state_enum = Enum::new("State".into()); + state_enum.variants = vec![Variant::new("Status".into()), Variant::new("Error".into())]; + schema.input_types.insert_type(state_enum.into()); + + // A function that references "Status" — should resolve to the Struct + let mut function = Function::new("get_status".into()); + function.input_type = Some(TypeReference::new("Status", vec![])); + schema.functions.push(function); + + let normalizer = Normalizer::new(); + let result = normalizer.normalize(&schema); + assert!( + result.is_ok(), + "Normalization should succeed: {:?}", + result.err() + ); + + let semantic = result.unwrap(); + let func = semantic.functions.values().next().unwrap(); + + // The function's input_type should resolve to the Status struct's ID + let resolved_id = func + .input_type + .as_ref() + .expect("input_type should be resolved"); + + // It should be a Struct kind, not a Variant kind + assert_eq!( + resolved_id.kind, + crate::SymbolKind::Struct, + "Function's input_type should resolve to a Struct, not a Variant. Got: {resolved_id:?}" + ); + } + + #[test] + fn test_generate_unique_name_same_inner_module() { + // Regression: two types with the same inner module and type name but + // different outer modules must produce different unique names. + let name_a = generate_unique_name("services::user::Profile"); + let name_b = generate_unique_name("auth::user::Profile"); + + assert_ne!( + name_a, name_b, + "services::user::Profile and auth::user::Profile must produce different names, \ + got '{name_a}' and '{name_b}'" + ); + + // Verify they follow the expected PascalCase convention + assert!( + name_a.contains("Services") || name_a.contains("services"), + "Expected 'services' component in name, got '{name_a}'" + ); + assert!( + name_b.contains("Auth") || name_b.contains("auth"), + "Expected 'auth' component in name, got '{name_b}'" + ); + } + + #[test] + fn test_function_symbol_path_matches_id() { + // Regression: after normalization, a function's SymbolId should be + // retrievable from the symbol table via its path. + let mut schema = Schema::new(); + schema.name = "API".to_string(); + + let mut function = Function::new("get_user".into()); + function.input_type = None; + function.output_type = None; + schema.functions.push(function); + + let normalizer = Normalizer::new(); + let semantic = normalizer + .normalize(&schema) + .expect("Normalization should succeed"); + + // Get the function's ID + let (function_id, _) = semantic.functions.iter().next().unwrap(); + + // Verify the symbol table can find it by path + let found = semantic.symbol_table.get_by_path(&function_id.path); + assert!( + found.is_some(), + "symbol_table.get_by_path({:?}) should return Some, but got None. \ + Function ID: {function_id:?}", + function_id.path + ); + + let symbol_info = found.unwrap(); + assert_eq!( + symbol_info.kind, + crate::SymbolKind::Endpoint, + "Symbol should be an Endpoint, got {:?}", + symbol_info.kind + ); + } +} diff --git a/reflectapi-schema/src/semantic.rs b/reflectapi-schema/src/semantic.rs new file mode 100644 index 00000000..48ffa7dc --- /dev/null +++ b/reflectapi-schema/src/semantic.rs @@ -0,0 +1,492 @@ +/// Semantic Intermediate Representation for ReflectAPI +/// +/// This module provides immutable, semantically-validated representations +/// of API schemas that have been processed through the normalization pipeline. +/// Unlike the raw schema types, these representations are guaranteed to be: +/// - Fully resolved (no dangling references) +/// - Semantically consistent (no conflicting definitions) +/// - Deterministically ordered (BTreeMap/BTreeSet for stable output) +use crate::SymbolId; +use std::collections::{BTreeMap, BTreeSet}; + +/// Semantic schema with fully resolved types and deterministic ordering +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SemanticSchema { + pub id: SymbolId, + pub name: String, + pub description: String, + + /// Functions ordered by SymbolId for deterministic output + pub functions: BTreeMap, + + /// All type definitions ordered by SymbolId + pub types: BTreeMap, + + /// Symbol table for efficient lookups + pub symbol_table: SymbolTable, +} + +/// Fully resolved function definition +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SemanticFunction { + pub id: SymbolId, + pub name: String, + pub path: String, + pub description: String, + pub deprecation_note: Option, + + /// Resolved type references (no dangling pointers) + pub input_type: Option, + pub input_headers: Option, + pub output_type: Option, + pub error_type: Option, + + pub serialization: Vec, + pub readonly: bool, + pub tags: BTreeSet, +} + +/// Resolved type definition with semantic validation +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum SemanticType { + Primitive(SemanticPrimitive), + Struct(SemanticStruct), + Enum(SemanticEnum), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SemanticPrimitive { + pub id: SymbolId, + pub name: String, + pub original_name: String, + pub description: String, + + /// Resolved generic parameters + pub parameters: Vec, + + /// Resolved fallback type reference + pub fallback: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SemanticStruct { + pub id: SymbolId, + pub name: String, + pub original_name: String, + pub serde_name: String, + pub description: String, + + /// Resolved generic parameters + pub parameters: Vec, + + /// Fields ordered deterministically + pub fields: BTreeMap, + + /// Semantic properties + pub transparent: bool, + pub is_tuple: bool, + pub is_unit: bool, + + /// Language-specific configuration + pub codegen_config: crate::LanguageSpecificTypeCodegenConfig, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SemanticEnum { + pub id: SymbolId, + pub name: String, + pub original_name: String, + pub serde_name: String, + pub description: String, + + /// Resolved generic parameters + pub parameters: Vec, + + /// Variants ordered deterministically + pub variants: BTreeMap, + + /// Serde representation strategy + pub representation: crate::Representation, + + /// Language-specific configuration + pub codegen_config: crate::LanguageSpecificTypeCodegenConfig, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SemanticField { + pub id: SymbolId, + pub name: String, + pub serde_name: String, + pub description: String, + pub deprecation_note: Option, + + /// Resolved type reference + pub type_ref: ResolvedTypeReference, + + /// Field properties + pub required: bool, + pub flattened: bool, + + /// Transform callback for custom processing + pub transform_callback: String, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SemanticVariant { + pub id: SymbolId, + pub name: String, + pub serde_name: String, + pub description: String, + + /// Fields ordered deterministically + pub fields: BTreeMap, + + /// Variant properties + pub discriminant: Option, + pub untagged: bool, + pub field_style: FieldStyle, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum FieldStyle { + Named, + Unnamed, + Unit, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SemanticTypeParameter { + pub name: String, + pub description: String, + + /// Constraints on the type parameter + pub bounds: Vec, + pub default: Option, +} + +/// Resolved type reference with guaranteed validity +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ResolvedTypeReference { + /// Target symbol (guaranteed to exist in symbol table) + pub target: SymbolId, + + /// Resolved generic arguments + pub arguments: Vec, + + /// Original type reference for debugging + pub original_name: String, +} + +/// Symbol table for efficient lookups and validation +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SymbolTable { + /// Map from SymbolId to symbol information + pub symbols: BTreeMap, + + /// Map from name path to SymbolId for lookups + name_to_id: BTreeMap, SymbolId>, + + /// Dependencies between symbols + pub dependencies: BTreeMap>, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SymbolInfo { + pub id: SymbolId, + pub name: String, + pub path: Vec, + pub kind: crate::SymbolKind, + + /// Whether this symbol is fully resolved + pub resolved: bool, + + /// Dependencies of this symbol + pub dependencies: BTreeSet, +} + +impl SymbolTable { + pub fn new() -> Self { + Self { + symbols: BTreeMap::new(), + name_to_id: BTreeMap::new(), + dependencies: BTreeMap::new(), + } + } + + /// Register a new symbol in the table + pub fn register(&mut self, symbol: SymbolInfo) { + let id = symbol.id.clone(); + let path = symbol.path.clone(); + + self.symbols.insert(id.clone(), symbol); + self.name_to_id.insert(path, id); + } + + /// Lookup symbol by ID + pub fn get(&self, id: &SymbolId) -> Option<&SymbolInfo> { + self.symbols.get(id) + } + + /// Lookup symbol by name path + pub fn get_by_path(&self, path: &[String]) -> Option<&SymbolInfo> { + self.name_to_id + .get(path) + .and_then(|id| self.symbols.get(id)) + } + + /// Get all symbols of a specific kind + pub fn get_by_kind<'a>( + &'a self, + kind: &'a crate::SymbolKind, + ) -> impl Iterator + 'a { + self.symbols.values().filter(move |info| &info.kind == kind) + } + + /// Add dependency relationship + pub fn add_dependency(&mut self, dependent: SymbolId, dependency: SymbolId) { + self.dependencies + .entry(dependent.clone()) + .or_default() + .insert(dependency.clone()); + + // Update symbol info + if let Some(symbol) = self.symbols.get_mut(&dependent) { + symbol.dependencies.insert(dependency); + } + } + + /// Get dependencies of a symbol + pub fn get_dependencies(&self, id: &SymbolId) -> Option<&BTreeSet> { + self.dependencies.get(id) + } + + /// Topological sort for dependency resolution + pub fn topological_sort(&self) -> Result, Vec> { + let mut visited = BTreeSet::new(); + let mut temp_visited = BTreeSet::new(); + let mut result = Vec::new(); + + for id in self.symbols.keys() { + if !visited.contains(id) { + self.visit_topological(id, &mut visited, &mut temp_visited, &mut result)?; + } + } + + Ok(result) + } + + fn visit_topological( + &self, + id: &SymbolId, + visited: &mut BTreeSet, + temp_visited: &mut BTreeSet, + result: &mut Vec, + ) -> Result<(), Vec> { + if temp_visited.contains(id) { + return Err(vec![id.clone()]); + } + + if visited.contains(id) { + return Ok(()); + } + + temp_visited.insert(id.clone()); + + if let Some(dependencies) = self.dependencies.get(id) { + for dep in dependencies { + self.visit_topological(dep, visited, temp_visited, result)?; + } + } + + temp_visited.remove(id); + visited.insert(id.clone()); + result.push(id.clone()); + + Ok(()) + } +} + +impl Default for SymbolTable { + fn default() -> Self { + Self::new() + } +} + +impl SemanticSchema { + /// Look up a type by its name via the symbol table's resolution cache. + /// Falls back to linear scan if the name isn't in the symbol table. + /// Also checks original_name for lookups by pre-normalization qualified name. + pub fn get_type_by_name(&self, name: &str) -> Option<&SemanticType> { + // Try symbol table lookup first (O(log n)) + let path = name.split("::").map(|s| s.to_string()).collect::>(); + if let Some(info) = self.symbol_table.get_by_path(&path) { + if let Some(ty) = self.types.get(&info.id) { + return Some(ty); + } + } + // Fallback: linear scan by name (handles post-normalization name changes) + if let Some(ty) = self.types.values().find(|t| t.name() == name) { + return Some(ty); + } + // Fallback: linear scan by original_name (handles pre-normalization lookups) + self.types.values().find(|t| t.original_name() == name) + } + + /// Look up a type by SymbolId. + pub fn get_type(&self, id: &SymbolId) -> Option<&SemanticType> { + self.types.get(id) + } + + /// Iterate all types in deterministic order. + pub fn types(&self) -> impl Iterator { + self.types.values() + } + + /// Iterate all functions in deterministic order. + pub fn functions(&self) -> impl Iterator { + self.functions.values() + } + + /// Ordered type names (deterministic via BTreeMap). + pub fn type_names(&self) -> impl Iterator { + self.types.values().map(|t| t.name()) + } +} + +impl SemanticType { + pub fn id(&self) -> &SymbolId { + match self { + SemanticType::Primitive(p) => &p.id, + SemanticType::Struct(s) => &s.id, + SemanticType::Enum(e) => &e.id, + } + } + + pub fn name(&self) -> &str { + match self { + SemanticType::Primitive(p) => &p.name, + SemanticType::Struct(s) => &s.name, + SemanticType::Enum(e) => &e.name, + } + } + + pub fn original_name(&self) -> &str { + match self { + SemanticType::Primitive(p) => &p.original_name, + SemanticType::Struct(s) => &s.original_name, + SemanticType::Enum(e) => &e.original_name, + } + } +} + +impl ResolvedTypeReference { + /// Create a new resolved type reference + pub fn new( + target: SymbolId, + arguments: Vec, + original_name: String, + ) -> Self { + Self { + target, + arguments, + original_name, + } + } + + /// Check if this is a primitive type reference + pub fn is_primitive(&self, symbol_table: &SymbolTable) -> bool { + symbol_table + .get(&self.target) + .map(|info| matches!(info.kind, crate::SymbolKind::Primitive)) + .unwrap_or(false) + } + + /// Check if this is a generic type (has arguments) + pub fn is_generic(&self) -> bool { + !self.arguments.is_empty() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{SymbolId, SymbolKind}; + + #[test] + fn test_symbol_table_basic_operations() { + let mut table = SymbolTable::new(); + + let user_id = SymbolId::struct_id(vec!["User".to_string()]); + let user_info = SymbolInfo { + id: user_id.clone(), + name: "User".to_string(), + path: vec!["User".to_string()], + kind: SymbolKind::Struct, + resolved: true, + dependencies: BTreeSet::new(), + }; + + table.register(user_info); + + assert!(table.get(&user_id).is_some()); + assert!(table.get_by_path(&["User".to_string()]).is_some()); + + let structs: Vec<_> = table.get_by_kind(&SymbolKind::Struct).collect(); + assert_eq!(structs.len(), 1); + } + + #[test] + fn test_symbol_table_dependencies() { + let mut table = SymbolTable::new(); + + let user_id = SymbolId::struct_id(vec!["User".to_string()]); + let post_id = SymbolId::struct_id(vec!["Post".to_string()]); + + table.register(SymbolInfo { + id: user_id.clone(), + name: "User".to_string(), + path: vec!["User".to_string()], + kind: SymbolKind::Struct, + resolved: true, + dependencies: BTreeSet::new(), + }); + + table.register(SymbolInfo { + id: post_id.clone(), + name: "Post".to_string(), + path: vec!["Post".to_string()], + kind: SymbolKind::Struct, + resolved: true, + dependencies: BTreeSet::new(), + }); + + table.add_dependency(post_id.clone(), user_id.clone()); + + let deps = table.get_dependencies(&post_id).unwrap(); + assert!(deps.contains(&user_id)); + + let sorted = table.topological_sort().unwrap(); + let user_pos = sorted.iter().position(|id| id == &user_id).unwrap(); + let post_pos = sorted.iter().position(|id| id == &post_id).unwrap(); + assert!( + user_pos < post_pos, + "User should come before Post in topological order" + ); + } + + #[test] + fn test_resolved_type_reference() { + let string_id = SymbolId::new(SymbolKind::Primitive, vec!["String".to_string()]); + let vec_id = SymbolId::new(SymbolKind::Struct, vec!["Vec".to_string()]); + + let string_ref = + ResolvedTypeReference::new(string_id.clone(), vec![], "String".to_string()); + + let vec_string_ref = + ResolvedTypeReference::new(vec_id, vec![string_ref], "Vec".to_string()); + + assert!(!vec_string_ref.arguments.is_empty()); + assert!(vec_string_ref.is_generic()); + assert_eq!(vec_string_ref.arguments[0].target, string_id); + } +} diff --git a/reflectapi-schema/src/symbol.rs b/reflectapi-schema/src/symbol.rs new file mode 100644 index 00000000..d7e40d19 --- /dev/null +++ b/reflectapi-schema/src/symbol.rs @@ -0,0 +1,184 @@ +/// Stable, unique identifier for symbols that persists across all pipeline stages +#[derive( + Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize, +)] +pub struct SymbolId { + pub kind: SymbolKind, + pub path: Vec, + pub disambiguator: u32, +} + +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize, +)] +pub enum SymbolKind { + Struct, + Enum, + TypeAlias, + Endpoint, + Variant, + Field, + Primitive, +} + +/// Well-known stdlib and common crate types used in ReflectAPI schemas. +/// Each entry is (fully-qualified name, SymbolKind). +pub const STDLIB_TYPES: &[(&str, SymbolKind)] = &[ + ("std::option::Option", SymbolKind::Enum), + ("std::vec::Vec", SymbolKind::Primitive), + ("std::collections::HashMap", SymbolKind::Primitive), + ("std::collections::BTreeMap", SymbolKind::Primitive), + ("std::string::String", SymbolKind::Primitive), + ("std::tuple::Tuple0", SymbolKind::Primitive), + ("std::boxed::Box", SymbolKind::Primitive), + ("std::rc::Rc", SymbolKind::Primitive), + ("std::sync::Arc", SymbolKind::Primitive), + ("i32", SymbolKind::Primitive), + ("u32", SymbolKind::Primitive), + ("i64", SymbolKind::Primitive), + ("u64", SymbolKind::Primitive), + ("f32", SymbolKind::Primitive), + ("f64", SymbolKind::Primitive), + ("bool", SymbolKind::Primitive), + ("u8", SymbolKind::Primitive), + ("i8", SymbolKind::Primitive), + ("chrono::Utc", SymbolKind::Primitive), + ("chrono::FixedOffset", SymbolKind::Primitive), + ("chrono::DateTime", SymbolKind::Primitive), + ("uuid::Uuid", SymbolKind::Primitive), + ("url::Url", SymbolKind::Primitive), + ("serde_json::Value", SymbolKind::Primitive), +]; + +/// Prefixes that identify well-known stdlib and common crate types. +/// Used for broad matching when exact name lookup is not sufficient +/// (e.g., types not explicitly listed in STDLIB_TYPES). +pub const STDLIB_TYPE_PREFIXES: &[&str] = &["std::", "chrono::", "uuid::"]; + +impl Default for SymbolId { + fn default() -> Self { + Self { + kind: SymbolKind::Struct, + path: vec!["unknown".to_string()], + disambiguator: 0, + } + } +} + +impl SymbolId { + /// Create a new symbol ID with path and kind + pub fn new(kind: SymbolKind, path: Vec) -> Self { + Self { + kind, + path, + disambiguator: 0, + } + } + + /// Create a new symbol ID with disambiguation + pub fn with_disambiguator(kind: SymbolKind, path: Vec, disambiguator: u32) -> Self { + Self { + kind, + path, + disambiguator, + } + } + + /// Check if this is an unknown/default symbol ID + pub fn is_unknown(&self) -> bool { + self.path.len() == 1 && self.path[0] == "unknown" + } + + /// Create a symbol ID for a struct + pub fn struct_id(path: Vec) -> Self { + Self::new(SymbolKind::Struct, path) + } + + /// Create a symbol ID for an enum + pub fn enum_id(path: Vec) -> Self { + Self::new(SymbolKind::Enum, path) + } + + /// Create a symbol ID for an endpoint/function + pub fn endpoint_id(path: Vec) -> Self { + Self::new(SymbolKind::Endpoint, path) + } + + /// Create a symbol ID for a variant + pub fn variant_id(enum_path: Vec, variant_name: String) -> Self { + let mut path = enum_path; + path.push(variant_name); + Self::new(SymbolKind::Variant, path) + } + + /// Create a symbol ID for a field + pub fn field_id(parent_path: Vec, field_name: String) -> Self { + let mut path = parent_path; + path.push(field_name); + Self::new(SymbolKind::Field, path) + } + + /// Get the simple name (last component of path) + pub fn name(&self) -> Option<&str> { + self.path.last().map(|s| s.as_str()) + } + + /// Get the qualified name as a "::" separated string + pub fn qualified_name(&self) -> String { + self.path.join("::") + } + + /// Check if this is the same symbol (ignoring disambiguator) + pub fn same_symbol(&self, other: &SymbolId) -> bool { + self.kind == other.kind && self.path == other.path + } +} + +impl std::fmt::Display for SymbolId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}({})", self.kind, self.qualified_name())?; + if self.disambiguator > 0 { + write!(f, "#{}", self.disambiguator)?; + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_symbol_id_creation() { + let struct_id = SymbolId::struct_id(vec!["api".to_string(), "User".to_string()]); + assert_eq!(struct_id.kind, SymbolKind::Struct); + assert_eq!(struct_id.path, vec!["api", "User"]); + assert_eq!(struct_id.disambiguator, 0); + assert_eq!(struct_id.name(), Some("User")); + assert_eq!(struct_id.qualified_name(), "api::User"); + } + + #[test] + fn test_symbol_id_display() { + let struct_id = SymbolId::struct_id(vec!["api".to_string(), "User".to_string()]); + assert_eq!(format!("{struct_id}"), "Struct(api::User)"); + + let disambiguated = SymbolId::with_disambiguator( + SymbolKind::Struct, + vec!["api".to_string(), "User".to_string()], + 1, + ); + assert_eq!(format!("{disambiguated}"), "Struct(api::User)#1"); + } + + #[test] + fn test_same_symbol() { + let id1 = SymbolId::struct_id(vec!["api".to_string(), "User".to_string()]); + let id2 = SymbolId::with_disambiguator( + SymbolKind::Struct, + vec!["api".to_string(), "User".to_string()], + 1, + ); + assert!(id1.same_symbol(&id2)); + } +} diff --git a/reflectapi/Cargo.toml b/reflectapi/Cargo.toml index c665dffc..6986f5f6 100644 --- a/reflectapi/Cargo.toml +++ b/reflectapi/Cargo.toml @@ -47,7 +47,6 @@ rust_decimal = { version = "1.35.0", optional = true, features = ["serde"] } axum = { version = "0.8.1", optional = true } # optional 3rd party dependencies for enabling codegen -askama = { version = "0.12.1", optional = true } anyhow = { version = "1.0.81", optional = true } indexmap = { version = "2.2.6", optional = true, features = ["serde"] } check_keyword = { version = "0.2.0", optional = true } @@ -77,7 +76,7 @@ rust_decimal = ["dep:rust_decimal"] # based on different web server frameworks axum = ["dep:axum", "builder"] # feature flag for enabling codegen libraries -codegen = ["dep:askama", "dep:anyhow", "dep:indexmap", "dep:check_keyword", "dep:serde_json"] +codegen = ["dep:anyhow", "dep:indexmap", "dep:check_keyword", "dep:serde_json"] rt = ["dep:http", "dep:serde_json", "dep:bytes", "dep:url"] glob = ["reflectapi-schema/glob"] json = ["dep:serde_json"] diff --git a/reflectapi/src/builder/handler.rs b/reflectapi/src/builder/handler.rs index 290f678e..8a23d873 100644 --- a/reflectapi/src/builder/handler.rs +++ b/reflectapi/src/builder/handler.rs @@ -144,6 +144,7 @@ where .unwrap_or_default(); let function_def = Function { + id: Default::default(), name: rb.name.clone(), path: rb.path.clone(), deprecation_note: rb.deprecation_note, diff --git a/reflectapi/src/codegen/openapi.rs b/reflectapi/src/codegen/openapi.rs index e1747f60..e682061c 100644 --- a/reflectapi/src/codegen/openapi.rs +++ b/reflectapi/src/codegen/openapi.rs @@ -601,6 +601,7 @@ impl Converter<'_> { static STRING_TYPE: OnceLock = OnceLock::new(); return STRING_TYPE.get_or_init(|| { crate::Type::Primitive(crate::Primitive { + id: Default::default(), name: "std::string::String".into(), description: "UTF-8 encoded string".into(), parameters: vec![], @@ -811,6 +812,7 @@ impl Converter<'_> { crate::TypeReference::new(variant.name().to_owned(), type_ref.arguments.clone()); let mut strukt = crate::Struct { + id: Default::default(), name: variant.name().to_owned(), serde_name: variant.serde_name.to_owned(), description: variant.description().to_owned(), diff --git a/reflectapi/src/codegen/python.rs b/reflectapi/src/codegen/python.rs index 9e4df705..a72f4f2b 100644 --- a/reflectapi/src/codegen/python.rs +++ b/reflectapi/src/codegen/python.rs @@ -1,22 +1,22 @@ -use std::collections::{BTreeMap, BTreeSet, HashSet, VecDeque}; - -use anyhow::Context; -use askama::Template; +use std::collections::{BTreeMap, BTreeSet, HashSet}; use crate::{Schema, TypeReference}; use reflectapi_schema::{Function, Type}; -/// Information needed to generate a factory class later -#[derive(Clone, Debug)] -struct FactoryInfo { - enum_def: reflectapi_schema::Enum, - enum_name: String, - union_members: Vec, - is_internally_tagged: bool, +/// Sanitize text for inclusion in a Python triple-quoted docstring. +/// Escapes backslashes (which act as line continuation) and triple-quote +/// sequences (which would close the docstring prematurely). +fn sanitize_for_docstring(text: &str) -> String { + text.replace('\\', "\\\\").replace("\"\"\"", "\\\"\\\"\\\"") } -fn to_valid_python_identifier(name: &str) -> String { - safe_python_identifier(name) +/// Sanitize text for inclusion in a Python double-quoted string literal. +/// Escapes backslashes, double quotes, and replaces newlines with \n. +fn sanitize_for_string_literal(text: &str) -> String { + text.replace('\\', "\\\\") + .replace('"', "\\\"") + .replace('\n', "\\n") + .replace('\r', "\\r") } /// Configuration for Python client generation @@ -40,7 +40,7 @@ impl Default for Config { package_name: "api_client".to_string(), generate_async: true, generate_sync: true, - generate_testing: true, + generate_testing: false, base_url: None, } } @@ -104,11 +104,12 @@ fn generate_optimized_imports(imports: &templates::Imports) -> String { typing_imports.insert("Literal"); } - // Pydantic imports + // Pydantic imports — Field is always imported since it's used for + // descriptions, aliases, discriminators, and defaults across many contexts. third_party_imports.insert("BaseModel"); third_party_imports.insert("ConfigDict"); + third_party_imports.insert("Field"); if imports.has_discriminated_unions { - third_party_imports.insert("Field"); third_party_imports.insert("RootModel"); } if imports.has_externally_tagged_enums { @@ -196,128 +197,7 @@ fn generate_optimized_imports(imports: &templates::Imports) -> String { /// * `type_names` - List of type names to sort /// * `schema` - Schema containing type definitions and their dependencies /// -/// # Returns -/// * `Ok(Vec)` - Types sorted in dependency order (dependencies first) -/// * `Err` - If circular dependencies are detected in the type graph -fn topological_sort_types(type_names: &[String], schema: &Schema) -> anyhow::Result> { - let mut dependencies: BTreeMap> = BTreeMap::new(); - let mut in_degree: BTreeMap = BTreeMap::new(); - - // Initialize in-degree count for all types - for type_name in type_names { - in_degree.insert(type_name.clone(), 0); - dependencies.insert(type_name.clone(), BTreeSet::new()); - } - - // Build dependency graph - if A depends on B, then B must be defined before A - for type_name in type_names { - if let Some(type_def) = schema.get_type(type_name) { - let deps = collect_type_dependencies(type_def, type_names); - for dep in &deps { - if type_names.contains(dep) && dep != type_name { - // type_name depends on dep, so dep must come before type_name - dependencies.get_mut(type_name).unwrap().insert(dep.clone()); - *in_degree.get_mut(type_name).unwrap() += 1; - } - } - } - } - - // Kahn's algorithm for topological sorting - let mut queue: VecDeque = VecDeque::new(); - let mut result = Vec::new(); - - // Start with types that have no dependencies - for (type_name, °ree) in &in_degree { - if degree == 0 { - queue.push_back(type_name.clone()); - } - } - - while let Some(current) = queue.pop_front() { - result.push(current.clone()); - - // Reduce in-degree for types that depend on the current type - for other_type in type_names { - if dependencies.get(other_type).unwrap().contains(¤t) { - *in_degree.get_mut(other_type).unwrap() -= 1; - if in_degree[other_type] == 0 { - queue.push_back(other_type.clone()); - } - } - } - } - - // Check for cycles - if result.len() != type_names.len() { - let remaining: Vec<_> = type_names.iter().filter(|n| !result.contains(n)).collect(); - return Err(anyhow::anyhow!( - "Circular dependency detected in types: {:?}", - remaining - )); - } - - Ok(result) -} - -/// Collect all type dependencies for a given type -fn collect_type_dependencies(type_def: &Type, available_types: &[String]) -> BTreeSet { - let mut deps = BTreeSet::new(); - - match type_def { - Type::Struct(struct_def) => { - for field in struct_def.fields.iter() { - collect_type_ref_dependencies(&field.type_ref, &mut deps, available_types); - } - } - Type::Enum(enum_def) => { - for variant in &enum_def.variants { - match &variant.fields { - reflectapi_schema::Fields::Named(fields) => { - for field in fields { - collect_type_ref_dependencies( - &field.type_ref, - &mut deps, - available_types, - ); - } - } - reflectapi_schema::Fields::Unnamed(fields) => { - for field in fields { - collect_type_ref_dependencies( - &field.type_ref, - &mut deps, - available_types, - ); - } - } - reflectapi_schema::Fields::None => {} - } - } - } - Type::Primitive(_) => {} - } - - deps -} - -/// Recursively collect type reference dependencies -fn collect_type_ref_dependencies( - type_ref: &TypeReference, - deps: &mut BTreeSet, - available_types: &[String], -) { - if available_types.contains(&type_ref.name) { - deps.insert(type_ref.name.clone()); - } - - // Handle generic arguments - for param in &type_ref.arguments { - collect_type_ref_dependencies(param, deps, available_types); - } -} - -/// Collect all TypeVars used by a type +/// Collect all TypeVars used by a type. fn collect_type_vars_from_type( type_def: &Type, schema: &Schema, @@ -429,7 +309,13 @@ fn collect_generic_type_vars( } } -/// Render a struct that contains flattened fields using direct field expansion +/// Render a struct that contains flattened fields using direct field expansion. +/// +/// For flattened structs, fields are expanded inline into the parent model. +/// For flattened internally-tagged enums, we generate per-variant models that +/// merge the parent's fields with each variant's fields + the tag discriminator, +/// then emit a discriminated union RootModel. This matches the wire format that +/// serde produces with `#[serde(flatten)]` on internally-tagged enums. fn render_struct_with_flatten( struct_def: &reflectapi_schema::Struct, schema: &Schema, @@ -437,32 +323,347 @@ fn render_struct_with_flatten( used_type_vars: &mut BTreeSet, ) -> anyhow::Result { let struct_name = improve_class_name(&struct_def.name); - - // Collect all fields (regular + flattened) into a single flat model - let mut all_fields = Vec::new(); let active_generics: Vec = struct_def .parameters .iter() .map(|p| p.name.clone()) .collect(); - // Track used generic type variables for generic in &active_generics { used_type_vars.insert(generic.clone()); } - // Add regular fields + // Check if any flattened field is an internally-tagged enum + let flattened_internal_enum = + struct_def + .fields + .iter() + .filter(|f| f.flattened()) + .find_map(|field| { + let type_name = resolve_flattened_type_name(&field.type_ref); + match schema.get_type(type_name) { + Some(reflectapi_schema::Type::Enum(enum_def)) => { + match &enum_def.representation { + reflectapi_schema::Representation::Internal { tag } => { + Some((field, enum_def.clone(), tag.clone())) + } + _ => None, + } + } + _ => None, + } + }); + + if let Some((_enum_field, enum_def, tag)) = flattened_internal_enum { + // Wire-compatible path: generate per-variant models with merged fields + render_struct_with_flattened_internal_enum( + struct_def, + &struct_name, + &enum_def, + &tag, + schema, + implemented_types, + &active_generics, + used_type_vars, + ) + } else { + // Standard path: expand all flattened fields inline + render_struct_with_flatten_standard( + struct_def, + &struct_name, + schema, + implemented_types, + &active_generics, + used_type_vars, + ) + } +} + +/// Resolve the target type name for a flattened field, unwrapping Option +fn resolve_flattened_type_name(type_ref: &TypeReference) -> &str { + if (type_ref.name == "std::option::Option" || type_ref.name == "reflectapi::Option") + && !type_ref.arguments.is_empty() + { + &type_ref.arguments[0].name + } else { + &type_ref.name + } +} + +/// Render a struct with a flattened internally-tagged enum by generating +/// per-variant models that merge parent fields + variant fields + tag. +#[allow(clippy::too_many_arguments)] +fn render_struct_with_flattened_internal_enum( + struct_def: &reflectapi_schema::Struct, + struct_name: &str, + enum_def: &reflectapi_schema::Enum, + tag: &str, + schema: &Schema, + implemented_types: &BTreeMap, + active_generics: &[String], + used_type_vars: &mut BTreeSet, +) -> anyhow::Result { + use reflectapi_schema::Fields; + + let mut output = String::new(); + let mut union_variant_names: Vec = Vec::new(); + + // Collect the parent struct's non-flattened fields + any flattened struct fields + let mut base_fields: Vec = Vec::new(); for field in struct_def.fields.iter().filter(|f| !f.flattened()) { - let field_name = sanitize_field_name_with_alias(field.name()); + let (python_name, alias) = sanitize_field_name_with_alias(field.name(), field.serde_name()); let field_type = type_ref_to_python_type( &field.type_ref, schema, implemented_types, - &active_generics, + active_generics, used_type_vars, )?; + base_fields.push(templates::Field { + name: python_name, + type_annotation: if field.required { + field_type + } else { + format!("{field_type} | None") + }, + description: Some(field.description().to_string()), + deprecation_note: field.deprecation_note.clone(), + optional: !field.required, + default_value: if field.required { + None + } else { + Some("None".to_string()) + }, + alias, + }); + } + + // Also expand any flattened struct fields (non-enum) into base_fields + for field in struct_def.fields.iter().filter(|f| f.flattened()) { + let type_name = resolve_flattened_type_name(&field.type_ref); + if let Some(reflectapi_schema::Type::Struct(_)) = schema.get_type(type_name) { + let flattened = collect_flattened_fields( + &field.type_ref, + schema, + implemented_types, + active_generics, + field.required, + 0, + used_type_vars, + Some(field.name()), + )?; + base_fields.extend(flattened); + // Enum fields are handled below as variants + } else if let Some(reflectapi_schema::Type::Enum(enum_def)) = schema.get_type(type_name) { + // Check if this is the internally-tagged enum we're expanding + // (it's handled below as variants). Other enums get emitted as regular fields. + let is_the_expanding_enum = matches!( + &enum_def.representation, + reflectapi_schema::Representation::Internal { .. } + ); + if !is_the_expanding_enum { + let field_type = type_ref_to_python_type( + &field.type_ref, + schema, + implemented_types, + active_generics, + used_type_vars, + )?; + let (python_name, alias) = + sanitize_field_name_with_alias(field.name(), field.serde_name()); + base_fields.push(templates::Field { + name: python_name, + type_annotation: if field.required { + field_type + } else { + format!("{field_type} | None") + }, + description: Some(field.description().to_string()), + deprecation_note: field.deprecation_note.clone(), + optional: !field.required, + default_value: if field.required { + None + } else { + Some("None".to_string()) + }, + alias, + }); + } + } + } + + // Generate per-variant models + for variant in &enum_def.variants { + let variant_class_name = format!("{}{}", struct_name, to_pascal_case(variant.name())); + union_variant_names.push(variant_class_name.clone()); + + // Start with base fields from the parent struct + let mut fields = base_fields.clone(); + + // Add the tag discriminator field + let (sanitized_tag, tag_alias) = sanitize_field_name_with_alias(tag, tag); + fields.push(templates::Field { + name: sanitized_tag.clone(), + type_annotation: format!("Literal['{}']", variant.serde_name()), + description: Some("Discriminator field".to_string()), + deprecation_note: None, + optional: false, + default_value: Some(format!("\"{}\"", variant.serde_name())), + alias: tag_alias.clone(), + }); + + // Add variant-specific fields + match &variant.fields { + Fields::Named(named_fields) => { + for vf in named_fields { + let field_type = type_ref_to_python_type( + &vf.type_ref, + schema, + implemented_types, + active_generics, + used_type_vars, + )?; + let is_option = vf.type_ref.name == "std::option::Option" + || vf.type_ref.name == "reflectapi::Option"; + let (optional, default_value, final_type) = if !vf.required { + if is_option { + (true, Some("None".to_string()), field_type) + } else { + ( + true, + Some("None".to_string()), + format!("{field_type} | None"), + ) + } + } else if is_option { + (true, Some("None".to_string()), field_type) + } else { + (false, None, field_type) + }; + let (sanitized, alias) = + sanitize_field_name_with_alias(vf.name(), vf.serde_name()); + fields.push(templates::Field { + name: sanitized, + type_annotation: final_type, + description: Some(vf.description().to_string()), + deprecation_note: vf.deprecation_note.clone(), + optional, + default_value, + alias, + }); + } + } + Fields::Unnamed(unnamed_fields) if unnamed_fields.len() == 1 => { + // Tuple variant with one field — expand inner struct fields + let inner = &unnamed_fields[0]; + let inner_name = if inner.type_ref.name == "std::boxed::Box" { + inner + .type_ref + .arguments + .first() + .map(|a| a.name.as_str()) + .unwrap_or(&inner.type_ref.name) + } else { + &inner.type_ref.name + }; + if let Some(reflectapi_schema::Type::Struct(inner_struct)) = + schema.get_type(inner_name) + { + for sf in inner_struct.fields.iter() { + let field_type = type_ref_to_python_type( + &sf.type_ref, + schema, + implemented_types, + active_generics, + used_type_vars, + )?; + let (sanitized, alias) = + sanitize_field_name_with_alias(sf.name(), sf.serde_name()); + fields.push(templates::Field { + name: sanitized, + type_annotation: if sf.required { + field_type + } else { + format!("{field_type} | None") + }, + description: Some(sf.description().to_string()), + deprecation_note: sf.deprecation_note.clone(), + optional: !sf.required, + default_value: if sf.required { + None + } else { + Some("None".to_string()) + }, + alias, + }); + } + } + } + Fields::None => { + // Unit variant — no additional fields beyond tag + } + _ => { + // Multi-field tuple variant — not supported for flattening + } + } + + // Render the variant class + let variant_template = templates::DataClass { + name: variant_class_name, + description: Some(format!("'{}' variant of {}", variant.name(), struct_name)), + fields, + is_tuple: false, + is_generic: !active_generics.is_empty(), + generic_params: active_generics.to_vec(), + }; + output.push_str(&variant_template.render()); + output.push('\n'); + } + + // Handle empty enum (no variants) + if union_variant_names.is_empty() { + output.push_str(&format!( + "\nclass {struct_name}(RootModel):\n \"\"\"Empty discriminated union (no variants)\"\"\"\n root: None = None\n" + )); + return Ok(output); + } + + // Render the parent type as a discriminated union RootModel + let (sanitized_tag, _) = sanitize_field_name_with_alias(tag, tag); + let union_type = union_variant_names.join(",\n "); + output.push_str(&format!( + "\nclass {struct_name}(RootModel):\n root: Annotated[\n Union[\n {union_type},\n ],\n Field(discriminator=\"{sanitized_tag}\"),\n ]\n" + )); + + // Note: model_rebuild() for per-variant classes is handled by the global + // rebuild section after namespace classes are defined. Inline rebuild here + // would fail because dotted namespace references (used in type annotations) + // cannot be resolved until namespace classes exist. + + Ok(output) +} + +/// Standard flatten path: expand all flattened struct fields inline into a single model. +fn render_struct_with_flatten_standard( + struct_def: &reflectapi_schema::Struct, + struct_name: &str, + schema: &Schema, + implemented_types: &BTreeMap, + active_generics: &[String], + used_type_vars: &mut BTreeSet, +) -> anyhow::Result { + let mut all_fields = Vec::new(); - let (python_name, alias) = field_name; + // Add regular fields + for field in struct_def.fields.iter().filter(|f| !f.flattened()) { + let (python_name, alias) = sanitize_field_name_with_alias(field.name(), field.serde_name()); + let field_type = type_ref_to_python_type( + &field.type_ref, + schema, + implemented_types, + active_generics, + used_type_vars, + )?; all_fields.push(templates::Field { name: python_name, @@ -489,25 +690,25 @@ fn render_struct_with_flatten( &field.type_ref, schema, implemented_types, - &active_generics, + active_generics, field.required, - 0, // Start at depth 0 + 0, used_type_vars, + Some(field.name()), )?; all_fields.extend(flattened_fields); } - // Generate as a regular Pydantic model with all fields flattened let struct_template = templates::DataClass { - name: struct_name, + name: struct_name.to_string(), description: Some(struct_def.description().to_string()), fields: all_fields, is_tuple: false, is_generic: !active_generics.is_empty(), - generic_params: active_generics, + generic_params: active_generics.to_vec(), }; - let rendered = struct_template.render()?; + let rendered = struct_template.render(); Ok(rendered) } @@ -772,58 +973,109 @@ __all__ = {} ) } +/// Build a tree of namespace modules from rendered type strings. +/// +/// Each original type name is split on `::`. The last segment is the leaf +/// type (already rendered); the preceding segments define the namespace path. +/// The rendered code for each type is placed into the leaf module. +fn modules_from_rendered_types( + original_type_names: Vec, + mut rendered_types: BTreeMap, +) -> templates::Module { + use indexmap::IndexMap; + + let mut root_module = templates::Module { + name: String::new(), + types: vec![], + submodules: IndexMap::new(), + }; + + for original_type_name in original_type_names { + let mut module = &mut root_module; + let mut parts: Vec<&str> = original_type_name.split("::").collect(); + parts.pop(); // Remove the leaf type name — already embedded in the rendered code. + for part in parts { + module = module + .submodules + .entry(part.to_string()) + .or_insert_with(|| templates::Module { + name: part.to_string(), + types: vec![], + submodules: IndexMap::new(), + }); + } + if let Some(rendered_type) = rendered_types.remove(&original_type_name) { + module.types.push(templates::ModuleType { + rendered: rendered_type, + }); + } + } + + root_module +} + pub fn generate(mut schema: Schema, config: &Config) -> anyhow::Result { let implemented_types = build_implemented_types(); - // Consolidate types to avoid duplicates - schema.consolidate_types(); - - // Validate all type references exist + // Consolidate input/output types FIRST so both the SemanticSchema and + // the raw Schema share the same unified type names. + let all_type_names = schema.consolidate_types(); validate_type_references(&schema)?; + // Build the semantic IR with a codegen-specific pipeline that skips + // TypeConsolidation (already done above) and NamingResolution (which + // would rename types and create a name-domain mismatch with the raw + // Schema). Only CircularDependencyResolution runs. + let semantic = reflectapi_schema::Normalizer::new() + .normalize_with_pipeline( + &schema, + reflectapi_schema::PipelineBuilder::new() + .consolidation(reflectapi_schema::Consolidation::Skip) + .naming(reflectapi_schema::Naming::Skip) + .build(), + ) + .map_err(|errors| { + anyhow::anyhow!( + "Schema normalization failed: {}", + errors + .iter() + .map(|e| e.to_string()) + .collect::>() + .join("; ") + ) + })?; + let mut generated_code = Vec::new(); // Generate file header let file_header = templates::FileHeader { package_name: config.package_name.clone(), }; - generated_code.push( - file_header - .render() - .context("Failed to render file header")?, - ); - - // Check if we have enums in the schema - let all_type_names = schema.consolidate_types(); - let has_enums = all_type_names.iter().any(|name| { - if let Some(type_def) = schema.get_type(name) { - matches!(type_def, reflectapi_schema::Type::Enum(_)) - } else { - false - } - }); + generated_code.push(file_header.render()); + // Use the semantic IR for import detection — iterate types once, + // matching on SemanticType which provides the fully resolved view. + let has_enums = semantic + .types() + .any(|t| matches!(t, reflectapi_schema::SemanticType::Enum(_))); - // Check if we need Literal import and Field discriminator (for tagged enums) let (has_literal, has_discriminated_unions, has_externally_tagged_enums) = { let mut has_literal = false; let mut has_discriminated_unions = false; let mut has_externally_tagged_enums = false; - for name in &all_type_names { - if let Some(reflectapi_schema::Type::Enum(enum_def)) = schema.get_type(name) { - match enum_def.representation { + for sem_type in semantic.types() { + if let reflectapi_schema::SemanticType::Enum(sem_enum) = sem_type { + match &sem_enum.representation { reflectapi_schema::Representation::Internal { .. } => { has_literal = true; has_discriminated_unions = true; } - reflectapi_schema::Representation::External => { - // Check if this enum has complex variants that need RootModel - let has_complex_variants = - enum_def.variants.iter().any(|v| match &v.fields { - reflectapi_schema::Fields::Named(_) => true, - reflectapi_schema::Fields::Unnamed(fields) => !fields.is_empty(), - reflectapi_schema::Fields::None => false, - }); + reflectapi_schema::Representation::External + | reflectapi_schema::Representation::Adjacent { .. } => { + let has_complex_variants = sem_enum + .variants + .values() + .any(|v| !matches!(v.field_style, reflectapi_schema::FieldStyle::Unit)); if has_complex_variants { has_externally_tagged_enums = true; } @@ -849,11 +1101,8 @@ pub fn generate(mut schema: Schema, config: &Config) -> anyhow::Result { let has_reflectapi_infallible = schema_uses_type(&schema, &all_type_names, "reflectapi::Infallible"); - // Flatten support uses direct field expansion in generated models - let has_flatten_support = false; - - // Check if we need warnings import (for deprecated functions) - let has_warnings = schema.functions().any(|f| f.deprecation_note.is_some()); + // Use semantic IR for function introspection + let has_warnings = semantic.functions().any(|f| f.deprecation_note.is_some()); // Check if we need datetime imports (for chrono and time types) let has_datetime = check_datetime_usage(&schema, &all_type_names); @@ -870,7 +1119,6 @@ pub fn generate(mut schema: Schema, config: &Config) -> anyhow::Result { has_reflectapi_option, has_reflectapi_empty, has_reflectapi_infallible, - has_flatten_support, has_warnings, has_datetime, has_uuid, @@ -894,99 +1142,140 @@ pub fn generate(mut schema: Schema, config: &Config) -> anyhow::Result { "std::option::Option", ]; - // Collect TypeVars used across all types + // Build the set of Python class names that will be emitted, so we can + // detect TypeVar-vs-class name collisions below. + let emitted_class_names: HashSet = semantic + .types() + .filter(|st| !runtime_provided_types.contains(&st.name())) + .filter_map(|st| schema.get_type(st.name())) + .map(|t| improve_class_name(t.name())) + .collect(); + + // Collect TypeVars used across all types, using semantic IR ordering. + // Since the codegen pipeline skips NamingResolution, sem_type.name() + // matches the raw Schema's type names exactly — no original_name bridging needed. let mut used_type_vars: BTreeSet = BTreeSet::new(); - // Use topological sort if possible, fall back to alphabetical on circular dependencies - let sorted_type_names = topological_sort_types(&all_type_names, &schema).unwrap_or_else(|_| { - // Circular dependencies detected, use alphabetical order - let mut sorted = all_type_names.clone(); - sorted.sort(); - sorted - }); - for original_type_name in &sorted_type_names { - if runtime_provided_types.contains(&original_type_name.as_str()) { + for sem_type in semantic.types() { + let type_name = sem_type.name(); + if runtime_provided_types.contains(&type_name) { continue; } - let type_def = schema.get_type(original_type_name).unwrap(); + let type_def = match schema.get_type(type_name) { + Some(t) => t, + None => continue, + }; // Collect TypeVars from this type collect_type_vars_from_type(type_def, &schema, &implemented_types, &mut used_type_vars)?; } + // Build a rename map for TypeVars that collide with class names. + // When a Rust type parameter has the same name as a top-level type + // (e.g., `Identity` is both a type parameter and a struct), the class + // definition would overwrite the TypeVar. We prefix these with `_T_` + // so the TypeVar and class can coexist in Python's single namespace. + let typevar_rename_map: BTreeMap = used_type_vars + .iter() + .filter(|tv| emitted_class_names.contains(tv.as_str())) + .map(|tv| (tv.clone(), format!("_T_{tv}"))) + .collect(); + + // Apply the rename map to the schema's type parameter names and type + // references. This ensures all downstream rendering functions + // automatically use the renamed TypeVar names without needing to + // thread a rename map through every function signature. + if !typevar_rename_map.is_empty() { + rename_type_params_in_schema(&mut schema, &typevar_rename_map); + } + + // Apply renames to the used_type_vars set + let renamed_type_vars: BTreeSet = used_type_vars + .iter() + .map(|tv| { + typevar_rename_map + .get(tv) + .cloned() + .unwrap_or_else(|| tv.clone()) + }) + .collect(); + // Generate TypeVar declarations - if !used_type_vars.is_empty() { + if !renamed_type_vars.is_empty() { generated_code.push("".to_string()); generated_code.push("# Type variables for generic types".to_string()); generated_code.push("".to_string()); - for type_var in &used_type_vars { + for type_var in &renamed_type_vars { generated_code.push(format!("{type_var} = TypeVar(\"{type_var}\")")); } generated_code.push("".to_string()); } - // Render all types (models and enums) without factories first + // Render all types (models and enums) let mut rendered_types = BTreeMap::new(); - let mut factory_data = Vec::new(); // Collect factory data for later generation - - // Sort types topologically to handle dependencies, fall back to alphabetical on circular deps - let sorted_type_names = topological_sort_types(&all_type_names, &schema).unwrap_or_else(|_| { - // Circular dependencies detected, use alphabetical order - let mut sorted = all_type_names.clone(); - sorted.sort(); - sorted - }); - for original_type_name in sorted_type_names { - // Skip types provided by the runtime - if runtime_provided_types.contains(&original_type_name.as_str()) { + // Use SemanticSchema for type ordering — it provides deterministic + // BTreeMap ordering from the Normalizer's dependency analysis. + // Names match the raw Schema directly (no NamingResolution was applied). + let mut rendered_type_names_in_order: Vec = Vec::new(); + + for sem_type in semantic.types() { + let type_name = sem_type.name().to_string(); + + if runtime_provided_types.contains(&type_name.as_str()) { continue; } - let type_def = schema.get_type(&original_type_name).unwrap(); - let name = improve_class_name(type_def.name()); + let type_def = match schema.get_type(&type_name) { + Some(t) => t, + None => { + continue; + } + }; // TypeVars have already been collected, use empty set for rendering let mut dummy_type_vars = BTreeSet::new(); - let (rendered, factory_info) = render_type_without_factory( - type_def, - &schema, - &implemented_types, - &mut dummy_type_vars, - )?; - - // Store factory info for later generation - if let Some(info) = factory_info { - factory_data.push(info); - } + let rendered = render_type(type_def, &schema, &implemented_types, &mut dummy_type_vars)?; // Only store non-empty renders (excludes unwrapped tuple structs) if !rendered.trim().is_empty() { - rendered_types.insert(name.clone(), rendered.clone()); - generated_code.push(rendered); + rendered_types.insert(type_name.clone(), rendered); + rendered_type_names_in_order.push(type_name); } } + // Collect rendered type keys before passing ownership to the module tree builder. + let rendered_type_keys: Vec = rendered_types.keys().cloned().collect(); + + // Build namespace module tree and render it + let module_tree = modules_from_rendered_types(rendered_type_names_in_order, rendered_types); + let module_tree_code = module_tree.render(); + if !module_tree_code.trim().is_empty() { + generated_code.push(module_tree_code); + } + // TypeVar declarations are now generated at the top of the file (after imports) - // Generate client class with nested method organization - let functions_by_name: BTreeMap = + // Generate client class with nested method organization. + // Use SemanticSchema for deterministic function ordering, but + // look up raw Function objects for rendering (render_function + // needs the raw TypeReference fields). + let raw_functions_by_name: BTreeMap = schema.functions().map(|f| (f.name.clone(), f)).collect(); - // Group functions by their prefix and separate top-level functions let mut function_groups: BTreeMap> = BTreeMap::new(); let mut top_level_functions: Vec = Vec::new(); - for function_schema in functions_by_name.values() { + for sem_func in semantic.functions() { + let function_schema = match raw_functions_by_name.get(&sem_func.name) { + Some(f) => f, + None => continue, // Skip functions not in raw schema (shouldn't happen) + }; let rendered_function = render_function(function_schema, &schema, &implemented_types)?; // Check for grouping patterns: underscore or dot notation - if let Some(separator_pos) = function_schema - .name - .find('_') - .or_else(|| function_schema.name.find('.')) - { - let group_name = &function_schema.name[..separator_pos]; - let method_name = &function_schema.name[separator_pos + 1..]; + if let Some(separator_pos) = sem_func.name.find('_').or_else(|| sem_func.name.find('.')) { + let group_name = &sem_func.name[..separator_pos]; + let method_name = &sem_func.name[separator_pos + 1..]; // Create a modified function with the shortened name for nested access let mut nested_function = rendered_function.clone(); @@ -995,7 +1284,7 @@ pub fn generate(mut schema: Schema, config: &Config) -> anyhow::Result { nested_function.original_name = Some(rendered_function.name.clone()); function_groups - .entry(to_valid_python_identifier(group_name)) + .entry(safe_python_identifier(group_name)) .or_default() .push(nested_function); } else { @@ -1025,19 +1314,7 @@ pub fn generate(mut schema: Schema, config: &Config) -> anyhow::Result { generate_sync: config.generate_sync, base_url: config.base_url.clone(), }; - generated_code.push( - client_template - .render() - .context("Failed to render client class")?, - ); - - // Generate nested class structure - let nested_classes = generate_nested_class_structure(&rendered_types, &schema); - if !nested_classes.is_empty() { - generated_code.push("# Nested class definitions for better organization".to_string()); - generated_code.push(nested_classes); - generated_code.push("".to_string()); - } + generated_code.push(client_template.render()); // Add external type definitions and model rebuilds for Pydantic forward references let mut external_types_and_rebuilds = vec![ @@ -1050,11 +1327,11 @@ pub fn generate(mut schema: Schema, config: &Config) -> anyhow::Result { "# Rebuild models to resolve forward references".to_string(), "try:".to_string(), ]; - let mut sorted_type_names: Vec<_> = rendered_types.keys().collect(); - sorted_type_names.sort(); - for type_name in sorted_type_names { - if !type_name.starts_with("std::") && !type_name.starts_with("reflectapi::") { - external_types_and_rebuilds.push(format!(" {type_name}.model_rebuild()")); + let sorted_type_names: Vec<&String> = rendered_type_keys.iter().collect(); + for original_name in &sorted_type_names { + if !original_name.starts_with("std::") && !original_name.starts_with("reflectapi::") { + let dotted = type_name_to_python_ref(original_name); + external_types_and_rebuilds.push(format!(" {dotted}.model_rebuild()")); } } external_types_and_rebuilds.push("except AttributeError:".to_string()); @@ -1062,29 +1339,6 @@ pub fn generate(mut schema: Schema, config: &Config) -> anyhow::Result { .push(" # Some types may not have model_rebuild method".to_string()); external_types_and_rebuilds.push(" pass".to_string()); external_types_and_rebuilds.push("".to_string()); - external_types_and_rebuilds.push( - "# Factory classes (generated after model rebuild to avoid forward references)".to_string(), - ); - - // Generate all factory classes now that types are defined and rebuilt - for factory_info in &factory_data { - let factory_code = if factory_info.is_internally_tagged { - generate_internally_tagged_factory_class( - &factory_info.enum_def, - &factory_info.enum_name, - &factory_info.union_members, - )? - } else { - generate_factory_class_with_representation( - &factory_info.enum_def, - &factory_info.enum_name, - &factory_info.union_members, - &factory_info.enum_def.representation, - )? - }; - external_types_and_rebuilds.push(factory_code); - external_types_and_rebuilds.push("".to_string()); - } generated_code.push(external_types_and_rebuilds.join("\n")); @@ -1092,17 +1346,16 @@ pub fn generate(mut schema: Schema, config: &Config) -> anyhow::Result { if config.generate_testing { // contains user-defined types that have Pydantic classes generated for them. // Note types with fallbacks to primitives are not added. - let mut user_defined_types: Vec = rendered_types.keys().cloned().collect(); + let mut user_defined_types: Vec = rendered_type_keys + .iter() + .map(|original_name| type_name_to_python_ref(original_name)) + .collect(); user_defined_types.sort(); let testing_template = templates::TestingModule { types: user_defined_types, }; - generated_code.push( - testing_template - .render() - .context("Failed to render testing module")?, - ); + generated_code.push(testing_template.render()); } let result = generated_code.join("\n\n"); @@ -1111,6 +1364,137 @@ pub fn generate(mut schema: Schema, config: &Config) -> anyhow::Result { format_python_code(&result) } +/// Rename type parameters in the schema to avoid TypeVar/class name collisions. +/// +/// When a Rust type parameter (e.g., `Identity`) has the same name as a +/// top-level type, the Python codegen would produce both a TypeVar and a +/// class with the same name, causing the class to shadow the TypeVar. +/// +/// This function renames the parameters in-place in the schema's type +/// definitions and updates all type references that point to those +/// parameters, so all downstream rendering automatically uses the safe names. +fn rename_type_params_in_schema(schema: &mut Schema, rename_map: &BTreeMap) { + // Process both input_types and output_types since consolidate_types() + // keeps non-conflicting types in their original typespace. + let input_type_names: Vec = schema + .input_types + .types() + .map(|t| t.name().to_string()) + .collect(); + for type_name in input_type_names { + if let Some(type_def) = schema.input_types.get_type_mut(&type_name) { + rename_type_params_in_type(type_def, rename_map); + } + } + + let output_type_names: Vec = schema + .output_types + .types() + .map(|t| t.name().to_string()) + .collect(); + for type_name in output_type_names { + if let Some(type_def) = schema.output_types.get_type_mut(&type_name) { + rename_type_params_in_type(type_def, rename_map); + } + } +} + +/// Rename type parameters within a single type definition. +fn rename_type_params_in_type( + type_def: &mut reflectapi_schema::Type, + rename_map: &BTreeMap, +) { + match type_def { + reflectapi_schema::Type::Struct(s) => { + // Check if this struct has any parameters that need renaming + let has_renames = s + .parameters + .iter() + .any(|p| rename_map.contains_key(&p.name)); + if !has_renames { + return; + } + // Rename parameters + for param in &mut s.parameters { + if let Some(new_name) = rename_map.get(¶m.name) { + param.name = new_name.clone(); + } + } + // Rename type references in fields + match &mut s.fields { + reflectapi_schema::Fields::Named(fields) + | reflectapi_schema::Fields::Unnamed(fields) => { + for field in fields { + rename_type_ref(&mut field.type_ref, rename_map); + } + } + reflectapi_schema::Fields::None => {} + } + } + reflectapi_schema::Type::Enum(e) => { + let has_renames = e + .parameters + .iter() + .any(|p| rename_map.contains_key(&p.name)); + if !has_renames { + return; + } + for param in &mut e.parameters { + if let Some(new_name) = rename_map.get(¶m.name) { + param.name = new_name.clone(); + } + } + for variant in &mut e.variants { + match &mut variant.fields { + reflectapi_schema::Fields::Named(fields) + | reflectapi_schema::Fields::Unnamed(fields) => { + for field in fields { + rename_type_ref(&mut field.type_ref, rename_map); + } + } + reflectapi_schema::Fields::None => {} + } + } + } + reflectapi_schema::Type::Primitive(p) => { + let has_renames = p + .parameters + .iter() + .any(|pp| rename_map.contains_key(&pp.name)); + if !has_renames { + return; + } + for param in &mut p.parameters { + if let Some(new_name) = rename_map.get(¶m.name) { + param.name = new_name.clone(); + } + } + if let Some(fallback) = &mut p.fallback { + rename_type_ref(fallback, rename_map); + } + } + } +} + +/// Recursively rename type parameter references in a TypeReference tree. +/// +/// Only renames bare references (no generic arguments) that match the rename +/// map, since type parameters are always leaf references with no arguments. +/// A reference like `Identity` with arguments would be a concrete type +/// instantiation, not a type parameter usage. +fn rename_type_ref(type_ref: &mut TypeReference, rename_map: &BTreeMap) { + // Only rename bare names (no arguments) — these are type parameter usages. + // References with arguments are concrete type instantiations (e.g., Vec). + if type_ref.arguments.is_empty() { + if let Some(new_name) = rename_map.get(&type_ref.name) { + type_ref.name = new_name.clone(); + } + } + for arg in &mut type_ref.arguments { + rename_type_ref(arg, rename_map); + } +} + /// Check if a type name looks like a generic type variable fn is_probable_typevar(name: &str) -> bool { // Likely a TypeVar if it's a bare identifier not present in schema and starts with uppercase @@ -1194,26 +1578,26 @@ fn infer_enum_generic_params(enum_def: &reflectapi_schema::Enum, schema: &Schema result } -fn render_type_without_factory( +fn render_type( type_def: &Type, schema: &Schema, implemented_types: &BTreeMap, used_type_vars: &mut BTreeSet, -) -> anyhow::Result<(String, Option)> { +) -> anyhow::Result { match type_def { - Type::Struct(s) => Ok(( - render_struct(s, schema, implemented_types, used_type_vars)?, - None, - )), - Type::Enum(e) => render_enum_without_factory(e, schema, implemented_types, used_type_vars), + Type::Struct(s) => render_struct(s, schema, implemented_types, used_type_vars), + Type::Enum(e) => render_enum(e, schema, implemented_types, used_type_vars), Type::Primitive(_p) => { // Primitive types are handled by implemented_types mapping - Ok((String::new(), None)) // This shouldn't be reached normally + Ok(String::new()) // This shouldn't be reached normally } } } -/// Recursively collect fields from flattened structures +/// Recursively collect fields from flattened structures and enums. +/// `field_name` is the original Rust field name for the flattened field +/// (used when emitting enum types as regular fields). +#[allow(clippy::too_many_arguments)] fn collect_flattened_fields( type_ref: &TypeReference, schema: &Schema, @@ -1222,6 +1606,7 @@ fn collect_flattened_fields( parent_required: bool, depth: usize, used_type_vars: &mut BTreeSet, + field_name: Option<&str>, ) -> anyhow::Result> { // Prevent infinite recursion if depth > 10 { @@ -1248,75 +1633,184 @@ fn collect_flattened_fields( &type_ref.name }; - if let Some(reflectapi_schema::Type::Struct(struct_def)) = schema.get_type(target_type_name) { - for field in struct_def.fields.iter() { - if field.flattened() { - // Recursively collect fields from nested flattened structures - let nested_fields = collect_flattened_fields( - &field.type_ref, - schema, - implemented_types, - active_generics, - parent_required && field.required, - depth + 1, - used_type_vars, - )?; - collected_fields.extend(nested_fields); - } else { - // Regular field in flattened struct - let field_type = type_ref_to_python_type( - &field.type_ref, - schema, - implemented_types, - active_generics, - used_type_vars, - )?; - - let is_option_type = field.type_ref.name == "std::option::Option" - || field.type_ref.name == "reflectapi::Option"; - - let (optional, default_value, final_field_type) = - if !field.required || !parent_required { - if is_option_type { - (true, Some("None".to_string()), field_type) - } else { - ( - true, - Some("None".to_string()), - format!("{field_type} | None"), - ) - } - } else if is_option_type { - (true, Some("None".to_string()), field_type) - } else { - (false, None, field_type) - }; - - let (sanitized, alias) = sanitize_field_name_with_alias(field.name()); - collected_fields.push(templates::Field { - name: sanitized, - type_annotation: final_field_type, - description: Some(format!( - "(flattened{}) {}", - if depth > 1 { - format!(" depth={depth}") - } else { - String::new() - }, - field.description() - )), - deprecation_note: field.deprecation_note.clone(), - optional, - default_value, - alias, - }); + match schema.get_type(target_type_name) { + Some(reflectapi_schema::Type::Struct(struct_def)) => { + for field in struct_def.fields.iter() { + if field.flattened() { + // Recursively collect fields from nested flattened structures + let nested_fields = collect_flattened_fields( + &field.type_ref, + schema, + implemented_types, + active_generics, + parent_required && field.required, + depth + 1, + used_type_vars, + Some(field.name()), + )?; + collected_fields.extend(nested_fields); + } else { + // Regular field in flattened struct + collected_fields.push(make_flattened_field( + field, + schema, + implemented_types, + active_generics, + parent_required, + depth, + used_type_vars, + )?); + } } } + Some(reflectapi_schema::Type::Enum(enum_def)) => { + // Flattened enum: expand variant fields into the parent model. + // For internally-tagged enums, each variant's fields + the tag field + // get merged into the parent struct. For other representations, + // we emit the enum as a regular typed field since Pydantic cannot + // truly flatten non-internally-tagged unions. + collect_flattened_enum_fields( + enum_def, + type_ref, + schema, + implemented_types, + active_generics, + parent_required, + used_type_vars, + &mut collected_fields, + field_name, + )?; + } + Some(reflectapi_schema::Type::Primitive(_)) | None => { + // Primitives (including unit types) and unresolved types cannot + // be meaningfully flattened — skip them, matching prior behavior. + // This handles cases like flattened generic parameters that resolve + // to () (std::tuple::Tuple0). + } } Ok(collected_fields) } +/// Create a single flattened field entry from a struct field +fn make_flattened_field( + field: &reflectapi_schema::Field, + schema: &Schema, + implemented_types: &BTreeMap, + active_generics: &[String], + parent_required: bool, + depth: usize, + used_type_vars: &mut BTreeSet, +) -> anyhow::Result { + let field_type = type_ref_to_python_type( + &field.type_ref, + schema, + implemented_types, + active_generics, + used_type_vars, + )?; + + let is_option_type = + field.type_ref.name == "std::option::Option" || field.type_ref.name == "reflectapi::Option"; + + let (optional, default_value, final_field_type) = if !field.required || !parent_required { + if is_option_type { + (true, Some("None".to_string()), field_type) + } else { + ( + true, + Some("None".to_string()), + format!("{field_type} | None"), + ) + } + } else if is_option_type { + (true, Some("None".to_string()), field_type) + } else { + (false, None, field_type) + }; + + let (sanitized, alias) = sanitize_field_name_with_alias(field.name(), field.serde_name()); + Ok(templates::Field { + name: sanitized, + type_annotation: final_field_type, + description: Some(format!( + "(flattened{}) {}", + if depth > 1 { + format!(" depth={depth}") + } else { + String::new() + }, + field.description() + )), + deprecation_note: field.deprecation_note.clone(), + optional, + default_value, + alias, + }) +} + +/// Handle flattened enum fields by emitting the enum as a typed field. +/// +/// For internally-tagged enums (`#[serde(tag = "...")]`), serde merges the +/// tag + variant fields into the parent struct. Pydantic can't directly +/// represent this, so we emit the enum's Python union type as a regular field. +/// The model uses `extra="allow"` to accept the flattened wire format. +#[allow(clippy::too_many_arguments)] +fn collect_flattened_enum_fields( + enum_def: &reflectapi_schema::Enum, + type_ref: &TypeReference, + schema: &Schema, + implemented_types: &BTreeMap, + active_generics: &[String], + parent_required: bool, + used_type_vars: &mut BTreeSet, + collected_fields: &mut Vec, + original_field_name: Option<&str>, +) -> anyhow::Result<()> { + let enum_python_type = type_ref_to_python_type( + type_ref, + schema, + implemented_types, + active_generics, + used_type_vars, + )?; + + // Use the original Rust field name if available, otherwise derive from type name + let field_name = original_field_name + .map(|s| s.to_string()) + .unwrap_or_else(|| { + type_ref + .name + .split("::") + .last() + .unwrap_or(&type_ref.name) + .to_lowercase() + }); + let (sanitized, alias) = sanitize_field_name_with_alias(&field_name, &field_name); + + let (optional, default_value, final_type) = if !parent_required { + ( + true, + Some("None".to_string()), + format!("{enum_python_type} | None"), + ) + } else { + (false, None, enum_python_type) + }; + + collected_fields.push(templates::Field { + name: sanitized, + type_annotation: final_type, + description: Some(format!("(flattened enum: {})", enum_def.name)), + deprecation_note: None, + optional, + default_value, + alias, + }); + + Ok(()) +} + fn render_struct( struct_def: &reflectapi_schema::Struct, schema: &Schema, @@ -1384,7 +1878,8 @@ fn render_struct( (false, None, base_field_type) }; - let (sanitized, alias) = sanitize_field_name_with_alias(field.name()); + let (sanitized, alias) = + sanitize_field_name_with_alias(field.name(), field.serde_name()); Ok(templates::Field { name: sanitized, type_annotation: field_type, @@ -1397,24 +1892,9 @@ fn render_struct( }) .collect::, anyhow::Error>>()?; - // Collect flattened fields recursively using the new helper function - let mut flattened_fields: Vec = Vec::new(); - for field in struct_def.fields.iter().filter(|f| f.flattened()) { - let fields = collect_flattened_fields( - &field.type_ref, - schema, - implemented_types, - &active_generics, - field.required, - 0, - used_type_vars, - )?; - flattened_fields.extend(fields); - } - - // Combine regular fields with flattened field information - let mut all_fields = regular_fields; - all_fields.extend(flattened_fields); + // Note: flattened fields are handled by render_struct_with_flatten (early return + // at the top of this function). This path only handles non-flattened structs. + let all_fields = regular_fields; // Check if this is a generic struct (has type parameters) let has_generics = !struct_def.parameters.is_empty(); @@ -1429,22 +1909,21 @@ fn render_struct( generic_params: active_generics.clone(), }; - class_template.render().context("Failed to render struct") + Ok(class_template.render()) } -fn render_enum_without_factory( +fn render_enum( enum_def: &reflectapi_schema::Enum, schema: &Schema, implemented_types: &BTreeMap, used_type_vars: &mut BTreeSet, -) -> anyhow::Result<(String, Option)> { +) -> anyhow::Result { use reflectapi_schema::{Fields, Representation}; // Check if this is a tagged enum (internally tagged) match &enum_def.representation { Representation::Internal { tag } => { - // Internally tagged enums need factories but they're generated after model rebuild - let (rendered, union_variant_names) = render_internally_tagged_enum_without_factory( + let (rendered, _union_variant_names) = render_internally_tagged_enum( enum_def, tag, schema, @@ -1452,19 +1931,11 @@ fn render_enum_without_factory( used_type_vars, )?; - // Return factory info so it can be generated later - let factory_info = FactoryInfo { - enum_def: enum_def.clone(), - enum_name: improve_class_name(&enum_def.name), - union_members: union_variant_names, - is_internally_tagged: true, - }; - - Ok((rendered, Some(factory_info))) + Ok(rendered) } Representation::Adjacent { tag, content } => { // Adjacently tagged enums are represented as { tag: "Variant", content: ... } - let (rendered, union_variant_names) = render_adjacently_tagged_enum_without_factory( + let (rendered, _union_variant_names) = render_adjacently_tagged_enum( enum_def, tag, content, @@ -1473,30 +1944,18 @@ fn render_enum_without_factory( used_type_vars, )?; - // Return factory info so it can be generated later - let factory_info = FactoryInfo { - enum_def: enum_def.clone(), - enum_name: improve_class_name(&enum_def.name), - union_members: union_variant_names, - is_internally_tagged: false, // Adjacent tagged, not internal - }; - - Ok((rendered, Some(factory_info))) + Ok(rendered) } Representation::None => { - // Untagged enums don't use factories - let rendered = - render_untagged_enum(enum_def, schema, implemented_types, used_type_vars)?; - Ok((rendered, None)) + // Untagged enums + render_untagged_enum(enum_def, schema, implemented_types, used_type_vars) } _ => { // Check if this is a primitive-represented enum (has discriminant values) let has_discriminants = enum_def.variants.iter().any(|v| v.discriminant.is_some()); if has_discriminants { - // Primitive enums don't use factories - let rendered = render_primitive_enum(enum_def)?; - Ok((rendered, None)) + render_primitive_enum(enum_def) } else { // Check if this has complex variants (tuple or struct variants) let has_complex_variants = enum_def.variants.iter().any(|v| { @@ -1508,22 +1967,15 @@ fn render_enum_without_factory( }); if has_complex_variants { - // This is an externally tagged enum with complex variants - needs factory - let (rendered, union_members) = render_externally_tagged_enum_without_factory( + // This is an externally tagged enum with complex variants + render_externally_tagged_enum( enum_def, schema, implemented_types, used_type_vars, - )?; - let factory_info = FactoryInfo { - enum_def: enum_def.clone(), - enum_name: improve_class_name(&enum_def.name), - union_members, - is_internally_tagged: false, - }; - Ok((rendered, Some(factory_info))) + ) } else { - // Simple string enum - no factory needed + // Simple string enum let variants = enum_def .variants .iter() @@ -1540,15 +1992,14 @@ fn render_enum_without_factory( variants, }; - let rendered = enum_template.render().context("Failed to render enum")?; - Ok((rendered, None)) + Ok(enum_template.render()) } } } } } -fn render_adjacently_tagged_enum_without_factory( +fn render_adjacently_tagged_enum( enum_def: &reflectapi_schema::Enum, tag: &str, content: &str, @@ -1604,7 +2055,7 @@ fn render_adjacently_tagged_enum_without_factory( is_generic: !generic_params.is_empty(), generic_params: generic_params.clone(), }; - variant_models.push(variant_model.render()?); + variant_models.push(variant_model.render()); union_variants.push(variant_class_name); } Fields::Named(named_fields) => { @@ -1636,7 +2087,8 @@ fn render_adjacently_tagged_enum_without_factory( } else { (false, None, field_type) }; - let (sanitized, alias) = sanitize_field_name_with_alias(field.name()); + let (sanitized, alias) = + sanitize_field_name_with_alias(field.name(), field.serde_name()); fields.push(templates::Field { name: sanitized, type_annotation: final_field_type, @@ -1655,7 +2107,7 @@ fn render_adjacently_tagged_enum_without_factory( is_generic: !generic_params.is_empty(), generic_params: generic_params.clone(), }; - variant_models.push(variant_model.render()?); + variant_models.push(variant_model.render()); union_variants.push(variant_class_name); } } @@ -1709,18 +2161,19 @@ fn generate_adjacent_dispatch_cases( use reflectapi_schema::Fields; let mut cases = Vec::new(); for variant in &enum_def.variants { - let vname = variant.name(); + let wire_name = variant.serde_name(); + let rust_name = variant.name(); match &variant.fields { Fields::None => { cases.push(format!( - " if tag == \"{vname}\":\n return \"{vname}\"" + " if tag == \"{wire_name}\":\n return \"{wire_name}\"" )); } Fields::Unnamed(unnamed_fields) => { - let class_name = format!("{enum_name}{}Variant", to_pascal_case(vname)); + let class_name = format!("{enum_name}{}Variant", to_pascal_case(rust_name)); if unnamed_fields.len() == 1 { cases.push(format!( - " if tag == \"{vname}\":\n return {class_name}(field_0=content)" + " if tag == \"{wire_name}\":\n return {class_name}(field_0=content)" )); } else { let assigns = (0..unnamed_fields.len()) @@ -1728,14 +2181,14 @@ fn generate_adjacent_dispatch_cases( .collect::>() .join(", "); cases.push(format!( - " if tag == \"{vname}\":\n if isinstance(content, list):\n return {class_name}({assigns})\n else:\n raise ValueError(\"Expected list for tuple variant {vname}\")" + " if tag == \"{wire_name}\":\n if isinstance(content, list):\n return {class_name}({assigns})\n else:\n raise ValueError(\"Expected list for tuple variant {wire_name}\")" )); } } Fields::Named(_named_fields) => { - let class_name = format!("{enum_name}{}Variant", to_pascal_case(vname)); + let class_name = format!("{enum_name}{}Variant", to_pascal_case(rust_name)); cases.push(format!( - " if tag == \"{vname}\":\n return {class_name}(**content)" + " if tag == \"{wire_name}\":\n return {class_name}(**content)" )); } } @@ -1752,20 +2205,21 @@ fn generate_adjacent_serialize_cases( use reflectapi_schema::Fields; let mut cases = Vec::new(); for variant in &enum_def.variants { - let vname = variant.name(); + let wire_name = variant.serde_name(); + let rust_name = variant.name(); match &variant.fields { Fields::None => { cases.push(format!( - " if self.root == \"{vname}\":\n return {{\"{tag}\": \"{vname}\"}}" + " if self.root == \"{wire_name}\":\n return {{\"{tag}\": \"{wire_name}\"}}" )); } Fields::Unnamed(unnamed_fields) => { - let class_name = format!("{enum_name}{}Variant", to_pascal_case(vname)); + let class_name = format!("{enum_name}{}Variant", to_pascal_case(rust_name)); // For tuple variants in adjacently tagged enums, serialize the content properly if unnamed_fields.len() == 1 { // Single field tuple: serialize the field value directly cases.push(format!( - " if isinstance(self.root, {class_name}):\n return {{\"{tag}\": \"{vname}\", \"{content}\": self.root.field_0}}" + " if isinstance(self.root, {class_name}):\n return {{\"{tag}\": \"{wire_name}\", \"{content}\": self.root.field_0}}" )); } else { // Multiple field tuple: serialize as array @@ -1773,15 +2227,15 @@ fn generate_adjacent_serialize_cases( .map(|i| format!("self.root.field_{i}")) .collect(); cases.push(format!( - " if isinstance(self.root, {class_name}):\n return {{\"{tag}\": \"{vname}\", \"{content}\": [{}]}}", + " if isinstance(self.root, {class_name}):\n return {{\"{tag}\": \"{wire_name}\", \"{content}\": [{}]}}", field_accesses.join(", ") )); } } Fields::Named(_named_fields) => { - let class_name = format!("{enum_name}{}Variant", to_pascal_case(vname)); + let class_name = format!("{enum_name}{}Variant", to_pascal_case(rust_name)); cases.push(format!( - " if isinstance(self.root, {class_name}):\n return {{\"{tag}\": \"{vname}\", \"{content}\": self.root.model_dump(exclude_none=True)}}" + " if isinstance(self.root, {class_name}):\n return {{\"{tag}\": \"{wire_name}\", \"{content}\": self.root.model_dump()}}" )); } } @@ -1789,81 +2243,34 @@ fn generate_adjacent_serialize_cases( Ok(cases.join("\n")) } -fn render_externally_tagged_enum_without_factory( +fn render_externally_tagged_enum( enum_def: &reflectapi_schema::Enum, schema: &Schema, implemented_types: &BTreeMap, used_type_vars: &mut BTreeSet, -) -> anyhow::Result<(String, Vec)> { - // Generate the full enum (with factory) - let full_enum = - render_externally_tagged_enum(enum_def, schema, implemented_types, used_type_vars)?; - - // Extract just the part before the factory class (more specific split) - let enum_name = improve_class_name(&enum_def.name); - let factory_class_pattern = format!("\n\nclass {enum_name}Factory:"); - let parts: Vec<&str> = full_enum.split(&factory_class_pattern).collect(); - let enum_without_factory = parts[0].to_string(); - - // Extract union member names for factory generation later - let union_variants = extract_union_members_from_enum(enum_def)?; - - Ok((enum_without_factory, union_variants)) -} - -fn extract_union_members_from_enum( - enum_def: &reflectapi_schema::Enum, -) -> anyhow::Result> { +) -> anyhow::Result { use reflectapi_schema::Fields; let enum_name = improve_class_name(&enum_def.name); + let mut variant_models = Vec::new(); let mut union_variants = Vec::new(); + let mut instance_validator_cases = Vec::new(); + let mut validator_cases = Vec::new(); + let mut dict_validator_cases = Vec::new(); + let mut serializer_cases = Vec::new(); + + // Collect active generic parameter names for this enum + let generic_params: Vec = infer_enum_generic_params(enum_def, schema); + + // Track used generic type variables + for generic in &generic_params { + used_type_vars.insert(generic.clone()); + } + // Generate variant models and build validation/serialization logic for variant in &enum_def.variants { let variant_name = variant.name(); - match &variant.fields { - Fields::None => { - union_variants.push(format!("Literal[\"{variant_name}\"]")); - } - Fields::Unnamed(_) | Fields::Named(_) => { - let variant_class_name = - format!("{}{}Variant", enum_name, to_pascal_case(variant_name)); - union_variants.push(variant_class_name); - } - } - } - - Ok(union_variants) -} - -fn render_externally_tagged_enum( - enum_def: &reflectapi_schema::Enum, - schema: &Schema, - implemented_types: &BTreeMap, - used_type_vars: &mut BTreeSet, -) -> anyhow::Result { - use reflectapi_schema::Fields; - - let enum_name = improve_class_name(&enum_def.name); - let mut variant_models = Vec::new(); - let mut union_variants = Vec::new(); - let mut instance_validator_cases = Vec::new(); - let mut validator_cases = Vec::new(); - let mut dict_validator_cases = Vec::new(); - let mut serializer_cases = Vec::new(); - - // Collect active generic parameter names for this enum - let generic_params: Vec = infer_enum_generic_params(enum_def, schema); - - // Track used generic type variables - for generic in &generic_params { - used_type_vars.insert(generic.clone()); - } - - // Generate variant models and build validation/serialization logic - for variant in &enum_def.variants { - let variant_name = variant.name(); - + match &variant.fields { Fields::None => { // Unit variant: represented as string literal @@ -1916,7 +2323,7 @@ fn render_externally_tagged_enum( generic_params: generic_params.clone(), }; - variant_models.push(variant_model.render()?); + variant_models.push(variant_model.render()); let union_member = if !generic_params.is_empty() { format!("{}[{}]", variant_class_name, generic_params.join(", ")) } else { @@ -1978,7 +2385,8 @@ fn render_externally_tagged_enum( (false, None, field_type) }; - let (sanitized, alias) = sanitize_field_name_with_alias(field.name()); + let (sanitized, alias) = + sanitize_field_name_with_alias(field.name(), field.serde_name()); fields.push(templates::Field { name: sanitized, type_annotation: final_field_type, @@ -1999,7 +2407,7 @@ fn render_externally_tagged_enum( generic_params: generic_params.clone(), }; - variant_models.push(variant_model.render()?); + variant_models.push(variant_model.render()); let union_member = if !generic_params.is_empty() { format!("{}[{}]", variant_class_name, generic_params.join(", ")) } else { @@ -2017,7 +2425,7 @@ fn render_externally_tagged_enum( )); serializer_cases.push(format!( - " if isinstance(self.root, {variant_class_name}):\n return {{\"{variant_name}\": self.root.model_dump(exclude_none=True)}}" + " if isinstance(self.root, {variant_class_name}):\n return {{\"{variant_name}\": self.root.model_dump()}}" )); } } @@ -2026,17 +2434,6 @@ fn render_externally_tagged_enum( // Check if this enum is generic let is_generic = !generic_params.is_empty(); - // Generate TypeVar definitions if generic - let type_var_definitions = if is_generic { - generic_params - .iter() - .map(|param| format!("{param} = TypeVar('{param}')")) - .collect::>() - .join("\n") - } else { - String::new() - }; - // Always use RootModel approach; add Generic[...] when needed let template = templates::ExternallyTaggedEnumRootModel { name: enum_name.clone(), @@ -2055,386 +2452,15 @@ fn render_externally_tagged_enum( is_generic, generic_params: generic_params.clone(), }; - let enum_code = template - .render() - .context("Failed to render externally tagged enum")?; - - // Generate factory class for ergonomic instantiation - let factory_class_code = generate_externally_tagged_factory_class(enum_def, &enum_name)?; - - // Combine all parts - let mut result = String::new(); - - // Add TypeVar definitions at the top if generic - if !type_var_definitions.is_empty() { - result.push_str(&type_var_definitions); - result.push_str("\n\n"); - } + let enum_code = template.render(); - // Add the enum code - result.push_str(&enum_code); - result.push_str("\n\n"); - - // Add the factory code - result.push_str(&factory_class_code); + // TypeVar definitions are emitted once at the top of the file; + // inline declarations are suppressed to avoid collisions with class names. + let result = enum_code; Ok(result) } -fn generate_factory_class_with_representation( - enum_def: &reflectapi_schema::Enum, - enum_name: &str, - union_members: &[String], - representation: &reflectapi_schema::Representation, -) -> anyhow::Result { - use reflectapi_schema::Fields; - - let factory_name = format!("{enum_name}Factory"); - let mut class_attributes = Vec::new(); - let mut static_methods = Vec::new(); - - // Check if this enum is generic - let is_generic = !enum_def.parameters.is_empty(); - let generic_params: Vec = if is_generic { - enum_def.parameters.iter().map(|p| p.name.clone()).collect() - } else { - Vec::new() - }; - - let generic_type_params = if is_generic { - format!("[{}]", generic_params.join(", ")) - } else { - String::new() - }; - - for (i, variant) in enum_def.variants.iter().enumerate() { - let variant_class_name = &union_members[i]; - - match &variant.fields { - Fields::None => { - // For generic enums, skip unit variants as they cannot be instantiated - // (Generic externally tagged enums use Approach B which doesn't support unit variant instantiation) - if !is_generic { - // Unit variant - creation method depends on representation - match representation { - reflectapi_schema::Representation::Adjacent { tag, .. } => { - // For adjacently tagged enums, unit variants need to be created as static methods - // returning the RootModel with dictionary format that the validator expects - let method_name = to_snake_case(variant.name()); - static_methods.push(format!( - r#" @staticmethod - def {}() -> {}: - '''Creates the '{}' variant of the {} enum.''' - return {}.model_validate({{"{}": "{}"}})"#, - method_name, - enum_name, - variant.name(), - enum_name, - enum_name, - tag, - variant.name() - )); - } - reflectapi_schema::Representation::External => { - // For externally tagged enums, unit variants are also static methods - let method_name = to_snake_case(variant.name()); - static_methods.push(format!( - r#" @staticmethod - def {}() -> {}: - '''Creates the '{}' variant of the {} enum.''' - return {}("{}")"#, - method_name, - enum_name, - variant.name(), - enum_name, - enum_name, - variant.name() - )); - } - _ => { - // For other representations, create as class attribute directly - class_attributes.push(format!( - " {} = {}(\"{}\")", - variant.name().to_uppercase(), - enum_name, - variant.name() - )); - } - } - } - } - Fields::Unnamed(_) | Fields::Named(_) => { - // Complex variant - create static method - let method_name = to_snake_case(variant.name()); - let method_params = generate_factory_method_params(variant)?; - let method_args = generate_factory_method_args(variant)?; - - // For discriminated unions, methods should return the main enum type - let (return_type, factory_body) = match representation { - reflectapi_schema::Representation::Internal { .. } - | reflectapi_schema::Representation::Adjacent { .. } - | reflectapi_schema::Representation::External => { - // For discriminated unions, return the main enum type and wrap the variant - let main_return_type = if is_generic { - format!("{enum_name}{generic_type_params}") - } else { - enum_name.to_string() - }; - let variant_type = if is_generic && !variant_class_name.contains('[') { - format!("{variant_class_name}{generic_type_params}") - } else { - variant_class_name.clone() - }; - let factory_body = - format!("return {enum_name}({variant_type}({method_args}))"); - (main_return_type, factory_body) - } - _ => { - // For other representations, return the variant type directly - let return_type = if is_generic && !variant_class_name.contains('[') { - format!("{variant_class_name}{generic_type_params}") - } else { - variant_class_name.clone() - }; - let factory_body = format!("return {return_type}({method_args})"); - (return_type, factory_body) - } - }; - - static_methods.push(format!( - r#" @staticmethod - def {}({}) -> {}: - '''Creates the '{}' variant of the {} enum.''' - {}"#, - method_name, - method_params, - return_type, - variant.name(), - enum_name, - factory_body - )); - } - } - } - - let enum_description = if enum_def.description().is_empty() { - format!("{enum_name} variants") - } else { - sanitize_description(enum_def.description()) - }; - - let mut factory_code = format!( - r#"class {factory_name}: - '''Factory class for creating {enum_name} variants with ergonomic syntax. - - {enum_description} - '''"# - ); - - if !class_attributes.is_empty() { - factory_code.push_str("\n\n"); - factory_code.push_str(&class_attributes.join("\n")); - } - - if !static_methods.is_empty() { - factory_code.push_str("\n\n"); - factory_code.push_str(&static_methods.join("\n\n")); - } - - Ok(factory_code) -} - -fn generate_internally_tagged_factory_class( - enum_def: &reflectapi_schema::Enum, - enum_name: &str, - union_variant_names: &[String], -) -> anyhow::Result { - use reflectapi_schema::Fields; - - let factory_name = format!("{enum_name}Factory"); - let mut class_attributes = Vec::new(); - let mut static_methods = Vec::new(); - - for (i, variant) in enum_def.variants.iter().enumerate() { - let variant_name = variant.name(); - let variant_class_name = &union_variant_names[i]; - - match &variant.fields { - Fields::None => { - // Unit variant - instantiate the variant class directly - // For internally tagged enums, unit variants are BaseModel classes - class_attributes.push(format!( - " {} = {}()", - variant_name.to_uppercase(), - variant_class_name - )); - } - Fields::Unnamed(_) | Fields::Named(_) => { - // Complex variant - create static method - let method_name = to_snake_case(variant_name); - let method_params = generate_factory_method_params(variant)?; - let method_args = generate_factory_method_args(variant)?; - - static_methods.push(format!( - r#" @staticmethod - def {method_name}({method_params}) -> {variant_class_name}: - '''Creates the '{variant_name}' variant of the {enum_name} enum.''' - return {variant_class_name}({method_args})"# - )); - } - } - } - - let enum_description = if enum_def.description().is_empty() { - format!("{enum_name} variants") - } else { - sanitize_description(enum_def.description()) - }; - - let mut factory_code = format!( - r#"class {factory_name}: - '''Factory class for creating {enum_name} variants with ergonomic syntax. - - {enum_description} - '''"# - ); - - if !class_attributes.is_empty() { - factory_code.push_str("\n\n"); - factory_code.push_str(&class_attributes.join("\n")); - } - - if !static_methods.is_empty() { - factory_code.push_str("\n\n"); - factory_code.push_str(&static_methods.join("\n\n")); - } - - Ok(factory_code) -} - -fn generate_externally_tagged_factory_class( - enum_def: &reflectapi_schema::Enum, - enum_name: &str, -) -> anyhow::Result { - use reflectapi_schema::Fields; - - let factory_name = format!("{enum_name}Factory"); - let class_attributes: Vec = Vec::new(); - let mut static_methods = Vec::new(); - - for variant in &enum_def.variants { - let variant_name = variant.name(); - - match &variant.fields { - Fields::None => { - // Skip unit variants for externally tagged enums - // They're already handled by the RootModel validator and instantiating - // them here can cause forward reference issues - // Users can create them with: EnumName("variant_name") - } - Fields::Unnamed(_) | Fields::Named(_) => { - // Complex variant - create static method that returns wrapped RootModel - let method_name = to_snake_case(variant_name); - let variant_class_name = - format!("{}{}Variant", enum_name, to_pascal_case(variant_name)); - let method_params = generate_factory_method_params(variant)?; - let method_args = generate_factory_method_args(variant)?; - - static_methods.push(format!( - " @staticmethod\n def {method_name}({method_params}) -> {enum_name}:\n \"\"\"Creates the '{variant_name}' variant of the {enum_name} enum.\"\"\"\n return {enum_name}({variant_class_name}({method_args}))" - )); - } - } - } - - let mut factory_code = format!( - "class {factory_name}:\n \"\"\"Factory class for creating {enum_name} variants with ergonomic syntax.\n\n {enum_name} variants\n \"\"\"" - ); - - if !class_attributes.is_empty() { - factory_code.push_str("\n\n"); - factory_code.push_str(&class_attributes.join("\n")); - } - - if !static_methods.is_empty() { - factory_code.push_str("\n\n"); - factory_code.push_str(&static_methods.join("\n\n")); - } - - Ok(factory_code) -} - -fn generate_factory_method_params(variant: &reflectapi_schema::Variant) -> anyhow::Result { - use reflectapi_schema::Fields; - - match &variant.fields { - Fields::None => Ok(String::new()), - Fields::Unnamed(unnamed_fields) => { - let params: Vec = unnamed_fields - .iter() - .enumerate() - .map(|(i, field)| { - let param_name = format!("field_{i}"); - if field.required { - param_name - } else { - format!("{param_name} = None") - } - }) - .collect(); - Ok(params.join(", ")) - } - Fields::Named(named_fields) => { - let mut params: Vec = Vec::new(); - - // Separate required and optional parameters for better ergonomics - let mut required_params: Vec = Vec::new(); - let mut optional_params: Vec = Vec::new(); - - for field in named_fields { - let param_name = to_snake_case(field.serde_name()); - if field.required { - required_params.push(param_name); - } else { - optional_params.push(format!("{param_name} = None")); - } - } - - // Put required parameters first, then optional ones - params.extend(required_params); - params.extend(optional_params); - - Ok(params.join(", ")) - } - } -} - -fn generate_factory_method_args(variant: &reflectapi_schema::Variant) -> anyhow::Result { - use reflectapi_schema::Fields; - - match &variant.fields { - Fields::None => Ok(String::new()), - Fields::Unnamed(unnamed_fields) => { - let args: Vec = (0..unnamed_fields.len()) - .map(|i| format!("field_{i}=field_{i}")) - .collect(); - Ok(args.join(", ")) - } - Fields::Named(named_fields) => { - let args: Vec = named_fields - .iter() - .map(|field| { - let serde_name = field.serde_name(); - let param_name = to_snake_case(serde_name); - let field_name = sanitize_field_name(field.name()); - format!("{field_name}={param_name}") - }) - .collect(); - Ok(args.join(", ")) - } - } -} - fn render_primitive_enum(enum_def: &reflectapi_schema::Enum) -> anyhow::Result { // Determine if this is an integer or float enum let is_float_enum = false; @@ -2466,12 +2492,10 @@ fn render_primitive_enum(enum_def: &reflectapi_schema::Enum) -> anyhow::Result>() - .join("\n") - } else { - String::new() - }; + // TypeVar definitions are emitted once at the top of the file; + // inline declarations are suppressed to avoid collisions with class names. // Generate individual classes for each variant for variant in &enum_def.variants { @@ -2623,8 +2639,10 @@ fn render_internally_tagged_enum_core( (false, None, field_type) }; - let (sanitized, alias) = - sanitize_field_name_with_alias(struct_field.name()); + let (sanitized, alias) = sanitize_field_name_with_alias( + struct_field.name(), + struct_field.serde_name(), + ); fields.push(templates::Field { name: sanitized, type_annotation: final_field_type, @@ -2688,7 +2706,8 @@ fn render_internally_tagged_enum_core( (false, None, field_type) }; - let (sanitized, alias) = sanitize_field_name_with_alias(field.name()); + let (sanitized, alias) = + sanitize_field_name_with_alias(field.name(), field.serde_name()); fields.push(templates::Field { name: sanitized, type_annotation: final_field_type, @@ -2715,11 +2734,7 @@ fn render_internally_tagged_enum_core( generic_params: generic_params.clone(), }; - variant_class_definitions.push( - variant_template - .render() - .context("Failed to render variant class")?, - ); + variant_class_definitions.push(variant_template.render()); } // Generate the discriminated union @@ -2749,17 +2764,11 @@ fn render_internally_tagged_enum_core( generic_params: generic_params.clone(), }; - let union_definition = union_template.render().context("Failed to render union")?; + let union_definition = union_template.render(); // Combine all parts let mut result = String::new(); - // Add TypeVar definitions at the top if generic - if !type_var_definitions.is_empty() { - result.push_str(&type_var_definitions); - result.push_str("\n\n"); - } - // Add variant classes result.push_str(&variant_class_definitions.join("\n\n")); if !result.is_empty() { @@ -2796,9 +2805,6 @@ fn render_internally_tagged_enum_core( } } - // Don't generate factory inline - it will be generated after model rebuild - // to avoid forward reference issues - Ok((result, union_variant_names)) } @@ -2858,7 +2864,8 @@ fn render_untagged_enum( (false, None, field_type) }; - let (sanitized, alias) = sanitize_field_name_with_alias(field.name()); + let (sanitized, alias) = + sanitize_field_name_with_alias(field.name(), field.serde_name()); fields.push(templates::Field { name: sanitized, type_annotation: final_field_type, @@ -2925,11 +2932,7 @@ fn render_untagged_enum( generic_params: vec![], }; - variant_classes.push( - variant_template - .render() - .context("Failed to render untagged variant class")?, - ); + variant_classes.push(variant_template.render()); union_variants.push(templates::UnionVariant { name: variant.name().to_string(), type_annotation: variant_class_name.clone(), @@ -2944,9 +2947,7 @@ fn render_untagged_enum( description: Some(enum_def.description().to_string()), variants: union_variants, }; - let union_definition = union_template - .render() - .context("Failed to render untagged union")?; + let union_definition = union_template.render(); // Combine all parts let mut result = variant_classes.join("\n\n"); @@ -2955,7 +2956,7 @@ fn render_untagged_enum( } result.push_str(&union_definition); - // Untagged enums don't use factory classes - variants serialize directly to their values + // Untagged enums - variants serialize directly to their values Ok(result) } @@ -3285,12 +3286,18 @@ fn to_pascal_case(s: &str) -> String { .collect() } -/// Improve Python class names to be more readable and Pythonic +/// Produce a unique flat Python class name from a potentially-qualified Rust +/// type name. +/// +/// For qualified names (containing `::`), ALL segments are joined into a +/// single PascalCase identifier to guarantee uniqueness across namespaces. +/// For example: `"reflectapi_demo::tests::serde::Offer"` → `"ReflectapiDemoTestsSerdeOffer"`. +/// +/// For type *references* (in annotations), use [`type_name_to_python_ref`] +/// instead, which produces a dotted path like `reflectapi_demo.tests.serde.Offer`. fn improve_class_name(original_name: &str) -> String { - // Handle Rust module paths with :: (e.g., "nomatches::IfConflictOnInsert" -> "NomatchesIfConflictOnInsert") + // Handle Rust module paths with :: if original_name.contains("::") { - // Convert Rust-style module paths to PascalCase - // e.g., "nomatches::IfConflictOnInsertRequired" -> "NomatchesIfConflictOnInsertRequired" let parts: Vec<&str> = original_name.split("::").collect(); return parts .iter() @@ -3301,15 +3308,35 @@ fn improve_class_name(original_name: &str) -> String { // Handle dotted namespaces (e.g., "myapi.model.Pet" -> "Pet") if original_name.contains('.') { - let parts: Vec<&str> = original_name.split('.').collect(); - if let Some(last_part) = parts.last() { - return improve_class_name_part(last_part); + if let Some(pos) = original_name.rfind('.') { + return improve_class_name_part(&original_name[pos + 1..]); } } improve_class_name_part(original_name) } +/// Convert a fully-qualified Rust type name to a dotted Python reference. +/// +/// Each `::` segment becomes a dot-separated component. Namespace segments +/// keep their original casing (typically snake_case), while the final leaf +/// segment is run through `improve_class_name_part` (PascalCase). +/// +/// Example: `"reflectapi_demo::tests::serde::Offer"` → `"reflectapi_demo.tests.serde.Offer"` +fn type_name_to_python_ref(original_name: &str) -> String { + let parts: Vec<&str> = original_name.split("::").collect(); + if parts.len() <= 1 { + // No namespace — just return the PascalCase leaf. + return improve_class_name(original_name); + } + // Namespace segments keep their original casing; the leaf gets PascalCase. + let namespace_parts = &parts[..parts.len() - 1]; + let leaf = parts.last().unwrap(); + let mut dotted_parts: Vec = namespace_parts.iter().map(|p| p.to_string()).collect(); + dotted_parts.push(improve_class_name_part(leaf)); + dotted_parts.join(".") +} + /// Improve a single part of a class name fn improve_class_name_part(name_part: &str) -> String { let pascal_name = to_pascal_case(name_part); @@ -3385,211 +3412,24 @@ fn to_screaming_snake_case(s: &str) -> String { to_snake_case(s).to_uppercase() } -/// Generate nested class structure for better Python ergonomics -fn generate_nested_class_structure( - rendered_types: &BTreeMap, - _schema: &Schema, -) -> String { - let mut nested_classes = Vec::new(); - let mut namespace_groups: BTreeMap> = BTreeMap::new(); - - // Group types by their namespace - for type_name in rendered_types.keys() { - if let Some(namespace) = extract_namespace_from_type_name(type_name) { - namespace_groups - .entry(namespace) - .or_default() - .push(type_name.clone()); - } - } - - // Special handling for Kind unions - try to associate them with their related Input/Output types - if let Some(unknown_kinds) = namespace_groups.remove("UnknownKind") { - for kind_type in unknown_kinds { - if kind_type == "MyapiModelKind" { - // Look for related Pet types - if namespace_groups.contains_key("Pet") { - namespace_groups.get_mut("Pet").unwrap().push(kind_type); - } - } - } - } - - // Generate nested classes for each namespace group - let mut namespace_pairs: Vec<_> = namespace_groups.into_iter().collect(); - namespace_pairs.sort_by(|a, b| a.0.cmp(&b.0)); // Sort by namespace name for deterministic output - for (namespace, type_names) in namespace_pairs { - if type_names.len() >= 2 { - // Only create nested classes if there are enough related types - let nested_class = generate_namespace_class(&namespace, &type_names, rendered_types); - if !nested_class.is_empty() { - nested_classes.push(nested_class); - } - } - } - - nested_classes.join("\n\n") -} - -/// Extract namespace from a type name (e.g., "MyapiModelInputPet" -> "Pet") -fn extract_namespace_from_type_name(type_name: &str) -> Option { - // Look for patterns like "MyapiModelXxxYyy" -> "Yyy" - if let Some(without_prefix) = type_name.strip_prefix("MyapiModel") { - // Look for common patterns - if let Some(stripped) = without_prefix.strip_prefix("Input") { - return Some(stripped.to_string()); // Remove "Input" - } else if let Some(stripped) = without_prefix.strip_prefix("Output") { - return Some(stripped.to_string()); // Remove "Output" - } else if let Some(remainder) = without_prefix.strip_prefix("Kind") { - if remainder.is_empty() { - // This is the main Kind union type like "MyapiModelKind" - assign to a generic namespace - // We need to infer which namespace this belongs to from the schema context - // For now, return a generic namespace that we can map later - return Some("UnknownKind".to_string()); - } else { - return Some(remainder.to_string()); // Return the variant name - } - } else { - return Some(without_prefix.to_string()); - } - } else if let Some(without_prefix) = type_name.strip_prefix("MyapiProto") { - // Extract base name from request/response patterns - if let Some(pos) = without_prefix.find("Request") { - return Some(without_prefix[..pos].to_string()); - } else if let Some(pos) = without_prefix.find("Response") { - return Some(without_prefix[..pos].to_string()); - } else if let Some(pos) = without_prefix.find("Error") { - return Some(without_prefix[..pos].to_string()); - } - } - - None -} - -/// Generate a namespace class containing related types -fn generate_namespace_class( - namespace: &str, - type_names: &[String], - _rendered_types: &BTreeMap, -) -> String { - let mut class_content = Vec::new(); - - // Find the main types for this namespace - let mut input_type = None; - let mut output_type = None; - let mut kind_variants = Vec::new(); - let mut request_types = Vec::new(); - let mut error_types = Vec::new(); - - for type_name in type_names { - if type_name.contains("Input") { - input_type = Some(type_name); - } else if type_name.contains("Output") { - output_type = Some(type_name); - } else if type_name.contains("Kind") { - // Include both individual variants (MyapiModelKindDog) and the union type (MyapiModelKind) - kind_variants.push(type_name); - } else if type_name.contains("Request") { - request_types.push(type_name); - } else if type_name.contains("Error") { - error_types.push(type_name); - } - } - - // Only generate if we have meaningful groupings - if input_type.is_some() || output_type.is_some() || !kind_variants.is_empty() { - class_content.push(format!("class {namespace}:")); - class_content.push(" \"\"\"Grouped types for better organization.\"\"\"".to_string()); - - // Add type aliases for the main types - if let Some(input) = input_type { - class_content.push(format!(" Input = {input}")); - } - if let Some(output) = output_type { - class_content.push(format!(" Output = {output}")); - } - - // Special handling for Kind types - check if there's a main union type we should expose - let main_kind_type = "MyapiModelKind".to_string(); - if kind_variants.contains(&(&main_kind_type)) { - class_content.push(" ".to_string()); - class_content.push(" class Kind:".to_string()); - class_content.push(" \"\"\"Kind variants for this type.\"\"\"".to_string()); - class_content.push(format!(" Union = {main_kind_type}")); - - // Also manually add the variants we know exist for common types - if namespace == "Pet" { - class_content.push(" Dog = MyapiModelKindDog".to_string()); - class_content.push(" Cat = MyapiModelKindCat".to_string()); - } - } - - // Add requests nested class if we have request types - if !request_types.is_empty() { - class_content.push(" ".to_string()); - class_content.push(" class Requests:".to_string()); - class_content.push(" \"\"\"Request types for this namespace.\"\"\"".to_string()); - - for request_name in &request_types { - if let Some(request_suffix) = extract_request_suffix(request_name) { - class_content.push(format!(" {request_suffix} = {request_name}")); - } - } - } - - // Add errors nested class if we have error types - if !error_types.is_empty() { - class_content.push(" ".to_string()); - class_content.push(" class Errors:".to_string()); - class_content.push(" \"\"\"Error types for this namespace.\"\"\"".to_string()); - - for error_name in &error_types { - if let Some(error_suffix) = extract_error_suffix(error_name) { - class_content.push(format!(" {error_suffix} = {error_name}")); - } - } - } - - return class_content.join("\n"); - } - - String::new() -} - -/// Extract meaningful suffix from request type name -fn extract_request_suffix(request_name: &str) -> Option { - if let Some(pos) = request_name.find("Request") { - let prefix = &request_name[..pos]; - if let Some(stripped) = prefix.strip_prefix("MyapiProto") { - return Some(stripped.to_string()); - } - } - None -} - -/// Extract meaningful suffix from error type name -fn extract_error_suffix(error_name: &str) -> Option { - if let Some(pos) = error_name.find("Error") { - let prefix = &error_name[..pos]; - if let Some(stripped) = prefix.strip_prefix("MyapiProto") { - return Some(stripped.to_string()); - } - } - None -} - -fn sanitize_field_name(s: &str) -> String { - to_valid_python_identifier(&to_snake_case(s)) -} +fn sanitize_field_name_with_alias(name: &str, serde_name: &str) -> (String, Option) { + let snake_case = to_snake_case(name); + let sanitized = safe_python_identifier(&snake_case); -fn sanitize_field_name_with_alias(s: &str) -> (String, Option) { - let snake_case = to_snake_case(s); - let sanitized = to_valid_python_identifier(&snake_case); + // Strip leading underscores - Pydantic v2 treats _-prefixed fields as private + let sanitized = sanitized.trim_start_matches('_').to_string(); + let sanitized = if sanitized.is_empty() { + // Edge case: name was all underscores + "field".to_string() + } else { + sanitized + }; - // If the sanitized name is different from the snake_case version, - // it means we had to modify it due to Python keywords/builtins - if sanitized != snake_case { - (sanitized, Some(snake_case)) + // The wire name (serde_name) is what goes over JSON. + // We need an alias whenever the Python field name differs from the wire name. + let wire_name = serde_name; + if sanitized != wire_name { + (sanitized, Some(wire_name.to_string())) } else { (sanitized, None) } @@ -3757,7 +3597,8 @@ fn type_ref_to_python_type( } } - let base_type = improve_class_name(&type_ref.name); + // Use dotted namespace path for type references (e.g. "mod::Sub::Ty" → "mod.Sub.Ty") + let base_type = type_name_to_python_ref(&type_ref.name); // Handle generic types with arguments - follow TypeScript pattern if !type_ref.arguments.is_empty() { @@ -4508,54 +4349,211 @@ fn sanitize_description(desc: &str) -> String { } pub mod templates { - use super::*; + use std::fmt::Write; + + use indexmap::IndexMap; + + /// A tree node representing a Python namespace. + /// + /// Types are always rendered at the module top-level (no nesting) to + /// avoid Python class-scope resolution issues. The namespace hierarchy + /// is then rendered as a separate set of namespace `class` wrappers + /// that contain type aliases pointing to the top-level definitions. + /// This allows dotted access like `reflectapi_demo.tests.serde.Offer` + /// while keeping all type definitions in the module globals where + /// Pydantic can resolve forward-reference annotation strings. + /// Entry in a Module's type list: the rendered code plus metadata + /// needed for namespace alias generation. + pub struct ModuleType { + /// The rendered Python source code for this type. + pub rendered: String, + } + + pub struct Module { + pub name: String, + pub types: Vec, + pub submodules: IndexMap, + } - #[derive(Template)] - #[template( - source = r#"''' -Generated Python client for {{ package_name }}. + impl Module { + fn is_empty(&self) -> bool { + self.types.is_empty() && self.submodules.values().all(|m| m.is_empty()) + } -DO NOT MODIFY THIS FILE MANUALLY. -This file is automatically generated by ReflectAPI. -''' + fn has_namespaces(&self) -> bool { + !self.submodules.is_empty() + } + + /// Render this module tree as Python source code. + /// + /// Produces two sections: + /// 1. All type definitions at module top-level (flat) + /// 2. Namespace class hierarchy with aliases for dotted access + pub fn render(&self) -> String { + let mut out = String::new(); + + // Part 1: Emit all types at the top level (flat). + self.collect_types_flat(&mut out); + + // Part 2: Emit namespace class hierarchy with aliases. + if self.has_namespaces() { + writeln!(out).unwrap(); + writeln!(out, "# Namespace classes for dotted access to types").unwrap(); + self.render_namespace_aliases(&mut out, 0); + } + + out + } + + /// Recursively collect all type definitions from the tree and emit + /// them at the top level (no indentation wrapping). + fn collect_types_flat(&self, out: &mut String) { + for mt in &self.types { + out.push_str(&mt.rendered); + out.push('\n'); + } + for sub in self.submodules.values() { + sub.collect_types_flat(out); + } + } + + /// Extract class and type-alias names defined in rendered type code. + /// + /// Looks for patterns like `class FooBar(` or `FooBarVariants = ` + /// at the start of lines. + fn extract_defined_names(type_code: &str) -> Vec { + let mut names = Vec::new(); + for line in type_code.lines() { + // Only match top-level definitions (no leading whitespace) + // to avoid leaking enum members or nested assignments + if line.starts_with(' ') || line.starts_with('\t') { + continue; + } + let trimmed = line.trim(); + if let Some(rest) = trimmed.strip_prefix("class ") { + if let Some(paren) = rest.find('(') { + let name = &rest[..paren]; + if !name.is_empty() { + names.push(name.to_string()); + } + } else if let Some(colon) = rest.find(':') { + let name = &rest[..colon]; + if !name.is_empty() { + names.push(name.to_string()); + } + } + } else if let Some(eq_pos) = trimmed.find(" = ") { + let name = &trimmed[..eq_pos]; + let value = trimmed[eq_pos + 3..].trim(); + // Only match PascalCase type aliases (not enum members, constants, + // or internal *Variants union aliases). + // Skip short names (1-2 chars) which are likely TypeVars, and + // also skip any assignment whose value contains `TypeVar`. + if name.chars().next().is_some_and(|c| c.is_ascii_uppercase()) + && !name.chars().all(|c| c.is_ascii_uppercase() || c == '_') + && !name.ends_with("Variants") + && name.len() > 2 + && !value.contains("TypeVar") + { + names.push(name.to_string()); + } + } + } + names + } + + /// Render namespace alias classes for dotted access. + /// + /// `ns_path` accumulates the namespace segments for computing the + /// flat name prefix that needs to be stripped. + fn render_namespace_aliases(&self, out: &mut String, indent_level: usize) { + self.render_namespace_aliases_inner(out, indent_level, &[]); + } + + fn render_namespace_aliases_inner( + &self, + out: &mut String, + indent_level: usize, + ns_path: &[&str], + ) { + for sub in self.submodules.values() { + if sub.is_empty() { + continue; + } + let indent = " ".repeat(indent_level * 4); + let inner_indent = " ".repeat((indent_level + 1) * 4); + + writeln!(out, "{indent}class {}:", sub.name).unwrap(); + writeln!( + out, + "{inner_indent}\"\"\"Namespace for {} types.\"\"\"", + sub.name + ) + .unwrap(); + + // Compute the flat PascalCase prefix for this namespace level. + // e.g., for path ["reflectapi_demo", "tests", "serde"], prefix = "ReflectapiDemoTestsSerde" + let mut full_path: Vec<&str> = ns_path.to_vec(); + full_path.push(&sub.name); + let flat_prefix: String = full_path + .iter() + .map(|seg| { + // PascalCase each segment (same logic as to_pascal_case) + seg.replace("::", "_") + .split('_') + .map(|word| { + let mut chars = word.chars(); + match chars.next() { + None => String::new(), + Some(first) => first.to_uppercase().chain(chars).collect(), + } + }) + .collect::>() + .join("") + }) + .collect::>() + .join(""); + + // Add aliases for ALL names defined in this module's type code. + // Strip the flat namespace prefix to produce leaf alias names. + for mt in &sub.types { + for flat_name in Self::extract_defined_names(&mt.rendered) { + let leaf = if flat_name.starts_with(&flat_prefix) { + &flat_name[flat_prefix.len()..] + } else { + &flat_name + }; + // Skip empty leaves (shouldn't happen, but be safe) + if !leaf.is_empty() { + writeln!(out, "{inner_indent}{leaf} = {flat_name}").unwrap(); + } + } + } + + // Recurse into submodules + if !sub.submodules.is_empty() { + writeln!(out).unwrap(); + sub.render_namespace_aliases_inner(out, indent_level + 1, &full_path); + } + + writeln!(out).unwrap(); + } + } + } -from __future__ import annotations -"#, - ext = "txt" - )] pub struct FileHeader { pub package_name: String, } - #[derive(Template)] - #[template( - source = r#" -# Standard library imports -{% if has_datetime %}from datetime import datetime{% if has_date %}, date{% endif %}{% if has_timedelta %}, timedelta{% endif %} -{% else if has_date %}from datetime import date{% if has_timedelta %}, timedelta{% endif %} -{% else if has_timedelta %}from datetime import timedelta -{% endif %}{% if has_enums %}from enum import Enum -{% endif %}from typing import Any, Optional, TypeVar, Generic, Union{% if has_annotated %}, Annotated{% endif %}{% if has_literal %}, Literal{% endif %} -{% if has_uuid %}from uuid import UUID -{% endif %}{% if has_warnings %}import warnings -{% endif %} - -# Third-party imports -from pydantic import BaseModel, ConfigDict, Field{% if has_externally_tagged_enums %}, RootModel, model_validator, model_serializer, PrivateAttr{% endif %} - -# Runtime imports -{% if has_async %}{% if has_sync %}from reflectapi_runtime import AsyncClientBase, ClientBase, ApiResponse{% else %}from reflectapi_runtime import AsyncClientBase, ApiResponse{% endif %}{% else %}{% if has_sync %}from reflectapi_runtime import ClientBase, ApiResponse{% endif %}{% endif %} -{% if has_reflectapi_option %}from reflectapi_runtime import ReflectapiOption -{% endif %}{% if has_reflectapi_empty %}from reflectapi_runtime import ReflectapiEmpty -{% endif %}{% if has_reflectapi_infallible %}from reflectapi_runtime import ReflectapiInfallible -{% endif %}{% if has_testing %}from reflectapi_runtime.testing import MockClient, create_api_response -{% endif %} - -{% for type_var in global_type_vars %}{{ type_var }} = TypeVar('{{ type_var }}') -{% endfor %} -"#, - ext = "txt" - )] + impl FileHeader { + pub fn render(&self) -> String { + format!( + "'''\nGenerated Python client for {}.\n\nDO NOT MODIFY THIS FILE MANUALLY.\nThis file is automatically generated by ReflectAPI.\n'''\n\nfrom __future__ import annotations\n", + self.package_name + ) + } + } + pub struct Imports { pub has_async: bool, pub has_sync: bool, @@ -4564,7 +4562,6 @@ from pydantic import BaseModel, ConfigDict, Field{% if has_externally_tagged_enu pub has_reflectapi_option: bool, pub has_reflectapi_empty: bool, pub has_reflectapi_infallible: bool, - pub has_flatten_support: bool, pub has_warnings: bool, pub has_datetime: bool, pub has_uuid: bool, @@ -4578,19 +4575,6 @@ from pydantic import BaseModel, ConfigDict, Field{% if has_externally_tagged_enu pub global_type_vars: Vec, } - #[derive(Template)] - #[template( - source = r#"class {{ name }}(BaseModel{% if is_generic %}, Generic[{% for param in generic_params %}{{ param }}{% if !loop.last %}, {% endif %}{% endfor %}]{% endif %}): -{% if description.is_some() && !description.as_deref().unwrap().is_empty() %} """{{ description.as_deref().unwrap() }}""" -{% else %} """Generated data model.""" -{% endif %} - model_config = ConfigDict(extra="ignore", populate_by_name=True) - -{% for field in fields %} {{ field.name }}: {{ field.type_annotation }}{% if field.alias.is_some() %} = Field{% if field.default_value.is_some() %}(default={{ field.default_value.as_ref().unwrap() }}, serialization_alias='{{ field.alias.as_deref().unwrap() }}', validation_alias='{{ field.alias.as_deref().unwrap() }}'){% else if field.optional %}(default=None, serialization_alias='{{ field.alias.as_deref().unwrap() }}', validation_alias='{{ field.alias.as_deref().unwrap() }}'){% else %}(serialization_alias='{{ field.alias.as_deref().unwrap() }}', validation_alias='{{ field.alias.as_deref().unwrap() }}'){% endif %}{% else %}{% if field.optional %} = None{% else if field.default_value.is_some() %} = {{ field.default_value.as_ref().unwrap() }}{% endif %}{% endif %} -{% endfor %} -"#, - ext = "txt" - )] pub struct DataClass { pub name: String, pub description: Option, @@ -4600,40 +4584,108 @@ from pydantic import BaseModel, ConfigDict, Field{% if has_externally_tagged_enu pub generic_params: Vec, } - #[derive(Template)] - #[template( - source = r#"class {{ name }}(str, Enum): -{% if description.is_some() && !description.as_deref().unwrap().is_empty() %} """{{ description.as_deref().unwrap() }}""" -{% else %} """Generated enum.""" -{% endif %} + impl DataClass { + pub fn render(&self) -> String { + let mut s = String::new(); + if self.is_generic { + let params = self.generic_params.join(", "); + writeln!(s, "class {}(BaseModel, Generic[{}]):", self.name, params).unwrap(); + } else { + writeln!(s, "class {}(BaseModel):", self.name).unwrap(); + } + if let Some(desc) = &self.description { + let desc = super::sanitize_for_docstring(desc); + if !desc.is_empty() { + writeln!(s, " \"\"\"{desc}\"\"\"").unwrap(); + } else { + writeln!(s, " \"\"\"Generated data model.\"\"\"").unwrap(); + } + } else { + writeln!(s, " \"\"\"Generated data model.\"\"\"").unwrap(); + } + writeln!(s).unwrap(); + writeln!( + s, + " model_config = ConfigDict(extra=\"ignore\", populate_by_name=True)" + ) + .unwrap(); + writeln!(s).unwrap(); + for field in &self.fields { + write!(s, " {}: {}", field.name, field.type_annotation).unwrap(); + + // Build Field() kwargs: description, alias, default + let desc = field + .description + .as_ref() + .filter(|d| !d.is_empty() && !d.starts_with("(flattened")) + .map(|d| super::sanitize_for_string_literal(d)); + let has_field_args = desc.is_some() + || field.alias.is_some() + || (field.optional && field.alias.is_none()); + + if has_field_args && (desc.is_some() || field.alias.is_some()) { + // Need Field() with named arguments + write!(s, " = Field(").unwrap(); + let mut args = Vec::new(); + if let Some(default) = &field.default_value { + args.push(format!("default={default}")); + } else if field.optional { + args.push("default=None".to_string()); + } + if let Some(alias) = &field.alias { + args.push(format!("serialization_alias='{alias}'")); + args.push(format!("validation_alias='{alias}'")); + } + if let Some(ref d) = desc { + args.push(format!("description=\"{d}\"")); + } + write!(s, "{}", args.join(", ")).unwrap(); + write!(s, ")").unwrap(); + } else if field.optional { + write!(s, " = None").unwrap(); + } else if let Some(default) = &field.default_value { + write!(s, " = {default}").unwrap(); + } + writeln!(s).unwrap(); + } + writeln!(s).unwrap(); + s + } + } -{% if variants.is_empty() %} pass -{% else %}{% for variant in variants %} {{ variant.name }} = "{{ variant.value }}" -{% endfor %}{% endif %} -"#, - ext = "txt" - )] pub struct EnumClass { pub name: String, pub description: Option, pub variants: Vec, } - #[derive(Template)] - #[template( - source = r#"{% if is_int_enum %}from enum import IntEnum{% else %}from enum import Enum{% endif %} - -class {{ name }}({% if is_int_enum %}IntEnum{% else %}Enum{% endif %}): -{% if description.is_some() %} """{{ description.as_deref().unwrap() }}""" + impl EnumClass { + pub fn render(&self) -> String { + let mut s = String::new(); + writeln!(s, "class {}(str, Enum):", self.name).unwrap(); + if let Some(desc) = &self.description { + let desc = super::sanitize_for_docstring(desc); + if !desc.is_empty() { + writeln!(s, " \"\"\"{desc}\"\"\"").unwrap(); + } else { + writeln!(s, " \"\"\"Generated enum.\"\"\"").unwrap(); + } + } else { + writeln!(s, " \"\"\"Generated enum.\"\"\"").unwrap(); + } + writeln!(s).unwrap(); + if self.variants.is_empty() { + writeln!(s, " pass").unwrap(); + } else { + for variant in &self.variants { + writeln!(s, " {} = \"{}\"", variant.name, variant.value).unwrap(); + } + } + writeln!(s).unwrap(); + s + } + } -{% endif %}{% for variant in variants %} - {{ variant.name }} = {{ variant.value }} -{% if variant.description.is_some() %} """{{ variant.description.as_deref().unwrap() }}""" -{% endif %} -{% endfor %} -"#, - ext = "txt" - )] pub struct PrimitiveEnumClass { pub name: String, pub description: Option, @@ -4641,32 +4693,36 @@ class {{ name }}({% if is_int_enum %}IntEnum{% else %}Enum{% endif %}): pub is_int_enum: bool, } - #[derive(Template)] - #[template( - source = r#"{% if is_generic %} -class {{ name }}(Generic[{% for param in generic_params %}{{ param }}{% if !loop.last %}, {% endif %}{% endfor %}]): - """{{ description.as_deref().unwrap_or("Generated discriminated union type.") }}""" - - @classmethod - def __class_getitem__(cls, params): - """Enable subscripting for generic discriminated union.""" - if not isinstance(params, tuple): - params = (params,) - if len(params) != {{ generic_params.len() }}: - raise TypeError(f"Expected {{ generic_params.len() }} type parameters, got {len(params)}") - - return Annotated[ - Union[{% for variant in variants %}{{ variant.base_name }}[{% for param in generic_params %}params[{{ loop.index0 }}]{% if !loop.last %}, {% endif %}{% endfor %}]{% if !loop.last %}, {% endif %}{% endfor %}], - Field(discriminator='{{ discriminator_field }}') - ] -{% else %} -class {{ name }}(RootModel): - root: Annotated[Union[{% for variant in variants %}{{ variant.type_annotation }}{% if !loop.last %}, {% endif %}{% endfor %}], Field(discriminator='{{ discriminator_field }}')] -{% endif %} -{% if description.is_some() && !description.as_deref().unwrap_or("").is_empty() && !is_generic %}"""{{ description.as_deref().unwrap() }}"""{% endif %} -"#, - ext = "txt" - )] + impl PrimitiveEnumClass { + pub fn render(&self) -> String { + let mut s = String::new(); + if self.is_int_enum { + writeln!(s, "from enum import IntEnum").unwrap(); + } else { + writeln!(s, "from enum import Enum").unwrap(); + } + writeln!(s).unwrap(); + let base = if self.is_int_enum { "IntEnum" } else { "Enum" }; + writeln!(s, "class {}({}):", self.name, base).unwrap(); + if let Some(desc) = &self.description { + let desc = super::sanitize_for_docstring(desc); + writeln!(s, " \"\"\"{desc}\"\"\"").unwrap(); + writeln!(s).unwrap(); + } + for variant in &self.variants { + writeln!(s).unwrap(); + writeln!(s, " {} = {}", variant.name, variant.value).unwrap(); + if let Some(desc) = &variant.description { + let desc = super::sanitize_for_docstring(desc); + writeln!(s, " \"\"\"{desc}\"\"\"").unwrap(); + } + writeln!(s).unwrap(); + } + writeln!(s).unwrap(); + s + } + } + pub struct UnionClass { pub name: String, pub description: Option, @@ -4676,333 +4732,118 @@ class {{ name }}(RootModel): pub generic_params: Vec, } - #[derive(Template)] - #[template( - source = r#"{{ name }} = Union[{% for variant in variants %}{{ variant.type_annotation }}{% if !loop.last %}, {% endif %}{% endfor %}] -{% if description.is_some() && !description.as_deref().unwrap_or("").is_empty() %}"""{{ description.as_deref().unwrap() }}"""{% endif %} -"#, - ext = "txt" - )] + impl UnionClass { + pub fn render(&self) -> String { + let mut s = String::new(); + if self.is_generic { + let params = self.generic_params.join(", "); + writeln!(s).unwrap(); + writeln!(s, "class {}(Generic[{}]):", self.name, params).unwrap(); + let desc = super::sanitize_for_docstring( + self.description + .as_deref() + .unwrap_or("Generated discriminated union type."), + ); + writeln!(s, " \"\"\"{desc}\"\"\"").unwrap(); + writeln!(s).unwrap(); + writeln!(s, " @classmethod").unwrap(); + writeln!(s, " def __class_getitem__(cls, params):").unwrap(); + writeln!( + s, + " \"\"\"Enable subscripting for generic discriminated union.\"\"\"" + ) + .unwrap(); + writeln!(s, " if not isinstance(params, tuple):").unwrap(); + writeln!(s, " params = (params,)").unwrap(); + writeln!( + s, + " if len(params) != {}:", + self.generic_params.len() + ) + .unwrap(); + writeln!( + s, + " raise TypeError(f\"Expected {} type parameters, got {{len(params)}}\")", + self.generic_params.len() + ) + .unwrap(); + writeln!(s).unwrap(); + // Build the Union expression + let variant_exprs: Vec = self + .variants + .iter() + .map(|v| { + let param_exprs: Vec = (0..self.generic_params.len()) + .map(|i| format!("params[{i}]")) + .collect(); + format!("{}[{}]", v.base_name, param_exprs.join(", ")) + }) + .collect(); + writeln!(s, " return Annotated[").unwrap(); + writeln!(s, " Union[{}],", variant_exprs.join(", ")).unwrap(); + writeln!( + s, + " Field(discriminator='{}')", + self.discriminator_field + ) + .unwrap(); + writeln!(s, " ]").unwrap(); + } else { + writeln!(s).unwrap(); + writeln!(s, "class {}(RootModel):", self.name).unwrap(); + let type_annotations: Vec<&str> = self + .variants + .iter() + .map(|v| v.type_annotation.as_str()) + .collect(); + writeln!( + s, + " root: Annotated[Union[{}], Field(discriminator='{}')]", + type_annotations.join(", "), + self.discriminator_field + ) + .unwrap(); + } + writeln!(s).unwrap(); + if !self.is_generic { + if let Some(desc) = &self.description { + let desc = super::sanitize_for_docstring(desc); + if !desc.is_empty() { + writeln!(s, "\"\"\"{desc}\"\"\"").unwrap(); + } + } + } + writeln!(s).unwrap(); + s + } + } + pub struct UntaggedUnionClass { pub name: String, pub description: Option, pub variants: Vec, } - #[derive(Template)] - #[template( - source = r#"{% if generate_async %} -{% for group in function_groups %} -class Async{{ group.class_name }}: - """Async client for {{ group.name }} operations.""" - - def __init__(self, client: AsyncClientBase) -> None: - self._client = client -{% for function in group.functions %} - - async def {{ function.name }}( - self, -{%- for param in function.path_params %} - {{ param.name }}: {{ param.type_annotation }}, -{%- endfor %} -{%- if function.has_body %} - data: Optional[{{ function.input_type }}] = None, -{%- endif %} -{%- if function.headers_type.is_some() %} - headers: Optional[{{ function.headers_type.as_deref().unwrap() }}] = None, -{%- endif %} - ) -> ApiResponse[{{ function.output_type }}]: - """{{ function.description.as_deref().unwrap_or("") }}{% if function.has_body || !function.path_params.is_empty() %} - - Args:{% if function.has_body %} - data: Request data for the {{ function.name }} operation.{% endif %}{% if !function.path_params.is_empty() %} -{% for param in function.path_params %} {{ param.name }}: {{ param.description.as_deref().unwrap_or("Path parameter") }} -{% endfor %}{% endif %}{% endif %} - - Returns: - ApiResponse[{{ function.output_type }}]: Response containing {{ function.output_type }} data{% if function.deprecation_note.is_some() %} - - .. deprecated:: - {{ function.deprecation_note.as_deref().unwrap() }}{% endif %} - """ - {% if function.deprecation_note.is_some() %} - warnings.warn( - "{% if function.original_name.is_some() %}{{ function.original_name.as_deref().unwrap() }}{% else %}{{ function.name }}{% endif %} is deprecated{% if !function.deprecation_note.as_deref().unwrap().is_empty() %}: {{ function.deprecation_note.as_deref().unwrap() }}{% endif %}", - DeprecationWarning, - stacklevel=2, - ) - - {% endif -%} - path = "{{ function.path }}" -{% if !function.path_params.is_empty() %} - # Format path parameters using safer string formatting - path_params = { -{% for param in function.path_params %} - "{{ param.raw_name }}": str({{ param.name }}), -{% endfor %} - } - for param_name, param_value in path_params.items(): - path = path.replace("{" + param_name + "}", param_value) -{% endif %} - params: dict[str, Any] = {} - return await self._client._make_request( - "{{ function.method }}", - path, - params=params if params else None, -{% if function.has_body -%} -{% if function.is_input_primitive %} json_data=data, -{% else %} json_model=data, -{% endif -%} -{% endif -%} -{% if function.headers_type.is_some() %} headers_model=headers, -{% endif -%} -{% if function.output_type == "Any" %} response_model=None, -{% else %} response_model={{ function.output_type }}, -{% endif -%} - ) - -{% endfor %} - -{% endfor %} -class {{ async_class_name }}(AsyncClientBase): - """Async client for the API.""" - - def __init__( - self, - base_url: str{% if base_url.is_some() %} = "{{ base_url.as_ref().unwrap() }}"{% endif %}, - **kwargs: Any, - ) -> None: - super().__init__(base_url, **kwargs) -{% for group in function_groups %} - self.{{ group.name }} = Async{{ group.class_name }}(self) -{% endfor %} - -{% for function in top_level_functions %} - async def {{ function.name }}( - self, -{%- for param in function.path_params %} - {{ param.name }}: {{ param.type_annotation }}, -{%- endfor %} -{%- if function.has_body %} - data: Optional[{{ function.input_type }}] = None, -{%- endif %} -{%- if function.headers_type.is_some() %} - headers: Optional[{{ function.headers_type.as_deref().unwrap() }}] = None, -{%- endif %} - ) -> ApiResponse[{{ function.output_type }}]: - """{{ function.description.as_deref().unwrap_or("") }}{% if function.has_body %} - - Args: - data: Request data for the {{ function.name }} operation.{% endif %}{% if !function.path_params.is_empty() %} -{% for param in function.path_params %} {{ param.name }}: {{ param.description.as_deref().unwrap_or("Path parameter") }} -{% endfor %}{% endif %} - - Returns: - ApiResponse[{{ function.output_type }}]: Response containing {{ function.output_type }} data{% if function.deprecation_note.is_some() %} - - .. deprecated:: - {{ function.deprecation_note.as_deref().unwrap() }}{% endif %} - """ - {% if function.deprecation_note.is_some() %} - warnings.warn( - "{{ function.name }} is deprecated{% if !function.deprecation_note.as_deref().unwrap().is_empty() %}: {{ function.deprecation_note.as_deref().unwrap() }}{% endif %}", - DeprecationWarning, - stacklevel=2, - ) - - {% endif -%} - path = "{{ function.path }}" -{% if !function.path_params.is_empty() %} - # Format path parameters using safer string formatting - path_params = { -{% for param in function.path_params %} - "{{ param.name }}": str({{ param.name }}), -{% endfor %} - } - for param_name, param_value in path_params.items(): - path = path.replace("{" + param_name + "}", param_value) -{% endif %} - params: dict[str, Any] = {} - return await self._make_request( - "{{ function.method }}", - path, - params=params if params else None, -{% if function.has_body -%} -{% if function.is_input_primitive %} json_data=data, -{% else %} json_model=data, -{% endif -%} -{% endif -%} -{% if function.headers_type.is_some() %} headers_model=headers, -{% endif -%} -{% if function.output_type == "Any" %} response_model=None, -{% else %} response_model={{ function.output_type }}, -{% endif -%} - ) - -{% endfor %} - -{% endif %} - -{% if generate_sync %} -{% for group in function_groups %} -class {{ group.class_name }}: - """Synchronous client for {{ group.name }} operations.""" - - def __init__(self, client: ClientBase) -> None: - self._client = client -{% for function in group.functions %} - - def {{ function.name }}( - self, -{%- for param in function.path_params %} - {{ param.name }}: {{ param.type_annotation }}, -{%- endfor %} -{%- if function.has_body %} - data: Optional[{{ function.input_type }}] = None, -{%- endif %} -{%- if function.headers_type.is_some() %} - headers: Optional[{{ function.headers_type.as_deref().unwrap() }}] = None, -{%- endif %} - ) -> ApiResponse[{{ function.output_type }}]: - """{{ function.description.as_deref().unwrap_or("") }}{% if function.has_body || !function.path_params.is_empty() %} - - Args:{% if function.has_body %} - data: Request data for the {{ function.name }} operation.{% endif %}{% if !function.path_params.is_empty() %} -{% for param in function.path_params %} {{ param.name }}: {{ param.description.as_deref().unwrap_or("Path parameter") }} -{% endfor %}{% endif %}{% endif %} - - Returns: - ApiResponse[{{ function.output_type }}]: Response containing {{ function.output_type }} data{% if function.deprecation_note.is_some() %} - - .. deprecated:: - {{ function.deprecation_note.as_deref().unwrap() }}{% endif %} - """ - {% if function.deprecation_note.is_some() %} - warnings.warn( - "{% if function.original_name.is_some() %}{{ function.original_name.as_deref().unwrap() }}{% else %}{{ function.name }}{% endif %} is deprecated{% if !function.deprecation_note.as_deref().unwrap().is_empty() %}: {{ function.deprecation_note.as_deref().unwrap() }}{% endif %}", - DeprecationWarning, - stacklevel=2, - ) - - {% endif -%} - path = "{{ function.path }}" -{% if !function.path_params.is_empty() %} - # Format path parameters using safer string formatting - path_params = { -{% for param in function.path_params %} - "{{ param.raw_name }}": str({{ param.name }}), -{% endfor %} - } - for param_name, param_value in path_params.items(): - path = path.replace("{" + param_name + "}", param_value) -{% endif %} - params: dict[str, Any] = {} - return self._client._make_request( - "{{ function.method }}", - path, - params=params if params else None, -{% if function.has_body -%} -{% if function.is_input_primitive %} json_data=data, -{% else %} json_model=data, -{% endif -%} -{% endif -%} -{% if function.headers_type.is_some() %} headers_model=headers, -{% endif -%} -{% if function.output_type == "Any" %} response_model=None, -{% else %} response_model={{ function.output_type }}, -{% endif -%} - ) - -{% endfor %} - -{% endfor %} -class {{ class_name }}(ClientBase): - """Synchronous client for the API.""" - - def __init__( - self, - base_url: str{% if base_url.is_some() %} = "{{ base_url.as_ref().unwrap() }}"{% endif %}, - **kwargs: Any, - ) -> None: - super().__init__(base_url, **kwargs) -{% for group in function_groups %} - self.{{ group.name }} = {{ group.class_name }}(self) -{% endfor %} - -{% for function in top_level_functions %} - def {{ function.name }}( - self, -{%- for param in function.path_params %} - {{ param.name }}: {{ param.type_annotation }}, -{%- endfor %} -{%- if function.has_body %} - data: Optional[{{ function.input_type }}] = None, -{%- endif %} -{%- if function.headers_type.is_some() %} - headers: Optional[{{ function.headers_type.as_deref().unwrap() }}] = None, -{%- endif %} - ) -> ApiResponse[{{ function.output_type }}]: - """{{ function.description.as_deref().unwrap_or("") }}{% if function.has_body %} - - Args: - data: Request data for the {{ function.name }} operation.{% endif %}{% if !function.path_params.is_empty() %} -{% for param in function.path_params %} {{ param.name }}: {{ param.description.as_deref().unwrap_or("Path parameter") }} -{% endfor %}{% endif %} - - Returns: - ApiResponse[{{ function.output_type }}]: Response containing {{ function.output_type }} data{% if function.deprecation_note.is_some() %} - - .. deprecated:: - {{ function.deprecation_note.as_deref().unwrap() }}{% endif %} - """ - {% if function.deprecation_note.is_some() %} - warnings.warn( - "{{ function.name }} is deprecated{% if !function.deprecation_note.as_deref().unwrap().is_empty() %}: {{ function.deprecation_note.as_deref().unwrap() }}{% endif %}", - DeprecationWarning, - stacklevel=2, - ) - {% endif %} - path = "{{ function.path }}" -{% if !function.path_params.is_empty() %} - # Format path parameters using safer string formatting - path_params = { -{% for param in function.path_params %} - "{{ param.name }}": str({{ param.name }}), -{% endfor %} - } - for param_name, param_value in path_params.items(): - path = path.replace("{" + param_name + "}", param_value) -{% endif %} - - params: dict[str, Any] = {} - - return await self._make_request( - "{{ function.method }}", - path, - params=params if params else None, -{% if function.has_body %} -{% if function.is_input_primitive %} - json_data=data, -{% else %} - json_model=data, -{% endif %} -{% endif %} -{% if function.headers_type.is_some() %} - headers_model=headers, -{% endif %} -{% if function.output_type == "Any" %} - response_model=None, -{% else %} - response_model={{ function.output_type }}, -{% endif %} - ) - -{% endfor %} + impl UntaggedUnionClass { + pub fn render(&self) -> String { + let mut s = String::new(); + let type_annotations: Vec<&str> = self + .variants + .iter() + .map(|v| v.type_annotation.as_str()) + .collect(); + writeln!(s, "{} = Union[{}]", self.name, type_annotations.join(", ")).unwrap(); + if let Some(desc) = &self.description { + let desc = super::sanitize_for_docstring(desc); + if !desc.is_empty() { + writeln!(s, "\"\"\"{desc}\"\"\"").unwrap(); + } + } + writeln!(s).unwrap(); + s + } + } -{% endif %} -"#, - ext = "txt" - )] pub struct ClientClass { pub class_name: String, pub async_class_name: String, @@ -5013,27 +4854,337 @@ class {{ class_name }}(ClientBase): pub base_url: Option, } - #[derive(Template)] - #[template( - source = r#"# Testing utilities + impl ClientClass { + pub fn render(&self) -> String { + let mut s = String::new(); -{% for type_name in types %} -def create_{{ type_name.to_lowercase() }}_response(value: {{ type_name }}) -> ApiResponse[{{ type_name }}]: - """Create a mock ApiResponse for {{ type_name }}.""" - return create_api_response(value) + if self.generate_async { + // Async group classes + for group in &self.function_groups { + writeln!(s).unwrap(); + writeln!(s, "class Async{}:", group.class_name).unwrap(); + writeln!( + s, + " \"\"\"Async client for {} operations.\"\"\"", + group.name + ) + .unwrap(); + writeln!(s).unwrap(); + writeln!( + s, + " def __init__(self, client: AsyncClientBase) -> None:" + ) + .unwrap(); + writeln!(s, " self._client = client").unwrap(); -{% endfor %} + for function in &group.functions { + Self::write_function(&mut s, function, true, true, true); + } + writeln!(s).unwrap(); + } + + // Async client class + writeln!(s).unwrap(); + writeln!(s, "class {}(AsyncClientBase):", self.async_class_name).unwrap(); + writeln!(s, " \"\"\"Async client for the API.\"\"\"").unwrap(); + writeln!(s).unwrap(); + writeln!(s, " def __init__(").unwrap(); + writeln!(s, " self,").unwrap(); + if let Some(base_url) = &self.base_url { + writeln!(s, " base_url: str = \"{base_url}\",").unwrap(); + } else { + writeln!(s, " base_url: str,").unwrap(); + } + writeln!(s, " **kwargs: Any,").unwrap(); + writeln!(s, " ) -> None:").unwrap(); + writeln!(s, " super().__init__(base_url, **kwargs)").unwrap(); + writeln!(s).unwrap(); + for group in &self.function_groups { + writeln!(s).unwrap(); + writeln!( + s, + " self.{} = Async{}(self)", + group.name, group.class_name + ) + .unwrap(); + } + writeln!(s).unwrap(); + + for function in &self.top_level_functions { + Self::write_function(&mut s, function, true, false, true); + } + writeln!(s).unwrap(); + } + + writeln!(s).unwrap(); + + if self.generate_sync { + // Sync group classes + for group in &self.function_groups { + writeln!(s).unwrap(); + writeln!(s, "class {}:", group.class_name).unwrap(); + writeln!( + s, + " \"\"\"Synchronous client for {} operations.\"\"\"", + group.name + ) + .unwrap(); + writeln!(s).unwrap(); + writeln!(s, " def __init__(self, client: ClientBase) -> None:").unwrap(); + writeln!(s, " self._client = client").unwrap(); + + for function in &group.functions { + Self::write_function(&mut s, function, false, true, true); + } + writeln!(s).unwrap(); + } + + // Sync client class + writeln!(s).unwrap(); + writeln!(s, "class {}(ClientBase):", self.class_name).unwrap(); + writeln!(s, " \"\"\"Synchronous client for the API.\"\"\"").unwrap(); + writeln!(s).unwrap(); + writeln!(s, " def __init__(").unwrap(); + writeln!(s, " self,").unwrap(); + if let Some(base_url) = &self.base_url { + writeln!(s, " base_url: str = \"{base_url}\",").unwrap(); + } else { + writeln!(s, " base_url: str,").unwrap(); + } + writeln!(s, " **kwargs: Any,").unwrap(); + writeln!(s, " ) -> None:").unwrap(); + writeln!(s, " super().__init__(base_url, **kwargs)").unwrap(); + writeln!(s).unwrap(); + for group in &self.function_groups { + writeln!(s).unwrap(); + writeln!( + s, + " self.{} = {}(self)", + group.name, group.class_name + ) + .unwrap(); + } + writeln!(s).unwrap(); + + for function in &self.top_level_functions { + Self::write_function(&mut s, function, false, false, false); + } + writeln!(s).unwrap(); + } + + writeln!(s).unwrap(); + s + } + + fn write_function( + s: &mut String, + function: &Function, + is_async: bool, + is_group: bool, + use_raw_name_for_path_params: bool, + ) { + writeln!(s).unwrap(); + // Method signature + if is_async { + writeln!(s, " async def {}(", function.name).unwrap(); + } else { + writeln!(s, " def {}(", function.name).unwrap(); + } + writeln!(s, " self,").unwrap(); + for param in &function.path_params { + writeln!(s, " {}: {},", param.name, param.type_annotation).unwrap(); + } + if function.has_body { + writeln!(s, " data: Optional[{}] = None,", function.input_type).unwrap(); + } + if let Some(headers_type) = &function.headers_type { + writeln!(s, " headers: Optional[{headers_type}] = None,").unwrap(); + } + if let Some(error_type) = &function.error_type { + writeln!( + s, + " ) -> ApiResponse[{}, {}]:", + function.output_type, error_type + ) + .unwrap(); + } else { + writeln!(s, " ) -> ApiResponse[{}]:", function.output_type).unwrap(); + } + + // Docstring + let desc = super::sanitize_for_docstring(function.description.as_deref().unwrap_or("")); + write!(s, " \"\"\"{desc}").unwrap(); + if function.has_body || !function.path_params.is_empty() { + writeln!(s).unwrap(); + writeln!(s).unwrap(); + writeln!(s, " Args:").unwrap(); + if function.has_body { + writeln!( + s, + " data: Request data for the {} operation.", + function.name + ) + .unwrap(); + } + for param in &function.path_params { + let param_desc = super::sanitize_for_docstring( + param.description.as_deref().unwrap_or("Path parameter"), + ); + writeln!(s, " {}: {}", param.name, param_desc).unwrap(); + } + writeln!(s).unwrap(); + } else { + writeln!(s).unwrap(); + writeln!(s).unwrap(); + } + writeln!(s, " Returns:").unwrap(); + if let Some(error_type) = &function.error_type { + writeln!( + s, + " ApiResponse[{}, {}]: Success={}, Error={}", + function.output_type, error_type, function.output_type, error_type + ) + .unwrap(); + } else { + writeln!( + s, + " ApiResponse[{}]: Response containing {} data", + function.output_type, function.output_type + ) + .unwrap(); + } + if let Some(dep_note) = &function.deprecation_note { + let dep_note = super::sanitize_for_docstring(dep_note); + writeln!(s).unwrap(); + writeln!(s, " .. deprecated::").unwrap(); + writeln!(s, " {dep_note}").unwrap(); + } + writeln!(s, " \"\"\"").unwrap(); + + // Deprecation warning + if let Some(dep_note) = &function.deprecation_note { + writeln!(s).unwrap(); + let warn_name = if is_group { + function.original_name.as_deref().unwrap_or(&function.name) + } else { + &function.name + }; + let warn_msg = if dep_note.is_empty() { + format!("{warn_name} is deprecated") + } else { + format!("{warn_name} is deprecated: {dep_note}") + }; + writeln!(s, " warnings.warn(").unwrap(); + writeln!(s, " \"{warn_msg}\",").unwrap(); + writeln!(s, " DeprecationWarning,").unwrap(); + writeln!(s, " stacklevel=2,").unwrap(); + writeln!(s, " )").unwrap(); + writeln!(s).unwrap(); + } + + // Path + writeln!(s, " path = \"{}\"", function.path).unwrap(); + + // Path parameters + if !function.path_params.is_empty() { + writeln!( + s, + " # Format path parameters using safer string formatting" + ) + .unwrap(); + writeln!(s, " path_params = {{").unwrap(); + for param in &function.path_params { + let key = if use_raw_name_for_path_params { + ¶m.raw_name + } else { + ¶m.name + }; + writeln!(s, " \"{}\": str({}),", key, param.name).unwrap(); + } + writeln!(s, " }}").unwrap(); + writeln!( + s, + " for param_name, param_value in path_params.items():" + ) + .unwrap(); + writeln!( + s, + " path = path.replace(\"{{\" + param_name + \"}}\", param_value)" + ) + .unwrap(); + } + writeln!(s).unwrap(); + + // Request call + writeln!(s, " params: dict[str, Any] = {{}}").unwrap(); + + let client_prefix = if is_group { "self._client." } else { "self." }; + if is_async { + writeln!(s, " return await {client_prefix}_make_request(").unwrap(); + } else { + writeln!(s, " return {client_prefix}_make_request(").unwrap(); + } + writeln!(s, " \"{}\",", function.method).unwrap(); + writeln!(s, " path,").unwrap(); + writeln!(s, " params=params if params else None,").unwrap(); + if function.has_body { + if function.is_input_primitive { + writeln!(s, " json_data=data,").unwrap(); + } else { + writeln!(s, " json_model=data,").unwrap(); + } + } + if function.headers_type.is_some() { + writeln!(s, " headers_model=headers,").unwrap(); + } + if function.output_type == "Any" { + writeln!(s, " response_model=None,").unwrap(); + } else { + writeln!(s, " response_model={},", function.output_type).unwrap(); + } + if let Some(error_type) = &function.error_type { + writeln!(s, " error_model={error_type},").unwrap(); + } + writeln!(s, " )").unwrap(); + writeln!(s).unwrap(); + } + } -def create_mock_client() -> MockClient: - """Create a mock client for testing.""" - return MockClient() -"#, - ext = "txt" - )] pub struct TestingModule { pub types: Vec, } + impl TestingModule { + pub fn render(&self) -> String { + let mut s = String::new(); + writeln!(s, "# Testing utilities").unwrap(); + writeln!(s).unwrap(); + for type_name in &self.types { + // Convert dotted type ref to a valid Python function name fragment + let func_suffix = type_name.replace('.', "_").to_lowercase(); + writeln!(s).unwrap(); + writeln!( + s, + "def create_{func_suffix}_response(value: {type_name}) -> ApiResponse[{type_name}]:", + ) + .unwrap(); + writeln!( + s, + " \"\"\"Create a mock ApiResponse for {type_name}.\"\"\"" + ) + .unwrap(); + writeln!(s, " return create_api_response(value)").unwrap(); + writeln!(s).unwrap(); + } + writeln!(s).unwrap(); + writeln!(s, "def create_mock_client() -> MockClient:").unwrap(); + writeln!(s, " \"\"\"Create a mock client for testing.\"\"\"").unwrap(); + writeln!(s, " return MockClient()").unwrap(); + s + } + } + + #[derive(Clone)] pub struct Field { pub name: String, pub type_annotation: String, @@ -5096,55 +5247,56 @@ def create_mock_client() -> MockClient: } // Templates for externally tagged enum variants - #[derive(Template)] - #[template( - source = r#"class {{ name }}(BaseModel): -{% if description.is_some() && !description.as_deref().unwrap().is_empty() %} """{{ description.as_deref().unwrap() }}""" -{% else %} """Unit variant for externally tagged enum.""" -{% endif %} - model_config = ConfigDict(extra="ignore") - - def model_dump(self, **kwargs): - """Serialize as just the variant name string for unit variants.""" - return "{{ variant_name }}" - - def model_dump_json(self, **kwargs): - """Serialize as JSON string for unit variants.""" - import json - return json.dumps(self.model_dump(**kwargs)) -"#, - ext = "txt" - )] pub struct UnitVariantClass { pub name: String, pub variant_name: String, pub description: Option, } - #[derive(Template)] - #[template( - source = r#"class {{ name }}(BaseModel): -{% if description.is_some() && !description.as_deref().unwrap().is_empty() %} """{{ description.as_deref().unwrap() }}""" -{% else %} """Tuple variant for externally tagged enum.""" -{% endif %} - - model_config = ConfigDict(extra="ignore") - -{% for field in fields %} {{ field.name }}: {{ field.type_annotation }}{% if field.default_value.is_some() %} = {{ field.default_value.as_ref().unwrap() }}{% else %}{% if field.optional %} = None{% endif %}{% endif %} -{% endfor %} - - def model_dump(self, **kwargs): - """Serialize as externally tagged tuple variant.""" - fields = [{% for field in fields %}self.{{ field.name }}{% if !loop.last %}, {% endif %}{% endfor %}] - return {"{{ variant_name }}": fields} + impl UnitVariantClass { + pub fn render(&self) -> String { + let mut s = String::new(); + writeln!(s, "class {}(BaseModel):", self.name).unwrap(); + if let Some(desc) = &self.description { + let desc = super::sanitize_for_docstring(desc); + if !desc.is_empty() { + writeln!(s, " \"\"\"{desc}\"\"\"").unwrap(); + } else { + writeln!( + s, + " \"\"\"Unit variant for externally tagged enum.\"\"\"" + ) + .unwrap(); + } + } else { + writeln!( + s, + " \"\"\"Unit variant for externally tagged enum.\"\"\"" + ) + .unwrap(); + } + writeln!(s, " model_config = ConfigDict(extra=\"ignore\")").unwrap(); + writeln!(s).unwrap(); + writeln!(s, " def model_dump(self, **kwargs):").unwrap(); + writeln!( + s, + " \"\"\"Serialize as just the variant name string for unit variants.\"\"\"" + ) + .unwrap(); + writeln!(s, " return \"{}\"", self.variant_name).unwrap(); + writeln!(s).unwrap(); + writeln!(s, " def model_dump_json(self, **kwargs):").unwrap(); + writeln!( + s, + " \"\"\"Serialize as JSON string for unit variants.\"\"\"" + ) + .unwrap(); + writeln!(s, " import json").unwrap(); + writeln!(s, " return json.dumps(self.model_dump(**kwargs))").unwrap(); + s + } + } - def model_dump_json(self, **kwargs): - """Serialize as JSON for externally tagged tuple variant.""" - import json - return json.dumps(self.model_dump(**kwargs)) -"#, - ext = "txt" - )] pub struct TupleVariantClass { pub name: String, pub variant_name: String, @@ -5152,32 +5304,67 @@ def create_mock_client() -> MockClient: pub description: Option, } - #[derive(Template)] - #[template( - source = r#"class {{ name }}(BaseModel): -{% if description.is_some() && !description.as_deref().unwrap().is_empty() %} """{{ description.as_deref().unwrap() }}""" -{% else %} """Struct variant for externally tagged enum.""" -{% endif %} - model_config = ConfigDict(extra="ignore") - -{% for field in fields %} {{ field.name }}: {{ field.type_annotation }}{% if field.default_value.is_some() %} = {{ field.default_value.as_ref().unwrap() }}{% else %}{% if field.optional %} = None{% endif %}{% endif %} -{% endfor %} - - def model_dump(self, **kwargs): - """Serialize as externally tagged struct variant.""" - fields = {} -{% for field in fields %} if hasattr(self, '{{ field.name }}') and self.{{ field.name }} is not None: - fields['{{ field.name }}'] = self.{{ field.name }} -{% endfor %} - return {"{{ variant_name }}": fields} - - def model_dump_json(self, **kwargs): - """Serialize as JSON for externally tagged struct variant.""" - import json - return json.dumps(self.model_dump(**kwargs)) -"#, - ext = "txt" - )] + impl TupleVariantClass { + pub fn render(&self) -> String { + let mut s = String::new(); + writeln!(s, "class {}(BaseModel):", self.name).unwrap(); + if let Some(desc) = &self.description { + let desc = super::sanitize_for_docstring(desc); + if !desc.is_empty() { + writeln!(s, " \"\"\"{desc}\"\"\"").unwrap(); + } else { + writeln!( + s, + " \"\"\"Tuple variant for externally tagged enum.\"\"\"" + ) + .unwrap(); + } + } else { + writeln!( + s, + " \"\"\"Tuple variant for externally tagged enum.\"\"\"" + ) + .unwrap(); + } + writeln!(s).unwrap(); + writeln!(s, " model_config = ConfigDict(extra=\"ignore\")").unwrap(); + writeln!(s).unwrap(); + for field in &self.fields { + write!(s, " {}: {}", field.name, field.type_annotation).unwrap(); + if let Some(default) = &field.default_value { + write!(s, " = {default}").unwrap(); + } else if field.optional { + write!(s, " = None").unwrap(); + } + writeln!(s).unwrap(); + } + writeln!(s).unwrap(); + writeln!(s, " def model_dump(self, **kwargs):").unwrap(); + writeln!( + s, + " \"\"\"Serialize as externally tagged tuple variant.\"\"\"" + ) + .unwrap(); + let field_refs: Vec = self + .fields + .iter() + .map(|f| format!("self.{}", f.name)) + .collect(); + writeln!(s, " fields = [{}]", field_refs.join(", ")).unwrap(); + writeln!(s, " return {{\"{}\": fields}}", self.variant_name).unwrap(); + writeln!(s).unwrap(); + writeln!(s, " def model_dump_json(self, **kwargs):").unwrap(); + writeln!( + s, + " \"\"\"Serialize as JSON for externally tagged tuple variant.\"\"\"" + ) + .unwrap(); + writeln!(s, " import json").unwrap(); + writeln!(s, " return json.dumps(self.model_dump(**kwargs))").unwrap(); + s + } + } + pub struct StructVariantClass { pub name: String, pub variant_name: String, @@ -5185,15 +5372,75 @@ def create_mock_client() -> MockClient: pub description: Option, } - #[derive(Template)] - #[template( - source = r#"{% for variant_def in variant_definitions %}{{ variant_def }} + impl StructVariantClass { + pub fn render(&self) -> String { + let mut s = String::new(); + writeln!(s, "class {}(BaseModel):", self.name).unwrap(); + if let Some(desc) = &self.description { + let desc = super::sanitize_for_docstring(desc); + if !desc.is_empty() { + writeln!(s, " \"\"\"{desc}\"\"\"").unwrap(); + } else { + writeln!( + s, + " \"\"\"Struct variant for externally tagged enum.\"\"\"" + ) + .unwrap(); + } + } else { + writeln!( + s, + " \"\"\"Struct variant for externally tagged enum.\"\"\"" + ) + .unwrap(); + } + writeln!(s, " model_config = ConfigDict(extra=\"ignore\")").unwrap(); + writeln!(s).unwrap(); + for field in &self.fields { + write!(s, " {}: {}", field.name, field.type_annotation).unwrap(); + if let Some(default) = &field.default_value { + write!(s, " = {default}").unwrap(); + } else if field.optional { + write!(s, " = None").unwrap(); + } + writeln!(s).unwrap(); + } + writeln!(s).unwrap(); + writeln!(s, " def model_dump(self, **kwargs):").unwrap(); + writeln!( + s, + " \"\"\"Serialize as externally tagged struct variant.\"\"\"" + ) + .unwrap(); + writeln!(s, " fields = {{}}").unwrap(); + for field in &self.fields { + writeln!( + s, + " if hasattr(self, '{}') and self.{} is not None:", + field.name, field.name + ) + .unwrap(); + writeln!( + s, + " fields['{}'] = self.{}", + field.name, field.name + ) + .unwrap(); + } + writeln!(s, " return {{\"{}\": fields}}", self.variant_name).unwrap(); + writeln!(s).unwrap(); + writeln!(s, " def model_dump_json(self, **kwargs):").unwrap(); + writeln!( + s, + " \"\"\"Serialize as JSON for externally tagged struct variant.\"\"\"" + ) + .unwrap(); + writeln!(s, " import json").unwrap(); + writeln!(s, " return json.dumps(self.model_dump(**kwargs))").unwrap(); + s + } + } -{% endfor %}{{ name }} = Union[{{ union_variant_names|join(", ") }}] -{% if description.is_some() && !description.as_deref().unwrap_or("").is_empty() %}"""{{ description.as_deref().unwrap() }}"""{% endif %} -"#, - ext = "txt" - )] pub struct ExternallyTaggedUnionClass { pub name: String, pub description: Option, @@ -5201,68 +5448,31 @@ def create_mock_client() -> MockClient: pub union_variant_names: Vec, } - // Hybrid enum templates for Pythonic data-carrying enum variants - #[derive(Template)] - #[template( - source = r#"from enum import Enum -from dataclasses import dataclass -from typing import Union, Optional - -{% for data_class in data_classes -%} -{{ data_class }} - -{% endfor -%} -class {{ enum_name }}(str, Enum): - {% if description.is_some() && !description.as_deref().unwrap().is_empty() -%} - """{{ description.as_deref().unwrap() }}""" - {% endif -%} - # Unit variants as enum members -{% for variant in unit_variants %} {{ variant.name }} = "{{ variant.value }}"{% if variant.description.is_some() %} # {{ variant.description.as_deref().unwrap() }}{% endif %} -{% endfor %} - - def model_dump(self): - """Handle serialization for simple enum values.""" - return self.value -{% for method in factory_methods -%} -{{ method }} -{% endfor %} - -# Type annotation for the union -{{ union_name }} = Union[{{ union_members|join(", ") }}] -"#, - ext = "txt" - )] - pub struct HybridEnumClass { - pub enum_name: String, - pub description: Option, - pub unit_variants: Vec, - pub factory_methods: Vec, - pub data_classes: Vec, - pub union_members: Vec, - pub union_name: String, + impl ExternallyTaggedUnionClass { + pub fn render(&self) -> String { + let mut s = String::new(); + for variant_def in &self.variant_definitions { + writeln!(s, "{variant_def}").unwrap(); + writeln!(s).unwrap(); + } + writeln!( + s, + "{} = Union[{}]", + self.name, + self.union_variant_names.join(", ") + ) + .unwrap(); + if let Some(desc) = &self.description { + let desc = super::sanitize_for_docstring(desc); + if !desc.is_empty() { + writeln!(s, "\"\"\"{desc}\"\"\"").unwrap(); + } + } + writeln!(s).unwrap(); + s + } } - #[derive(Template)] - #[template( - source = r#"@dataclass -class {{ name }}: - {% if description.is_some() && !description.as_deref().unwrap().is_empty() %}"""{{ description.as_deref().unwrap() }}""" - {% endif %}{%- for field_type in field_types %} - {{ field_type }} -{%- endfor %} - - def model_dump(self) -> dict: - """Serialize tuple variant as externally tagged.""" - fields = [{% for field in field_names %}self.{{ field }}{% if !loop.last %}, {% endif %}{% endfor %}] - return {"{{ variant_name }}": fields} - - def model_dump_json(self, **kwargs) -> str: - """Serialize as JSON.""" - import json - return json.dumps(self.model_dump()) -"#, - ext = "txt" - )] pub struct TupleVariantDataClass { pub name: String, pub variant_name: String, @@ -5271,31 +5481,43 @@ class {{ name }}: pub description: Option, } - #[derive(Template)] - #[template( - source = r#"@dataclass -class {{ name }}: - {% if description.is_some() && !description.as_deref().unwrap().is_empty() %}"""{{ description.as_deref().unwrap() }}""" - {% endif %}{%- for field_def in field_definitions %} - {{ field_def }} -{%- endfor %} - - def model_dump(self) -> dict: - """Serialize struct variant as externally tagged.""" - result = {} -{%- for field_name in field_names %} - if hasattr(self, '{{ field_name }}') and self.{{ field_name }} is not None: - result['{{ field_name }}'] = self.{{ field_name }} -{%- endfor %} - return {"{{ variant_name }}": result} - - def model_dump_json(self, **kwargs) -> str: - """Serialize as JSON.""" - import json - return json.dumps(self.model_dump()) -"#, - ext = "txt" - )] + impl TupleVariantDataClass { + pub fn render(&self) -> String { + let mut s = String::new(); + writeln!(s, "@dataclass").unwrap(); + writeln!(s, "class {}:", self.name).unwrap(); + if let Some(desc) = &self.description { + let desc = super::sanitize_for_docstring(desc); + if !desc.is_empty() { + writeln!(s, " \"\"\"{desc}\"\"\"").unwrap(); + } + } + for field_type in &self.field_types { + writeln!(s, " {field_type}").unwrap(); + } + writeln!(s).unwrap(); + writeln!(s, " def model_dump(self) -> dict:").unwrap(); + writeln!( + s, + " \"\"\"Serialize tuple variant as externally tagged.\"\"\"" + ) + .unwrap(); + let field_refs: Vec = self + .field_names + .iter() + .map(|f| format!("self.{f}")) + .collect(); + writeln!(s, " fields = [{}]", field_refs.join(", ")).unwrap(); + writeln!(s, " return {{\"{}\": fields}}", self.variant_name).unwrap(); + writeln!(s).unwrap(); + writeln!(s, " def model_dump_json(self, **kwargs) -> str:").unwrap(); + writeln!(s, " \"\"\"Serialize as JSON.\"\"\"").unwrap(); + writeln!(s, " import json").unwrap(); + writeln!(s, " return json.dumps(self.model_dump())").unwrap(); + s + } + } + pub struct StructVariantDataClass { pub name: String, pub variant_name: String, @@ -5304,36 +5526,46 @@ class {{ name }}: pub description: Option, } - #[derive(Template)] - #[template(source = r#"{{ method_name }}"#, ext = "txt")] - pub struct FactoryMethod { - pub method_name: String, - pub variant_name: String, - pub class_name: String, - pub parameters: Vec, - pub field_names: Vec, - pub description: Option, + impl StructVariantDataClass { + pub fn render(&self) -> String { + let mut s = String::new(); + writeln!(s, "@dataclass").unwrap(); + writeln!(s, "class {}:", self.name).unwrap(); + if let Some(desc) = &self.description { + let desc = super::sanitize_for_docstring(desc); + if !desc.is_empty() { + writeln!(s, " \"\"\"{desc}\"\"\"").unwrap(); + } + } + for field_def in &self.field_definitions { + writeln!(s, " {field_def}").unwrap(); + } + writeln!(s).unwrap(); + writeln!(s, " def model_dump(self) -> dict:").unwrap(); + writeln!( + s, + " \"\"\"Serialize struct variant as externally tagged.\"\"\"" + ) + .unwrap(); + writeln!(s, " result = {{}}").unwrap(); + for field_name in &self.field_names { + writeln!( + s, + " if hasattr(self, '{field_name}') and self.{field_name} is not None:" + ) + .unwrap(); + writeln!(s, " result['{field_name}'] = self.{field_name}").unwrap(); + } + writeln!(s, " return {{\"{}\": result}}", self.variant_name).unwrap(); + writeln!(s).unwrap(); + writeln!(s, " def model_dump_json(self, **kwargs) -> str:").unwrap(); + writeln!(s, " \"\"\"Serialize as JSON.\"\"\"").unwrap(); + writeln!(s, " import json").unwrap(); + writeln!(s, " return json.dumps(self.model_dump())").unwrap(); + s + } } - #[derive(Template)] - #[template( - source = r#"{% if is_generic -%} -# TypeVar definitions for {{ union_name }} -{% for param in generic_params -%} -{{ param }} = TypeVar('{{ param }}') -{% endfor %} - -{% endif -%} -{% for variant_model in variant_models %}{{ variant_model }} - -{% endfor %} -# Discriminated union for {{ union_name }} -{{ union_name }} = Annotated[Union[{{ union_members|join(", ") }}], Field(discriminator='kind')] -{% if description.is_some() -%} -"""{{ description.as_deref().unwrap() }}""" -{% endif %}"#, - ext = "txt" - )] pub struct DiscriminatedUnionEnum { pub variant_models: Vec, pub union_members: Vec, @@ -5343,49 +5575,32 @@ class {{ name }}: pub generic_params: Vec, } - #[derive(Template)] - #[template( - source = r#"{% for variant_model in variant_models %}{{ variant_model }} - -{% endfor %} -# Externally tagged enum using RootModel -{% if is_single_variant %}{{ name }}Variants = {{ union_variants }} -{% else %}{{ name }}Variants = Union[{{ union_variants }}] -{% endif %} -class {{ name }}(RootModel[{{ name }}Variants]{% if is_generic %}, Generic[{% for param in generic_params %}{{ param }}{% if !loop.last %}, {% endif %}{% endfor %}]{% endif %}): - """{% if description.is_some() %}{{ description.as_deref().unwrap() }}{% else %}Externally tagged enum{% endif %}""" - -{% if is_generic %} @classmethod - def __class_getitem__(cls, params): - return cls -{% endif %} - - @model_validator(mode='before') - @classmethod - def _validate_externally_tagged(cls, data): - # Handle direct variant instances (for programmatic creation) -{{ instance_validator_cases }} - - # Handle JSON data (for deserialization) -{{ validator_cases }} - - if isinstance(data, dict): - if len(data) != 1: - raise ValueError("Externally tagged enum must have exactly one key") - - key, value = next(iter(data.items())) -{{ dict_validator_cases }} - - raise ValueError(f"Unknown variant for {{ name }}: {data}") - - @model_serializer - def _serialize_externally_tagged(self): -{{ serializer_cases }} + impl DiscriminatedUnionEnum { + pub fn render(&self) -> String { + let mut s = String::new(); + // TypeVar definitions are emitted once at the top of the file; + // inline declarations are suppressed to avoid collisions with class names. + for variant_model in &self.variant_models { + writeln!(s, "{variant_model}").unwrap(); + writeln!(s).unwrap(); + } + writeln!(s).unwrap(); + writeln!(s, "# Discriminated union for {}", self.union_name).unwrap(); + writeln!( + s, + "{} = Annotated[Union[{}], Field(discriminator='kind')]", + self.union_name, + self.union_members.join(", ") + ) + .unwrap(); + if let Some(desc) = &self.description { + let desc = super::sanitize_for_docstring(desc); + writeln!(s, "\"\"\"{desc}\"\"\"").unwrap(); + } + s + } + } - raise ValueError(f"Cannot serialize {{ name }} variant: {type(self.root)}") -"#, - ext = "txt" - )] pub struct ExternallyTaggedEnumRootModel { pub name: String, pub description: Option, @@ -5400,84 +5615,90 @@ class {{ name }}(RootModel[{{ name }}Variants]{% if is_generic %}, Generic[{% fo pub generic_params: Vec, } - #[derive(Template)] - #[template( - source = r#"{% if is_generic %} -# Generic externally tagged enum using Approach B: Generic Variant Models -{% for param in generic_params -%} -{{ param }} = TypeVar('{{ param }}') -{% endfor %} - -# Common non-generic base class with discriminator -class {{ name }}Base(BaseModel): - """Base class for {{ name }} variants with shared discriminator.""" - _kind: str = PrivateAttr() - -{% for variant_model in variant_models %}{{ variant_model }} - -{% endfor %} -# Type alias for parameterized union - users can create specific unions as needed -# Example: {{ name }}[SomeType, AnotherType] = Union[{{ name }}Variant1[SomeType], {{ name }}Variant2[AnotherType]] -class {{ name }}(Generic[{% for param in generic_params %}{{ param }}{% if !loop.last %}, {% endif %}{% endfor %}]): - """{% if description.is_some() %}{{ description.as_deref().unwrap() }}{% else %}Generic externally tagged enum using Approach B{% endif %} - - This is a generic enum where each variant is a separate generic class. - To create a specific instance, use the variant classes directly. - To create a union type, use Union[VariantClass[Type1], OtherVariant[Type2]]. - """ - - @classmethod - def __class_getitem__(cls, params): - """Create documentation about parameterized types.""" - if not isinstance(params, tuple): - params = (params,) - if len(params) != {{ generic_params.len() }}: - raise TypeError(f"Expected {{ generic_params.len() }} type parameters, got {len(params)}") - - # For Approach B, users should create unions directly using variant classes - # This method serves as documentation - variant_examples = [ - {% for variant_info in variant_info_list %}"{{ variant_info.class_name }}[{% for param in generic_params %}{{ param }}{% if !loop.last %}, {% endif %}{% endfor %}]"{% if !loop.last %}, - {% endif %}{% endfor %} - ] - - # Return a helpful hint rather than NotImplementedError - return f"Union[{', '.join(variant_examples)}] # Use this pattern to create specific unions" -{% else %} -# Non-generic externally tagged enum - use existing RootModel approach -{% if is_single_variant %}{{ name }}Variants = {{ union_variants }} -{% else %}{{ name }}Variants = Union[{{ union_variants }}] -{% endif %} -class {{ name }}(RootModel[{{ name }}Variants]): - """{% if description.is_some() %}{{ description.as_deref().unwrap() }}{% else %}Externally tagged enum{% endif %}""" - - @model_validator(mode='before') - @classmethod - def _validate_externally_tagged(cls, data): - # Handle direct variant instances (for programmatic creation) -{{ instance_validator_cases }} - - # Handle JSON data (for deserialization) -{{ validator_cases }} - - if isinstance(data, dict): - if len(data) != 1: - raise ValueError("Externally tagged enum must have exactly one key") - - key, value = next(iter(data.items())) -{{ dict_validator_cases }} - - raise ValueError(f"Unknown variant for {{ name }}: {data}") - - @model_serializer - def _serialize_externally_tagged(self): -{{ serializer_cases }} - - raise ValueError(f"Cannot serialize {{ name }} variant: {type(self.root)}") -{% endif %} -"#, - ext = "txt" - )] + impl ExternallyTaggedEnumRootModel { + pub fn render(&self) -> String { + let mut s = String::new(); + for variant_model in &self.variant_models { + writeln!(s, "{variant_model}").unwrap(); + writeln!(s).unwrap(); + } + writeln!(s).unwrap(); + writeln!(s, "# Externally tagged enum using RootModel").unwrap(); + if self.is_single_variant { + writeln!(s, "{}Variants = {}", self.name, self.union_variants).unwrap(); + } else { + writeln!(s, "{}Variants = Union[{}]", self.name, self.union_variants).unwrap(); + } + writeln!(s).unwrap(); + if self.is_generic { + let params = self.generic_params.join(", "); + writeln!( + s, + "class {}(RootModel[{}Variants], Generic[{}]):", + self.name, self.name, params + ) + .unwrap(); + } else { + writeln!(s, "class {}(RootModel[{}Variants]):", self.name, self.name).unwrap(); + } + let desc = super::sanitize_for_docstring( + self.description + .as_deref() + .unwrap_or("Externally tagged enum"), + ); + writeln!(s, " \"\"\"{desc}\"\"\"").unwrap(); + writeln!(s).unwrap(); + if self.is_generic { + writeln!(s, " @classmethod").unwrap(); + writeln!(s, " def __class_getitem__(cls, params):").unwrap(); + writeln!(s, " return cls").unwrap(); + writeln!(s).unwrap(); + } + writeln!(s, " @model_validator(mode='before')").unwrap(); + writeln!(s, " @classmethod").unwrap(); + writeln!(s, " def _validate_externally_tagged(cls, data):").unwrap(); + writeln!( + s, + " # Handle direct variant instances (for programmatic creation)" + ) + .unwrap(); + writeln!(s, "{}", self.instance_validator_cases).unwrap(); + writeln!(s).unwrap(); + writeln!(s, " # Handle JSON data (for deserialization)").unwrap(); + writeln!(s, "{}", self.validator_cases).unwrap(); + writeln!(s).unwrap(); + writeln!(s, " if isinstance(data, dict):").unwrap(); + writeln!(s, " if len(data) != 1:").unwrap(); + writeln!( + s, + " raise ValueError(\"Externally tagged enum must have exactly one key\")" + ) + .unwrap(); + writeln!(s).unwrap(); + writeln!(s, " key, value = next(iter(data.items()))").unwrap(); + writeln!(s, "{}", self.dict_validator_cases).unwrap(); + writeln!(s).unwrap(); + writeln!( + s, + " raise ValueError(f\"Unknown variant for {}: {{data}}\")", + self.name + ) + .unwrap(); + writeln!(s).unwrap(); + writeln!(s, " @model_serializer").unwrap(); + writeln!(s, " def _serialize_externally_tagged(self):").unwrap(); + writeln!(s, "{}", self.serializer_cases).unwrap(); + writeln!(s).unwrap(); + writeln!( + s, + " raise ValueError(f\"Cannot serialize {} variant: {{type(self.root)}}\")", + self.name + ) + .unwrap(); + s + } + } + pub struct GenericExternallyTaggedEnumApproachB { pub name: String, pub description: Option, @@ -5493,6 +5714,197 @@ class {{ name }}(RootModel[{{ name }}Variants]): pub variant_info_list: Vec, } + impl GenericExternallyTaggedEnumApproachB { + pub fn render(&self) -> String { + let mut s = String::new(); + if self.is_generic { + writeln!(s).unwrap(); + writeln!( + s, + "# Generic externally tagged enum using Approach B: Generic Variant Models" + ) + .unwrap(); + // TypeVar definitions are emitted once at the top of the file; + // inline declarations are suppressed to avoid collisions with class names. + writeln!(s).unwrap(); + writeln!(s, "# Common non-generic base class with discriminator").unwrap(); + writeln!(s, "class {}Base(BaseModel):", self.name).unwrap(); + writeln!( + s, + " \"\"\"Base class for {} variants with shared discriminator.\"\"\"", + self.name + ) + .unwrap(); + writeln!(s, " _kind: str = PrivateAttr()").unwrap(); + writeln!(s).unwrap(); + for variant_model in &self.variant_models { + writeln!(s, "{variant_model}").unwrap(); + writeln!(s).unwrap(); + } + writeln!(s).unwrap(); + let params = self.generic_params.join(", "); + writeln!( + s, + "# Type alias for parameterized union - users can create specific unions as needed" + ) + .unwrap(); + writeln!( + s, + "# Example: {}[SomeType, AnotherType] = Union[{}Variant1[SomeType], {}Variant2[AnotherType]]", + self.name, self.name, self.name + ) + .unwrap(); + writeln!(s, "class {}(Generic[{}]):", self.name, params).unwrap(); + let desc = super::sanitize_for_docstring( + self.description + .as_deref() + .unwrap_or("Generic externally tagged enum using Approach B"), + ); + writeln!(s, " \"\"\"{desc}").unwrap(); + writeln!(s).unwrap(); + writeln!( + s, + " This is a generic enum where each variant is a separate generic class." + ) + .unwrap(); + writeln!( + s, + " To create a specific instance, use the variant classes directly." + ) + .unwrap(); + writeln!( + s, + " To create a union type, use Union[VariantClass[Type1], OtherVariant[Type2]]." + ) + .unwrap(); + writeln!(s, " \"\"\"").unwrap(); + writeln!(s).unwrap(); + writeln!(s, " @classmethod").unwrap(); + writeln!(s, " def __class_getitem__(cls, params):").unwrap(); + writeln!( + s, + " \"\"\"Create documentation about parameterized types.\"\"\"" + ) + .unwrap(); + writeln!(s, " if not isinstance(params, tuple):").unwrap(); + writeln!(s, " params = (params,)").unwrap(); + writeln!( + s, + " if len(params) != {}:", + self.generic_params.len() + ) + .unwrap(); + writeln!( + s, + " raise TypeError(f\"Expected {} type parameters, got {{len(params)}}\")", + self.generic_params.len() + ) + .unwrap(); + writeln!(s).unwrap(); + writeln!( + s, + " # For Approach B, users should create unions directly using variant classes" + ) + .unwrap(); + writeln!(s, " # This method serves as documentation").unwrap(); + writeln!(s, " variant_examples = [").unwrap(); + for (i, variant_info) in self.variant_info_list.iter().enumerate() { + let generic_params_str = self.generic_params.join(", "); + if i < self.variant_info_list.len() - 1 { + writeln!( + s, + " \"{}[{}]\",", + variant_info.class_name, generic_params_str + ) + .unwrap(); + } else { + writeln!( + s, + " \"{}[{}]\"", + variant_info.class_name, generic_params_str + ) + .unwrap(); + } + } + writeln!(s, " ]").unwrap(); + writeln!(s).unwrap(); + writeln!( + s, + " # Return a helpful hint rather than NotImplementedError" + ) + .unwrap(); + writeln!( + s, + " return f\"Union[{{', '.join(variant_examples)}}] # Use this pattern to create specific unions\"" + ) + .unwrap(); + } else { + writeln!(s).unwrap(); + writeln!( + s, + "# Non-generic externally tagged enum - use existing RootModel approach" + ) + .unwrap(); + if self.is_single_variant { + writeln!(s, "{}Variants = {}", self.name, self.union_variants).unwrap(); + } else { + writeln!(s, "{}Variants = Union[{}]", self.name, self.union_variants).unwrap(); + } + writeln!(s, "class {}(RootModel[{}Variants]):", self.name, self.name).unwrap(); + let desc = super::sanitize_for_docstring( + self.description + .as_deref() + .unwrap_or("Externally tagged enum"), + ); + writeln!(s, " \"\"\"{desc}\"\"\"").unwrap(); + writeln!(s).unwrap(); + writeln!(s, " @model_validator(mode='before')").unwrap(); + writeln!(s, " @classmethod").unwrap(); + writeln!(s, " def _validate_externally_tagged(cls, data):").unwrap(); + writeln!( + s, + " # Handle direct variant instances (for programmatic creation)" + ) + .unwrap(); + writeln!(s, "{}", self.instance_validator_cases).unwrap(); + writeln!(s).unwrap(); + writeln!(s, " # Handle JSON data (for deserialization)").unwrap(); + writeln!(s, "{}", self.validator_cases).unwrap(); + writeln!(s).unwrap(); + writeln!(s, " if isinstance(data, dict):").unwrap(); + writeln!(s, " if len(data) != 1:").unwrap(); + writeln!( + s, + " raise ValueError(\"Externally tagged enum must have exactly one key\")" + ) + .unwrap(); + writeln!(s).unwrap(); + writeln!(s, " key, value = next(iter(data.items()))").unwrap(); + writeln!(s, "{}", self.dict_validator_cases).unwrap(); + writeln!(s).unwrap(); + writeln!( + s, + " raise ValueError(f\"Unknown variant for {}: {{data}}\")", + self.name + ) + .unwrap(); + writeln!(s).unwrap(); + writeln!(s, " @model_serializer").unwrap(); + writeln!(s, " def _serialize_externally_tagged(self):").unwrap(); + writeln!(s, "{}", self.serializer_cases).unwrap(); + writeln!(s).unwrap(); + writeln!( + s, + " raise ValueError(f\"Cannot serialize {} variant: {{type(self.root)}}\")", + self.name + ) + .unwrap(); + } + writeln!(s).unwrap(); + s + } + } + #[derive(Clone)] pub struct VariantInfo { pub class_name: String, diff --git a/reflectapi/src/codegen/rust.rs b/reflectapi/src/codegen/rust.rs index 4d4d2a10..6eac26c7 100644 --- a/reflectapi/src/codegen/rust.rs +++ b/reflectapi/src/codegen/rust.rs @@ -5,7 +5,6 @@ use std::{ }; use anyhow::Context; -use askama::Template; use indexmap::IndexMap; use reflectapi_schema::{Function, TypeReference, Visitor}; @@ -220,11 +219,7 @@ pub fn generate(mut schema: crate::Schema, config: &Config) -> anyhow::Result anyhow::Result anyhow::Result<()> { mod templates { use std::collections::BTreeSet; + use std::fmt::Write; - use askama::Template; use indexmap::IndexMap; - #[derive(Template)] - #[template( - source = "// DO NOT MODIFY THIS FILE MANUALLY -// This file was generated by reflectapi-cli -// -// Schema name: {{ name }} -// {{ description }} - -#![allow(non_camel_case_types)] -#![allow(dead_code)] - -pub use reflectapi::rt::*; -pub use interface::Interface;", - ext = "txt" - )] pub(super) struct __FileHeader { pub name: String, pub description: String, } - #[derive(Template)] - #[template( - source = " -{{ self.render_start() }} -{%- for type in types.iter() %} -{{ type }} -{%- endfor %} -{%- for module in self.submodules_sorted() %} -{{- module }} -{%- endfor %} - -{{ self.render_end() }}", - ext = "txt" - )] + impl __FileHeader { + pub fn render(&self) -> String { + format!( + "// DO NOT MODIFY THIS FILE MANUALLY\n\ + // This file was generated by reflectapi-cli\n\ + //\n\ + // Schema name: {}\n\ + // {}\n\ + \n\ + #![allow(non_camel_case_types)]\n\ + #![allow(dead_code)]\n\ + \n\ + pub use reflectapi::rt::*;\n\ + pub use interface::Interface;", + self.name, self.description + ) + } + } + pub(super) struct __Module { pub name: String, pub types: Vec, @@ -385,45 +364,24 @@ pub use interface::Interface;", self.types.is_empty() && self.submodules.iter().all(|(_, m)| m.is_empty()) } - fn render_start(&self) -> String { - if self.name.is_empty() || self.is_empty() { - "".into() - } else { - format!("pub mod {} {{", self.name) + pub fn render(&self) -> String { + let mut out = String::new(); + if !self.name.is_empty() && !self.is_empty() { + write!(out, "\npub mod {} {{", self.name).unwrap(); } - } - - fn render_end(&self) -> String { - if self.name.is_empty() || self.is_empty() { - "".into() - } else { - "}".into() + for t in &self.types { + write!(out, "\n{t}").unwrap(); + } + for module in self.submodules_sorted() { + out.push_str(&module.render()); + } + if !self.name.is_empty() && !self.is_empty() { + write!(out, "\n\n}}").unwrap(); } + out } } - #[derive(Template)] - #[template( - source = r#" -{{ description }}{{ self.render_attributes_derive() }} -pub struct {{ name }} {{ self.render_brackets().0 }} - {%- for field in fields.iter() %} - {{ field }}, - {%- endfor %} -{{ self.render_brackets().1 }} - -{% if is_error_type %} -impl std::fmt::Display for {{ name }} { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", reflectapi::rt::error_to_string(self)) - } -} - -impl std::error::Error for {{ name }} {} -{% endif %} -"#, - ext = "txt" - )] pub(super) struct __Struct { pub name: String, pub description: String, @@ -449,16 +407,11 @@ impl std::error::Error for {{ name }} {} let mut attrs = self.codegen_config.additional_derives.clone(); attrs.extend(self.base_derives.iter().cloned()); if self.is_input_type || self.is_error_type { - // Need `Serialize` for error types for their generated `Display` implementation. - // for client it is the inverse, input types are outgoing types attrs.insert("serde::Serialize".into()); } - if self.is_output_type { - // for client it is the inverse, output types are incoming types attrs.insert("serde::Deserialize".into()); } - if attrs.is_empty() { "".into() } else { @@ -468,30 +421,39 @@ impl std::error::Error for {{ name }} {} ) } } - } - #[derive(Template)] - #[template( - source = r#" -{{ description }}{{ self.render_attributes_derive() }} -{{ self.render_attributes() }}pub enum {{ name }} { - {%- for variant in variants.iter() %} - {{ variant }} - {%- endfor %} -} - -{% if is_error_type %} -impl std::fmt::Display for {{ name }} { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", reflectapi::rt::error_to_string(self)) + pub fn render(&self) -> String { + let brackets = self.render_brackets(); + let mut out = format!( + "\n{}{}\npub struct {} {}", + self.description, + self.render_attributes_derive(), + self.name, + brackets.0, + ); + for field in &self.fields { + write!(out, "\n {},", field.render()).unwrap(); + } + write!(out, "\n{}", brackets.1).unwrap(); + + if self.is_error_type { + write!( + out, + "\n\nimpl std::fmt::Display for {} {{\n\ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {{\n\ + write!(f, \"{{}}\", reflectapi::rt::error_to_string(self))\n\ + }}\n\ + }}\n\n\ + impl std::error::Error for {} {{}}\n", + self.name, self.name, + ) + .unwrap(); + } + out.push('\n'); + out + } } -} -impl std::error::Error for {{ name }} {} -{% endif %} -"#, - ext = "txt" - )] pub(super) struct __Enum { pub name: String, pub description: String, @@ -509,12 +471,9 @@ impl std::error::Error for {{ name }} {} let mut attrs = self.codegen_config.additional_derives.clone(); attrs.extend(self.base_derives.iter().cloned()); if self.is_input_type || self.is_error_type { - // Need `Serialize` for error types for their generated `Display` implementation. - // for client it is the inverse, input types are outgoing types attrs.insert("serde::Serialize".into()); } if self.is_output_type { - // for client it is the inverse, output types are incoming types attrs.insert("serde::Deserialize".into()); } if attrs.is_empty() { @@ -548,13 +507,38 @@ impl std::error::Error for {{ name }} {} format!("#[serde({})]\n ", attrs.join(", ")) } } + + pub fn render(&self) -> anyhow::Result { + let mut out = format!( + "\n{}{}\n{}pub enum {} {{", + self.description, + self.render_attributes_derive(), + self.render_attributes(), + self.name, + ); + for variant in &self.variants { + write!(out, "\n {}", variant.render()?).unwrap(); + } + out.push_str("\n}\n"); + + if self.is_error_type { + write!( + out, + "\nimpl std::fmt::Display for {} {{\n\ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {{\n\ + write!(f, \"{{}}\", reflectapi::rt::error_to_string(self))\n\ + }}\n\ + }}\n\n\ + impl std::error::Error for {} {{}}\n", + self.name, self.name, + ) + .unwrap(); + } + out.push('\n'); + Ok(out) + } } - #[derive(Template)] - #[template( - source = "{{ description }}{{ self.render_attributes() }}{{ self.render_self()? }},", - ext = "txt" - )] pub(super) struct __Variant { pub name: String, pub serde_name: String, @@ -565,6 +549,15 @@ impl std::error::Error for {{ name }} {} } impl __Variant { + pub fn render(&self) -> anyhow::Result { + Ok(format!( + "{}{}{},", + self.description, + self.render_attributes(), + self.render_self()?, + )) + } + fn render_self(&self) -> anyhow::Result { let brakets = self.render_brackets(); let r = format!( @@ -598,7 +591,7 @@ impl std::error::Error for {{ name }} {} fn render_fields(&self) -> anyhow::Result { let mut rendered_fields = Vec::new(); for field in self.fields.iter() { - rendered_fields.push(field.render()?); + rendered_fields.push(field.render()); } if rendered_fields.is_empty() { Ok("".into()) @@ -625,11 +618,7 @@ impl std::error::Error for {{ name }} {} } } - #[derive(Template, Clone)] - #[template( - source = "{{ description }}{{ self.render_attributes() }}{% if !self.is_unnamed() %}{{ self.render_visibility_modifier() }}{{ name }}: {{ type_ }}{% else %}{{ type_ }}{% endif %}", - ext = "txt" - )] + #[derive(Clone)] pub(super) struct __Field { pub name: String, pub serde_name: String, @@ -646,11 +635,11 @@ impl std::error::Error for {{ name }} {} self.name.parse::().is_ok() } - fn render_visibility_modifier(&self) -> String { + fn render_visibility_modifier(&self) -> &'static str { if self.public { - "pub ".into() + "pub " } else { - "".into() + "" } } @@ -663,13 +652,10 @@ impl std::error::Error for {{ name }} {} if self.optional { serde_attrs.push("default = \"Default::default\"".into()); - // this one is important to not serialize undefined values - // as this is the special built-in type which allows to differentiate between undefined and null if self.type_.starts_with("reflectapi::Option<") { serde_attrs .push("skip_serializing_if = \"reflectapi::Option::is_undefined\"".into()); } - // the rest are nice to have, we enumerate only commonly used std types if self.type_.starts_with("std::option::Option<") { serde_attrs .push("skip_serializing_if = \"std::option::Option::is_none\"".into()); @@ -714,37 +700,43 @@ impl std::error::Error for {{ name }} {} out } + + pub fn render(&self) -> String { + if self.is_unnamed() { + format!( + "{}{}{}", + self.description, + self.render_attributes(), + self.type_ + ) + } else { + format!( + "{}{}{}{}: {}", + self.description, + self.render_attributes(), + self.render_visibility_modifier(), + self.name, + self.type_, + ) + } + } } - #[derive(Template)] - #[template( - source = " -{{ description }}pub type {{ name }} = {{ type_ }};", - ext = "txt" - )] pub(super) struct __Alias { pub name: String, pub description: String, pub type_: String, } - #[derive(Template)] - #[template( - source = " -{{ description }}{{ self.render_attributes_derive() }} -pub struct {{ name }}; - -{% if is_error_type %} -impl std::fmt::Display for {{ name }} { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, \"{{ name }}\") + impl __Alias { + pub fn render(&self) -> String { + format!( + "\n{}pub type {} = {};", + self.description, self.name, self.type_ + ) + } } -} -impl std::error::Error for {{ name }} {} -{% endif %}", - ext = "txt" - )] pub(super) struct __Unit { pub name: String, pub description: String, @@ -760,11 +752,9 @@ impl std::error::Error for {{ name }} {} let mut attrs = self.codegen_config.additional_derives.clone(); attrs.extend(self.base_derives.iter().cloned()); if self.is_input_type { - // for client it is the inverse, input types are outgoing types attrs.insert("serde::Serialize".into()); } if self.is_output_type { - // for client it is the inverse, output types are incoming types attrs.insert("serde::Deserialize".into()); } if attrs.is_empty() { @@ -776,24 +766,32 @@ impl std::error::Error for {{ name }} {} ) } } + + pub fn render(&self) -> String { + let mut out = format!( + "\n{}{}\npub struct {};\n", + self.description, + self.render_attributes_derive(), + self.name, + ); + + if self.is_error_type { + write!( + out, + "\nimpl std::fmt::Display for {} {{\n\ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {{\n\ + write!(f, \"{}\")\n\ + }}\n\ + }}\n\n\ + impl std::error::Error for {} {{}}\n", + self.name, self.name, self.name, + ) + .unwrap(); + } + out + } } - #[derive(Template)] - #[template( - source = r#" - {%- if let Some(deprecation_note) = deprecation_note -%} - {%- if deprecation_note.is_empty() -%} - #[deprecated] - {%- else -%} - #[deprecated(note = "{{ deprecation_note }}")] - {%- endif -%} - {%- endif -%} - {{description}}{{attributes}}pub async fn {{ name }}(&self, input: {{ input_type }}, headers: {{ input_headers }}) - -> Result<{{ output_type }}, reflectapi::rt::Error<{{ error_type }}, C::Error>> { - reflectapi::rt::__request_impl(&self.client, self.base_url.join("{{ path }}").expect("checked base_url already and path is valid"), input, headers).await - }"#, - ext = "txt" - )] pub(super) struct __FunctionImplementationTemplate { pub name: String, pub description: String, @@ -806,34 +804,75 @@ impl std::error::Error for {{ name }} {} pub error_type: String, } - #[derive(Template)] - #[template( - source = r#" -impl {{ name }} { - pub fn try_new(client: C, base_url: reflectapi::rt::Url) -> std::result::Result { - if base_url.cannot_be_a_base() { - return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase); + impl __FunctionImplementationTemplate { + pub fn render(&self) -> String { + let mut out = String::new(); + if let Some(deprecation_note) = &self.deprecation_note { + if deprecation_note.is_empty() { + out.push_str(" #[deprecated]"); + } else { + write!(out, " #[deprecated(note = \"{deprecation_note}\")]").unwrap(); + } + } + write!( + out, + " {}{}pub async fn {}(&self, input: {}, headers: {})\n\ + -> Result<{}, reflectapi::rt::Error<{}, C::Error>> {{\n\ + reflectapi::rt::__request_impl(&self.client, self.base_url.join(\"{}\").expect(\"checked base_url already and path is valid\"), input, headers).await\n\ + }}", + self.description, + self.attributes, + self.name, + self.input_type, + self.input_headers, + self.output_type, + self.error_type, + self.path, + ) + .unwrap(); + out } - - Ok(Self { - {%- for field in fields.iter() %} - {{ field.name }}: {{ field.type_ }}::try_new(client.clone(), base_url.clone())?, - {%- endfor %} - client, - base_url, - }) } - {%- for func in functions.iter() %} - {{ func }} - {%- endfor %} -}"#, - ext = "txt" - )] + pub(super) struct __InterfaceImplementationTemplate { pub name: String, pub fields: Vec<__Field>, pub functions: Vec<__FunctionImplementationTemplate>, } + + impl __InterfaceImplementationTemplate { + pub fn render(&self) -> String { + let mut out = format!( + "\nimpl {} {{\n\ + pub fn try_new(client: C, base_url: reflectapi::rt::Url) -> std::result::Result {{\n\ + if base_url.cannot_be_a_base() {{\n\ + return Err(reflectapi::rt::UrlParseError::RelativeUrlWithCannotBeABaseBase);\n\ + }}\n\ + \n\ + Ok(Self {{", + self.name, + ); + for field in &self.fields { + write!( + out, + "\n {}: {}::try_new(client.clone(), base_url.clone())?,", + field.name, field.type_ + ) + .unwrap(); + } + out.push_str( + "\n client,\n\ + base_url,\n\ + })\n\ + }", + ); + for func in &self.functions { + write!(out, "\n {}", func.render()).unwrap(); + } + out.push_str("\n}"); + out + } + } } struct __FunctionGroup { @@ -1013,10 +1052,7 @@ fn __interface_types_from_function_group( interface_implementation.functions.push(func_impl); } - let mut result = vec![ - type_template.render().unwrap(), - interface_implementation.render().unwrap(), - ]; + let mut result = vec![type_template.render(), interface_implementation.render()]; for (subgroup_name, subgroup) in group.subgroups.iter() { result.extend(__interface_types_from_function_group( @@ -1087,9 +1123,7 @@ fn __render_type( codegen_config: struct_def.codegen_config.rust.clone(), base_derives: config.base_derives.clone(), }; - unit_struct_template - .render() - .context("Failed to render template")? + unit_struct_template.render() } else if struct_def.is_alias() { let field_type_ref = struct_def.fields.iter().next().unwrap().type_ref.clone(); let alias_template = templates::__Alias { @@ -1103,9 +1137,7 @@ fn __render_type( Some(type_def), ), }; - alias_template - .render() - .context("Failed to render template")? + alias_template.render() } else { let interface_template = templates::__Struct { name: type_name, @@ -1137,9 +1169,7 @@ fn __render_type( }) .collect::>(), }; - interface_template - .render() - .context("Failed to render template")? + interface_template.render() } } crate::Type::Enum(enum_def) => { @@ -1184,9 +1214,7 @@ fn __render_type( }) .collect::>(), }; - enum_template - .render() - .context("Failed to render template")? + enum_template.render()? } crate::Type::Primitive(_) => { // do nothing, we will use the primitive types as is diff --git a/reflectapi/src/codegen/typescript.rs b/reflectapi/src/codegen/typescript.rs index 471345ef..c396bd33 100644 --- a/reflectapi/src/codegen/typescript.rs +++ b/reflectapi/src/codegen/typescript.rs @@ -6,7 +6,6 @@ use std::{ use super::{format_with, END_BOILERPLATE, START_BOILERPLATE}; use anyhow::Context; -use askama::Template; use indexmap::IndexMap; use reflectapi_schema::Function; @@ -81,11 +80,7 @@ pub fn generate(mut schema: crate::Schema, config: &Config) -> anyhow::Result anyhow::Result anyhow::Result anyhow::Result<()> { } mod templates { - use askama::Template; use indexmap::IndexMap; + use std::fmt::Write; - #[derive(Template)] - #[template( - source = "// DO NOT MODIFY THIS FILE MANUALLY -// This file was generated by reflectapi-cli -// -// Schema name: {{ name }} -// {{ description }} - -export function client(base: string | Client): __definition.Interface { - return __implementation.__client(base) -}", - ext = "txt" - )] pub(super) struct FileHeader { pub name: String, pub description: String, } - #[derive(Template)] - #[template( - source = " -namespace __implementation { - -{{ start_boilerplate }} - -export function __client(base: string | Client): __definition.Interface { - const client_instance = typeof base === 'string' ? new ClientInstance(base) : base; - return { impl: {{ client_impl }} }.impl -} - -{{ end_boilerplate }} - -{{ implemented_functions }} + impl FileHeader { + pub fn render(&self) -> String { + format!( + "// DO NOT MODIFY THIS FILE MANUALLY\n\ + // This file was generated by reflectapi-cli\n\ + //\n\ + // Schema name: {}\n\ + // {}\n\ + \n\ + export function client(base: string | Client): __definition.Interface {{\n\ + return __implementation.__client(base)\n\ + }}", + self.name, self.description + ) + } + } -} -", - ext = "txt" - )] pub(super) struct FileFooter { pub start_boilerplate: &'static str, pub end_boilerplate: &'static str, @@ -256,20 +225,31 @@ export function __client(base: string | Client): __definition.Interface { pub implemented_functions: String, } - #[derive(Template)] - #[template( - source = " -{{ self.render_start() }} -{%- for type in types.iter() %} -{{ type }} -{%- endfor %} -{%- for module in self.submodules_sorted() %} -{{ module }} -{%- endfor %} - -{{ self.render_end() }}", - ext = "txt" - )] + impl FileFooter { + pub fn render(&self) -> String { + format!( + "\nnamespace __implementation {{\n\ + \n\ + {}\n\ + \n\ + export function __client(base: string | Client): __definition.Interface {{\n\ + const client_instance = typeof base === 'string' ? new ClientInstance(base) : base;\n\ + return {{ impl: {} }}.impl\n\ + }}\n\ + \n\ + {}\n\ + \n\ + {}\n\ + \n\ + }}\n", + self.start_boilerplate, + self.client_impl, + self.end_boilerplate, + self.implemented_functions, + ) + } + } + pub(super) struct Module { pub name: String, pub types: Vec, @@ -287,33 +267,25 @@ export function __client(base: string | Client): __definition.Interface { self.types.is_empty() && self.submodules.iter().all(|(_, m)| m.is_empty()) } - fn render_start(&self) -> String { - if self.name.is_empty() || self.is_empty() { - "".into() - } else { - format!("export namespace {} {{", self.name.replace('-', "_")) + pub fn render(&self) -> String { + let mut out = String::new(); + if !self.name.is_empty() && !self.is_empty() { + write!(out, "\nexport namespace {} {{", self.name.replace('-', "_")).unwrap(); } - } - - fn render_end(&self) -> String { - if self.name.is_empty() || self.is_empty() { - "".into() - } else { - "}".into() + for t in &self.types { + write!(out, "\n{t}").unwrap(); + } + for module in self.submodules_sorted() { + out.push('\n'); + out.push_str(&module.render()); } + if !self.name.is_empty() && !self.is_empty() { + write!(out, "\n\n}}").unwrap(); + } + out } } - #[derive(Template)] - #[template( - source = " -{{ description }}export {{ self.render_keyword() }} {{ name }} {{ self.render_brackets().0 }} - {%- for field in fields.iter() %} - {{ field }}, - {%- endfor %} -{{ self.render_brackets().1 }}{{ self.render_flattened_types() }}", - ext = "txt" - )] pub(super) struct Interface { pub name: String, pub description: String, @@ -323,11 +295,11 @@ export function __client(base: string | Client): __definition.Interface { } impl Interface { - fn render_keyword(&self) -> String { + fn render_keyword(&self) -> &'static str { if self.is_tuple || !self.flattened_types.is_empty() { - "type".into() + "type" } else { - "interface".into() + "interface" } } @@ -348,25 +320,41 @@ export function __client(base: string | Client): __definition.Interface { format!(" & {}", self.flattened_types.join(" &\n ")) } } + + pub fn render(&self) -> String { + let brackets = self.render_brackets(); + let mut out = format!( + "\n{}export {} {} {}", + self.description, + self.render_keyword(), + self.name, + brackets.0, + ); + for field in &self.fields { + write!(out, "\n {},", field.render()).unwrap(); + } + write!(out, "\n{}{}", brackets.1, self.render_flattened_types()).unwrap(); + out + } } - #[derive(Template)] - #[template( - source = " -{{ description }}export type {{ name }} = - {%- for variant in variants.iter() %} - {{ variant }} - {%- endfor %};", - ext = "txt" - )] pub(super) struct Enum { pub name: String, pub description: String, pub variants: Vec, } - #[derive(Template)] - #[template(source = "{{ description }}| {{ self.render_self()? }}", ext = "txt")] + impl Enum { + pub fn render(&self) -> anyhow::Result { + let mut out = format!("\n{}export type {} =", self.description, self.name,); + for variant in &self.variants { + write!(out, "\n {}", variant.render()?).unwrap(); + } + out.push(';'); + Ok(out) + } + } + pub(super) struct Variant { pub name: String, pub description: String, @@ -411,6 +399,10 @@ export function __client(base: string | Client): __definition.Interface { } impl Variant { + pub fn render(&self) -> anyhow::Result { + Ok(format!("{}| {}", self.description, self.render_self()?)) + } + fn field_brackets(&self) -> (String, String) { if self.fields.is_empty() { ("".into(), "".into()) @@ -530,7 +522,7 @@ export function __client(base: string | Client): __definition.Interface { } for field in self.fields.iter() { - rendered_fields.push(field.render()?); + rendered_fields.push(field.render()); } Ok(format!( @@ -544,11 +536,7 @@ export function __client(base: string | Client): __definition.Interface { // TODO The ? is in the wrong place for optional tuple fields. // i.e. syntax is { name?: string } for object-like things but [string?] for array-like things - #[derive(Debug, Template)] - #[template( - source = "{{ description }}{% if !self.is_unnamed() %}{{ self.normalized_name() }}{% if optional %}{{ \"?\" }}{% endif %}: {{ type_ }}{% else %}{{ type_ }}{% endif %}", - ext = "txt" - )] + #[derive(Debug)] pub(super) struct Field { pub name: String, pub description: String, @@ -570,29 +558,43 @@ export function __client(base: string | Client): __definition.Interface { self.name.clone() } } + + pub fn render(&self) -> String { + if self.is_unnamed() { + format!("{}{}", self.description, self.type_) + } else if self.optional { + format!( + "{}{}?: {}", + self.description, + self.normalized_name(), + self.type_ + ) + } else { + format!( + "{}{}: {}", + self.description, + self.normalized_name(), + self.type_ + ) + } + } } - #[derive(Template)] - #[template( - source = " -{{ description }}export type {{ name }} = {{ type_ }};", - ext = "txt" - )] pub(super) struct Alias { pub name: String, pub description: String, pub type_: String, } - #[derive(Template)] - #[template( - source = "function {{ name }}(client: Client) { - return (input: {{ input_type }}, headers: {{ input_headers }}, options?: RequestOptions) => __request< - {{ input_type }}, {{ input_headers }}, {{ output_type }}, {{ error_type }} - >(client, '{{ path }}', input, headers, options); -}", - ext = "txt" - )] + impl Alias { + pub fn render(&self) -> String { + format!( + "\n{}export type {} = {};", + self.description, self.name, self.type_ + ) + } + } + pub(super) struct FunctionImplementationTemplate { pub name: String, pub path: String, @@ -602,6 +604,24 @@ export function __client(base: string | Client): __definition.Interface { pub error_type: String, } + impl FunctionImplementationTemplate { + pub fn render(&self) -> String { + format!( + "function {name}(client: Client) {{\n\ + return (input: {input_type}, headers: {input_headers}, options?: RequestOptions) => __request<\n\ + {input_type}, {input_headers}, {output_type}, {error_type}\n\ + >(client, '{path}', input, headers, options);\n\ + }}", + name = self.name, + input_type = self.input_type, + input_headers = self.input_headers, + output_type = self.output_type, + error_type = self.error_type, + path = self.path, + ) + } + } + #[derive(Debug)] pub(super) struct ClientImplementationGroup { pub offset: usize, @@ -824,9 +844,7 @@ fn render_function( output_type, error_type, }; - function_template - .render() - .context("Failed to render template") + Ok(function_template.render()) } fn render_type( @@ -845,9 +863,7 @@ fn render_type( description: doc_to_ts_comments(&struct_def.description, None, 0), type_: type_ref_to_ts_ref(&field_type_ref, schema, implemented_types), }; - alias_template - .render() - .context("Failed to render template")? + alias_template.render() } else { let interface_template = templates::Interface { name: type_name, @@ -876,9 +892,7 @@ fn render_type( }) .collect::>(), }; - interface_template - .render() - .context("Failed to render template")? + interface_template.render() } } crate::Type::Enum(enum_def) => { @@ -906,9 +920,7 @@ fn render_type( }) .collect::>(), }; - enum_template - .render() - .context("Failed to render template")? + enum_template.render()? } crate::Type::Primitive(type_def) => { eprintln!( @@ -923,9 +935,7 @@ fn render_type( type_def.name ), }; - alias_template - .render() - .context("Failed to render template")? + alias_template.render() } }) } diff --git a/reflectapi/src/traits.rs b/reflectapi/src/traits.rs index 6ab001fa..e495ed7e 100644 --- a/reflectapi/src/traits.rs +++ b/reflectapi/src/traits.rs @@ -701,6 +701,7 @@ fn reflectapi_duration(schema: &mut crate::Typespace) -> crate::TypeReference { let type_name = "std::time::Duration"; if schema.reserve_type(type_name) { let type_def = crate::Struct { + id: Default::default(), name: type_name.into(), description: "Time duration type".into(), fields: crate::Fields::Named(vec![