ab-pydantic-patch 1.2.2__tar.gz → 1.2.3__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.
Files changed (58) hide show
  1. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/PKG-INFO +1 -1
  2. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/pyproject.toml +1 -1
  3. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/orm_patch.py +21 -4
  4. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/.gitignore +0 -0
  5. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/LICENSE +0 -0
  6. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/README.md +0 -0
  7. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/__init__.py +0 -0
  8. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/__init__.py +0 -0
  9. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/cache.py +0 -0
  10. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/classproperty.py +0 -0
  11. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/computed_field_type_hints.py +0 -0
  12. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/config.py +0 -0
  13. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/errors.py +0 -0
  14. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/field_type_hints.py +0 -0
  15. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/fields.py +0 -0
  16. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/forward_references.py +0 -0
  17. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/operation.py +0 -0
  18. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/orm_type_hints.py +0 -0
  19. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/payload.py +0 -0
  20. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/payload_types.py +0 -0
  21. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/transform.py +0 -0
  22. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/type_hints.py +0 -0
  23. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/core/types.py +0 -0
  24. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/examples/__init__.py +0 -0
  25. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/examples/pydantic_examples/__init__.py +0 -0
  26. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/examples/pydantic_examples/pydantic_computed_fields.py +0 -0
  27. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/examples/pydantic_examples/pydantic_discriminated_union_api_schema.py +0 -0
  28. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/examples/sqlmodel_examples/__init__.py +0 -0
  29. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/examples/sqlmodel_examples/app_broken.py +0 -0
  30. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/examples/sqlmodel_examples/app_resolved.py +0 -0
  31. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/examples/sqlmodel_examples/models/__init__.py +0 -0
  32. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/examples/sqlmodel_examples/models/project.py +0 -0
  33. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/examples/sqlmodel_examples/models/project_milestone.py +0 -0
  34. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/examples/sqlmodel_examples/models/project_task.py +0 -0
  35. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/examples/sqlmodel_examples/models/task_comment.py +0 -0
  36. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/examples/sqlmodel_examples/models/user.py +0 -0
  37. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/examples/sqlmodel_examples/sqlmodel_computed_fields.py +0 -0
  38. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/omit/__init__.py +0 -0
  39. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/omit/api.py +0 -0
  40. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/omit/config.py +0 -0
  41. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/omit/operation.py +0 -0
  42. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/partial/__init__.py +0 -0
  43. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/partial/api.py +0 -0
  44. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/partial/config.py +0 -0
  45. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/partial/operation.py +0 -0
  46. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/patch/__init__.py +0 -0
  47. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/patch/api.py +0 -0
  48. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/patch/config.py +0 -0
  49. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/patch/operation.py +0 -0
  50. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/pick/__init__.py +0 -0
  51. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/pick/api.py +0 -0
  52. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/pick/config.py +0 -0
  53. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/pick/operation.py +0 -0
  54. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/pydantic_jsonb.py +0 -0
  55. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/required/__init__.py +0 -0
  56. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/required/api.py +0 -0
  57. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/required/config.py +0 -0
  58. {ab_pydantic_patch-1.2.2 → ab_pydantic_patch-1.2.3}/src/ab_core/pydantic_patch/required/operation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ab-pydantic-patch
3
- Version: 1.2.2
3
+ Version: 1.2.3
4
4
  Summary: Python Pydantic support of TypeScript-style utility types, including Partial, Required, Pick, and Omit. Useful for PATCH endpoints driven from BaseModel / SQLModel classes.
5
5
  Author-email: Matt Coulter <mattcoul7@gmail.com>
6
6
  License-File: LICENSE
@@ -28,7 +28,7 @@ description = "Python Pydantic support of TypeScript-style utility types, includ
28
28
  name = "ab-pydantic-patch"
29
29
  readme = "README.md"
30
30
  requires-python = ">=3.12,<4.0"
31
- version = "1.2.2"
31
+ version = "1.2.3"
32
32
 
33
33
  [project.optional-dependencies]
34
34
  orm = [
@@ -27,11 +27,23 @@ def _provided_values(model: BaseModel) -> dict[str, object]:
27
27
  return {name: getattr(model, name) for name in model.model_fields_set}
28
28
 
29
29
 
30
- def _patch_scalar_value(instance: Any, key: str, value: Any) -> None:
30
+ def _patch_scalar_value(
31
+ instance: Any,
32
+ key: str,
33
+ value: Any,
34
+ *,
35
+ copy_nested_basemodel: bool = False,
36
+ ) -> None:
31
37
  current_value = getattr(instance, key, None)
32
38
 
33
39
  if isinstance(current_value, BaseModel) and isinstance(value, BaseModel):
34
- recursive_patch_scalar(current_value, value)
40
+ target_value = current_value.model_copy(deep=True) if copy_nested_basemodel else current_value
41
+
42
+ recursive_patch_scalar(target_value, value)
43
+
44
+ # Important for ORM scalar JSON/Pydantic fields:
45
+ # reassign the merged current value so SQLAlchemy sees the column changed.
46
+ setattr(instance, key, target_value)
35
47
  return
36
48
 
37
49
  setattr(instance, key, value)
@@ -94,7 +106,7 @@ def _recursive_patch_pydantic_scalar(
94
106
  instance: BaseModel,
95
107
  values: BaseModel,
96
108
  ) -> None:
97
- target_fields = set(instance.model_fields)
109
+ target_fields = set(type(instance).model_fields)
98
110
 
99
111
  for key, value in _provided_values(values).items():
100
112
  if key not in target_fields:
@@ -129,7 +141,12 @@ def _recursive_patch_orm_scalar(
129
141
  if relationship is None:
130
142
  if key not in scalar_attributes:
131
143
  continue
132
- _patch_scalar_value(orm_instance, key, value)
144
+ _patch_scalar_value(
145
+ orm_instance,
146
+ key,
147
+ value,
148
+ copy_nested_basemodel=True,
149
+ )
133
150
  continue
134
151
 
135
152
  if value is None: