This tool generates Python @dataclass definitions from a sample JSON value in your browser; nothing leaves your machine. The generated code is a starting point — it captures the shape of the JSON, not the validation rules behind it.
The basic mapping
JSON:
{
"name": "Alice",
"age": 30,
"active": true
}
Generated Python:
from dataclasses import dataclass
@dataclass
class Root:
name: str
age: int
active: bool
Three things happen:
- Field name. Same as the JSON key — Python conventionally uses
snake_casefor fields, which matches the most common JSON convention. - Type hint. Inferred from the value. String →
str, integer →int, decimal →float, boolean →bool, null →Optional[T], list →list[T], object → nested dataclass. - No defaults by default. Fields are required positional arguments unless declared with a default.
Number type inference
| JSON | Inferred Python |
|---|---|
42 | int |
42.0 | float |
42.5 | float |
1e10 | float |
The trap: if your sample has 42 (int) but production data sometimes has 42.5 (float), the generated int field will fail to construct. Float is safer for “any numeric” use.
Optional fields
JSON null and missing keys both suggest optionality. From a single sample the generator can’t see missing keys, and a null tells it nothing about the real type, so it emits Optional[Any] for a null field — with no default. Refine it by hand to Optional[T] (which is Union[T, None]) with a default:
from dataclasses import dataclass
from typing import Optional
@dataclass
class User:
name: str
email: Optional[str] = None # email was null in some sample
nickname: Optional[str] = None # nickname was missing in some sample
Default values let the dataclass be constructed without those fields.
In modern Python (3.10+), Optional[T] can be written as T | None:
@dataclass
class User:
name: str
email: str | None = None
The tool above emits the Optional[...] form, which works on every Python 3 version with dataclasses; switch to T | None by hand if you’re on 3.10+. (It does use the built-in list[...] generic, so the output needs Python 3.9 or later.)
Nested objects
JSON:
{
"user": {
"name": "Alice",
"address": {
"city": "NYC"
}
}
}
Generated Python:
@dataclass
class Address:
city: str
@dataclass
class User:
name: str
address: Address
@dataclass
class Root:
user: User
Each nested object becomes its own dataclass. The order of definitions is leaf-first (Address before User before Root) so each class refers to types defined earlier.
Lists
JSON: [1, 2, 3]
Python: list[int]
JSON: [{"name": "Alice"}]
Python: list[Item] (with Item being the inferred dataclass)
The element type is inferred from the first element.
For mixed-type lists ([1, "two", 3]), the inferred type is list (untyped) or list[Union[int, str]]. Most JSON-from-the-wild has homogeneous lists, but check your data.
What dataclass doesn’t give you for free
A @dataclass is a data carrier, not a validator. It accepts any value of the declared type — and Python’s type hints are not enforced at runtime. User(name=42) constructs fine, even though 42 isn’t a str.
For runtime validation:
- Pydantic — validates types on construction, coerces where appropriate, raises on mismatch.
- attrs with validators — similar to dataclass with optional runtime validators.
- TypedDict + manual validation — for cases where you want a dict-shaped value, not a class instance.
The tool above generates plain dataclasses. To switch to Pydantic, change @dataclass to class XxxModel(BaseModel): (no decorator needed) and Pydantic handles validation.
Deserializing JSON into a dataclass
Plain dataclasses don’t deserialize JSON automatically. You need:
import json
from dataclasses import dataclass
@dataclass
class User:
name: str
age: int
# Manual:
data = json.loads('{"name": "Alice", "age": 30}')
user = User(**data)
For nested structures, manual deserialization gets cumbersome. Options:
dacite—dacite.from_dict(data_class=User, data=data)walks the structure recursively.mashumaro— addsfrom_dictandto_dictmethods to dataclasses.pydantic—User.model_validate(data)validates and constructs.
For small projects, manual deserialization is fine. For anything with deep nesting or polymorphism, use a library.
Field name issues
JSON keys can contain characters Python identifiers can’t: -, ., leading digits, reserved words. The tool above sanitizes:
JSON: {"first-name": "Alice", "1st_choice": "blue"}
Python:
@dataclass
class Root:
first_name: str # hyphen → underscore
_1st_choice: str # leading digit → prefixed with _
This loses the JSON key. To preserve it, libraries like pydantic and mashumaro allow per-field aliases:
class User(BaseModel):
first_name: str = Field(alias="first-name")
Common pitfalls
- Single-sample inference. Capture variations: with optional fields present and absent, with
null, with empty lists, etc. The generator can only see what’s in the sample. intthat should befloat. If you can’t guarantee the value is always a whole number, declarefloat.- Heterogeneous list types.
list[Union[int, str]]is unusual in real APIs but possible. Generation tools usually default to the first element’s type. - Reserved-word field names.
class,from,import,for,if,def,return— JSON keys with these names can’t be Python field names. The tool appends an underscore (class_,from_). - Plain dataclass vs validated. A dataclass without validation accepts wrong types silently. For trustworthy parsing, switch to Pydantic or add manual validation.
- Forgetting to handle missing keys. Optional with a default lets
User(**data)work whenemailis missing; without the default, KeyError or TypeError on construction.
For other JSON-to-language conversions, see JSON to TypeScript, JSON to Go struct.