Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 2 additions & 2 deletions examples/ex_01_flext_result_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ def side_effects_and_folds(self) -> None:
self.audit_check("map_or.success_default", ok_value.map_or(0))
self.audit_check("map_or.failure_default", fail_value.map_or(0))
self.audit_check(
"map_or.success_func", ok_value.map_or("none", lambda n: f"n={n}")
"map_or.success_func", ok_value.map_or("none", "n={}".format)
)
self.audit_check(
"map_or.failure_func", fail_value.map_or("none", lambda n: f"n={n}")
"map_or.failure_func", fail_value.map_or("none", "n={}".format)
)
self.audit_check(
"fold.success",
Expand Down
14 changes: 12 additions & 2 deletions src/flext_core/_handlers_parts/flexthandlers_part_07.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,11 @@ def scan_class(
for name in dir(target_class)
if hasattr(method := getattr(target_class, name, None), c.HANDLER_ATTR)
]
return sorted(handlers, key=lambda x: x[1].priority, reverse=True)

def priority(item: tuple[str, p.DecoratorConfig]) -> int:
return item[1].priority

return sorted(handlers, key=priority, reverse=True)

@staticmethod
def scan_module(
Expand Down Expand Up @@ -135,7 +139,13 @@ def narrowed_func(

setattr(narrowed_func, c.HANDLER_ATTR, settings)
handlers.append((name, narrowed_func, settings))
return sorted(handlers, key=lambda x: (-x[2].priority, x[0]))

def priority_and_name(
item: tuple[str, Callable[..., t.Scalar | None], p.DecoratorConfig],
) -> tuple[int, str]:
return -item[2].priority, item[0]

return sorted(handlers, key=priority_and_name)


__all__: list[str] = ["FlextHandlers"]
8 changes: 6 additions & 2 deletions src/flext_core/_lazy_parts/flextlazy_part_02.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

import sys
from functools import partial
from types import ModuleType
from typing import TYPE_CHECKING, cast

Expand Down Expand Up @@ -207,8 +208,11 @@ def install(
names = tuple(dict.fromkeys((*normalized, *all_exports)))

module_globals["_LAZY_IMPORTS"] = normalized
module_globals["__getattr__"] = lambda name: self.get(
name, normalized, module_globals, module_name
module_globals["__getattr__"] = partial(
self.get,
lazy_imports=normalized,
module_globals=module_globals,
module_name=module_name,
)
module_globals["__dir__"] = lambda: list(names)
if publish_all:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
title="Attributes",
examples=[{"source": "api", "priority": "high"}],
),
] = mp.Field(default_factory=lambda: MappingProxyType({}))
] = mp.Field(default_factory=lambda: MappingProxyType(dict[str, t.JsonValue]()))

Check warning on line 108 in src/flext_core/_models/_base_parts/flextmodelsbase_part_02.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=flext-sh_flext-core&issues=AaBJpcor4Lrhi2iBwyqN&open=AaBJpcor4Lrhi2iBwyqN&pullRequest=412
metadata_value: Annotated[
t.Scalar | None,
mp.Field(default=None, description="Scalar metadata value."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
mp.Field(
description="Additional metric counters and timing values grouped by metric key."
),
] = mp.Field(default_factory=lambda: MappingProxyType({}))
] = mp.Field(default_factory=lambda: MappingProxyType(dict[str, t.JsonValue]()))

Check warning on line 68 in src/flext_core/_models/_context/__scope_parts/flextmodelscontextscope_part_01.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=flext-sh_flext-core&issues=AaBJpcl54Lrhi2iBwyqE&open=AaBJpcl54Lrhi2iBwyqE&pullRequest=412


__all__: list[str] = ["FlextModelsContextScope"]
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,16 @@
hooks: Annotated[
t.ContextHookMap,
mp.Field(
default_factory=lambda: MappingProxyType({}),
default_factory=lambda: MappingProxyType(
dict[str, t.SequenceOf[t.ContextHookCallable]]()

Check warning on line 38 in src/flext_core/_models/_context/__scope_parts/flextmodelscontextscope_part_02.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=flext-sh_flext-core&issues=AaBJpcn64Lrhi2iBwyqF&open=AaBJpcn64Lrhi2iBwyqF&pullRequest=412
),
description="Lifecycle hooks keyed by event name",
),
] = mp.Field(default_factory=lambda: MappingProxyType({}))
] = mp.Field(
default_factory=lambda: MappingProxyType(
dict[str, t.SequenceOf[t.ContextHookCallable]]()

Check warning on line 44 in src/flext_core/_models/_context/__scope_parts/flextmodelscontextscope_part_02.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=flext-sh_flext-core&issues=AaBJpcn64Lrhi2iBwyqG&open=AaBJpcn64Lrhi2iBwyqG&pullRequest=412
)
)
statistics: Annotated[
FlextModelsContextScopePart01.ContextStatistics,
mp.Field(
Expand All @@ -63,10 +69,21 @@
str, contextvars.ContextVar[FlextModelsContainers.ConfigMap | None]
],
mp.Field(
default_factory=lambda: MappingProxyType({}),
default_factory=lambda: MappingProxyType(
dict[
str,
contextvars.ContextVar[FlextModelsContainers.ConfigMap | None],
]()

Check warning on line 76 in src/flext_core/_models/_context/__scope_parts/flextmodelscontextscope_part_02.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=flext-sh_flext-core&issues=AaBJpcn64Lrhi2iBwyqH&open=AaBJpcn64Lrhi2iBwyqH&pullRequest=412
),
description="ContextVar registry keyed by scope name",
),
] = mp.Field(default_factory=lambda: MappingProxyType({}))
] = mp.Field(
default_factory=lambda: MappingProxyType(
dict[
str, contextvars.ContextVar[FlextModelsContainers.ConfigMap | None]
]()

Check warning on line 84 in src/flext_core/_models/_context/__scope_parts/flextmodelscontextscope_part_02.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=flext-sh_flext-core&issues=AaBJpcn64Lrhi2iBwyqI&open=AaBJpcn64Lrhi2iBwyqI&pullRequest=412
)
)

@classmethod
def create_default(
Expand Down
4 changes: 2 additions & 2 deletions src/flext_core/_models/_context/_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
data: Annotated[
t.MappingKV[str, t.JsonPayload],
Field(
default_factory=lambda: MappingProxyType({}),
default_factory=lambda: MappingProxyType(dict[str, t.JsonPayload]()),

Check warning on line 33 in src/flext_core/_models/_context/_export.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=flext-sh_flext-core&issues=AaBJpcoK4Lrhi2iBwyqJ&open=AaBJpcoK4Lrhi2iBwyqJ&pullRequest=412
description="All context data from all scopes",
),
]
Expand All @@ -52,7 +52,7 @@
)
),
Field(
default_factory=lambda: MappingProxyType({}),
default_factory=lambda: MappingProxyType(dict[str, t.JsonValue]()),

Check warning on line 55 in src/flext_core/_models/_context/_export.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=flext-sh_flext-core&issues=AaBJpcoK4Lrhi2iBwyqK&open=AaBJpcoK4Lrhi2iBwyqK&pullRequest=412
description="Usage statistics (operation counts, timing info)",
),
]
Expand Down
6 changes: 3 additions & 3 deletions src/flext_core/_models/cqrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
title="Query Filters",
examples=[{"status": "active", "tenant": "acme"}],
),
] = Field(default_factory=lambda: MappingProxyType({}))
] = Field(default_factory=lambda: MappingProxyType(dict[str, t.Scalar]()))

Check warning on line 133 in src/flext_core/_models/cqrs.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=flext-sh_flext-core&issues=AaBJpcp34Lrhi2iBwyqO&open=AaBJpcp34Lrhi2iBwyqO&pullRequest=412
pagination: Annotated[
_CqrsPagination,
Field(
Expand Down Expand Up @@ -238,11 +238,11 @@
] = Field(default_factory=lambda: _u().generate_prefixed_id("evt"))
data: Annotated[
t.MappingKV[str, t.Scalar], Field(description="Event payload data")
] = Field(default_factory=lambda: MappingProxyType({}))
] = Field(default_factory=lambda: MappingProxyType(dict[str, t.Scalar]()))

Check warning on line 241 in src/flext_core/_models/cqrs.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=flext-sh_flext-core&issues=AaBJpcp34Lrhi2iBwyqP&open=AaBJpcp34Lrhi2iBwyqP&pullRequest=412
metadata: Annotated[
t.MappingKV[str, t.Scalar],
Field(description="Event metadata (timestamps, correlation IDs, etc.)"),
] = Field(default_factory=lambda: MappingProxyType({}))
] = Field(default_factory=lambda: MappingProxyType(dict[str, t.Scalar]()))

Check warning on line 245 in src/flext_core/_models/cqrs.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=flext-sh_flext-core&issues=AaBJpcp34Lrhi2iBwyqQ&open=AaBJpcp34Lrhi2iBwyqQ&pullRequest=412

type FlextMessage = t.MessageUnion[Command, Query, Event]

Expand Down
4 changes: 2 additions & 2 deletions src/flext_core/_models/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
exception_counts: Annotated[
t.IntMapping,
mp.Field(description="Per-exception occurrence totals keyed by type name."),
] = mp.Field(default_factory=lambda: MappingProxyType({}))
] = mp.Field(default_factory=lambda: MappingProxyType(dict[str, int]()))

Check warning on line 31 in src/flext_core/_models/errors.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=flext-sh_flext-core&issues=AaBJpcoa4Lrhi2iBwyqL&open=AaBJpcoa4Lrhi2iBwyqL&pullRequest=412
exception_counts_summary: Annotated[
str,
mp.Field(description="Human-readable summary for logs and diagnostics."),
Expand Down Expand Up @@ -61,7 +61,7 @@
exception_counts: Annotated[
t.IntMapping,
mp.Field(description="Recorded counts keyed by exception type name."),
] = mp.Field(default_factory=lambda: MappingProxyType({}))
] = mp.Field(default_factory=lambda: MappingProxyType(dict[str, int]()))

Check warning on line 64 in src/flext_core/_models/errors.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this constructor call with a literal.

See more on https://sonarcloud.io/project/issues?id=flext-sh_flext-core&issues=AaBJpcoa4Lrhi2iBwyqM&open=AaBJpcoa4Lrhi2iBwyqM&pullRequest=412

@up.computed_field
@property
Expand Down
29 changes: 20 additions & 9 deletions src/flext_core/_models/pydantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from pathlib import Path
from re import Pattern
from types import EllipsisType
from typing import dataclass_transform
from typing import Literal, dataclass_transform

from pydantic import (
AfterValidator,
Expand All @@ -36,7 +36,7 @@
JsonValue,
PlainSerializer,
PlainValidator,
PrivateAttr,
PrivateAttr as PydanticPrivateAttr,
RootModel as PydanticRootModel,
SkipValidation,
TypeAdapter as PydanticTypeAdapter,
Expand Down Expand Up @@ -82,6 +82,17 @@
return field_factory(default, **kwargs)


def _private_attr[PrivateT](
default: PrivateT | PydanticUndefinedType = PydanticUndefined,
*,
default_factory: Callable[..., PrivateT] | None = None,
init: Literal[False] = False,
) -> PrivateT:
"""Typed FLEXT facade for ``pydantic.PrivateAttr``."""
private_attr_factory: Callable[..., PrivateT] = PydanticPrivateAttr
return private_attr_factory(default, default_factory=default_factory, init=init)


class FlextModelsPydantic:
"""Public base model classes from pydantic v2.

Expand All @@ -94,19 +105,22 @@
"""

@dataclass_transform(
kw_only_default=True, field_specifiers=(_field, Field, PrivateAttr)
kw_only_default=True,
field_specifiers=(_field, Field, PydanticPrivateAttr, _private_attr),
)
class BaseModel(PydanticBaseModel):
"""Canonical BaseModel exported through the FLEXT models facade."""

@dataclass_transform(
kw_only_default=True, field_specifiers=(_field, Field, PrivateAttr)
kw_only_default=True,
field_specifiers=(_field, Field, PydanticPrivateAttr, _private_attr),
)
class BaseSettings(PydanticBaseSettings):
"""Canonical BaseSettings exported through the FLEXT models facade."""

@dataclass_transform(
kw_only_default=True, field_specifiers=(_field, Field, PrivateAttr)
kw_only_default=True,
field_specifiers=(_field, Field, PydanticPrivateAttr, _private_attr),
)
class RootModel[RootValueT](PydanticRootModel[RootValueT]):
"""Canonical RootModel exported through the FLEXT models facade."""
Expand All @@ -116,10 +130,7 @@
SettingsConfigDict = _PydanticSettingsConfigDict

Field = staticmethod(_field)
# NOTE (multi-agent): mro-ecfu — staticmethod wrap matches Field above and
# u.PrivateAttr (_utilities/pydantic.py): pyright cannot model an unwrapped
# function class attribute called through the facade (mixins.py:59 error).
PrivateAttr = staticmethod(PrivateAttr)
PrivateAttr = staticmethod(_private_attr)

Check warning on line 133 in src/flext_core/_models/pydantic.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rename this field "PrivateAttr" to match the regular expression ^[_a-z][_a-z0-9]*$.

See more on https://sonarcloud.io/project/issues?id=flext-sh_flext-core&issues=AaBJoABmQxu_Ts8rDUs5&open=AaBJoABmQxu_Ts8rDUs5&pullRequest=412
SkipValidation = SkipValidation
# Same unwrapped-class-attribute problem as PrivateAttr above: pyright
# binds the bare decorator through the facade and infers the facade type
Expand Down
31 changes: 28 additions & 3 deletions src/flext_core/_runtime/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,32 @@

from __future__ import annotations

from ._container import FlextRuntimeContainer
from ._dependency import FlextRuntimeDependencyIntegration
from types import MappingProxyType
from typing import TYPE_CHECKING

__all__: list[str] = ["FlextRuntimeContainer", "FlextRuntimeDependencyIntegration"]
from flext_core.lazy import build_lazy_import_map, install_lazy_exports

if TYPE_CHECKING:
from ._container import FlextRuntimeContainer
from ._dependency import FlextRuntimeDependencyIntegration

__all__: tuple[str, ...] = (
"FlextRuntimeContainer",
"FlextRuntimeDependencyIntegration",
)

install_lazy_exports(
__name__,
globals(),
MappingProxyType(
build_lazy_import_map(
MappingProxyType({
"._container": ("FlextRuntimeContainer",),
"._dependency": ("FlextRuntimeDependencyIntegration",),
}),
alias_groups=MappingProxyType({}),
sort_keys=False,
)
),
public_exports=__all__,
)
Original file line number Diff line number Diff line change
Expand Up @@ -49,25 +49,19 @@ def _parse_try_direct[T](
if isinstance(value, target):
return value
target_name = target.__name__ if hasattr(target, "__name__") else "type"
parsed_direct: T = (
FlextUtilitiesModel
.validate_value(target, value)
.fold(
lambda error: FlextUtilitiesParserTargets._parse_with_default(
default,
default_factory,
c.ERR_PARSER_CANNOT_PARSE_TO_TARGET.format(
field_prefix=fp,
source_type=value.__class__.__name__,
target_name=target_name,
error=error,
),
),
lambda validated: validated,
)
.unwrap()
)
return parsed_direct
validation = FlextUtilitiesModel.validate_value(target, value)
if validation.success:
return validation.value
return FlextUtilitiesParserTargets._parse_with_default(
default,
default_factory,
c.ERR_PARSER_CANNOT_PARSE_TO_TARGET.format(
field_prefix=fp,
source_type=value.__class__.__name__,
target_name=target_name,
error=validation.error,
),
).unwrap()

@staticmethod
@r.safe
Expand Down
4 changes: 2 additions & 2 deletions src/flext_core/_utilities/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
FlextConstants as c,
FlextProtocols as p,
FlextResult as r,
FlextRuntime,
FlextTypes as t,
)
from flext_core._models.containers import FlextModelsContainers as mc
from flext_core._runtime._metadata import FlextRuntimeMetadata

from .collection_iter import FlextUtilitiesCollectionIter
from .collection_merge import FlextUtilitiesCollectionMerge
Expand All @@ -44,7 +44,7 @@ def normalize_domain_event_data(
for key, item in raw_source.items():
if item is None:
continue
normalized[key] = FlextRuntime.normalize_to_metadata(item)
normalized[key] = FlextRuntimeMetadata.normalize_to_metadata(item)
return normalized

@staticmethod
Expand Down
18 changes: 10 additions & 8 deletions src/flext_core/_utilities/collection_merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,9 @@
from collections.abc import Callable, Mapping
from typing import ClassVar, TypeGuard

from flext_core import (
FlextProtocols as p,
FlextResult as r,
FlextRuntime,
FlextTypes as t,
)
from flext_core import FlextProtocols as p, FlextResult as r, FlextTypes as t
from flext_core._constants.cqrs import FlextConstantsCqrs as _c_cqrs
from flext_core._runtime._metadata import FlextRuntimeMetadata
from flext_core._utilities.guards_type_core import FlextUtilitiesGuardsTypeCore


Expand All @@ -40,7 +36,10 @@ def _merge_deep_single_key(
if FlextUtilitiesCollectionMerge._is_json_mapping(
current_val
) and FlextUtilitiesCollectionMerge._is_json_mapping(value):
result[key] = FlextRuntime.normalize_to_metadata({**current_val, **value})
result[key] = FlextRuntimeMetadata.normalize_to_metadata({
**current_val,
**value,
})
return r[bool].ok(True)
result[key] = value
return r[bool].ok(True)
Expand Down Expand Up @@ -87,7 +86,10 @@ def _merge_append(
if FlextUtilitiesCollectionMerge._is_json_list(
current_val
) and FlextUtilitiesCollectionMerge._is_json_list(value):
result[key] = FlextRuntime.normalize_to_metadata([*current_val, *value])
result[key] = FlextRuntimeMetadata.normalize_to_metadata([
*current_val,
*value,
])
continue
result[key] = value
return r[t.JsonMapping].ok(result)
Expand Down
Loading
Loading