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.
- {typedal-4.6.0 → typedal-4.6.1}/.crush/crush.db-shm +0 -0
- typedal-4.6.1/.crush/crush.db-wal +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/CHANGELOG.md +6 -0
- {typedal-4.6.0 → typedal-4.6.1}/PKG-INFO +1 -1
- {typedal-4.6.0 → typedal-4.6.1}/docs/8_mixins.md +8 -1
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/__about__.py +1 -1
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/caching.py +2 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/mixins.py +12 -7
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_mixins.py +17 -0
- typedal-4.6.0/.crush/crush.db-wal +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/.crush/.gitignore +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/.crush/init +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/.crush/logs/crush.log +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/.github/workflows/su6.yml +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/.gitignore +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/.readthedocs.yml +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/README.md +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/coverage.svg +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/docs/10_advanced_apis.md +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/docs/1_getting_started.md +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/docs/2_defining_tables.md +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/docs/3_building_queries.md +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/docs/4_relationships.md +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/docs/5_py4web.md +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/docs/6_migrations.md +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/docs/7_configuration.md +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/docs/9_memoization.md +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/docs/css/code_blocks.css +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/docs/index.md +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/docs/requirements.txt +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/example_new.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/example_old.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/mkdocs.yml +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/pyproject.toml +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/__init__.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/cli.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/config.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/constants.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/core.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/define.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/fields.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/for_py4web.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/for_web2py.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/helpers.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/py.typed +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/query_builder.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/relationships.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/rows.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/serializers/as_json.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/tables.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/types.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/src/typedal/web2py_py4web_shared.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tasks.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/__init__.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/configs/simple.toml +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/configs/valid.env +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/configs/valid.toml +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/py314_tests.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_cli.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_config.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_docs_examples.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_helpers.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_json.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_main.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_mypy.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_orm.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_py4web.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_query_builder.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_relationships.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_row.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_stats.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_table.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_web2py.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/test_xx_others.py +0 -0
- {typedal-4.6.0 → typedal-4.6.1}/tests/timings.py +0 -0
|
Binary file
|
|
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
|
|
@@ -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")
|
|
@@ -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
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
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
|
|
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
|