Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Add generic omit_if to support more than just omit_if_default #643

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
Loading
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
lint
  • Loading branch information
redruin1 committed Apr 2, 2025
commit 9f8b9dcff6583b6c987596b5d2e07ac07e179351
2 changes: 1 addition & 1 deletion 2 bench/test_attrs_omit_defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import attr
import pytest

from cattr import BaseConverter, Converter, UnstructureStrategy
from cattr import Converter, UnstructureStrategy


class E(IntEnum):
Expand Down
8 changes: 6 additions & 2 deletions 8 src/cattrs/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from pathlib import Path
from typing import Any, Optional, Tuple, TypeVar, overload

from attrs import Attribute, Factory, resolve_types
from attrs import Attribute, resolve_types
from attrs import has as attrs_has

from ._compat import (
Expand Down Expand Up @@ -1248,7 +1248,11 @@ def gen_unstructure_attrs_fromdict(
}

return make_dict_unstructure_fn(
cl, self, _cattrs_omit_if_default=self.omit_if_default, _cattrs_omit_if=self.omit_if, **attrib_overrides
cl,
self,
_cattrs_omit_if_default=self.omit_if_default,
_cattrs_omit_if=self.omit_if,
**attrib_overrides,
)

def gen_unstructure_optional(self, cl: type[T]) -> Callable[[T], Any]:
Expand Down
21 changes: 9 additions & 12 deletions 21 src/cattrs/gen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,7 @@ def override(
:param omit: Whether to skip the field or not. `None` means apply default handling.
"""
return AttributeOverride(
omit_if_default,
rename,
location,
omit,
omit_if,
struct_hook,
unstruct_hook
omit_if_default, rename, location, omit, omit_if, struct_hook, unstruct_hook
)


Expand Down Expand Up @@ -101,7 +95,7 @@ def make_dict_unstructure_fn_from_attrs(
module name and qualname.
:param _cattrs_omit_if_default: If true, attributes equal to their default values
will be omitted in the result dictionary.
:param _cattrs_omit: Omits the attribute (at runtime) if the passed-in value
:param _cattrs_omit: Omits the attribute (at runtime) if the passed-in value
evaluates to true.
:param _cattrs_use_alias: If true, the attribute alias will be used as the
dictionary key by default.
Expand Down Expand Up @@ -195,14 +189,18 @@ def make_dict_unstructure_fn_from_attrs(
lines.append(f" if instance.{attr_name} != {def_name}:")
lines.append(f" res['{kn}'] = {invoke}")

elif omit_if: # callable
elif omit_if: # callable
omit_callable = f"__c_omit_{attr_name}"
attr_attr = f"__c_attr_{attr_name}"

lines.append(f" if not {omit_callable}(instance, {attr_attr}, instance.{attr_name}):")
lines.append(
f" if not {omit_callable}(instance, {attr_attr}, instance.{attr_name}):"
)
lines.append(f" res['{kn}'] = {invoke}")

globs[omit_callable] = omit_if # _cattrs_omit_if if override.omit_if is None else override.omit_if
globs[omit_callable] = (
omit_if # _cattrs_omit_if if override.omit_if is None else override.omit_if
)
globs[attr_attr] = a

else:
Expand Down Expand Up @@ -235,7 +233,6 @@ def make_dict_unstructure_fn_from_attrs(

return res

_never = lambda instance, attribute, value: False

def make_dict_unstructure_fn(
cl: type[T],
Expand Down
6 changes: 4 additions & 2 deletions 6 src/cattrs/gen/_consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
class AttributeOverride:
omit_if_default: bool | None = None
rename: str | None = None
location: str | tuple[str] | None = None,
location: str | tuple[str] | None = (None,)
omit: bool | None = None # Omit the field completely.
omit_if: Callable[[Any, Any, Any], bool] | bool | None = None # Omit if callable returns True.
omit_if: Callable[[Any, Any, Any], bool] | bool | None = (
None # Omit if callable returns True.
)
struct_hook: Callable[[Any, Any], Any] | None = None # Structure hook to use.
unstruct_hook: Callable[[Any], Any] | None = None # Structure hook to use.

Expand Down
17 changes: 9 additions & 8 deletions 17 tests/test_gen_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,29 +295,30 @@ class Example:
c: int = 123
d: set = field(factory=set)
e: int = field()

@e.default
def e_default(self) -> int:
return self.c

overridden: bool = None

def default_or_none(instance, attribute, value):
if value is None:
return True
elif isinstance(attribute.default, Factory):
if isinstance(attribute.default, Factory):
if attribute.default.takes_self:
return value == attribute.default.factory(instance)
else:
return value == attribute.default.factory()
else:
return value == attribute.default
return value == attribute.default.factory()
return value == attribute.default

converter.register_unstructure_hook(
Example, make_dict_unstructure_fn(
Example,
make_dict_unstructure_fn(
Example,
converter,
_cattrs_omit_if=default_or_none,
overridden=override(omit_if=False)
)
overridden=override(omit_if=False),
),
)

assert converter.unstructure(Example(100, None)) == {"a": 100, "overridden": None}
Expand Down
Morty Proxy This is a proxified and sanitized view of the page, visit original site.