CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-dataclasses-json

Easily serialize dataclasses to and from JSON.

Pending
Overview
Eval results
Files

undefined-parameters.mddocs/

Undefined Parameter Handling

Strategies for handling JSON fields that don't correspond to dataclass fields during deserialization. The library provides three approaches: raising exceptions, ignoring extra fields, or capturing them in a designated catch-all field.

Capabilities

Undefined Behavior Enum

The Undefined enum defines the available strategies for handling undefined parameters.

class Undefined(Enum):
    """
    Enumeration of strategies for handling undefined parameters during deserialization.
    """
    INCLUDE = ...   # Store undefined parameters in a CatchAll field
    RAISE = ...     # Raise UndefinedParameterError for any undefined parameters  
    EXCLUDE = ...   # Ignore undefined parameters silently

Usage example:

from dataclasses import dataclass
from dataclasses_json import dataclass_json, Undefined

@dataclass_json(undefined=Undefined.EXCLUDE)
@dataclass
class Person:
    name: str
    age: int

# JSON with extra field - will be ignored
json_data = '{"name": "Alice", "age": 30, "extra_field": "ignored"}'
person = Person.from_json(json_data)  # Works fine, extra_field ignored

CatchAll Field Type

The CatchAll type annotation designates a field to receive undefined parameters when using Undefined.INCLUDE.

# Type variable for catch-all fields (bound to Mapping)
CatchAllVar = TypeVar("CatchAllVar", bound=Mapping)
CatchAll = Optional[CatchAllVar]

Usage example:

from dataclasses import dataclass, field
from dataclasses_json import dataclass_json, Undefined, CatchAll

@dataclass_json(undefined=Undefined.INCLUDE)
@dataclass
class FlexibleData:
    name: str
    age: int
    # This field will receive all undefined parameters
    extra_data: CatchAll = field(default_factory=dict)

# JSON with extra fields
json_data = '{"name": "Bob", "age": 25, "city": "NYC", "country": "USA"}'
data = FlexibleData.from_json(json_data)

print(data.name)        # "Bob"
print(data.age)         # 25
print(data.extra_data)  # {"city": "NYC", "country": "USA"}

Undefined Parameter Exception

Exception raised when undefined parameters are encountered with Undefined.RAISE strategy.

class UndefinedParameterError(Exception):
    """
    Raised when undefined parameters are encountered and the current
    undefined parameter handling strategy is set to RAISE.
    
    Inherits from marshmallow.exceptions.ValidationError for consistency
    with the validation system.
    """

Usage example:

from dataclasses import dataclass
from dataclasses_json import dataclass_json, Undefined, UndefinedParameterError

@dataclass_json(undefined=Undefined.RAISE)
@dataclass
class StrictData:
    name: str
    age: int

try:
    # This will raise an exception due to extra field
    json_data = '{"name": "Charlie", "age": 35, "invalid_field": "error"}'
    data = StrictData.from_json(json_data)
except UndefinedParameterError as e:
    print(f"Undefined parameter error: {e}")

Undefined Handling Strategies

EXCLUDE Strategy (Default)

Silently ignores any fields in the JSON that don't correspond to dataclass fields.

@dataclass_json(undefined=Undefined.EXCLUDE)
@dataclass  
class Product:
    name: str
    price: float

# Extra fields are ignored
json_data = '{"name": "Widget", "price": 19.99, "discontinued": true, "vendor": "ACME"}'
product = Product.from_json(json_data)
# Only name and price are used, other fields ignored

Benefits:

  • Robust against API changes that add new fields
  • Simple and predictable behavior
  • No additional storage overhead

Use cases:

  • Consuming third-party APIs that may add fields
  • Backward compatibility when removing fields from dataclass
  • Simple data models where extra data isn't needed

RAISE Strategy

Throws UndefinedParameterError for any undefined fields, ensuring strict data validation.

@dataclass_json(undefined=Undefined.RAISE)
@dataclass
class StrictConfig:
    host: str
    port: int
    ssl_enabled: bool

# This will raise an exception
try:
    json_data = '{"host": "localhost", "port": 8080, "ssl_enabled": true, "timeout": 30}'
    config = StrictConfig.from_json(json_data)
except UndefinedParameterError:
    print("Strict validation failed - unexpected field found")

Benefits:

  • Catches data model mismatches early
  • Ensures complete control over data structure
  • Helps identify API contract violations

Use cases:

  • Configuration files where unexpected fields indicate errors
  • Internal APIs with strict contracts
  • Data validation scenarios requiring complete control

INCLUDE Strategy

Captures undefined parameters in a designated CatchAll field for later processing or storage.

@dataclass_json(undefined=Undefined.INCLUDE)
@dataclass
class ExtensibleRecord:
    id: str
    name: str
    # All undefined fields stored here
    metadata: CatchAll = field(default_factory=dict)

json_data = '{"id": "123", "name": "Test", "tags": ["a", "b"], "priority": "high"}'
record = ExtensibleRecord.from_json(json_data)

print(record.id)        # "123"
print(record.name)      # "Test"  
print(record.metadata)  # {"tags": ["a", "b"], "priority": "high"}

# Can access undefined data
print(record.metadata.get('priority'))  # "high"

Benefits:

  • Preserves all data from JSON input
  • Allows processing of dynamic or unknown fields
  • Enables round-trip serialization without data loss

Use cases:

  • Document stores with flexible schemas
  • Plugin systems with dynamic configuration
  • Data migration scenarios
  • APIs with optional extension fields

Advanced Usage Patterns

Per-Field Undefined Handling

You can specify undefined behavior at the field level using the config function:

from dataclasses import dataclass, field
from dataclasses_json import dataclass_json, config, Undefined

@dataclass_json
@dataclass
class MixedHandling:
    name: str
    # This field has custom undefined handling
    settings: dict = field(metadata=config(undefined=Undefined.RAISE))

Multiple CatchAll Fields

Only one CatchAll field is allowed per dataclass. Attempting to define multiple will raise an error:

@dataclass_json(undefined=Undefined.INCLUDE)
@dataclass
class InvalidMultipleCatchAll:
    name: str
    catch_all_1: CatchAll = field(default_factory=dict)
    catch_all_2: CatchAll = field(default_factory=dict)  # Error!

CatchAll Field Validation

The CatchAll field must be properly typed and have a default:

@dataclass_json(undefined=Undefined.INCLUDE)
@dataclass
class ValidCatchAll:
    name: str
    # Correct: Optional dict with default
    extra: CatchAll = field(default_factory=dict)

@dataclass_json(undefined=Undefined.INCLUDE)  
@dataclass
class InvalidCatchAll:
    name: str
    # Error: Missing default value
    extra: CatchAll

Combining with Schema Validation

Undefined parameter handling works seamlessly with marshmallow schema validation:

@dataclass_json(undefined=Undefined.INCLUDE)
@dataclass
class ValidatedFlexible:
    name: str = field(metadata=config(mm_field=fields.String(required=True)))
    age: int = field(metadata=config(mm_field=fields.Integer(validate=lambda x: x >= 0)))
    extra: CatchAll = field(default_factory=dict)

# Schema validation still applies to defined fields
schema = ValidatedFlexible.schema()
try:
    # This will fail validation (negative age)
    result = schema.loads('{"name": "Test", "age": -5, "city": "NYC"}')
except ValidationError:
    print("Validation failed for defined fields")

Serialization Behavior

When serializing back to JSON, the behavior depends on the strategy used during deserialization:

@dataclass_json(undefined=Undefined.INCLUDE)
@dataclass
class RoundTrip:
    name: str
    extra: CatchAll = field(default_factory=dict)

# Original JSON
original = '{"name": "Test", "city": "NYC", "tags": ["a", "b"]}'
obj = RoundTrip.from_json(original)

# Serialization includes captured fields
serialized = obj.to_json()
# Contains: {"name": "Test", "city": "NYC", "tags": ["a", "b"]}

# Round-trip preservation
restored = RoundTrip.from_json(serialized)
assert restored.extra == {"city": "NYC", "tags": ["a", "b"]}

Install with Tessl CLI

npx tessl i tessl/pypi-dataclasses-json

docs

core-serialization.md

field-configuration.md

global-configuration.md

index.md

undefined-parameters.md

tile.json