Skip to content

Enums & Literals in pyfake

Overview

pyfake supports both Literal[...] annotations and standard Python Enum classes. Literals are generated by picking one of the allowed values; enums are generated by selecting a valid enum value which Pydantic will coerce to the enum member when building model instances.


Simple Literal usage

Use typing.Literal for fields that must be one of a fixed set of values.

from typing import Literal
from pydantic import BaseModel
from pyfake import fake

class Item(BaseModel):
    status: Literal['active', 'inactive', 'pending']
    code: Literal[1, 2, 3]

print(fake(Item))
{'status': 'active', 'code': 2}

Notes: - Each generation picks one of the declared literal values uniformly at random. - Literals work with both string and numeric values.


Simple Enum usage

Define an Enum subclass and annotate the field with the enum type.

from enum import Enum
from pydantic import BaseModel
from pyfake import fake

class Color(Enum):
    RED = 'red'
    GREEN = 'green'
    BLUE = 'blue'

class Product(BaseModel):
    color: Color
    maybe_color: Color | None

print(fake(Product, num=3, seed=0))
[
{'color': <Color.GREEN: 'green'>, 'maybe_color': None},
{'color': <Color.RED: 'red'>, 'maybe_color': <Color.BLUE: 'blue'>},
{'color': <Color.BLUE: 'blue'>, 'maybe_color': None}
]

Note

  • The registry generates underlying enum values and Pydantic constructs the model, coercing those values into actual Enum members. When pyfake returns dicts (via model_dump()), you may see enum members (Python-mode); when serialising to JSON they will appear as their underlying values.
  • Enums with non-string values (e.g., ints) are supported the same way.

Receiving model instances vs dicts

  • By default pyfake returns dictionaries produced by model_dump(); for enums this often contains Enum members (depending on Pydantic mode).
  • Use as_dict=False to receive actual Pydantic model instances with enum members preserved exactly.
print(fake(Product, as_dict=False))
[Product(color=<Color.GREEN: 'green'>, maybe_color=None)]

Nullable / Optional Literals & Enums

If the annotation is Optional[...] or a union including None, the resolver marks the field as nullable and the registry may return None for that field. The current registry logic uses a probability check (rng.random() < 0.2) so None is produced roughly 20% of the time when a field is nullable.

from typing import Optional
from pydantic import BaseModel
from pyfake import fake

class Maybe(BaseModel):
    opt_literal: Optional[Literal['x', 'y']]
    opt_enum: Optional[Color]

print(fake(Maybe, num=6, seed=1))
[
{'opt_literal': None, 'opt_enum': 'red'},
{'opt_literal': 'x', 'opt_enum': None},
{'opt_literal': None, 'opt_enum': None},
...
]

Note: None probability is controlled by the registry and may change in future versions; present behaviour is ~20% when a union is nullable.


Defaults and explicit values

If you provide a non-None default for a field (e.g. Field(default=...) or a default on the dataclass), pyfake will return that default instead of generating a value. This applies to literals and enums as well.

from pydantic import Field

class WithDefault(BaseModel):
    color: Color = Field(default=Color.GREEN)

print(fake(WithDefault))
{'color': <Color.GREEN: 'green'>}

The registry checks GeneratorArgs.default before generation and honors explicit defaults.


Use cases & variations

  • Literal constrained APIs: Literal is great for small sets of fixed strings or numbers (status flags, small enums where you don't want to define a full Enum class).
  • Enum classes: preferred when you want a named set of choices that are reused across models and benefit from names and methods.
  • Mixed unions: Literal and Enum can appear inside unions with other types; each variant is resolved and generated independently.

Examples:

  • Literal with numeric choices:
class NumChoice(BaseModel):
    level: Literal[0, 1, 2]

print(fake(NumChoice))
  • Enum with integer values:
class Code(Enum):
    OK = 0
    FAIL = 1

class HasCode(BaseModel):
    code: Code

print(fake(HasCode))

Implementation notes (what the code does)

  • Resolver: pyfake.core.resolver.Resolver recognises Literal annotations and Enum types and builds a schema node. For enums the resolver stores the list of underlying values in schema['values'].
  • Registry generation: pyfake.core.registry.GeneratorRegistry._generate handles both cases:
  • literal: returns rng.choice(schema['values']).
  • enum: returns rng.choice(schema['values']) (the underlying value). Pydantic then constructs the model and coerces values to Enum members when building the instance.
  • default: if GeneratorArgs.default is set it is returned before any generation logic.
  • Nullable unions: registry checks schema.get('nullable') and returns None when RNG triggers (current threshold ~0.2).

Examples & limitations

  • Field(..., examples=...) values are captured by the resolver into GeneratorArgs.examples, but generators currently do not automatically prefer examples for enums/literals — this metadata is available for future heuristics or for custom registry logic.
  • If you need to bias generation towards certain enum members or literal choices, register a custom generator or post-process results.