TypeDAL 4.6.0__tar.gz → 4.6.1__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 (75) hide show
  1. {typedal-4.6.0 → typedal-4.6.1}/.crush/crush.db-shm +0 -0
  2. typedal-4.6.1/.crush/crush.db-wal +0 -0
  3. {typedal-4.6.0 → typedal-4.6.1}/CHANGELOG.md +6 -0
  4. {typedal-4.6.0 → typedal-4.6.1}/PKG-INFO +1 -1
  5. {typedal-4.6.0 → typedal-4.6.1}/docs/8_mixins.md +8 -1
  6. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/__about__.py +1 -1
  7. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/caching.py +2 -0
  8. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/mixins.py +12 -7
  9. {typedal-4.6.0 → typedal-4.6.1}/tests/test_mixins.py +17 -0
  10. typedal-4.6.0/.crush/crush.db-wal +0 -0
  11. {typedal-4.6.0 → typedal-4.6.1}/.crush/.gitignore +0 -0
  12. {typedal-4.6.0 → typedal-4.6.1}/.crush/init +0 -0
  13. {typedal-4.6.0 → typedal-4.6.1}/.crush/logs/crush.log +0 -0
  14. {typedal-4.6.0 → typedal-4.6.1}/.github/workflows/su6.yml +0 -0
  15. {typedal-4.6.0 → typedal-4.6.1}/.gitignore +0 -0
  16. {typedal-4.6.0 → typedal-4.6.1}/.readthedocs.yml +0 -0
  17. {typedal-4.6.0 → typedal-4.6.1}/README.md +0 -0
  18. {typedal-4.6.0 → typedal-4.6.1}/coverage.svg +0 -0
  19. {typedal-4.6.0 → typedal-4.6.1}/docs/10_advanced_apis.md +0 -0
  20. {typedal-4.6.0 → typedal-4.6.1}/docs/1_getting_started.md +0 -0
  21. {typedal-4.6.0 → typedal-4.6.1}/docs/2_defining_tables.md +0 -0
  22. {typedal-4.6.0 → typedal-4.6.1}/docs/3_building_queries.md +0 -0
  23. {typedal-4.6.0 → typedal-4.6.1}/docs/4_relationships.md +0 -0
  24. {typedal-4.6.0 → typedal-4.6.1}/docs/5_py4web.md +0 -0
  25. {typedal-4.6.0 → typedal-4.6.1}/docs/6_migrations.md +0 -0
  26. {typedal-4.6.0 → typedal-4.6.1}/docs/7_configuration.md +0 -0
  27. {typedal-4.6.0 → typedal-4.6.1}/docs/9_memoization.md +0 -0
  28. {typedal-4.6.0 → typedal-4.6.1}/docs/css/code_blocks.css +0 -0
  29. {typedal-4.6.0 → typedal-4.6.1}/docs/index.md +0 -0
  30. {typedal-4.6.0 → typedal-4.6.1}/docs/requirements.txt +0 -0
  31. {typedal-4.6.0 → typedal-4.6.1}/example_new.py +0 -0
  32. {typedal-4.6.0 → typedal-4.6.1}/example_old.py +0 -0
  33. {typedal-4.6.0 → typedal-4.6.1}/mkdocs.yml +0 -0
  34. {typedal-4.6.0 → typedal-4.6.1}/pyproject.toml +0 -0
  35. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/__init__.py +0 -0
  36. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/cli.py +0 -0
  37. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/config.py +0 -0
  38. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/constants.py +0 -0
  39. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/core.py +0 -0
  40. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/define.py +0 -0
  41. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/fields.py +0 -0
  42. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/for_py4web.py +0 -0
  43. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/for_web2py.py +0 -0
  44. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/helpers.py +0 -0
  45. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/py.typed +0 -0
  46. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/query_builder.py +0 -0
  47. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/relationships.py +0 -0
  48. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/rows.py +0 -0
  49. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/serializers/as_json.py +0 -0
  50. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/tables.py +0 -0
  51. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/types.py +0 -0
  52. {typedal-4.6.0 → typedal-4.6.1}/src/typedal/web2py_py4web_shared.py +0 -0
  53. {typedal-4.6.0 → typedal-4.6.1}/tasks.py +0 -0
  54. {typedal-4.6.0 → typedal-4.6.1}/tests/__init__.py +0 -0
  55. {typedal-4.6.0 → typedal-4.6.1}/tests/configs/simple.toml +0 -0
  56. {typedal-4.6.0 → typedal-4.6.1}/tests/configs/valid.env +0 -0
  57. {typedal-4.6.0 → typedal-4.6.1}/tests/configs/valid.toml +0 -0
  58. {typedal-4.6.0 → typedal-4.6.1}/tests/py314_tests.py +0 -0
  59. {typedal-4.6.0 → typedal-4.6.1}/tests/test_cli.py +0 -0
  60. {typedal-4.6.0 → typedal-4.6.1}/tests/test_config.py +0 -0
  61. {typedal-4.6.0 → typedal-4.6.1}/tests/test_docs_examples.py +0 -0
  62. {typedal-4.6.0 → typedal-4.6.1}/tests/test_helpers.py +0 -0
  63. {typedal-4.6.0 → typedal-4.6.1}/tests/test_json.py +0 -0
  64. {typedal-4.6.0 → typedal-4.6.1}/tests/test_main.py +0 -0
  65. {typedal-4.6.0 → typedal-4.6.1}/tests/test_mypy.py +0 -0
  66. {typedal-4.6.0 → typedal-4.6.1}/tests/test_orm.py +0 -0
  67. {typedal-4.6.0 → typedal-4.6.1}/tests/test_py4web.py +0 -0
  68. {typedal-4.6.0 → typedal-4.6.1}/tests/test_query_builder.py +0 -0
  69. {typedal-4.6.0 → typedal-4.6.1}/tests/test_relationships.py +0 -0
  70. {typedal-4.6.0 → typedal-4.6.1}/tests/test_row.py +0 -0
  71. {typedal-4.6.0 → typedal-4.6.1}/tests/test_stats.py +0 -0
  72. {typedal-4.6.0 → typedal-4.6.1}/tests/test_table.py +0 -0
  73. {typedal-4.6.0 → typedal-4.6.1}/tests/test_web2py.py +0 -0
  74. {typedal-4.6.0 → typedal-4.6.1}/tests/test_xx_others.py +0 -0
  75. {typedal-4.6.0 → typedal-4.6.1}/tests/timings.py +0 -0
Binary file
@@ -2,6 +2,12 @@
2
2
 
3
3
  <!--next-version-placeholder-->
4
4
 
5
+ ## v4.6.1 (2026-03-13)
6
+
7
+ ### Fix
8
+
9
+ * **pydantic:** Exclude fields with 'readable=False' similar to pydal/py4web/web2py behavior ([`e47cc44`](https://github.com/trialandsuccess/TypeDAL/commit/e47cc442aa7736ba1177bc32a7dc6de58c2551aa))
10
+
5
11
  ## v4.6.0 (2026-03-13)
6
12
 
7
13
  ### Documentation
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: TypeDAL
3
- Version: 4.6.0
3
+ Version: 4.6.1
4
4
  Summary: Typing support for PyDAL
5
5
  Project-URL: Documentation, https://typedal.readthedocs.io/
6
6
  Project-URL: Issues, https://github.com/trialandsuccess/TypeDAL/issues
@@ -56,7 +56,7 @@ or use them with `pydantic.TypeAdapter`.
56
56
  Add the mixin to enable `model_dump()` for serialization, including support for relationships and computed properties:
57
57
 
58
58
  ```python
59
- from typedal import TypedTable
59
+ from typedal import TypedField, TypedTable
60
60
  from typedal.mixins import PydanticMixin
61
61
 
62
62
 
@@ -67,6 +67,7 @@ class Author(TypedTable, PydanticMixin):
67
67
  class Book(TypedTable, PydanticMixin):
68
68
  title: str
69
69
  author: Author
70
+ private_notes = TypedField(str, readable=False)
70
71
 
71
72
  @property
72
73
  def display_title(self) -> str:
@@ -79,6 +80,12 @@ book = Book.where(id=1).join("author").first()
79
80
  # model_dump() serializes the full object graph
80
81
  data = book.model_dump()
81
82
  # -> {"id": 1, "title": "...", "author": {"id": 1, "name": "..."}, "display_title": "..."}
83
+ # (private_notes is omitted because readable=False)
84
+
85
+ # Runtime readability flags are also respected by model_dump()
86
+ Book.title.readable = False
87
+ data = book.model_dump()
88
+ # -> {"id": 1, "author": {"id": 1, "name": "..."}, "display_title": "..."}
82
89
 
83
90
  # Use mode="json" for JSON-serializable output (dates as ISO strings, etc.)
84
91
  data = book.model_dump(mode="json")
@@ -5,4 +5,4 @@ This file contains the Version info for this package.
5
5
  # SPDX-FileCopyrightText: 2023-present Robin van der Noord <robinvandernoord@gmail.com>
6
6
  #
7
7
  # SPDX-License-Identifier: MIT
8
- __version__ = "4.6.0"
8
+ __version__ = "4.6.1"
@@ -203,6 +203,7 @@ def _remove_cache(s: Set, tablename: str) -> None:
203
203
  indeces = s.select("id").column("id")
204
204
  remove_cache(indeces, tablename)
205
205
 
206
+
206
207
  def get_expire(
207
208
  expires_at: t.Optional[dt.datetime] = None,
208
209
  ttl: t.Optional[int | dt.timedelta] = None,
@@ -419,6 +420,7 @@ class Stats[T](t.TypedDict):
419
420
  valid: T
420
421
  expired: T
421
422
 
423
+
422
424
  RowStats = t.TypedDict(
423
425
  "RowStats",
424
426
  {
@@ -585,13 +585,18 @@ class PydanticMixin(Mixin):
585
585
 
586
586
  def model_dump(self, mode: str = "python", *, _shallow: bool = False) -> dict[str, t.Any]:
587
587
  """Serialize this model to a dict, with optional shallow nested output."""
588
- data = {
589
- field_name: getattr(self, field_name, None)
590
- for field_name in self._pydantic_fields(
591
- include_relationships=not _shallow,
592
- include_properties=not _shallow,
593
- )
594
- }
588
+ cls = type(self)
589
+ data: dict[str, t.Any] = {}
590
+ for field_name in self._pydantic_fields(
591
+ include_relationships=not _shallow,
592
+ include_properties=not _shallow,
593
+ ):
594
+ # Match web2py/pyDAL behavior: unreadable db fields are excluded from serialized output.
595
+ model_attr = getattr(cls, field_name, None)
596
+ if hasattr(model_attr, "readable") and not getattr(model_attr, "readable"):
597
+ continue
598
+
599
+ data[field_name] = getattr(self, field_name, None)
595
600
 
596
601
  if mode == "json":
597
602
  return dump_pydantic(data, _shallow_nested=True)
@@ -232,6 +232,11 @@ class PydanticTupleAndLiteralSchema(TypedTable, PydanticMixin):
232
232
  status: typing.Literal["draft", "published"]
233
233
 
234
234
 
235
+ class PydanticHiddenTypedField(TypedTable, PydanticMixin):
236
+ visible = TypedField(str)
237
+ hidden = TypedField(str, readable=False)
238
+
239
+
235
240
  @pytest.fixture
236
241
  def pydantic_db():
237
242
  db = TypeDAL("sqlite:memory")
@@ -241,6 +246,7 @@ def pydantic_db():
241
246
  db.define(PydanticStringRelationship)
242
247
  db.define(PydanticGenericResolvedRelationship)
243
248
  db.define(PydanticGenericUnresolvedRelationship)
249
+ db.define(PydanticHiddenTypedField)
244
250
  db.define(NonPydanticAuthor)
245
251
  yield db
246
252
 
@@ -443,6 +449,17 @@ def test_pydantic_fields_include_typedfield_and_skip_no_getter_property(pydantic
443
449
  assert "empty_prop" not in property_fields
444
450
 
445
451
 
452
+ def test_pydantic_skips_unreadable_typedfield_in_model_dump(pydantic_db):
453
+ row = PydanticHiddenTypedField.insert(visible="show", hidden="hide")
454
+ data = row.model_dump()
455
+ assert data == {"id": row.id, "visible": "show"}
456
+
457
+ PydanticHiddenTypedField.visible.readable = False
458
+ row = PydanticHiddenTypedField.insert(visible="show-2", hidden="hide-2")
459
+ data = row.model_dump()
460
+ assert data == {"id": row.id}
461
+
462
+
446
463
  def test_pydantic_compatibility_non_type_and_missing_relationship_type():
447
464
  # ForwardRef is not a runtime type; this should be a no-op, not a crash.
448
465
  PydanticMixin._ensure_pydantic_compatible_type("x", typing.ForwardRef("Anything"))
Binary file
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
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
File without changes