Skip to content
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

Added flag enums support #220

Merged
merged 29 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0637ee8
added flag enums support
daler-sz Jan 20, 2024
b23f95f
add allow_single_value, allow_duplicates, allow_compound, by_exact_va…
daler-sz Jan 20, 2024
04e91c2
fix formatting
daler-sz Jan 20, 2024
1ce09cd
Merge remote-tracking branch 'origin/develop' into flag-enums-support
daler-sz Jan 20, 2024
6275bad
resolve merge conflict
daler-sz Jan 20, 2024
23e540d
fix type hint in flag loader
daler-sz Jan 21, 2024
d1fbc15
renamed exception MultipleBadVariant
daler-sz Jan 21, 2024
4f76d94
rename extract_non_compound_cases_from_flag function & inline it
daler-sz Jan 21, 2024
3977a1f
remove partial return in flag loader provider
daler-sz Jan 21, 2024
9807899
fix typehits
daler-sz Jan 21, 2024
372c56b
fix typehints and remove ignores in _get_loader_process_data of flag …
daler-sz Jan 21, 2024
7a80b37
add name mapping for flags
daler-sz Jan 21, 2024
9b3c6b7
flag tests refactoring
daler-sz Jan 22, 2024
2f515d3
rename EnumMappingGenerator
daler-sz Jan 22, 2024
95b53bd
facades for flag provider
daler-sz Jan 22, 2024
b791461
now input_value is the last field of MultipleBadVariant
daler-sz Jan 23, 2024
ca2f4fe
EnumMappingGenerators refactor
daler-sz Jan 23, 2024
a0fdafc
make convert_snake_style work not only with snake_cas
daler-sz Jan 23, 2024
8ae1701
flag facades refactoring
daler-sz Jan 23, 2024
117f3bc
flag provider refactoring
daler-sz Jan 23, 2024
0d77734
add FlagByExactValueProvider
daler-sz Jan 24, 2024
c3fe0bb
name style tests refactoring
daler-sz Jan 24, 2024
36784e3
Merge remote-tracking branch 'origin/develop' into flag-enums-support
daler-sz Jan 25, 2024
53411e0
fix type in TypeLoadError
daler-sz Jan 25, 2024
05354a1
remove flag alias support
daler-sz Jan 25, 2024
47b1421
refactoring && tests improve
daler-sz Jan 26, 2024
2f29f96
flag docs & changelog
daler-sz Jan 26, 2024
f66b269
small changes
daler-sz Jan 26, 2024
f32cd58
small changes
daler-sz Jan 26, 2024
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
4 changes: 4 additions & 0 deletions docs/changelog/fragments/197.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Added flags support

Now adaptix has two different ways to process flags: :func:`.flag_by_exact_value` (by default)
and :func:`.flag_by_member_names`.
13 changes: 12 additions & 1 deletion docs/loading-and-dumping/specific-types-behavior.rst
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,18 @@ timedelta
Loader accepts instance of ``int``, ``float`` or ``Decimal`` representing seconds,
dumper serialize value via ``total_seconds`` method.

Enum subclasses

Flag subclasses
'''''''''''''''''''''''

Flag members by default are represented by their value. Note that flags with skipped
bits and negative values are not supported, so it is highly recommended to define flag
values via enum.auto() instead of manually specifying them.
Besides, adaptix provides another way to process flags: by list using their names.
See: :func:`.flag_by_member_names` for details.


Other Enum subclasses
'''''''''''''''''''''''

Enum members are represented by their value without any conversion.
Expand Down
4 changes: 2 additions & 2 deletions src/adaptix/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
enum_by_name,
enum_by_value,
flag_by_exact_value,
flag_by_list_using_name,
flag_by_member_names,
loader,
name_mapping,
validator,
Expand Down Expand Up @@ -62,7 +62,7 @@
'enum_by_name',
'enum_by_value',
'flag_by_exact_value',
'flag_by_list_using_name',
'flag_by_member_names',
'name_mapping',
'default_dict',
'AdornedRetort',
Expand Down
31 changes: 21 additions & 10 deletions src/adaptix/_internal/morphing/facade/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ def enum_by_value(first_pred: EnumPred, /, *preds: EnumPred, tp: TypeHint) -> Pr

def flag_by_exact_value(*preds: EnumPred) -> Provider:
"""Provider that represents flag members to the outside world by their value without any processing.
It does not support flags with skipped bits and negative values (it is recommended to use enum.auto() to define flag
values instead of manually specifying them).

:param preds: Predicates specifying where the provider should be used.
The provider will be applied if any predicates meet the conditions,
Expand All @@ -369,28 +371,37 @@ def flag_by_exact_value(*preds: EnumPred) -> Provider:
return _wrap_enum_provider(preds, FlagByExactValueProvider())


def flag_by_list_using_name(
def flag_by_member_names(
*preds: EnumPred,
allow_single_value: bool = False,
allow_duplicates: bool = True,
allow_compound: bool = True,
name_style: Optional[NameStyle] = None,
map: Optional[Mapping[Union[str, Enum], str]] = None # noqa: A002
) -> Provider:
"""Provider that represents flag members to the outside world by their name.
"""Provider that represents flag members to the outside world by list of their names.

Loader takes a flag members name list and returns united flag member
(given members combined by operator ``|``, namely `bitwise or`).

Dumper takes a flag member and returns a list of names of flag members, included in the given flag member.

:param preds: Predicates specifying where the provider should be used.
The provider will be applied if any predicates meet the conditions,
if no predicates are passed, the provider will be used for all Flags.
See :ref:`predicate-system` for details.
:param allow_single_value: Specifies if it is allowed to call loader by single value.
If it is allowed and loader called by single value, it will be interpreted as a list with single element.
:param allow_duplicates: Specifies if it is allowed to call loader by list with non-unique elements.
If it is not allowed and loader by list with non-unique elements, ValueError will be raised.
:param allow_compound: Specifies if it is allowed for loader to accept compound values and
if it is allowed for dumper to return compound values.
:param name_style: Name style that represents values to the outside world
:param map: Mapping for values to represent them to the outside world
:param allow_single_value: Allows calling the loader with a single value.
If this is allowed, singlular values are treated as one element list.
:param allow_duplicates: Allows calling the loader with a list containing non-unique elements.
Unless this is allowed, loader will raise :exc:`.DuplicatedValues` in that case.
:param allow_compound: Allows the loader to accept names of compound members
(e.g. ``WHITE = RED | GREEN | BLUE``) and the dumper to return names of compound members.
If this is allowed, dumper will use compound members names to serialize value.
:param name_style: Name style for representing members to the outside world.
If it is set, the provider will automatically convert the names of all flag members to the specified convention.
:param map: Mapping for representing members to the outside world.
If it is set, the provider will use it to rename members individually;
its keys can either be member names as strings or member instances.
:return: desired provider
"""
return _wrap_enum_provider(
Expand Down
6 changes: 6 additions & 0 deletions src/adaptix/load_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
AggregateLoadError,
BadVariantError,
DatetimeFormatMismatch,
DuplicatedValues,
ExcludedTypeLoadError,
ExtraFieldsError,
ExtraItemsError,
LoadError,
LoadExceptionGroup,
MsgError,
MultipleBadVariant,
NoRequiredFieldsError,
NoRequiredItemsError,
OutOfRange,
TypeLoadError,
UnionLoadError,
ValidationError,
Expand All @@ -32,4 +35,7 @@
'ValidationError',
'BadVariantError',
'DatetimeFormatMismatch',
'DuplicatedValues',
'OutOfRange',
'MultipleBadVariant'
)
8 changes: 4 additions & 4 deletions tests/unit/morphing/test_enum_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
Retort,
dumper,
enum_by_value,
flag_by_list_using_name,
flag_by_member_names,
loader,
)
from adaptix._internal.morphing.enum_provider import EnumExactValueProvider, EnumNameProvider
Expand Down Expand Up @@ -262,7 +262,7 @@ def test_flag_by_list_using_name(
strict_coercion=strict_coercion,
debug_trail=debug_trail,
recipe=[
flag_by_list_using_name(
flag_by_member_names(
allow_single_value=allow_single_value,
allow_duplicates=allow_duplicates,
allow_compound=allow_compound
Expand Down Expand Up @@ -331,7 +331,7 @@ def test_flag_by_list_using_name_with_bad_types(
strict_coercion=strict_coercion,
debug_trail=debug_trail,
recipe=[
flag_by_list_using_name(
flag_by_member_names(
allow_single_value=allow_single_value,
allow_duplicates=allow_duplicates,
allow_compound=allow_compound
Expand Down Expand Up @@ -369,7 +369,7 @@ def test_flag_by_list_using_name_with_mapping(strict_coercion, debug_trail):
strict_coercion=strict_coercion,
debug_trail=debug_trail,
recipe=[
flag_by_list_using_name(
flag_by_member_names(
name_style=NameStyle.CAMEL,
map={
"CASE_ONE": "CASE_1",
Expand Down
Loading