TypeDAL 4.9.6__tar.gz → 4.9.7__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 (81) hide show
  1. {typedal-4.9.6 → typedal-4.9.7}/CHANGELOG.md +6 -0
  2. {typedal-4.9.6 → typedal-4.9.7}/PKG-INFO +1 -1
  3. {typedal-4.9.6 → typedal-4.9.7}/pyproject.toml +1 -2
  4. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/__about__.py +1 -1
  5. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/cli.py +1 -2
  6. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/fields.py +6 -0
  7. {typedal-4.9.6 → typedal-4.9.7}/tasks.py +1 -1
  8. {typedal-4.9.6 → typedal-4.9.7}/tests/test_main.py +20 -0
  9. {typedal-4.9.6 → typedal-4.9.7}/tests/test_mypy.py +4 -4
  10. typedal-4.9.7/tests/test_py4web.py +91 -0
  11. {typedal-4.9.6 → typedal-4.9.7}/tests/test_relationships.py +20 -19
  12. typedal-4.9.6/tests/test_py4web.py +0 -92
  13. {typedal-4.9.6 → typedal-4.9.7}/.crush/.gitignore +0 -0
  14. {typedal-4.9.6 → typedal-4.9.7}/.crush/crush.db-shm +0 -0
  15. {typedal-4.9.6 → typedal-4.9.7}/.crush/crush.db-wal +0 -0
  16. {typedal-4.9.6 → typedal-4.9.7}/.crush/init +0 -0
  17. {typedal-4.9.6 → typedal-4.9.7}/.crush/logs/crush.log +0 -0
  18. {typedal-4.9.6 → typedal-4.9.7}/.github/workflows/su6.yml +0 -0
  19. {typedal-4.9.6 → typedal-4.9.7}/.gitignore +0 -0
  20. {typedal-4.9.6 → typedal-4.9.7}/.readthedocs.yml +0 -0
  21. {typedal-4.9.6 → typedal-4.9.7}/README.md +0 -0
  22. {typedal-4.9.6 → typedal-4.9.7}/coverage.svg +0 -0
  23. {typedal-4.9.6 → typedal-4.9.7}/docs/10_advanced_apis.md +0 -0
  24. {typedal-4.9.6 → typedal-4.9.7}/docs/1_getting_started.md +0 -0
  25. {typedal-4.9.6 → typedal-4.9.7}/docs/2_defining_tables.md +0 -0
  26. {typedal-4.9.6 → typedal-4.9.7}/docs/3_building_queries.md +0 -0
  27. {typedal-4.9.6 → typedal-4.9.7}/docs/4_relationships.md +0 -0
  28. {typedal-4.9.6 → typedal-4.9.7}/docs/5_py4web.md +0 -0
  29. {typedal-4.9.6 → typedal-4.9.7}/docs/6_migrations.md +0 -0
  30. {typedal-4.9.6 → typedal-4.9.7}/docs/7_configuration.md +0 -0
  31. {typedal-4.9.6 → typedal-4.9.7}/docs/8_mixins.md +0 -0
  32. {typedal-4.9.6 → typedal-4.9.7}/docs/9_memoization.md +0 -0
  33. {typedal-4.9.6 → typedal-4.9.7}/docs/css/code_blocks.css +0 -0
  34. {typedal-4.9.6 → typedal-4.9.7}/docs/index.md +0 -0
  35. {typedal-4.9.6 → typedal-4.9.7}/docs/requirements.txt +0 -0
  36. {typedal-4.9.6 → typedal-4.9.7}/example_new.py +0 -0
  37. {typedal-4.9.6 → typedal-4.9.7}/example_old.py +0 -0
  38. {typedal-4.9.6 → typedal-4.9.7}/mkdocs.yml +0 -0
  39. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/__init__.py +0 -0
  40. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/caching.py +0 -0
  41. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/config.py +0 -0
  42. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/constants.py +0 -0
  43. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/core.py +0 -0
  44. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/define.py +0 -0
  45. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/enum_helpers.py +0 -0
  46. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/for_py4web.py +0 -0
  47. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/for_web2py.py +0 -0
  48. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/helpers.py +0 -0
  49. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/mixins.py +0 -0
  50. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/py.typed +0 -0
  51. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/query_builder.py +0 -0
  52. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/relationships.py +0 -0
  53. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/rows.py +0 -0
  54. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/serializers/as_json.py +0 -0
  55. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/serializers/typescript.py +0 -0
  56. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/tables.py +0 -0
  57. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/types.py +0 -0
  58. {typedal-4.9.6 → typedal-4.9.7}/src/typedal/web2py_py4web_shared.py +0 -0
  59. {typedal-4.9.6 → typedal-4.9.7}/tests/__init__.py +0 -0
  60. {typedal-4.9.6 → typedal-4.9.7}/tests/configs/simple.toml +0 -0
  61. {typedal-4.9.6 → typedal-4.9.7}/tests/configs/valid.env +0 -0
  62. {typedal-4.9.6 → typedal-4.9.7}/tests/configs/valid.toml +0 -0
  63. {typedal-4.9.6 → typedal-4.9.7}/tests/conftest.py +0 -0
  64. {typedal-4.9.6 → typedal-4.9.7}/tests/py314_tests.py +0 -0
  65. {typedal-4.9.6 → typedal-4.9.7}/tests/test_cli.py +0 -0
  66. {typedal-4.9.6 → typedal-4.9.7}/tests/test_config.py +0 -0
  67. {typedal-4.9.6 → typedal-4.9.7}/tests/test_docs_examples.py +0 -0
  68. {typedal-4.9.6 → typedal-4.9.7}/tests/test_helpers.py +0 -0
  69. {typedal-4.9.6 → typedal-4.9.7}/tests/test_json.py +0 -0
  70. {typedal-4.9.6 → typedal-4.9.7}/tests/test_mixins.py +0 -0
  71. {typedal-4.9.6 → typedal-4.9.7}/tests/test_orm.py +0 -0
  72. {typedal-4.9.6 → typedal-4.9.7}/tests/test_query_builder.py +0 -0
  73. {typedal-4.9.6 → typedal-4.9.7}/tests/test_row.py +0 -0
  74. {typedal-4.9.6 → typedal-4.9.7}/tests/test_stats.py +0 -0
  75. {typedal-4.9.6 → typedal-4.9.7}/tests/test_table.py +0 -0
  76. {typedal-4.9.6 → typedal-4.9.7}/tests/test_typescript.py +0 -0
  77. {typedal-4.9.6 → typedal-4.9.7}/tests/test_typing_mypy.md +0 -0
  78. {typedal-4.9.6 → typedal-4.9.7}/tests/test_typing_pyright.md +0 -0
  79. {typedal-4.9.6 → typedal-4.9.7}/tests/test_web2py.py +0 -0
  80. {typedal-4.9.6 → typedal-4.9.7}/tests/test_xx_others.py +0 -0
  81. {typedal-4.9.6 → typedal-4.9.7}/tests/timings.py +0 -0
@@ -2,6 +2,12 @@
2
2
 
3
3
  <!--next-version-placeholder-->
4
4
 
5
+ ## v4.9.7 (2026-07-14)
6
+
7
+ ### Fix
8
+
9
+ * **fields:** Clear field requirements during unbind ([`7e054f9`](https://github.com/trialandsuccess/TypeDAL/commit/7e054f947358a3fbb491db0d777410433da43d44))
10
+
5
11
  ## v4.9.6 (2026-07-14)
6
12
 
7
13
  ### Fix
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: TypeDAL
3
- Version: 4.9.6
3
+ Version: 4.9.7
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
@@ -193,8 +193,7 @@ exclude = ["venv", ".bak"]
193
193
  target-version = "py314"
194
194
  line-length = 120
195
195
 
196
- extend-exclude = ["*.bak/", "venv*/"]
197
-
196
+ extend-exclude = ["*.bak/", "venv*/", "tests/", "example_*.py"]
198
197
  [tool.ruff.lint]
199
198
 
200
199
  select = [
@@ -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.9.6"
8
+ __version__ = "4.9.7"
@@ -425,8 +425,7 @@ def fake_migrations(
425
425
 
426
426
  previously_migrated = (
427
427
  db(
428
- db.ewh_implemented_features.name.belongs(to_fake)
429
- & (db.ewh_implemented_features.installed == True), # noqa E712
428
+ db.ewh_implemented_features.name.belongs(to_fake) & (db.ewh_implemented_features.installed == True), # noqa E712
430
429
  )
431
430
  .select(db.ewh_implemented_features.name)
432
431
  .column("name")
@@ -199,6 +199,12 @@ class TypedField[T_Value](Expression): # pragma: no cover
199
199
 
200
200
  def unbind(self) -> None:
201
201
  """Remove references to the pydal objects created during ``bind``."""
202
+ if getattr(self, "requires", None):
203
+ if isinstance(self.requires, list):
204
+ self.requires.clear()
205
+ else:
206
+ self.requires = []
207
+
202
208
  self._table = None
203
209
  self._field = None
204
210
 
@@ -33,7 +33,7 @@ def generate_nav_entries() -> list[str]:
33
33
 
34
34
 
35
35
  @task
36
- def update_docs_nav(ctx: Context) -> None:
36
+ def update_docs_nav(_: Context) -> None:
37
37
  """Update mkdocs.yml nav section from actual markdown files to prevent sync issues."""
38
38
  mkdocs_file = Path(__file__).parent / "mkdocs.yml"
39
39
 
@@ -14,6 +14,7 @@ from src.typedal import TypedRows
14
14
  from src.typedal.__about__ import __version__
15
15
  from src.typedal.enum_helpers import InvalidEnumValue
16
16
  from src.typedal.fields import *
17
+ from src.typedal.web2py_py4web_shared import AuthUser
17
18
 
18
19
 
19
20
  def test_about():
@@ -47,6 +48,25 @@ def test_database_is_garbage_collected_after_close():
47
48
  assert db_ref() is None
48
49
 
49
50
 
51
+ def test_database_with_auth_user_is_garbage_collected_after_close():
52
+ db = TypeDAL("sqlite:memory", enable_typedal_caching=False)
53
+ db.define(AuthUser, redefine=True)
54
+
55
+ AuthUser.after_insert(lambda row, db=db: print(db))
56
+
57
+ db_ref = weakref.ref(db)
58
+
59
+ db.close()
60
+
61
+ assert AuthUser._db is None
62
+ assert AuthUser._table is None
63
+
64
+ del db
65
+ gc.collect()
66
+
67
+ assert db_ref() is None
68
+
69
+
50
70
  def test_mixed_defines(capsys):
51
71
  ### DEFINE
52
72
 
@@ -178,12 +178,12 @@ def mypy_test_mixin_typed_table_argument() -> None:
178
178
 
179
179
  @pytest.mark.mypy_testing
180
180
  def mypy_test_cachefn() -> None:
181
- def cache_model(key: str, fn: CacheFn, expire: int) -> Rows:
181
+ def cache_model(_key: str, fn: CacheFn, _expire: int) -> Rows:
182
182
  return fn()
183
183
 
184
- cache_valid: CacheTuple = (cache_model, 3000)
184
+ _cache_valid: CacheTuple = (cache_model, 3000)
185
185
 
186
- def invalid_cache_model(key: str, fn: typing.Callable[..., list[str]], _: int = None) -> list[str]:
186
+ def invalid_cache_model(_key: str, fn: typing.Callable[..., list[str]], _expire: int = None) -> list[str]:
187
187
  return fn()
188
188
 
189
- cache_invalid: CacheTuple = (invalid_cache_model, 3000) # E: [assignment]
189
+ _cache_invalid: CacheTuple = (invalid_cache_model, 3000) # E: [assignment]
@@ -0,0 +1,91 @@
1
+ import json
2
+ import tempfile
3
+
4
+ from contextlib_chdir import chdir
5
+ from pydal.validators import IS_EMAIL, IS_NOT_IN_DB
6
+
7
+ from src.typedal import TypedTable
8
+ from src.typedal.for_py4web import DAL, AuthUser, setup_py4web_tables
9
+ from src.typedal.serializers import as_json
10
+ from typedal.config import TypeDALConfig
11
+
12
+ db = DAL("sqlite:memory")
13
+
14
+
15
+ def test_P4W():
16
+ assert hasattr(DAL, "on_request")
17
+ assert hasattr(db, "on_request")
18
+
19
+
20
+ def test_serialize():
21
+ @db.define()
22
+ class JsonTable(TypedTable):
23
+ field: str
24
+
25
+ row = JsonTable.insert(field="Hey")
26
+
27
+ loaded_data = json.loads(as_json.encode(JsonTable))
28
+ assert loaded_data
29
+ assert isinstance(loaded_data, dict)
30
+ loaded_data = json.loads(as_json.encode(row))
31
+ assert isinstance(loaded_data, dict)
32
+ assert loaded_data
33
+
34
+ loaded_data = json.loads(as_json.encode(JsonTable.paginate(limit=1)))
35
+
36
+ assert loaded_data["pagination"]
37
+ assert loaded_data["data"]
38
+
39
+
40
+ def test_auth_user():
41
+ setup_py4web_tables(db)
42
+ requirements = AuthUser.email.requires
43
+
44
+ assert requirements
45
+ assert isinstance(requirements, list)
46
+ assert len(requirements) == 2
47
+
48
+ assert isinstance(requirements[0], IS_EMAIL)
49
+ assert isinstance(requirements[1], IS_NOT_IN_DB)
50
+
51
+
52
+ def test_py4web_dal_singleton():
53
+ with tempfile.TemporaryDirectory() as d, chdir(d):
54
+ # note: typedal caching is disabled here because otherwise the cache table might send logs to {d}/log.sql
55
+ # which can lead to problems in other tests :(
56
+ db_1a = DAL("sqlite:memory", enable_typedal_caching=False)
57
+ db_1b = DAL("sqlite:memory", enable_typedal_caching=False)
58
+
59
+ db_2a = DAL("sqlite://test_py4web_dal_singleton", folder=d, enable_typedal_caching=False)
60
+ db_2b = DAL("sqlite://test_py4web_dal_singleton", folder=d, enable_typedal_caching=False)
61
+
62
+ conf = {"database": "sqlite:memory", "dialect": "sqlite", "pyproject": "", "flag_location": f"{d}/flags"}
63
+ db_3a = DAL(config=TypeDALConfig.load(conf))
64
+ db_3b = DAL(config=TypeDALConfig.load(conf))
65
+
66
+ assert db_1a is db_1b
67
+ assert db_1a._uri == db_1b._uri
68
+ assert db_1a._db_uid == db_1b._db_uid
69
+
70
+ assert db_2a is db_2b
71
+ assert db_2a._uri == db_2b._uri
72
+ assert db_2a._db_uid == db_2b._db_uid
73
+
74
+ assert db_1a is not db_2a
75
+ assert db_1a._uri != db_2a._uri
76
+ assert db_1a._db_uid != db_2a._db_uid
77
+
78
+ assert db_1b is not db_2b
79
+ assert db_1b._uri != db_2b._uri
80
+ assert db_1b._db_uid != db_2b._db_uid
81
+
82
+ assert db_3a is db_3b
83
+ assert db_3a is not db_1a
84
+ assert db_3a is not db_2a
85
+
86
+ assert db_1a._uri == db_1b._uri
87
+ assert db_3a._uri == db_1a._uri
88
+ assert db_3a._uri != db_2a._uri
89
+
90
+ # reset singletons for later use:
91
+ DAL._clear()
@@ -129,8 +129,8 @@ def _setup_data():
129
129
 
130
130
  # no relationships:
131
131
  new_author = User.insert(name="Untagged Author", roles=[], main_role=writer, extra_roles=[])
132
- untagged1 = Article.insert(title="Untagged Article 1", author=new_author)
133
- untagged2 = Article.insert(title="Untagged Article 2", author=new_author)
132
+ _untagged1 = Article.insert(title="Untagged Article 1", author=new_author)
133
+ _untagged2 = Article.insert(title="Untagged Article 2", author=new_author)
134
134
 
135
135
  # articles
136
136
 
@@ -355,10 +355,9 @@ def test_reprs():
355
355
 
356
356
  assert "AND" not in repr(relation)
357
357
 
358
- relation = Article.join("author", condition_and=lambda article, author: author.name != "Hank").relationships[
358
+ relation = Article.join("author", condition_and=lambda _article, author: author.name != "Hank").relationships[
359
359
  "author"
360
360
  ]
361
-
362
361
  assert "AND" in repr(relation) and "Hank" in repr(relation)
363
362
 
364
363
 
@@ -436,7 +435,7 @@ def test_join_with_different_condition():
436
435
  role_with_users = Role.join(
437
436
  "users",
438
437
  method="inner",
439
- condition_and=lambda role, user: ~user.name.like("Reader%"),
438
+ condition_and=lambda _role, user: ~user.name.like("Reader%"),
440
439
  ).first()
441
440
 
442
441
  assert role_with_users.users
@@ -446,7 +445,7 @@ def test_join_with_different_condition():
446
445
  role_with_users = Role.join(
447
446
  "users",
448
447
  method="left",
449
- condition_and=lambda role, user: ~user.name.like("Reader%"),
448
+ condition_and=lambda _role, user: ~user.name.like("Reader%"),
450
449
  ).first()
451
450
 
452
451
  assert role_with_users.users
@@ -729,11 +728,11 @@ def test_memoize_nested_dependencies():
729
728
  assert len(users) > 0
730
729
 
731
730
  # First memoize - should be fresh
732
- result1, status = db.memoize(process_users, users)
731
+ _result1, status = db.memoize(process_users, users)
733
732
  assert status == "fresh"
734
733
 
735
734
  # Second call - should be cached
736
- result2, status = db.memoize(process_users, users)
735
+ _result2, status = db.memoize(process_users, users)
737
736
  assert status == "cached"
738
737
 
739
738
  # Update a Role that was accessed inside process_users
@@ -742,7 +741,7 @@ def test_memoize_nested_dependencies():
742
741
 
743
742
  # Third call - should be fresh (invalidated by Role change)
744
743
  # but currently will still be "cached" because we only tracked User deps
745
- result3, status = db.memoize(process_users, users)
744
+ _result3, status = db.memoize(process_users, users)
746
745
  assert status == "fresh"
747
746
 
748
747
 
@@ -755,25 +754,25 @@ def test_memoize_nested_dependencies2():
755
754
  # (which happens when using _determine_dependencies_auto)
756
755
  return list(User.join())
757
756
 
758
- bogus, status = db.memoize(something_slow)
757
+ _bogus, status = db.memoize(something_slow)
759
758
  assert status == "fresh"
760
759
 
761
760
  # no change
762
- bogus, status = db.memoize(something_slow)
761
+ _bogus, status = db.memoize(something_slow)
763
762
  assert status == "cached"
764
763
 
765
764
  # user change
766
765
  User.first().update_record(name="New Name :)")
767
- bogus, status = db.memoize(something_slow)
766
+ _bogus, status = db.memoize(something_slow)
768
767
  assert status == "fresh"
769
768
 
770
769
  # role change
771
770
  Role.first().update_record(name="New Role Name :)")
772
- bogus, status = db.memoize(something_slow)
771
+ _bogus, status = db.memoize(something_slow)
773
772
  assert status == "fresh"
774
773
 
775
774
  # no change
776
- bogus, status = db.memoize(something_slow)
775
+ _bogus, status = db.memoize(something_slow)
777
776
  assert status == "cached"
778
777
 
779
778
 
@@ -931,7 +930,8 @@ def test_accessing_raw_data():
931
930
 
932
931
  user = User.where(id=4).join("articles").first()
933
932
 
934
- # <User({"id": 4, "name": "Untagged Author", "roles": [], "gid": "967da807-eb13-46dc-a0f3-d5c04751edf4", "main_role": 2, "extra_roles": []}) + ['articles']>
933
+ # <User({"id": 4, "name": "Untagged Author", "roles": [],
934
+ # "gid": "967da807-eb13-46dc-a0f3-d5c04751edf4", "main_role": 2, "extra_roles": []}) + ['articles']>
935
935
  assert user._row
936
936
 
937
937
  # one row per user+article combination like how postgres returns it:
@@ -1031,9 +1031,9 @@ def test_nested_join_with_shared_foreign_key():
1031
1031
  tech_corp = Company.insert(name="Tech Corp")
1032
1032
 
1033
1033
  # Create multiple offices in the same city for the same company
1034
- office1 = Office.insert(address="123 Market St", city_id=san_francisco.id, company=tech_corp.id)
1035
- office2 = Office.insert(address="456 Mission St", city_id=san_francisco.id, company=tech_corp.id)
1036
- office3 = Office.insert(address="789 Howard St", city_id=san_francisco.id, company=tech_corp.id)
1034
+ _office1 = Office.insert(address="123 Market St", city_id=san_francisco.id, company=tech_corp.id)
1035
+ _office2 = Office.insert(address="456 Mission St", city_id=san_francisco.id, company=tech_corp.id)
1036
+ _office3 = Office.insert(address="789 Howard St", city_id=san_francisco.id, company=tech_corp.id)
1037
1037
 
1038
1038
  db.commit()
1039
1039
 
@@ -1072,7 +1072,8 @@ def test_nested_join_with_shared_foreign_key():
1072
1072
  f"Office {idx} ('{office.address}'): city relationship is None (BUG!)"
1073
1073
  )
1074
1074
  assert isinstance(office.city_alternative, City), (
1075
- f"Office {idx}: city ({office.city_alternative}) is not a City instance but a {type(office.city_alternative)}"
1075
+ f"Office {idx}: city ({office.city_alternative}) "
1076
+ f"is not a City instance but a {type(office.city_alternative)}"
1076
1077
  )
1077
1078
  assert office.city_alternative.name == "San Francisco", (
1078
1079
  f"Office {idx}: expected 'San Francisco', got '{office.city_alternative.name}'"
@@ -1,92 +0,0 @@
1
- import json
2
- import tempfile
3
-
4
- from contextlib_chdir import chdir
5
- from pydal.validators import IS_EMAIL, IS_NOT_IN_DB
6
-
7
- from src.typedal import TypedTable
8
- from src.typedal.for_py4web import DAL, AuthUser, setup_py4web_tables
9
- from src.typedal.serializers import as_json
10
- from typedal.config import TypeDALConfig
11
-
12
- db = DAL("sqlite:memory")
13
-
14
-
15
- def test_P4W():
16
- assert hasattr(DAL, "on_request")
17
- assert hasattr(db, "on_request")
18
-
19
-
20
- def test_serialize():
21
- @db.define()
22
- class JsonTable(TypedTable):
23
- field: str
24
-
25
- row = JsonTable.insert(field="Hey")
26
-
27
- l = json.loads(as_json.encode(JsonTable))
28
- assert l
29
- assert isinstance(l, dict)
30
- l = json.loads(as_json.encode(row))
31
- assert isinstance(l, dict)
32
- assert l
33
-
34
- l = json.loads(as_json.encode(JsonTable.paginate(limit=1)))
35
-
36
- assert l["pagination"]
37
- assert l["data"]
38
-
39
-
40
- def test_auth_user():
41
- setup_py4web_tables(db)
42
- requirements = AuthUser.email.requires
43
-
44
- assert requirements
45
- assert isinstance(requirements, list)
46
- assert len(requirements) == 2
47
-
48
- assert isinstance(requirements[0], IS_EMAIL)
49
- assert isinstance(requirements[1], IS_NOT_IN_DB)
50
-
51
-
52
- def test_py4web_dal_singleton():
53
- with tempfile.TemporaryDirectory() as d:
54
- with chdir(d):
55
- # note: typedal caching is disabled here because otherwise the cache table might send logs to {d}/log.sql
56
- # which can lead to problems in other tests :(
57
- db_1a = DAL("sqlite:memory", enable_typedal_caching=False)
58
- db_1b = DAL("sqlite:memory", enable_typedal_caching=False)
59
-
60
- db_2a = DAL("sqlite://test_py4web_dal_singleton", folder=d, enable_typedal_caching=False)
61
- db_2b = DAL("sqlite://test_py4web_dal_singleton", folder=d, enable_typedal_caching=False)
62
-
63
- conf = {"database": "sqlite:memory", "dialect": "sqlite", "pyproject": "", "flag_location": f"{d}/flags"}
64
- db_3a = DAL(config=TypeDALConfig.load(conf))
65
- db_3b = DAL(config=TypeDALConfig.load(conf))
66
-
67
- assert db_1a is db_1b
68
- assert db_1a._uri == db_1b._uri
69
- assert db_1a._db_uid == db_1b._db_uid
70
-
71
- assert db_2a is db_2b
72
- assert db_2a._uri == db_2b._uri
73
- assert db_2a._db_uid == db_2b._db_uid
74
-
75
- assert db_1a is not db_2a
76
- assert db_1a._uri != db_2a._uri
77
- assert db_1a._db_uid != db_2a._db_uid
78
-
79
- assert db_1b is not db_2b
80
- assert db_1b._uri != db_2b._uri
81
- assert db_1b._db_uid != db_2b._db_uid
82
-
83
- assert db_3a is db_3b
84
- assert db_3a is not db_1a
85
- assert db_3a is not db_2a
86
-
87
- assert db_1a._uri == db_1b._uri
88
- assert db_3a._uri == db_1a._uri
89
- assert db_3a._uri != db_2a._uri
90
-
91
- # reset singletons for later use:
92
- DAL._clear()
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