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))
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
Enummembers. Whenpyfakereturns dicts (viamodel_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
pyfakereturns dictionaries produced bymodel_dump(); for enums this often containsEnummembers (depending on Pydantic mode). - Use
as_dict=Falseto receive actual Pydantic model instances with enum members preserved exactly.
print(fake(Product, as_dict=False))
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))
The registry checks GeneratorArgs.default before generation and honors explicit defaults.
Use cases & variations
- Literal constrained APIs:
Literalis 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:
LiteralandEnumcan 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.ResolverrecognisesLiteralannotations andEnumtypes and builds a schema node. For enums the resolver stores the list of underlying values inschema['values']. - Registry generation:
pyfake.core.registry.GeneratorRegistry._generatehandles both cases: literal: returnsrng.choice(schema['values']).enum: returnsrng.choice(schema['values'])(the underlying value). Pydantic then constructs the model and coerces values toEnummembers when building the instance.default: ifGeneratorArgs.defaultis set it is returned before any generation logic.- Nullable unions: registry checks
schema.get('nullable')and returnsNonewhen RNG triggers (current threshold ~0.2).
Examples & limitations
Field(..., examples=...)values are captured by the resolver intoGeneratorArgs.examples, but generators currently do not automatically preferexamplesfor 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.