statezero 0.1.0b3__py3-none-any.whl → 0.1.0b5__py3-none-any.whl

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.

Potentially problematic release.


This version of statezero might be problematic. Click here for more details.

@@ -13,6 +13,7 @@ from statezero.adaptors.django.config import config, registry
13
13
  from statezero.core.interfaces import AbstractDataSerializer, AbstractQueryOptimizer
14
14
  from statezero.core.types import RequestType
15
15
  from statezero.adaptors.django.helpers import collect_from_queryset
16
+ from statezero.core.hook_checks import _check_pre_hook_result, _check_post_hook_result
16
17
 
17
18
  logger = logging.getLogger(__name__)
18
19
 
@@ -82,7 +83,7 @@ class FlexiblePrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
82
83
 
83
84
  # Otherwise, use the standard to_internal_value
84
85
  return super().to_internal_value(data)
85
-
86
+
86
87
  class FExpressionMixin:
87
88
  """
88
89
  A mixin that can handle F expression objects in serializer write operations.
@@ -344,7 +345,7 @@ class DRFDynamicSerializer(AbstractDataSerializer):
344
345
  fields_per_model=fields_map,
345
346
  get_model_name_func=config.orm_provider.get_model_name,
346
347
  )
347
-
348
+
348
349
  if "requested-fields::" in fields_map:
349
350
  requested_fields = fields_map["requested-fields::"]
350
351
  data = query_optimizer.optimize(
@@ -359,7 +360,7 @@ class DRFDynamicSerializer(AbstractDataSerializer):
359
360
  logger.debug(f"Query optimized for {model.__name__} with no explicit field selection")
360
361
  except Exception as e:
361
362
  logger.error(f"Error optimizing query for {model.__name__}: {e}")
362
-
363
+
363
364
  return data
364
365
 
365
366
  def serialize(
@@ -385,7 +386,7 @@ class DRFDynamicSerializer(AbstractDataSerializer):
385
386
  """
386
387
  # Validate fields_map
387
388
  assert fields_map is not None, "fields_map is required and cannot be None"
388
-
389
+
389
390
  # Handle None data
390
391
  if data is None:
391
392
  return {
@@ -393,10 +394,10 @@ class DRFDynamicSerializer(AbstractDataSerializer):
393
394
  "included": {},
394
395
  "model_name": None
395
396
  }
396
-
397
+
397
398
  # Apply query optimization
398
399
  data = self._optimize_queryset(data, model, fields_map)
399
-
400
+
400
401
  # Use the fields_map context for all operations
401
402
  with fields_map_context(fields_map):
402
403
  # Collect all model instances based on the fields_map
@@ -406,7 +407,7 @@ class DRFDynamicSerializer(AbstractDataSerializer):
406
407
  get_model_name=config.orm_provider.get_model_name,
407
408
  get_model=config.orm_provider.get_model_by_name
408
409
  )
409
-
410
+
410
411
  # Extract primary keys for the top-level model
411
412
  model_name = config.orm_provider.get_model_name(model)
412
413
  pk_field = model._meta.pk.name
@@ -418,7 +419,7 @@ class DRFDynamicSerializer(AbstractDataSerializer):
418
419
  "included": {},
419
420
  "model_name": model_name
420
421
  }
421
-
422
+
422
423
  # For QuerySets, gather all instances
423
424
  if isinstance(data, models.QuerySet):
424
425
  top_level_instances = list(data)
@@ -428,26 +429,26 @@ class DRFDynamicSerializer(AbstractDataSerializer):
428
429
  # For many=True with a list of instances
429
430
  elif many and isinstance(data, list):
430
431
  top_level_instances = [item for item in data if isinstance(item, model)]
431
-
432
+
432
433
  # Extract primary keys for top-level instances
433
434
  result["data"] = [getattr(instance, pk_field) for instance in top_level_instances]
434
-
435
+
435
436
  # Apply zen-queries protection if configured
436
437
  query_protection = getattr(settings, 'ZEN_STRICT_SERIALIZATION', False)
437
-
438
+
438
439
  # Serialize each group of models
439
440
  for model_type, instances in collected_models.items():
440
441
  # Skip empty collections
441
442
  if not instances:
442
443
  continue
443
-
444
+
444
445
  try:
445
446
  # Get the model class for this type
446
447
  model_class = config.orm_provider.get_model_by_name(model_type)
447
-
448
+
448
449
  # Create a serializer for this model type
449
450
  serializer_class = DynamicModelSerializer.for_model(model_class)
450
-
451
+
451
452
  # Apply zen-queries protection if configured
452
453
  if query_protection:
453
454
  with queries_disabled():
@@ -461,15 +462,15 @@ class DRFDynamicSerializer(AbstractDataSerializer):
461
462
  # [{pk: 1, ...}, {pk: 2, ...}] -> {1: {...}, 2: {...}}
462
463
  # Create a dictionary indexed by primary key for easy lookup in the frontend
463
464
  pk_indexed_data = dict(zip(pluck(pk_field_name, serialized_data), serialized_data))
464
-
465
+
465
466
  # Add the serialized data to the result
466
467
  result["included"][model_type] = pk_indexed_data
467
-
468
+
468
469
  except Exception as e:
469
470
  logger.error(f"Error serializing {model_type}: {e}")
470
471
  # Include an empty list for this model type to maintain the expected structure
471
472
  result["included"][model_type] = {}
472
-
473
+
473
474
  return result
474
475
 
475
476
  def deserialize(
@@ -487,12 +488,22 @@ class DRFDynamicSerializer(AbstractDataSerializer):
487
488
  with fields_map_context(fields_map):
488
489
  # Create serializer class
489
490
  serializer_class = DynamicModelSerializer.for_model(model)
491
+ available_fields = set(serializer_class().fields.keys())
490
492
 
491
493
  try:
492
494
  model_config = registry.get_config(model)
493
495
  if model_config.pre_hooks:
494
496
  for hook in model_config.pre_hooks:
495
- data = hook(data, request=request)
497
+ hook_result = hook(data, request=request)
498
+ if settings.DEBUG:
499
+ data = _check_pre_hook_result(
500
+ original_data=data,
501
+ result_data=hook_result,
502
+ model=model,
503
+ serializer_fields=available_fields
504
+ )
505
+ else:
506
+ data = hook_result or data
496
507
  except ValueError:
497
508
  # No model config available
498
509
  model_config = None
@@ -508,10 +519,18 @@ class DRFDynamicSerializer(AbstractDataSerializer):
508
519
 
509
520
  if model_config and model_config.post_hooks:
510
521
  for hook in model_config.post_hooks:
511
- validated_data = hook(validated_data, request=request)
512
-
522
+ hook_result = hook(validated_data, request=request)
523
+ if settings.DEBUG:
524
+ validated_data = _check_post_hook_result(
525
+ original_data=validated_data,
526
+ result_data=hook_result,
527
+ model=model
528
+ )
529
+ else:
530
+ validated_data = hook_result or validated_data
531
+
513
532
  return validated_data
514
-
533
+
515
534
  def save(
516
535
  self,
517
536
  model: Type[models.Model],
@@ -533,12 +552,12 @@ class DRFDynamicSerializer(AbstractDataSerializer):
533
552
 
534
553
  # Create an unrestricted fields map
535
554
  unrestricted_fields_map = {model_name: all_fields}
536
-
555
+
537
556
  # Use the context manager with the unrestricted fields map
538
557
  with fields_map_context(unrestricted_fields_map):
539
558
  # Create serializer class
540
559
  serializer_class = DynamicModelSerializer.for_model(model)
541
-
560
+
542
561
  # Create serializer
543
562
  serializer = serializer_class(
544
563
  instance=instance, # Will be None for creation
@@ -546,9 +565,9 @@ class DRFDynamicSerializer(AbstractDataSerializer):
546
565
  partial=partial if instance else False, # partial only makes sense for updates
547
566
  request=request
548
567
  )
549
-
568
+
550
569
  # Validate the data
551
570
  serializer.is_valid(raise_exception=True)
552
-
571
+
553
572
  # Save and return the instance
554
- return serializer.save()
573
+ return serializer.save()