piccolo 1.27.1__py3-none-any.whl → 1.29.0__py3-none-any.whl
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.
- piccolo/__init__.py +1 -1
- piccolo/apps/app/commands/new.py +3 -3
- piccolo/apps/asgi/commands/new.py +2 -3
- piccolo/apps/asgi/commands/templates/app/_blacksheep_app.py.jinja +57 -29
- piccolo/apps/asgi/commands/templates/app/_esmerald_app.py.jinja +48 -21
- piccolo/apps/asgi/commands/templates/app/_falcon_app.py.jinja +63 -8
- piccolo/apps/asgi/commands/templates/app/_fastapi_app.py.jinja +51 -24
- piccolo/apps/asgi/commands/templates/app/_litestar_app.py.jinja +34 -10
- piccolo/apps/asgi/commands/templates/app/_quart_app.py.jinja +38 -15
- piccolo/apps/asgi/commands/templates/app/_sanic_app.py.jinja +34 -11
- piccolo/apps/fixtures/commands/dump.py +8 -8
- piccolo/apps/fixtures/commands/load.py +5 -5
- piccolo/apps/fixtures/commands/shared.py +9 -9
- piccolo/apps/migrations/auto/diffable_table.py +12 -12
- piccolo/apps/migrations/auto/migration_manager.py +59 -66
- piccolo/apps/migrations/auto/operations.py +14 -14
- piccolo/apps/migrations/auto/schema_differ.py +35 -34
- piccolo/apps/migrations/auto/schema_snapshot.py +3 -4
- piccolo/apps/migrations/auto/serialisation.py +27 -24
- piccolo/apps/migrations/auto/serialisation_legacy.py +2 -2
- piccolo/apps/migrations/commands/backwards.py +1 -2
- piccolo/apps/migrations/commands/base.py +12 -12
- piccolo/apps/migrations/commands/check.py +2 -3
- piccolo/apps/migrations/commands/clean.py +3 -3
- piccolo/apps/migrations/commands/forwards.py +1 -2
- piccolo/apps/migrations/commands/new.py +6 -6
- piccolo/apps/migrations/tables.py +3 -3
- piccolo/apps/playground/commands/run.py +72 -13
- piccolo/apps/schema/commands/generate.py +49 -49
- piccolo/apps/schema/commands/graph.py +5 -5
- piccolo/apps/shell/commands/run.py +1 -2
- piccolo/apps/sql_shell/commands/run.py +4 -4
- piccolo/apps/tester/commands/run.py +3 -3
- piccolo/apps/user/commands/change_permissions.py +6 -6
- piccolo/apps/user/commands/create.py +7 -7
- piccolo/apps/user/commands/list.py +2 -2
- piccolo/apps/user/tables.py +8 -8
- piccolo/columns/base.py +84 -52
- piccolo/columns/choices.py +2 -2
- piccolo/columns/column_types.py +299 -177
- piccolo/columns/combination.py +15 -12
- piccolo/columns/defaults/base.py +4 -4
- piccolo/columns/defaults/date.py +4 -3
- piccolo/columns/defaults/interval.py +4 -3
- piccolo/columns/defaults/time.py +4 -3
- piccolo/columns/defaults/timestamp.py +4 -3
- piccolo/columns/defaults/timestamptz.py +4 -3
- piccolo/columns/defaults/uuid.py +3 -2
- piccolo/columns/m2m.py +28 -35
- piccolo/columns/readable.py +4 -3
- piccolo/columns/reference.py +9 -9
- piccolo/conf/apps.py +53 -54
- piccolo/custom_types.py +28 -6
- piccolo/engine/base.py +14 -14
- piccolo/engine/cockroach.py +5 -4
- piccolo/engine/finder.py +2 -2
- piccolo/engine/postgres.py +20 -19
- piccolo/engine/sqlite.py +23 -22
- piccolo/query/base.py +30 -29
- piccolo/query/functions/__init__.py +12 -0
- piccolo/query/functions/aggregate.py +4 -3
- piccolo/query/functions/array.py +151 -0
- piccolo/query/functions/base.py +3 -3
- piccolo/query/functions/datetime.py +22 -22
- piccolo/query/functions/string.py +4 -4
- piccolo/query/functions/type_conversion.py +30 -15
- piccolo/query/methods/alter.py +47 -46
- piccolo/query/methods/count.py +11 -10
- piccolo/query/methods/create.py +6 -5
- piccolo/query/methods/create_index.py +9 -8
- piccolo/query/methods/delete.py +7 -6
- piccolo/query/methods/drop_index.py +7 -6
- piccolo/query/methods/exists.py +6 -5
- piccolo/query/methods/indexes.py +4 -4
- piccolo/query/methods/insert.py +21 -14
- piccolo/query/methods/objects.py +60 -50
- piccolo/query/methods/raw.py +7 -6
- piccolo/query/methods/refresh.py +8 -7
- piccolo/query/methods/select.py +56 -49
- piccolo/query/methods/table_exists.py +5 -5
- piccolo/query/methods/update.py +8 -7
- piccolo/query/mixins.py +56 -61
- piccolo/query/operators/json.py +11 -11
- piccolo/query/proxy.py +8 -9
- piccolo/querystring.py +14 -15
- piccolo/schema.py +10 -10
- piccolo/table.py +105 -98
- piccolo/table_reflection.py +9 -9
- piccolo/testing/model_builder.py +16 -13
- piccolo/testing/random_builder.py +14 -2
- piccolo/testing/test_case.py +4 -4
- piccolo/utils/dictionary.py +3 -3
- piccolo/utils/encoding.py +5 -5
- piccolo/utils/lazy_loader.py +3 -3
- piccolo/utils/list.py +7 -8
- piccolo/utils/objects.py +4 -6
- piccolo/utils/pydantic.py +21 -24
- piccolo/utils/sql_values.py +3 -3
- piccolo/utils/sync.py +4 -3
- piccolo/utils/warnings.py +1 -2
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/METADATA +1 -1
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/RECORD +132 -131
- tests/apps/fixtures/commands/test_dump_load.py +1 -2
- tests/apps/migrations/auto/integration/test_migrations.py +32 -7
- tests/apps/migrations/auto/test_migration_manager.py +2 -2
- tests/apps/migrations/auto/test_schema_differ.py +22 -23
- tests/apps/migrations/commands/test_forwards_backwards.py +3 -3
- tests/columns/m2m/base.py +20 -49
- tests/columns/test_array.py +176 -10
- tests/columns/test_boolean.py +2 -4
- tests/columns/test_combination.py +29 -1
- tests/columns/test_db_column_name.py +2 -2
- tests/engine/test_extra_nodes.py +2 -2
- tests/engine/test_pool.py +3 -3
- tests/engine/test_transaction.py +4 -4
- tests/query/test_freeze.py +4 -4
- tests/table/instance/test_get_related.py +2 -2
- tests/table/test_alter.py +4 -4
- tests/table/test_indexes.py +1 -2
- tests/table/test_metaclass.py +7 -3
- tests/table/test_refresh.py +2 -2
- tests/table/test_select.py +58 -0
- tests/table/test_str.py +30 -22
- tests/table/test_update.py +18 -3
- tests/testing/test_model_builder.py +1 -2
- tests/testing/test_random_builder.py +5 -0
- tests/utils/test_pydantic.py +152 -134
- tests/utils/test_table_reflection.py +1 -2
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/WHEEL +0 -0
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/entry_points.txt +0 -0
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/licenses/LICENSE +0 -0
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/top_level.txt +0 -0
tests/utils/test_pydantic.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import decimal
|
2
|
-
|
2
|
+
from typing import Optional, cast
|
3
3
|
from unittest import TestCase
|
4
4
|
|
5
5
|
import pydantic
|
@@ -29,10 +29,10 @@ from piccolo.utils.pydantic import create_pydantic_model
|
|
29
29
|
|
30
30
|
class TestVarcharColumn(TestCase):
|
31
31
|
def test_varchar_length(self):
|
32
|
-
class
|
32
|
+
class Manager(Table):
|
33
33
|
name = Varchar(length=10)
|
34
34
|
|
35
|
-
pydantic_model = create_pydantic_model(table=
|
35
|
+
pydantic_model = create_pydantic_model(table=Manager)
|
36
36
|
|
37
37
|
with self.assertRaises(ValidationError):
|
38
38
|
pydantic_model(name="This is a really long name")
|
@@ -42,10 +42,10 @@ class TestVarcharColumn(TestCase):
|
|
42
42
|
|
43
43
|
class TestEmailColumn(TestCase):
|
44
44
|
def test_email(self):
|
45
|
-
class
|
45
|
+
class Manager(Table):
|
46
46
|
email = Email()
|
47
47
|
|
48
|
-
pydantic_model = create_pydantic_model(table=
|
48
|
+
pydantic_model = create_pydantic_model(table=Manager)
|
49
49
|
|
50
50
|
self.assertEqual(
|
51
51
|
pydantic_model.model_json_schema()["properties"]["email"]["anyOf"][
|
@@ -67,28 +67,28 @@ class TestNumericColumn(TestCase):
|
|
67
67
|
"""
|
68
68
|
|
69
69
|
def test_numeric_digits(self):
|
70
|
-
class
|
71
|
-
|
70
|
+
class Band(Table):
|
71
|
+
royalties = Numeric(digits=(5, 1))
|
72
72
|
|
73
|
-
pydantic_model = create_pydantic_model(table=
|
73
|
+
pydantic_model = create_pydantic_model(table=Band)
|
74
74
|
|
75
75
|
with self.assertRaises(ValidationError):
|
76
76
|
# This should fail as there are too much numbers after the decimal
|
77
77
|
# point
|
78
|
-
pydantic_model(
|
78
|
+
pydantic_model(royalties=decimal.Decimal("1.11"))
|
79
79
|
|
80
80
|
with self.assertRaises(ValidationError):
|
81
81
|
# This should fail as there are too much numbers in total
|
82
|
-
pydantic_model(
|
82
|
+
pydantic_model(royalties=decimal.Decimal("11111.1"))
|
83
83
|
|
84
|
-
pydantic_model(
|
84
|
+
pydantic_model(royalties=decimal.Decimal("1.0"))
|
85
85
|
|
86
86
|
def test_numeric_without_digits(self):
|
87
|
-
class
|
88
|
-
|
87
|
+
class Band(Table):
|
88
|
+
royalties = Numeric()
|
89
89
|
|
90
90
|
try:
|
91
|
-
create_pydantic_model(table=
|
91
|
+
create_pydantic_model(table=Band)
|
92
92
|
except TypeError:
|
93
93
|
self.fail(
|
94
94
|
"Creating numeric field without"
|
@@ -138,7 +138,7 @@ class TestArrayColumn(TestCase):
|
|
138
138
|
|
139
139
|
self.assertEqual(
|
140
140
|
pydantic_model.model_fields["members"].annotation,
|
141
|
-
|
141
|
+
list[list[pydantic.constr(max_length=255)]],
|
142
142
|
)
|
143
143
|
|
144
144
|
# Should not raise a validation error:
|
@@ -297,13 +297,13 @@ class TestColumnHelpText(TestCase):
|
|
297
297
|
def test_column_help_text_present(self):
|
298
298
|
help_text = "In millions of US dollars."
|
299
299
|
|
300
|
-
class
|
301
|
-
|
300
|
+
class Band(Table):
|
301
|
+
royalties = Numeric(digits=(5, 1), help_text=help_text)
|
302
302
|
|
303
|
-
pydantic_model = create_pydantic_model(table=
|
303
|
+
pydantic_model = create_pydantic_model(table=Band)
|
304
304
|
|
305
305
|
self.assertEqual(
|
306
|
-
pydantic_model.model_json_schema()["properties"]["
|
306
|
+
pydantic_model.model_json_schema()["properties"]["royalties"][
|
307
307
|
"extra"
|
308
308
|
]["help_text"],
|
309
309
|
help_text,
|
@@ -317,12 +317,12 @@ class TestTableHelpText(TestCase):
|
|
317
317
|
"""
|
318
318
|
|
319
319
|
def test_table_help_text_present(self):
|
320
|
-
help_text = "
|
320
|
+
help_text = "Bands playing concerts."
|
321
321
|
|
322
|
-
class
|
322
|
+
class Band(Table, help_text=help_text):
|
323
323
|
name = Varchar()
|
324
324
|
|
325
|
-
pydantic_model = create_pydantic_model(table=
|
325
|
+
pydantic_model = create_pydantic_model(table=Band)
|
326
326
|
|
327
327
|
self.assertEqual(
|
328
328
|
pydantic_model.model_json_schema()["extra"]["help_text"],
|
@@ -332,10 +332,10 @@ class TestTableHelpText(TestCase):
|
|
332
332
|
|
333
333
|
class TestUniqueColumn(TestCase):
|
334
334
|
def test_unique_column_true(self):
|
335
|
-
class
|
335
|
+
class Manager(Table):
|
336
336
|
name = Varchar(unique=True)
|
337
337
|
|
338
|
-
pydantic_model = create_pydantic_model(table=
|
338
|
+
pydantic_model = create_pydantic_model(table=Manager)
|
339
339
|
|
340
340
|
self.assertEqual(
|
341
341
|
pydantic_model.model_json_schema()["properties"]["name"]["extra"][
|
@@ -345,10 +345,10 @@ class TestUniqueColumn(TestCase):
|
|
345
345
|
)
|
346
346
|
|
347
347
|
def test_unique_column_false(self):
|
348
|
-
class
|
348
|
+
class Manager(Table):
|
349
349
|
name = Varchar()
|
350
350
|
|
351
|
-
pydantic_model = create_pydantic_model(table=
|
351
|
+
pydantic_model = create_pydantic_model(table=Manager)
|
352
352
|
|
353
353
|
self.assertEqual(
|
354
354
|
pydantic_model.model_json_schema()["properties"]["name"]["extra"][
|
@@ -360,48 +360,66 @@ class TestUniqueColumn(TestCase):
|
|
360
360
|
|
361
361
|
class TestJSONColumn(TestCase):
|
362
362
|
def test_default(self):
|
363
|
-
class
|
364
|
-
|
365
|
-
|
363
|
+
class Studio(Table):
|
364
|
+
facilities = JSON()
|
365
|
+
facilities_b = JSONB()
|
366
366
|
|
367
|
-
pydantic_model = create_pydantic_model(table=
|
367
|
+
pydantic_model = create_pydantic_model(table=Studio)
|
368
368
|
|
369
|
-
json_string = '{"
|
369
|
+
json_string = '{"guitar_amps": 6}'
|
370
370
|
|
371
|
-
model_instance = pydantic_model(
|
372
|
-
|
373
|
-
|
371
|
+
model_instance = pydantic_model(
|
372
|
+
facilities=json_string, facilities_b=json_string
|
373
|
+
)
|
374
|
+
self.assertEqual(
|
375
|
+
model_instance.facilities,
|
376
|
+
json_string,
|
377
|
+
)
|
378
|
+
self.assertEqual(
|
379
|
+
model_instance.facilities_b,
|
380
|
+
json_string,
|
381
|
+
)
|
374
382
|
|
375
383
|
def test_deserialize_json(self):
|
376
|
-
class
|
377
|
-
|
378
|
-
|
384
|
+
class Studio(Table):
|
385
|
+
facilities = JSON()
|
386
|
+
facilities_b = JSONB()
|
379
387
|
|
380
388
|
pydantic_model = create_pydantic_model(
|
381
|
-
table=
|
389
|
+
table=Studio, deserialize_json=True
|
382
390
|
)
|
383
391
|
|
384
|
-
json_string = '{"
|
385
|
-
output = {"
|
392
|
+
json_string = '{"guitar_amps": 6}'
|
393
|
+
output = {"guitar_amps": 6}
|
386
394
|
|
387
|
-
model_instance = pydantic_model(
|
388
|
-
|
389
|
-
|
395
|
+
model_instance = pydantic_model(
|
396
|
+
facilities=json_string, facilities_b=json_string
|
397
|
+
)
|
398
|
+
self.assertEqual(
|
399
|
+
model_instance.facilities,
|
400
|
+
output,
|
401
|
+
)
|
402
|
+
self.assertEqual(
|
403
|
+
model_instance.facilities_b,
|
404
|
+
output,
|
405
|
+
)
|
390
406
|
|
391
407
|
def test_validation(self):
|
392
|
-
class
|
393
|
-
|
394
|
-
|
408
|
+
class Studio(Table):
|
409
|
+
facilities = JSON()
|
410
|
+
facilities_b = JSONB()
|
395
411
|
|
396
412
|
for deserialize_json in (True, False):
|
397
413
|
pydantic_model = create_pydantic_model(
|
398
|
-
table=
|
414
|
+
table=Studio, deserialize_json=deserialize_json
|
399
415
|
)
|
400
416
|
|
401
417
|
json_string = "error"
|
402
418
|
|
403
419
|
with self.assertRaises(pydantic.ValidationError):
|
404
|
-
pydantic_model(
|
420
|
+
pydantic_model(
|
421
|
+
facilities=json_string, facilities_b=json_string
|
422
|
+
)
|
405
423
|
|
406
424
|
def test_json_widget(self):
|
407
425
|
"""
|
@@ -409,112 +427,112 @@ class TestJSONColumn(TestCase):
|
|
409
427
|
special widget in Piccolo Admin.
|
410
428
|
"""
|
411
429
|
|
412
|
-
class
|
413
|
-
|
430
|
+
class Studio(Table):
|
431
|
+
facilities = JSON()
|
414
432
|
|
415
|
-
pydantic_model = create_pydantic_model(table=
|
433
|
+
pydantic_model = create_pydantic_model(table=Studio)
|
416
434
|
|
417
435
|
self.assertEqual(
|
418
|
-
pydantic_model.model_json_schema()["properties"]["
|
436
|
+
pydantic_model.model_json_schema()["properties"]["facilities"][
|
419
437
|
"extra"
|
420
438
|
]["widget"],
|
421
439
|
"json",
|
422
440
|
)
|
423
441
|
|
424
442
|
def test_null_value(self):
|
425
|
-
class
|
426
|
-
|
427
|
-
|
443
|
+
class Studio(Table):
|
444
|
+
facilities = JSON(null=True)
|
445
|
+
facilities_b = JSONB(null=True)
|
428
446
|
|
429
|
-
pydantic_model = create_pydantic_model(table=
|
430
|
-
movie = pydantic_model(
|
447
|
+
pydantic_model = create_pydantic_model(table=Studio)
|
448
|
+
movie = pydantic_model(facilities=None, facilities_b=None)
|
431
449
|
|
432
|
-
self.assertIsNone(movie.
|
433
|
-
self.assertIsNone(movie.
|
450
|
+
self.assertIsNone(movie.facilities)
|
451
|
+
self.assertIsNone(movie.facilities_b)
|
434
452
|
|
435
453
|
|
436
454
|
class TestExcludeColumns(TestCase):
|
437
455
|
def test_all(self):
|
438
|
-
class
|
439
|
-
|
440
|
-
|
456
|
+
class Band(Table):
|
457
|
+
name = Varchar()
|
458
|
+
bio = Text()
|
441
459
|
|
442
|
-
pydantic_model = create_pydantic_model(
|
460
|
+
pydantic_model = create_pydantic_model(Band, exclude_columns=())
|
443
461
|
|
444
462
|
properties = pydantic_model.model_json_schema()["properties"]
|
445
|
-
self.assertIsInstance(properties["
|
446
|
-
self.assertIsInstance(properties["
|
463
|
+
self.assertIsInstance(properties["name"], dict)
|
464
|
+
self.assertIsInstance(properties["bio"], dict)
|
447
465
|
|
448
466
|
def test_exclude(self):
|
449
|
-
class
|
450
|
-
|
451
|
-
|
467
|
+
class Band(Table):
|
468
|
+
name = Varchar()
|
469
|
+
album = Varchar()
|
452
470
|
|
453
471
|
pydantic_model = create_pydantic_model(
|
454
|
-
|
455
|
-
exclude_columns=(
|
472
|
+
Band,
|
473
|
+
exclude_columns=(Band.name,),
|
456
474
|
)
|
457
475
|
|
458
476
|
properties = pydantic_model.model_json_schema()["properties"]
|
459
|
-
self.assertIsInstance(properties.get("
|
460
|
-
self.assertIsNone(properties.get("
|
477
|
+
self.assertIsInstance(properties.get("album"), dict)
|
478
|
+
self.assertIsNone(properties.get("dict"))
|
461
479
|
|
462
480
|
def test_exclude_all_manually(self):
|
463
|
-
class
|
464
|
-
|
465
|
-
|
481
|
+
class Band(Table):
|
482
|
+
name = Varchar()
|
483
|
+
album = Varchar()
|
466
484
|
|
467
485
|
pydantic_model = create_pydantic_model(
|
468
|
-
|
469
|
-
exclude_columns=(
|
486
|
+
Band,
|
487
|
+
exclude_columns=(Band.name, Band.album),
|
470
488
|
)
|
471
489
|
|
472
490
|
self.assertEqual(pydantic_model.model_json_schema()["properties"], {})
|
473
491
|
|
474
492
|
def test_exclude_all_meta(self):
|
475
|
-
class
|
476
|
-
|
477
|
-
|
493
|
+
class Band(Table):
|
494
|
+
name = Varchar()
|
495
|
+
album = Varchar()
|
478
496
|
|
479
497
|
pydantic_model = create_pydantic_model(
|
480
|
-
|
481
|
-
exclude_columns=tuple(
|
498
|
+
Band,
|
499
|
+
exclude_columns=tuple(Band._meta.columns),
|
482
500
|
)
|
483
501
|
|
484
502
|
self.assertEqual(pydantic_model.model_json_schema()["properties"], {})
|
485
503
|
|
486
504
|
def test_invalid_column_str(self):
|
487
|
-
class
|
488
|
-
|
489
|
-
|
505
|
+
class Band(Table):
|
506
|
+
name = Varchar()
|
507
|
+
album = Varchar()
|
490
508
|
|
491
509
|
with self.assertRaises(ValueError):
|
492
510
|
create_pydantic_model(
|
493
|
-
|
494
|
-
exclude_columns=("
|
511
|
+
Band,
|
512
|
+
exclude_columns=("album",),
|
495
513
|
)
|
496
514
|
|
497
515
|
def test_invalid_column_different_table(self):
|
498
|
-
class
|
499
|
-
|
500
|
-
|
516
|
+
class Band(Table):
|
517
|
+
name = Varchar()
|
518
|
+
album = Varchar()
|
501
519
|
|
502
|
-
class
|
503
|
-
|
520
|
+
class Band2(Table):
|
521
|
+
photo = Varchar()
|
504
522
|
|
505
523
|
with self.assertRaises(ValueError):
|
506
|
-
create_pydantic_model(
|
524
|
+
create_pydantic_model(Band, exclude_columns=(Band2.photo,))
|
507
525
|
|
508
526
|
def test_invalid_column_different_table_same_type(self):
|
509
|
-
class
|
510
|
-
|
511
|
-
|
527
|
+
class Band(Table):
|
528
|
+
name = Varchar()
|
529
|
+
album = Varchar()
|
512
530
|
|
513
|
-
class
|
514
|
-
|
531
|
+
class Band2(Table):
|
532
|
+
name = Varchar()
|
515
533
|
|
516
534
|
with self.assertRaises(ValueError):
|
517
|
-
create_pydantic_model(
|
535
|
+
create_pydantic_model(Band, exclude_columns=(Band2.name,))
|
518
536
|
|
519
537
|
def test_exclude_nested(self):
|
520
538
|
class Manager(Table):
|
@@ -630,8 +648,8 @@ class TestNestedModel(TestCase):
|
|
630
648
|
|
631
649
|
#######################################################################
|
632
650
|
|
633
|
-
ManagerModel =
|
634
|
-
|
651
|
+
ManagerModel = cast(
|
652
|
+
type[pydantic.BaseModel],
|
635
653
|
BandModel.model_fields["manager"].annotation,
|
636
654
|
)
|
637
655
|
self.assertTrue(issubclass(ManagerModel, pydantic.BaseModel))
|
@@ -641,8 +659,8 @@ class TestNestedModel(TestCase):
|
|
641
659
|
|
642
660
|
#######################################################################
|
643
661
|
|
644
|
-
CountryModel =
|
645
|
-
|
662
|
+
CountryModel = cast(
|
663
|
+
type[pydantic.BaseModel],
|
646
664
|
ManagerModel.model_fields["country"].annotation,
|
647
665
|
)
|
648
666
|
self.assertTrue(issubclass(CountryModel, pydantic.BaseModel))
|
@@ -681,8 +699,8 @@ class TestNestedModel(TestCase):
|
|
681
699
|
|
682
700
|
BandModel = create_pydantic_model(table=Band, nested=(Band.manager,))
|
683
701
|
|
684
|
-
ManagerModel =
|
685
|
-
|
702
|
+
ManagerModel = cast(
|
703
|
+
type[pydantic.BaseModel],
|
686
704
|
BandModel.model_fields["manager"].annotation,
|
687
705
|
)
|
688
706
|
self.assertTrue(issubclass(ManagerModel, pydantic.BaseModel))
|
@@ -694,7 +712,7 @@ class TestNestedModel(TestCase):
|
|
694
712
|
AssistantManagerType = BandModel.model_fields[
|
695
713
|
"assistant_manager"
|
696
714
|
].annotation
|
697
|
-
self.assertIs(AssistantManagerType,
|
715
|
+
self.assertIs(AssistantManagerType, Optional[int])
|
698
716
|
|
699
717
|
#######################################################################
|
700
718
|
# Test two levels deep
|
@@ -703,8 +721,8 @@ class TestNestedModel(TestCase):
|
|
703
721
|
table=Band, nested=(Band.manager._.country,)
|
704
722
|
)
|
705
723
|
|
706
|
-
ManagerModel =
|
707
|
-
|
724
|
+
ManagerModel = cast(
|
725
|
+
type[pydantic.BaseModel],
|
708
726
|
BandModel.model_fields["manager"].annotation,
|
709
727
|
)
|
710
728
|
self.assertTrue(issubclass(ManagerModel, pydantic.BaseModel))
|
@@ -713,14 +731,14 @@ class TestNestedModel(TestCase):
|
|
713
731
|
)
|
714
732
|
self.assertEqual(ManagerModel.__qualname__, "Band.manager")
|
715
733
|
|
716
|
-
AssistantManagerType =
|
717
|
-
|
734
|
+
AssistantManagerType = cast(
|
735
|
+
type[pydantic.BaseModel],
|
718
736
|
BandModel.model_fields["assistant_manager"].annotation,
|
719
737
|
)
|
720
|
-
self.assertIs(AssistantManagerType,
|
738
|
+
self.assertIs(AssistantManagerType, Optional[int])
|
721
739
|
|
722
|
-
CountryModel =
|
723
|
-
|
740
|
+
CountryModel = cast(
|
741
|
+
type[pydantic.BaseModel],
|
724
742
|
ManagerModel.model_fields["country"].annotation,
|
725
743
|
)
|
726
744
|
self.assertTrue(issubclass(CountryModel, pydantic.BaseModel))
|
@@ -737,10 +755,10 @@ class TestNestedModel(TestCase):
|
|
737
755
|
)
|
738
756
|
|
739
757
|
VenueModel = ConcertModel.model_fields["venue"].annotation
|
740
|
-
self.assertIs(VenueModel,
|
758
|
+
self.assertIs(VenueModel, Optional[int])
|
741
759
|
|
742
|
-
BandModel =
|
743
|
-
|
760
|
+
BandModel = cast(
|
761
|
+
type[pydantic.BaseModel],
|
744
762
|
ConcertModel.model_fields["band_1"].annotation,
|
745
763
|
)
|
746
764
|
self.assertTrue(issubclass(BandModel, pydantic.BaseModel))
|
@@ -750,8 +768,8 @@ class TestNestedModel(TestCase):
|
|
750
768
|
)
|
751
769
|
self.assertEqual(BandModel.__qualname__, "Concert.band_1")
|
752
770
|
|
753
|
-
ManagerModel =
|
754
|
-
|
771
|
+
ManagerModel = cast(
|
772
|
+
type[pydantic.BaseModel],
|
755
773
|
BandModel.model_fields["manager"].annotation,
|
756
774
|
)
|
757
775
|
self.assertTrue(issubclass(ManagerModel, pydantic.BaseModel))
|
@@ -764,10 +782,10 @@ class TestNestedModel(TestCase):
|
|
764
782
|
AssistantManagerType = BandModel.model_fields[
|
765
783
|
"assistant_manager"
|
766
784
|
].annotation
|
767
|
-
self.assertIs(AssistantManagerType,
|
785
|
+
self.assertIs(AssistantManagerType, Optional[int])
|
768
786
|
|
769
787
|
CountryModel = ManagerModel.model_fields["country"].annotation
|
770
|
-
self.assertIs(CountryModel,
|
788
|
+
self.assertIs(CountryModel, Optional[int])
|
771
789
|
|
772
790
|
#######################################################################
|
773
791
|
# Test with `model_name` arg
|
@@ -778,8 +796,8 @@ class TestNestedModel(TestCase):
|
|
778
796
|
model_name="MyConcertModel",
|
779
797
|
)
|
780
798
|
|
781
|
-
BandModel =
|
782
|
-
|
799
|
+
BandModel = cast(
|
800
|
+
type[pydantic.BaseModel],
|
783
801
|
MyConcertModel.model_fields["band_1"].annotation,
|
784
802
|
)
|
785
803
|
self.assertEqual(BandModel.__qualname__, "MyConcertModel.band_1")
|
@@ -810,8 +828,8 @@ class TestNestedModel(TestCase):
|
|
810
828
|
table=Band, nested=True, include_default_columns=True
|
811
829
|
)
|
812
830
|
|
813
|
-
ManagerModel =
|
814
|
-
|
831
|
+
ManagerModel = cast(
|
832
|
+
type[pydantic.BaseModel],
|
815
833
|
BandModel.model_fields["manager"].annotation,
|
816
834
|
)
|
817
835
|
self.assertTrue(issubclass(ManagerModel, pydantic.BaseModel))
|
@@ -820,8 +838,8 @@ class TestNestedModel(TestCase):
|
|
820
838
|
["id", "name", "country"],
|
821
839
|
)
|
822
840
|
|
823
|
-
CountryModel =
|
824
|
-
|
841
|
+
CountryModel = cast(
|
842
|
+
type[pydantic.BaseModel],
|
825
843
|
ManagerModel.model_fields["country"].annotation,
|
826
844
|
)
|
827
845
|
self.assertTrue(issubclass(CountryModel, pydantic.BaseModel))
|
@@ -855,27 +873,27 @@ class TestRecursionDepth(TestCase):
|
|
855
873
|
table=Concert, nested=True, max_recursion_depth=2
|
856
874
|
)
|
857
875
|
|
858
|
-
VenueModel =
|
859
|
-
|
876
|
+
VenueModel = cast(
|
877
|
+
type[pydantic.BaseModel],
|
860
878
|
ConcertModel.model_fields["venue"].annotation,
|
861
879
|
)
|
862
880
|
self.assertTrue(issubclass(VenueModel, pydantic.BaseModel))
|
863
881
|
|
864
|
-
BandModel =
|
865
|
-
|
882
|
+
BandModel = cast(
|
883
|
+
type[pydantic.BaseModel],
|
866
884
|
ConcertModel.model_fields["band"].annotation,
|
867
885
|
)
|
868
886
|
self.assertTrue(issubclass(BandModel, pydantic.BaseModel))
|
869
887
|
|
870
|
-
ManagerModel =
|
871
|
-
|
888
|
+
ManagerModel = cast(
|
889
|
+
type[pydantic.BaseModel],
|
872
890
|
BandModel.model_fields["manager"].annotation,
|
873
891
|
)
|
874
892
|
self.assertTrue(issubclass(ManagerModel, pydantic.BaseModel))
|
875
893
|
|
876
894
|
# We should have hit the recursion depth:
|
877
895
|
CountryModel = ManagerModel.model_fields["country"].annotation
|
878
|
-
self.assertIs(CountryModel,
|
896
|
+
self.assertIs(CountryModel, Optional[int])
|
879
897
|
|
880
898
|
|
881
899
|
class TestDBColumnName(TestCase):
|
@@ -892,7 +910,7 @@ class TestDBColumnName(TestCase):
|
|
892
910
|
|
893
911
|
model = BandModel(regrettable_column_name="test")
|
894
912
|
|
895
|
-
self.assertEqual(model.name, "test")
|
913
|
+
self.assertEqual(model.name, "test")
|
896
914
|
|
897
915
|
|
898
916
|
class TestJSONSchemaExtra(TestCase):
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import typing as t
|
2
1
|
from unittest import TestCase
|
3
2
|
|
4
3
|
from piccolo.columns import Varchar
|
@@ -22,7 +21,7 @@ class TestTableStorage(TestCase):
|
|
22
21
|
table_class.alter().drop_table(if_exists=True).run_sync()
|
23
22
|
|
24
23
|
def _compare_table_columns(
|
25
|
-
self, table_1:
|
24
|
+
self, table_1: type[Table], table_2: type[Table]
|
26
25
|
):
|
27
26
|
"""
|
28
27
|
Make sure that for each column in table_1, there is a corresponding
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|