Skip to main content

Pydantic BaseModel with flagged fields by name

Project description

pydantic-flagged

PyPI Tests License Black Pyright

pydantic-flagged is a small extension of Pydantic v2 that introduces the concept of flagged fields. A flagged field is defined by its name matching a condition––for example, ending with an underscore (_). Once flagged fields are identified, you can include or exclude them from serialization with a simple API.


Table of Contents


Overview

By default, pydantic-flagged treats any field whose name ends with an underscore as "flagged." Using flagged fields, you can:

  • Exclude them from serialized output (flagged="exclude")
  • Include only flagged fields while dropping all others (flagged="include")

This behavior can be configured and applied to an entire model class, or dynamically at serialization time via model_dump or model_dump_json.


Installation

pip install pydantic-flagged

Make sure you're using Pydantic v2 or higher. If you rely on Pydantic v1, this package will not work as expected.


Quick Start

Use BaseModelFlagged instead of pydantic.BaseModel. For simplicity, let's assume the default flag rule (names ending in _) and see what happens.

from pydantic_flagged import BaseModelFlagged

class MyModel(BaseModelFlagged):
    one: int = 0
    two_: int = 0  # flagged because it ends with an underscore

print(MyModel().model_dump(flagged="exclude"))
# {'one': 0}

Here, two_ is excluded from the output because we called model_dump(flagged="exclude"). If you switched to flagged="include", only two_ would remain.


Why Flagged Fields?

You might sometimes have fields that you use internally but don’t want to expose externally, or vice versa. Flagging fields and selectively including/excluding them at serialization time can be a convenient way to maintain clarity in your code. While you could accomplish something similar using custom serialization logic, flagged fields make this much simpler and more explicit.


Customization and Class-Level Configuration

pydantic-flagged provides several class-level variables that let you define:

  1. How a field is flagged (model_flagged_fields_define)
  2. When flagged fields are included or excluded by default (model_flagged_fields_ser_mode)
  3. Which context key signals flagged behavior at dump time (model_flagged_fields_ser_mode_context_key)

Define Your Own Flag Rules

Instead of always relying on the default rule (names ending in _), you can set model_flagged_fields_define to:

  • A callable that takes a field name and returns a boolean
  • A set or list or tuple of field names (only those in this collection are flagged)

Example:

class MyModel(BaseModelFlagged):
    model_flagged_fields_define = ["secret_field", "debug_field"]
    secret_field: int = 42
    debug_field: str = "verbose logs"
    normal_field: bool = True

m = MyModel()
print(m.model_flagged_fields.keys())
# dict_keys(['secret_field', 'debug_field'])

Class-Level Default Serialization Mode

If you want to always exclude flagged fields by default, set:

class Child(BaseModelFlagged):
    model_flagged_fields_define = lambda name: name.endswith("_")
    model_flagged_fields_ser_mode = "exclude"

    one: int = 0
    two_: int = 0  # flagged

child = Child()
print(child.model_dump())
# {'one': 0}

Even if you embed Child in a larger model, this class-level setting applies to the Child instance automatically (though you can still override at dump time).

Customization via Context Keys

By default, pydantic-flagged looks for a context key named "flagged" when deciding how to handle flagged fields. If you want to allow multiple different types of flagged models in your hierarchy––all with different rules––you can rename this key per class:

class Color(BaseModelFlagged):
    model_flagged_fields_ser_mode_context_key = "color_flagged"
    # ...

Then, in your model_dump, you can pass a context dict that contains different keys for each model type:

big_model_instance.model_dump(
    context={
        "flagged": "exclude",       # affects normal flagged classes
        "color_flagged": "include"  # specifically for Color
    }
)

Nested Models

If you embed a BaseModelFlagged subclass inside another model, its class-level default serialization mode (if any) still applies. However, you can override it at the time of serialization by passing either:

  1. The flagged parameter directly (.model_dump(flagged="exclude")), which will override for that specific instance.
  2. A context dictionary (.model_dump(context={"flagged": "include"})), which will cascade through nested flagged models that share the same model_flagged_fields_ser_mode_context_key.

Example

import pydantic
from pydantic_flagged import BaseModelFlagged

class Child(BaseModelFlagged):
    model_flagged_fields_define = lambda name: name.endswith("_")
    model_flagged_fields_ser_mode = "exclude"
    visible: int = 0
    invisible_: int = 0

class Parent(pydantic.BaseModel):
    child: Child = Child()

# Default: the child's "exclude" rule hides `invisible_`.
print(Parent().model_dump())
# {'child': {'visible': 0}}

# Override: now we *include* flagged fields for all flagged models in this hierarchy
print(Parent().model_dump(flagged="include"))
# {'child': {'invisible_': 0}}

Advanced Usage Examples

Here are some real-world patterns from the tests:

from pydantic_flagged import BaseModelFlagged
import pydantic

class Point(BaseModelFlagged):
    # Exclude flagged by default
    model_flagged_fields_define = lambda name: name.endswith("_")
    model_flagged_fields_ser_mode = "exclude"
    x: int = 0
    y_: int = 0  # flagged

class Color(BaseModelFlagged):
    # We'll define a custom key for flagged logic
    model_flagged_fields_define = lambda name: name.endswith("_")
    model_flagged_fields_ser_mode_context_key = "color_flagged"
    r: int = 0
    g_: int = 0  # flagged
    b_: int = 0  # flagged

print(Point().model_dump())             # {'x': 0}
print(Color().model_dump(flagged="include"))  # {'g_': 0, 'b_': 0}

class Stuff(pydantic.BaseModel):
    point: Point = Point()
    color: Color = Color()

# We pass a context that includes instructions for *both* standard flagged fields
# and the "color_flagged" fields.
print(
    Stuff().model_dump(
        context={
            "flagged": "include",         # for Point
            "color_flagged": "exclude"    # for Color
        }
    )
)
# {'point': {'y_': 0}, 'color': {'r': 0}}

Contributing

Contributions are welcome! Feel free to open issues, suggest ideas, or submit pull requests on GitHub. Please run tests and format your code with black before submitting any PRs.

Running Tests

pytest tests

License

This project is licensed under the MIT License.
© 2023-present Ryan Young. All rights reserved.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pydantic_flagged-0.0.1.tar.gz (10.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pydantic_flagged-0.0.1-py2.py3-none-any.whl (8.4 kB view details)

Uploaded Python 2Python 3

File details

Details for the file pydantic_flagged-0.0.1.tar.gz.

File metadata

  • Download URL: pydantic_flagged-0.0.1.tar.gz
  • Upload date:
  • Size: 10.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for pydantic_flagged-0.0.1.tar.gz
Algorithm Hash digest
SHA256 7394927bff1612798d12a682760337da68dd2e7ea25aba7f55851d5f29f15109
MD5 fcdffad8d55a28d64bf6e654ce8026fc
BLAKE2b-256 a07c4bcbacfc4dcfdfd00b779faa0bce95e9fa10ac8380c430c07a8259a9a6f5

See more details on using hashes here.

File details

Details for the file pydantic_flagged-0.0.1-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for pydantic_flagged-0.0.1-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 27becbc7533909c92218ca4f614b03cf5f0b7d6cb45aecf733b36b94c30b517f
MD5 276b5bc3f4a10663ec47ead3fc458123
BLAKE2b-256 baffbcdb6847e16abf2bf47fd6d14504ab7b42ee4730c8380362d4e36f22c63b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page