neuroglia-python 0.7.7__tar.gz → 0.7.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/PKG-INFO +1 -1
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/pyproject.toml +1 -1
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/__init__.py +1 -1
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/serialization/json.py +125 -6
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/LICENSE +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/README.md +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/application/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/application/background_scheduler.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/coordination/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/coordination/abstractions.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/coordination/leader_election.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/coordination/redis_backend.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/core/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/core/module_loader.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/core/operation_result.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/core/problem_details.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/core/type_extensions.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/core/type_finder.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/core/type_registry.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/abstractions.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/exceptions.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/abstractions.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/event_sourcing/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/event_sourcing/abstractions.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/event_sourcing/event_sourcing_repository.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/event_sourcing/event_store/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/event_sourcing/event_store/event_store.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/event_sourcing/read_model_reconciliator.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/filesystem/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/filesystem/filesystem_repository.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/memory/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/memory/memory_repository.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/mongo/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/mongo/enhanced_mongo_repository.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/mongo/mongo_repository.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/mongo/motor_query.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/mongo/motor_repository.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/mongo/serialization_helper.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/mongo/typed_mongo_query.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/resources/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/resources/in_memory_storage_backend.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/resources/postgres_resource_store.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/resources/redis_resource_store.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/resources/resource_repository.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/tracing_mixin.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/queries/generic/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/queries/generic/get_by_id_query.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/queries/generic/list_query.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/queryable.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/resources/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/resources/abstractions.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/resources/controller.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/resources/serializers/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/resources/serializers/xml_serializer.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/resources/serializers/yaml_serializer.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/resources/state_machine.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/resources/watcher.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/unit_of_work.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/dependency_injection/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/dependency_injection/service_provider.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/dependency_injection/service_provider_backup.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/eventing/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/eventing/cloud_events/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/eventing/cloud_events/cloud_event.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/eventing/cloud_events/decorators.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/eventing/cloud_events/infrastructure/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/eventing/cloud_events/infrastructure/cloud_event_bus.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/eventing/cloud_events/infrastructure/cloud_event_ingestor.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/eventing/cloud_events/infrastructure/cloud_event_middleware.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/eventing/cloud_events/infrastructure/cloud_event_publisher.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/eventing/tracing.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/expressions/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/expressions/javascript_expression_translator.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/extensions/cqrs_metrics_extensions.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/extensions/mediator_extensions.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/extensions/state_persistence_extensions.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/hosting/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/hosting/abstractions.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/hosting/configuration/data_access_layer.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/hosting/web.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/integration/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/integration/cache_repository.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/integration/http_service_client.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/integration/models.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/logging/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/logging/logger.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/mapping/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/mapping/mapper.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/mediation/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/mediation/behaviors/domain_event_cloudevent_behavior.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/mediation/behaviors/domain_event_dispatching_middleware.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/mediation/mediator.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/mediation/metrics_middleware.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/mediation/pipeline_behavior.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/mediation/simple.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/mediation/tracing_middleware.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/mvc/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/mvc/controller_base.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/observability/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/observability/framework.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/observability/logging.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/observability/metrics.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/observability/otel_sdk.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/observability/settings.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/observability/tracing.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/py.typed +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/reactive/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/reactive/rx_async.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/serialization/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/serialization/abstractions.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/serialization/aggregate_serializer.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/utils/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/utils/camel_model.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/utils/case_conversion.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/validation/__init__.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/validation/business_rules.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/validation/exceptions.py +0 -0
- {neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/validation/validators.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "neuroglia-python"
|
|
3
|
-
version = "0.7.
|
|
3
|
+
version = "0.7.9"
|
|
4
4
|
description = "Port from .NET to Python of the Neuroglia Framework"
|
|
5
5
|
authors = ["Charles d'Avernas <charles.davernas@neuroglia.io>", "Bruno van de Werve <bvandewe@gmail.com>"]
|
|
6
6
|
license = "Apache"
|
|
@@ -445,6 +445,10 @@ class JsonSerializer(TextSerializer):
|
|
|
445
445
|
|
|
446
446
|
def _deserialize_object(self, data: dict, expected_type: type) -> Any:
|
|
447
447
|
"""Deserialize a dictionary into an object using type annotations."""
|
|
448
|
+
# Handle Pydantic BaseModel types using model_validate for proper initialization
|
|
449
|
+
if self._is_pydantic_model(expected_type):
|
|
450
|
+
return expected_type.model_validate(data)
|
|
451
|
+
|
|
448
452
|
fields = {}
|
|
449
453
|
|
|
450
454
|
# Collect all type annotations from the class hierarchy
|
|
@@ -553,11 +557,33 @@ class JsonSerializer(TextSerializer):
|
|
|
553
557
|
return bool(re.match(r"^-?\d+\.?\d*(?:[eE][+-]?\d+)?$", value.strip()))
|
|
554
558
|
|
|
555
559
|
def _is_datetime_string(self, value: str) -> bool:
|
|
556
|
-
"""
|
|
560
|
+
"""
|
|
561
|
+
Check if a string looks like an ISO datetime.
|
|
562
|
+
|
|
563
|
+
Uses a conservative approach to avoid false positives:
|
|
564
|
+
- Requires the string to contain 'T' or a time separator to distinguish
|
|
565
|
+
datetime strings from date-only strings in type inference scenarios
|
|
566
|
+
- Validates with datetime.fromisoformat after initial filtering
|
|
567
|
+
- Catches TypeError for non-string inputs that slip through
|
|
568
|
+
|
|
569
|
+
Note: Date-only strings like '2025-12-15' are NOT matched as datetime strings
|
|
570
|
+
in type inference to avoid unexpected conversions. If you need to deserialize
|
|
571
|
+
date-only strings, provide explicit type hints.
|
|
572
|
+
"""
|
|
573
|
+
# Fast pre-check: must be a non-empty string
|
|
574
|
+
if not isinstance(value, str) or not value:
|
|
575
|
+
return False
|
|
576
|
+
|
|
577
|
+
# Require 'T' separator to distinguish datetime from date-only strings
|
|
578
|
+
# This prevents date-only strings like '2025-12-15' from being converted
|
|
579
|
+
# to datetime objects when the intended type might be a plain date or string
|
|
580
|
+
if "T" not in value and " " not in value:
|
|
581
|
+
return False
|
|
582
|
+
|
|
557
583
|
try:
|
|
558
584
|
datetime.fromisoformat(value.replace("Z", "+00:00"))
|
|
559
585
|
return True
|
|
560
|
-
except (ValueError, AttributeError):
|
|
586
|
+
except (ValueError, AttributeError, TypeError):
|
|
561
587
|
return False
|
|
562
588
|
|
|
563
589
|
def _try_deserialize_enum(self, value: str, target_type: type) -> Any:
|
|
@@ -581,6 +607,15 @@ class JsonSerializer(TextSerializer):
|
|
|
581
607
|
"""
|
|
582
608
|
Fallback enum detection that only checks the target type's module.
|
|
583
609
|
Used when TypeRegistry is not available.
|
|
610
|
+
|
|
611
|
+
Matching priority (returns on first match):
|
|
612
|
+
1. Exact match on enum member value
|
|
613
|
+
2. Exact match on enum member name
|
|
614
|
+
3. Case-insensitive match on value (lowercase comparison)
|
|
615
|
+
4. Case-insensitive match on name (uppercase comparison for CONSTANT_CASE convention)
|
|
616
|
+
|
|
617
|
+
Note: This returns the first matching enum from the module. For deterministic
|
|
618
|
+
behavior with multiple enum types, use TypeRegistry with explicit module registration.
|
|
584
619
|
"""
|
|
585
620
|
try:
|
|
586
621
|
import sys
|
|
@@ -592,11 +627,25 @@ class JsonSerializer(TextSerializer):
|
|
|
592
627
|
|
|
593
628
|
module = sys.modules.get(target_module)
|
|
594
629
|
if module:
|
|
630
|
+
value_lower = value.lower()
|
|
631
|
+
value_upper = value.upper()
|
|
632
|
+
|
|
595
633
|
for attr_name in dir(module):
|
|
596
634
|
attr = getattr(module, attr_name)
|
|
597
635
|
if isinstance(attr, type) and issubclass(attr, Enum) and attr != Enum:
|
|
598
636
|
for enum_member in attr:
|
|
599
|
-
|
|
637
|
+
# Priority 1: Exact match on value
|
|
638
|
+
if enum_member.value == value:
|
|
639
|
+
return enum_member
|
|
640
|
+
# Priority 2: Exact match on name
|
|
641
|
+
if enum_member.name == value:
|
|
642
|
+
return enum_member
|
|
643
|
+
# Priority 3: Case-insensitive match on value
|
|
644
|
+
member_value = enum_member.value
|
|
645
|
+
if isinstance(member_value, str) and member_value.lower() == value_lower:
|
|
646
|
+
return enum_member
|
|
647
|
+
# Priority 4: Case-insensitive match on name (CONSTANT_CASE convention)
|
|
648
|
+
if enum_member.name.upper() == value_upper:
|
|
600
649
|
return enum_member
|
|
601
650
|
except Exception:
|
|
602
651
|
pass
|
|
@@ -688,6 +737,10 @@ class JsonSerializer(TextSerializer):
|
|
|
688
737
|
object.__setattr__(instance, key, val)
|
|
689
738
|
return instance
|
|
690
739
|
|
|
740
|
+
# Handle Pydantic BaseModel deserialization
|
|
741
|
+
if self._is_pydantic_model(expected_type):
|
|
742
|
+
return expected_type.model_validate(value)
|
|
743
|
+
|
|
691
744
|
origin_expected = get_origin(expected_type)
|
|
692
745
|
if expected_type == dict or origin_expected is dict:
|
|
693
746
|
# If the expected type is a plain dict, we need to deserialize each value in the dict.
|
|
@@ -725,20 +778,41 @@ class JsonSerializer(TextSerializer):
|
|
|
725
778
|
# Check if the item should be a dataclass instance
|
|
726
779
|
if isinstance(v, dict) and is_dataclass(item_type):
|
|
727
780
|
# Deserialize dict to dataclass using proper field deserialization
|
|
781
|
+
# Use get_type_hints() to properly resolve type annotations (e.g., dict[str, Any])
|
|
782
|
+
try:
|
|
783
|
+
dataclass_type_hints = get_type_hints(item_type)
|
|
784
|
+
except (NameError, TypeError, AttributeError):
|
|
785
|
+
dataclass_type_hints = {field.name: field.type for field in fields(item_type)}
|
|
786
|
+
except Exception:
|
|
787
|
+
dataclass_type_hints = {field.name: field.type for field in fields(item_type)}
|
|
728
788
|
field_dict = {}
|
|
729
789
|
for field in fields(item_type):
|
|
730
790
|
if field.name in v:
|
|
731
|
-
field_type = field.type
|
|
791
|
+
field_type = dataclass_type_hints.get(field.name, field.type)
|
|
732
792
|
if isinstance(field_type, str):
|
|
733
793
|
field_dict[field.name] = v[field.name]
|
|
734
794
|
else:
|
|
735
795
|
field_value = self._deserialize_nested(v[field.name], field_type)
|
|
736
796
|
field_dict[field.name] = field_value
|
|
797
|
+
# Ensure Optional fields missing from the payload are explicitly populated
|
|
798
|
+
for field in fields(item_type):
|
|
799
|
+
if field.name in field_dict:
|
|
800
|
+
continue
|
|
801
|
+
resolved_type = dataclass_type_hints.get(field.name, field.type)
|
|
802
|
+
if field.default is not MISSING:
|
|
803
|
+
field_dict[field.name] = field.default
|
|
804
|
+
elif field.default_factory is not MISSING: # type: ignore[attr-defined]
|
|
805
|
+
field_dict[field.name] = field.default_factory() # type: ignore[attr-defined]
|
|
806
|
+
elif self._is_optional_type(resolved_type):
|
|
807
|
+
field_dict[field.name] = None
|
|
737
808
|
# Create instance and set fields (works for frozen and non-frozen dataclasses)
|
|
738
809
|
item_instance: Any = object.__new__(cast(type, item_type))
|
|
739
810
|
for key, val in field_dict.items():
|
|
740
811
|
object.__setattr__(item_instance, key, val)
|
|
741
812
|
values.append(item_instance)
|
|
813
|
+
elif isinstance(v, dict) and self._is_pydantic_model(item_type):
|
|
814
|
+
# Use Pydantic's model_validate for proper model initialization
|
|
815
|
+
values.append(item_type.model_validate(v))
|
|
742
816
|
else:
|
|
743
817
|
# For non-dataclass types, use regular deserialization
|
|
744
818
|
deserialized = self._deserialize_nested(v, item_type)
|
|
@@ -757,10 +831,33 @@ class JsonSerializer(TextSerializer):
|
|
|
757
831
|
return value
|
|
758
832
|
|
|
759
833
|
elif hasattr(expected_type, "__bases__") and expected_type.__bases__ and issubclass(expected_type, Enum):
|
|
760
|
-
# Handle Enum deserialization -
|
|
834
|
+
# Handle Enum deserialization with priority-based matching:
|
|
835
|
+
# 1. Exact match on value
|
|
836
|
+
# 2. Exact match on name
|
|
837
|
+
# 3. Case-insensitive match on value (for string values)
|
|
838
|
+
# 4. Case-insensitive match on name
|
|
839
|
+
value_str = str(value) if not isinstance(value, str) else value
|
|
840
|
+
value_lower = value_str.lower()
|
|
841
|
+
value_upper = value_str.upper()
|
|
842
|
+
|
|
843
|
+
for enum_member in expected_type:
|
|
844
|
+
# Priority 1: Exact match on value
|
|
845
|
+
if enum_member.value == value:
|
|
846
|
+
return enum_member
|
|
847
|
+
# Priority 2: Exact match on name
|
|
848
|
+
if enum_member.name == value_str:
|
|
849
|
+
return enum_member
|
|
850
|
+
|
|
851
|
+
# Second pass for case-insensitive matching
|
|
761
852
|
for enum_member in expected_type:
|
|
762
|
-
|
|
853
|
+
# Priority 3: Case-insensitive match on value
|
|
854
|
+
member_value = enum_member.value
|
|
855
|
+
if isinstance(member_value, str) and member_value.lower() == value_lower:
|
|
763
856
|
return enum_member
|
|
857
|
+
# Priority 4: Case-insensitive match on name
|
|
858
|
+
if enum_member.name.upper() == value_upper:
|
|
859
|
+
return enum_member
|
|
860
|
+
|
|
764
861
|
raise ValueError(f"Invalid enum value for {expected_type.__name__}: {value}")
|
|
765
862
|
|
|
766
863
|
else:
|
|
@@ -774,6 +871,28 @@ class JsonSerializer(TextSerializer):
|
|
|
774
871
|
return any(arg is type(None) for arg in get_args(annotation))
|
|
775
872
|
return False
|
|
776
873
|
|
|
874
|
+
def _is_pydantic_model(self, cls: Any) -> bool:
|
|
875
|
+
"""
|
|
876
|
+
Check if a type is a Pydantic BaseModel subclass.
|
|
877
|
+
|
|
878
|
+
Uses duck typing to avoid hard dependency on Pydantic being installed.
|
|
879
|
+
Pydantic v2 models have a `model_validate` classmethod that accepts dict data.
|
|
880
|
+
|
|
881
|
+
Args:
|
|
882
|
+
cls: The type to check
|
|
883
|
+
|
|
884
|
+
Returns:
|
|
885
|
+
True if the type appears to be a Pydantic BaseModel, False otherwise
|
|
886
|
+
"""
|
|
887
|
+
if not isinstance(cls, type):
|
|
888
|
+
return False
|
|
889
|
+
# Check for Pydantic v2 model_validate method (preferred detection)
|
|
890
|
+
if hasattr(cls, "model_validate") and callable(getattr(cls, "model_validate", None)):
|
|
891
|
+
# Additional check: Pydantic models also have model_fields
|
|
892
|
+
if hasattr(cls, "model_fields"):
|
|
893
|
+
return True
|
|
894
|
+
return False
|
|
895
|
+
|
|
777
896
|
@staticmethod
|
|
778
897
|
def configure(builder: "ApplicationBuilderBase", modules: Optional[list[str]] = None) -> "ApplicationBuilderBase":
|
|
779
898
|
"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/application/background_scheduler.py
RENAMED
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/coordination/abstractions.py
RENAMED
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/coordination/leader_election.py
RENAMED
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/coordination/redis_backend.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/__init__.py
RENAMED
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/abstractions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/infrastructure/tracing_mixin.py
RENAMED
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/queries/generic/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/queries/generic/list_query.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/resources/abstractions.py
RENAMED
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/resources/controller.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/data/resources/state_machine.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/dependency_injection/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/eventing/cloud_events/__init__.py
RENAMED
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/eventing/cloud_events/cloud_event.py
RENAMED
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/eventing/cloud_events/decorators.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/extensions/mediator_extensions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/integration/cache_repository.py
RENAMED
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/integration/http_service_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/mediation/metrics_middleware.py
RENAMED
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/mediation/pipeline_behavior.py
RENAMED
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/mediation/tracing_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/serialization/abstractions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{neuroglia_python-0.7.7 → neuroglia_python-0.7.9}/src/neuroglia/validation/business_rules.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|