TypeDAL 3.14.1__tar.gz → 3.14.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.
Potentially problematic release.
This version of TypeDAL might be problematic. Click here for more details.
- {typedal-3.14.1 → typedal-3.14.3}/CHANGELOG.md +12 -0
- {typedal-3.14.1 → typedal-3.14.3}/PKG-INFO +1 -1
- {typedal-3.14.1 → typedal-3.14.3}/src/typedal/__about__.py +1 -1
- {typedal-3.14.1 → typedal-3.14.3}/src/typedal/cli.py +1 -2
- {typedal-3.14.1 → typedal-3.14.3}/src/typedal/fields.py +32 -2
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_config.py +21 -4
- {typedal-3.14.1 → typedal-3.14.3}/.github/workflows/su6.yml +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/.gitignore +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/.readthedocs.yml +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/README.md +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/coverage.svg +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/docs/1_getting_started.md +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/docs/2_defining_tables.md +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/docs/3_building_queries.md +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/docs/4_relationships.md +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/docs/5_py4web.md +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/docs/6_migrations.md +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/docs/7_mixins.md +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/docs/css/code_blocks.css +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/docs/index.md +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/docs/requirements.txt +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/example_new.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/example_old.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/mkdocs.yml +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/pyproject.toml +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/src/typedal/__init__.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/src/typedal/caching.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/src/typedal/config.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/src/typedal/core.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/src/typedal/for_py4web.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/src/typedal/for_web2py.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/src/typedal/helpers.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/src/typedal/mixins.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/src/typedal/py.typed +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/src/typedal/serializers/as_json.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/src/typedal/types.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/src/typedal/web2py_py4web_shared.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/__init__.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/configs/simple.toml +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/configs/valid.env +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/configs/valid.toml +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_cli.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_docs_examples.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_helpers.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_json.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_main.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_mixins.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_mypy.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_orm.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_py4web.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_query_builder.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_relationships.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_row.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_stats.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_table.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_web2py.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/test_xx_others.py +0 -0
- {typedal-3.14.1 → typedal-3.14.3}/tests/timings.py +0 -0
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
<!--next-version-placeholder-->
|
|
4
4
|
|
|
5
|
+
## v3.14.3 (2025-06-09)
|
|
6
|
+
|
|
7
|
+
### Fix
|
|
8
|
+
|
|
9
|
+
* Improved `point` parsing ([`9d8aa8a`](https://github.com/trialandsuccess/TypeDAL/commit/9d8aa8a9e23e09b5818153f0d9674176822d3893))
|
|
10
|
+
|
|
11
|
+
## v3.14.2 (2025-06-05)
|
|
12
|
+
|
|
13
|
+
### Fix
|
|
14
|
+
|
|
15
|
+
* **PointField:** Don't crash if invalid point is parsed ([`e14b4a3`](https://github.com/trialandsuccess/TypeDAL/commit/e14b4a349799799cc94e8fb62d9da9a0fafdcd36))
|
|
16
|
+
|
|
5
17
|
## v3.14.1 (2025-05-27)
|
|
6
18
|
|
|
7
19
|
### Fix
|
|
@@ -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,41 @@ 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: tuple[str, str] | str) -> str:
|
|
271
|
+
if not value:
|
|
272
|
+
return ""
|
|
273
|
+
|
|
274
|
+
# Convert string to tuple if needed
|
|
275
|
+
if isinstance(value, str):
|
|
276
|
+
value = value.strip("() ")
|
|
277
|
+
if not value:
|
|
278
|
+
return ""
|
|
279
|
+
value = tuple(float(x.strip()) for x in value.split(","))
|
|
280
|
+
|
|
281
|
+
# Validate and format
|
|
282
|
+
if len(value) != 2:
|
|
283
|
+
raise ValueError("Point must have exactly 2 coordinates")
|
|
284
|
+
|
|
285
|
+
x, y = value
|
|
286
|
+
return f"({x},{y})"
|
|
287
|
+
|
|
288
|
+
|
|
259
289
|
NativePointField = SQLCustomType(
|
|
260
290
|
type="string",
|
|
261
291
|
native="point",
|
|
262
|
-
encoder=
|
|
263
|
-
decoder=
|
|
292
|
+
encoder=safe_encode_native_point,
|
|
293
|
+
decoder=safe_decode_native_point,
|
|
264
294
|
)
|
|
265
295
|
|
|
266
296
|
|
|
@@ -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
|
-
|
|
240
|
-
|
|
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):
|
|
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
|