TypeDAL 3.14.0__tar.gz → 3.14.2__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.

Potentially problematic release.


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

Files changed (58) hide show
  1. {typedal-3.14.0 → typedal-3.14.2}/CHANGELOG.md +12 -0
  2. {typedal-3.14.0 → typedal-3.14.2}/PKG-INFO +2 -2
  3. {typedal-3.14.0 → typedal-3.14.2}/src/typedal/__about__.py +1 -1
  4. {typedal-3.14.0 → typedal-3.14.2}/src/typedal/cli.py +1 -2
  5. {typedal-3.14.0 → typedal-3.14.2}/src/typedal/fields.py +25 -2
  6. {typedal-3.14.0 → typedal-3.14.2}/src/typedal/mixins.py +4 -0
  7. {typedal-3.14.0 → typedal-3.14.2}/tests/test_config.py +21 -4
  8. {typedal-3.14.0 → typedal-3.14.2}/tests/test_mixins.py +8 -1
  9. {typedal-3.14.0 → typedal-3.14.2}/.github/workflows/su6.yml +0 -0
  10. {typedal-3.14.0 → typedal-3.14.2}/.gitignore +0 -0
  11. {typedal-3.14.0 → typedal-3.14.2}/.readthedocs.yml +0 -0
  12. {typedal-3.14.0 → typedal-3.14.2}/README.md +0 -0
  13. {typedal-3.14.0 → typedal-3.14.2}/coverage.svg +0 -0
  14. {typedal-3.14.0 → typedal-3.14.2}/docs/1_getting_started.md +0 -0
  15. {typedal-3.14.0 → typedal-3.14.2}/docs/2_defining_tables.md +0 -0
  16. {typedal-3.14.0 → typedal-3.14.2}/docs/3_building_queries.md +0 -0
  17. {typedal-3.14.0 → typedal-3.14.2}/docs/4_relationships.md +0 -0
  18. {typedal-3.14.0 → typedal-3.14.2}/docs/5_py4web.md +0 -0
  19. {typedal-3.14.0 → typedal-3.14.2}/docs/6_migrations.md +0 -0
  20. {typedal-3.14.0 → typedal-3.14.2}/docs/7_mixins.md +0 -0
  21. {typedal-3.14.0 → typedal-3.14.2}/docs/css/code_blocks.css +0 -0
  22. {typedal-3.14.0 → typedal-3.14.2}/docs/index.md +0 -0
  23. {typedal-3.14.0 → typedal-3.14.2}/docs/requirements.txt +0 -0
  24. {typedal-3.14.0 → typedal-3.14.2}/example_new.py +0 -0
  25. {typedal-3.14.0 → typedal-3.14.2}/example_old.py +0 -0
  26. {typedal-3.14.0 → typedal-3.14.2}/mkdocs.yml +0 -0
  27. {typedal-3.14.0 → typedal-3.14.2}/pyproject.toml +0 -0
  28. {typedal-3.14.0 → typedal-3.14.2}/src/typedal/__init__.py +0 -0
  29. {typedal-3.14.0 → typedal-3.14.2}/src/typedal/caching.py +0 -0
  30. {typedal-3.14.0 → typedal-3.14.2}/src/typedal/config.py +0 -0
  31. {typedal-3.14.0 → typedal-3.14.2}/src/typedal/core.py +0 -0
  32. {typedal-3.14.0 → typedal-3.14.2}/src/typedal/for_py4web.py +0 -0
  33. {typedal-3.14.0 → typedal-3.14.2}/src/typedal/for_web2py.py +0 -0
  34. {typedal-3.14.0 → typedal-3.14.2}/src/typedal/helpers.py +0 -0
  35. {typedal-3.14.0 → typedal-3.14.2}/src/typedal/py.typed +0 -0
  36. {typedal-3.14.0 → typedal-3.14.2}/src/typedal/serializers/as_json.py +0 -0
  37. {typedal-3.14.0 → typedal-3.14.2}/src/typedal/types.py +0 -0
  38. {typedal-3.14.0 → typedal-3.14.2}/src/typedal/web2py_py4web_shared.py +0 -0
  39. {typedal-3.14.0 → typedal-3.14.2}/tests/__init__.py +0 -0
  40. {typedal-3.14.0 → typedal-3.14.2}/tests/configs/simple.toml +0 -0
  41. {typedal-3.14.0 → typedal-3.14.2}/tests/configs/valid.env +0 -0
  42. {typedal-3.14.0 → typedal-3.14.2}/tests/configs/valid.toml +0 -0
  43. {typedal-3.14.0 → typedal-3.14.2}/tests/test_cli.py +0 -0
  44. {typedal-3.14.0 → typedal-3.14.2}/tests/test_docs_examples.py +0 -0
  45. {typedal-3.14.0 → typedal-3.14.2}/tests/test_helpers.py +0 -0
  46. {typedal-3.14.0 → typedal-3.14.2}/tests/test_json.py +0 -0
  47. {typedal-3.14.0 → typedal-3.14.2}/tests/test_main.py +0 -0
  48. {typedal-3.14.0 → typedal-3.14.2}/tests/test_mypy.py +0 -0
  49. {typedal-3.14.0 → typedal-3.14.2}/tests/test_orm.py +0 -0
  50. {typedal-3.14.0 → typedal-3.14.2}/tests/test_py4web.py +0 -0
  51. {typedal-3.14.0 → typedal-3.14.2}/tests/test_query_builder.py +0 -0
  52. {typedal-3.14.0 → typedal-3.14.2}/tests/test_relationships.py +0 -0
  53. {typedal-3.14.0 → typedal-3.14.2}/tests/test_row.py +0 -0
  54. {typedal-3.14.0 → typedal-3.14.2}/tests/test_stats.py +0 -0
  55. {typedal-3.14.0 → typedal-3.14.2}/tests/test_table.py +0 -0
  56. {typedal-3.14.0 → typedal-3.14.2}/tests/test_web2py.py +0 -0
  57. {typedal-3.14.0 → typedal-3.14.2}/tests/test_xx_others.py +0 -0
  58. {typedal-3.14.0 → typedal-3.14.2}/tests/timings.py +0 -0
@@ -2,6 +2,18 @@
2
2
 
3
3
  <!--next-version-placeholder-->
4
4
 
5
+ ## v3.14.2 (2025-06-05)
6
+
7
+ ### Fix
8
+
9
+ * **PointField:** Don't crash if invalid point is parsed ([`e14b4a3`](https://github.com/trialandsuccess/TypeDAL/commit/e14b4a349799799cc94e8fb62d9da9a0fafdcd36))
10
+
11
+ ## v3.14.1 (2025-05-27)
12
+
13
+ ### Fix
14
+
15
+ * Don't force slug if already manually set ([`a33b2b5`](https://github.com/trialandsuccess/TypeDAL/commit/a33b2b523a56ae9adc6fb4c49a5708efe7950977))
16
+
5
17
  ## v3.14.0 (2025-05-15)
6
18
 
7
19
  ### Feature
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.3
2
2
  Name: TypeDAL
3
- Version: 3.14.0
3
+ Version: 3.14.2
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
@@ -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__ = "3.14.0"
8
+ __version__ = "3.14.2"
@@ -392,8 +392,7 @@ def fake_migrations(
392
392
 
393
393
  previously_migrated = (
394
394
  db(
395
- db.ewh_implemented_features.name.belongs(to_fake)
396
- & (db.ewh_implemented_features.installed == True) # noqa E712
395
+ db.ewh_implemented_features.name.belongs(to_fake) & (db.ewh_implemented_features.installed == True) # noqa E712
397
396
  )
398
397
  .select(db.ewh_implemented_features.name)
399
398
  .column("name")
@@ -256,11 +256,34 @@ def TimestampField(**kw: Unpack[FieldSettings]) -> TypedField[dt.datetime]:
256
256
  )
257
257
 
258
258
 
259
+ def safe_decode_native_point(value: str | None):
260
+ if not value:
261
+ return ()
262
+
263
+ try:
264
+ return ast.literal_eval(value)
265
+ except ValueError: # pragma: no cover
266
+ # should not happen when inserted with `safe_encode_native_point` but you never know
267
+ return ()
268
+
269
+
270
+ def safe_encode_native_point(value):
271
+ if not value:
272
+ return ""
273
+
274
+ if isinstance(value, str):
275
+ value = tuple(float(_) for _ in value.strip("(").strip(")").split(","))
276
+ if not (isinstance(value, tuple) and len(value) == 2):
277
+ raise ValueError("Invalid point tuple")
278
+
279
+ return str(value)
280
+
281
+
259
282
  NativePointField = SQLCustomType(
260
283
  type="string",
261
284
  native="point",
262
- encoder=str,
263
- decoder=ast.literal_eval,
285
+ encoder=safe_encode_native_point,
286
+ decoder=safe_decode_native_point,
264
287
  )
265
288
 
266
289
 
@@ -197,6 +197,10 @@ class SlugMixin(Mixin):
197
197
 
198
198
  @classmethod
199
199
  def __generate_slug_before_insert(cls, row: OpRow) -> None:
200
+ if row.get("slug"):
201
+ # manually set -> skip
202
+ return None
203
+
200
204
  settings = cls.__settings__
201
205
 
202
206
  text_input = row[settings["slug_field"]]
@@ -219,7 +219,11 @@ def test_point_fields_sqlite(at_temp_dir):
219
219
  class Point(TypedTable):
220
220
  pt = PointField()
221
221
 
222
+ class OptionalPoint(TypedTable):
223
+ maybe_pt = PointField(notnull=False)
224
+
222
225
  db.define(Point)
226
+ db.define(OptionalPoint)
223
227
 
224
228
  row1 = Point.insert(pt=(1, 0))
225
229
  row2 = Point.insert(pt="(1, 0)")
@@ -236,8 +240,13 @@ def test_point_fields_sqlite(at_temp_dir):
236
240
  with pytest.raises(Exception):
237
241
  Point.insert(pt="123")
238
242
 
239
- # note: psql will check this whereas sqlite won't:
240
- Point.insert(pt=())
243
+ with pytest.raises(Exception):
244
+ Point.insert(pt=())
245
+
246
+ db.rollback()
247
+
248
+ row3 = OptionalPoint.insert(maybe_pt=())
249
+ assert row3.maybe_pt == ()
241
250
 
242
251
  assert '"pt" point NOT NULL' in Point._sql()
243
252
 
@@ -253,7 +262,11 @@ def test_point_fields_psql(at_temp_dir):
253
262
  class Point(TypedTable):
254
263
  pt = PointField()
255
264
 
265
+ class OptionalPoint(TypedTable):
266
+ maybe_pt = PointField(notnull=False)
267
+
256
268
  db.define(Point)
269
+ db.define(OptionalPoint)
257
270
 
258
271
  row1 = Point.insert(pt=(1, 0))
259
272
  row2 = Point.insert(pt="(1, 0)")
@@ -270,12 +283,16 @@ def test_point_fields_psql(at_temp_dir):
270
283
  with pytest.raises(Exception):
271
284
  Point.insert(pt="123")
272
285
 
273
- # note: psql will check this whereas sqlite won't:
274
-
275
286
  with pytest.raises(Exception):
276
287
  Point.insert(pt=())
277
288
 
289
+ db.rollback()
290
+
291
+ row3 = OptionalPoint.insert(maybe_pt=())
292
+ assert row3.maybe_pt == ()
293
+
278
294
  assert '"pt" point NOT NULL' in Point._sql()
295
+ assert "NOT NULL" not in OptionalPoint._sql()
279
296
 
280
297
 
281
298
  def test_uuid_fields_psql(at_temp_dir):
@@ -95,7 +95,7 @@ def test_slug(db):
95
95
  assert error is None
96
96
 
97
97
  assert row.name == "Two Words"
98
- assert row.slug.startswith("two-words")
98
+ assert row.slug.startswith("two-words-")
99
99
 
100
100
  row, error = TableWithSlugSuffix.validate_and_insert(name="Two Words")
101
101
  assert error is None
@@ -103,6 +103,13 @@ def test_slug(db):
103
103
  assert row.name == "Two Words"
104
104
  assert row.slug.startswith("two-words")
105
105
 
106
+ # test manual slug:
107
+ manual_slug = "some-other-slug-manually-defined"
108
+ # validate_and_insert will fail because 'slug' is not writable
109
+ row = TableWithMixins.insert(name="Some Name", slug=manual_slug)
110
+
111
+ assert row.slug == manual_slug
112
+
106
113
 
107
114
  def test_timestamps(db):
108
115
  row = TableWithTimestamps.insert(unrelated="Hi")
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