plexus-python-common 1.0.65__py3-none-any.whl → 1.0.66__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.
- plexus/common/utils/jsonutils.py +6 -2
- plexus/common/utils/ormutils.py +65 -31
- plexus/common/utils/tagutils.py +17 -14
- plexus/common/utils/testutils.py +2 -1
- {plexus_python_common-1.0.65.dist-info → plexus_python_common-1.0.66.dist-info}/METADATA +1 -1
- {plexus_python_common-1.0.65.dist-info → plexus_python_common-1.0.66.dist-info}/RECORD +8 -8
- {plexus_python_common-1.0.65.dist-info → plexus_python_common-1.0.66.dist-info}/WHEEL +0 -0
- {plexus_python_common-1.0.65.dist-info → plexus_python_common-1.0.66.dist-info}/top_level.txt +0 -0
plexus/common/utils/jsonutils.py
CHANGED
|
@@ -21,7 +21,9 @@ __all__ = [
|
|
|
21
21
|
]
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
def json_datetime_decoder(v: Any) -> datetime.datetime:
|
|
24
|
+
def json_datetime_decoder(v: Any) -> datetime.datetime | None:
|
|
25
|
+
if v is None:
|
|
26
|
+
return None
|
|
25
27
|
if isinstance(v, str):
|
|
26
28
|
return json_datetime_decoder(dt_parse(v, extended_format(with_us=True, with_tz=True)))
|
|
27
29
|
if isinstance(v, datetime.datetime):
|
|
@@ -29,7 +31,9 @@ def json_datetime_decoder(v: Any) -> datetime.datetime:
|
|
|
29
31
|
raise ValueError("unexpected type of value for datetime decoder")
|
|
30
32
|
|
|
31
33
|
|
|
32
|
-
def json_datetime_encoder(v: Any) -> str:
|
|
34
|
+
def json_datetime_encoder(v: Any) -> str | None:
|
|
35
|
+
if v is None:
|
|
36
|
+
return None
|
|
33
37
|
if isinstance(v, str):
|
|
34
38
|
return json_datetime_encoder(dt_parse(v, extended_format(with_us=True, with_tz=True)))
|
|
35
39
|
if isinstance(v, datetime.datetime):
|
plexus/common/utils/ormutils.py
CHANGED
|
@@ -28,6 +28,10 @@ __all__ = [
|
|
|
28
28
|
"ChangingModelMixinProtocol",
|
|
29
29
|
"SnapshotModelMixinProtocol",
|
|
30
30
|
"RevisionModelMixinProtocol",
|
|
31
|
+
"SQLiteDateTime",
|
|
32
|
+
"model_sqn_type",
|
|
33
|
+
"model_datetime_tz_type",
|
|
34
|
+
"model_revision_type",
|
|
31
35
|
"SequenceModelMixin",
|
|
32
36
|
"ChangingModelMixin",
|
|
33
37
|
"SnapshotModelMixin",
|
|
@@ -391,12 +395,26 @@ class RevisionModelMixinProtocol(SequenceModelMixinProtocol):
|
|
|
391
395
|
...
|
|
392
396
|
|
|
393
397
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
398
|
+
class SQLiteDateTime(sa.TypeDecorator):
|
|
399
|
+
"""
|
|
400
|
+
Custom SQLAlchemy type decorator for handling timezone-aware datetimes in SQLite.
|
|
401
|
+
"""
|
|
402
|
+
impl = sa.DateTime
|
|
403
|
+
cache_ok = True
|
|
404
|
+
|
|
405
|
+
def process_bind_param(self, value: datetime.datetime | None, dialect) -> datetime.datetime | None:
|
|
406
|
+
if value is None:
|
|
407
|
+
return None
|
|
408
|
+
if value.tzinfo is None:
|
|
409
|
+
return value.replace(tzinfo=datetime.timezone.utc)
|
|
410
|
+
if value.tzinfo == datetime.timezone.utc:
|
|
411
|
+
return value
|
|
412
|
+
raise ValueError("Only UTC timezone-aware datetimes are supported")
|
|
413
|
+
|
|
414
|
+
def process_result_value(self, value: datetime.datetime | None, dialect) -> datetime.datetime | None:
|
|
415
|
+
if value is None:
|
|
416
|
+
return None
|
|
417
|
+
return value.replace(tzinfo=datetime.timezone.utc)
|
|
400
418
|
|
|
401
419
|
|
|
402
420
|
def model_sqn_type(dialect: str | None = None) -> sa.types.TypeEngine[int]:
|
|
@@ -428,7 +446,7 @@ def model_datetime_tz_type(dialect: str | None = None) -> sa.types.TypeEngine[da
|
|
|
428
446
|
if dialect == dialects.postgresql:
|
|
429
447
|
return sa_pg.TIMESTAMP(timezone=True)
|
|
430
448
|
if dialect == dialects.sqlite:
|
|
431
|
-
return
|
|
449
|
+
return SQLiteDateTime
|
|
432
450
|
raise ValueError(f"unsupported database dialect '{dialect}'")
|
|
433
451
|
|
|
434
452
|
|
|
@@ -448,6 +466,14 @@ def model_revision_type(dialect: str | None = None) -> sa.types.TypeEngine[int]:
|
|
|
448
466
|
raise ValueError(f"unsupported database dialect '{dialect}'")
|
|
449
467
|
|
|
450
468
|
|
|
469
|
+
# At the present time, we cannot express intersection of Protocol and SQLModel directly.
|
|
470
|
+
# Thus, we define union types here for the mixins.
|
|
471
|
+
SequenceModelMixin = SequenceModelMixinProtocol | SQLModel
|
|
472
|
+
ChangingModelMixin = ChangingModelMixinProtocol | SQLModel
|
|
473
|
+
SnapshotModelMixin = SnapshotModelMixinProtocol | SQLModel
|
|
474
|
+
RevisionModelMixin = RevisionModelMixinProtocol | SQLModel
|
|
475
|
+
|
|
476
|
+
|
|
451
477
|
def make_sequence_model_mixin(dialect: str | None = None) -> type[SequenceModelMixin]:
|
|
452
478
|
"""
|
|
453
479
|
Creates a mixin class for SQLModel models that adds a unique identifier field ``sqn``.
|
|
@@ -496,14 +522,14 @@ def make_changing_model_mixin(dialect: str | None = None) -> type[ChangingModelM
|
|
|
496
522
|
|
|
497
523
|
@pdt.field_validator("created_at", mode="after")
|
|
498
524
|
@classmethod
|
|
499
|
-
def validate_created_at(cls, v: datetime.datetime) -> datetime.datetime:
|
|
525
|
+
def validate_created_at(cls, v: datetime.datetime | None) -> datetime.datetime | None:
|
|
500
526
|
if v is not None:
|
|
501
527
|
validate_dt_timezone(v)
|
|
502
528
|
return v
|
|
503
529
|
|
|
504
530
|
@pdt.field_validator("updated_at", mode="after")
|
|
505
531
|
@classmethod
|
|
506
|
-
def validate_updated_at(cls, v: datetime.datetime) -> datetime.datetime:
|
|
532
|
+
def validate_updated_at(cls, v: datetime.datetime | None) -> datetime.datetime | None:
|
|
507
533
|
if v is not None:
|
|
508
534
|
validate_dt_timezone(v)
|
|
509
535
|
return v
|
|
@@ -571,14 +597,14 @@ def make_snapshot_model_mixin(dialect: str | None = None) -> type[SnapshotModelM
|
|
|
571
597
|
|
|
572
598
|
@pdt.field_validator("created_at", mode="after")
|
|
573
599
|
@classmethod
|
|
574
|
-
def validate_created_at(cls, v: datetime.datetime) -> datetime.datetime:
|
|
600
|
+
def validate_created_at(cls, v: datetime.datetime | None) -> datetime.datetime | None:
|
|
575
601
|
if v is not None:
|
|
576
602
|
validate_dt_timezone(v)
|
|
577
603
|
return v
|
|
578
604
|
|
|
579
605
|
@pdt.field_validator("expired_at", mode="after")
|
|
580
606
|
@classmethod
|
|
581
|
-
def validate_expired_at(cls, v: datetime.datetime) -> datetime.datetime:
|
|
607
|
+
def validate_expired_at(cls, v: datetime.datetime | None) -> datetime.datetime | None:
|
|
582
608
|
if v is not None:
|
|
583
609
|
validate_dt_timezone(v)
|
|
584
610
|
return v
|
|
@@ -684,28 +710,28 @@ def make_revision_model_mixin(dialect: str | None = None) -> type[RevisionModelM
|
|
|
684
710
|
|
|
685
711
|
@pdt.field_validator("created_at", mode="after")
|
|
686
712
|
@classmethod
|
|
687
|
-
def validate_created_at(cls, v: datetime.datetime) -> datetime.datetime:
|
|
713
|
+
def validate_created_at(cls, v: datetime.datetime | None) -> datetime.datetime | None:
|
|
688
714
|
if v is not None:
|
|
689
715
|
validate_dt_timezone(v)
|
|
690
716
|
return v
|
|
691
717
|
|
|
692
718
|
@pdt.field_validator("updated_at", mode="after")
|
|
693
719
|
@classmethod
|
|
694
|
-
def validate_updated_at(cls, v: datetime.datetime) -> datetime.datetime:
|
|
720
|
+
def validate_updated_at(cls, v: datetime.datetime | None) -> datetime.datetime | None:
|
|
695
721
|
if v is not None:
|
|
696
722
|
validate_dt_timezone(v)
|
|
697
723
|
return v
|
|
698
724
|
|
|
699
725
|
@pdt.field_validator("expired_at", mode="after")
|
|
700
726
|
@classmethod
|
|
701
|
-
def validate_expired_at(cls, v: datetime.datetime) -> datetime.datetime:
|
|
727
|
+
def validate_expired_at(cls, v: datetime.datetime | None) -> datetime.datetime | None:
|
|
702
728
|
if v is not None:
|
|
703
729
|
validate_dt_timezone(v)
|
|
704
730
|
return v
|
|
705
731
|
|
|
706
732
|
@pdt.field_validator("revision", mode="after")
|
|
707
733
|
@classmethod
|
|
708
|
-
def validate_revision(cls, v: int) -> int:
|
|
734
|
+
def validate_revision(cls, v: int | None) -> int | None:
|
|
709
735
|
if v is not None and not v > 0:
|
|
710
736
|
raise ValueError("revision number must be positive integer")
|
|
711
737
|
return v
|
|
@@ -941,11 +967,12 @@ def clone_sequence_model_instance[SequenceModelT: SequenceModelMixin](
|
|
|
941
967
|
model: type[SequenceModelT],
|
|
942
968
|
instance: SequenceModelMixin,
|
|
943
969
|
*,
|
|
970
|
+
validate_only: bool = False,
|
|
944
971
|
clear_meta_fields: bool = True,
|
|
945
|
-
inplace: bool = False,
|
|
946
972
|
) -> SequenceModelT:
|
|
947
973
|
result = model.model_validate(instance)
|
|
948
|
-
|
|
974
|
+
if validate_only:
|
|
975
|
+
return instance
|
|
949
976
|
if clear_meta_fields:
|
|
950
977
|
result.sqn = None
|
|
951
978
|
return result
|
|
@@ -955,11 +982,12 @@ def clone_changing_model_instance[ChangingModelT: ChangingModelMixin](
|
|
|
955
982
|
model: type[ChangingModelT],
|
|
956
983
|
instance: ChangingModelMixin,
|
|
957
984
|
*,
|
|
985
|
+
validate_only: bool = False,
|
|
958
986
|
clear_meta_fields: bool = True,
|
|
959
|
-
inplace: bool = False,
|
|
960
987
|
) -> ChangingModelT:
|
|
961
988
|
result = model.model_validate(instance)
|
|
962
|
-
|
|
989
|
+
if validate_only:
|
|
990
|
+
return instance
|
|
963
991
|
if clear_meta_fields:
|
|
964
992
|
result.sqn = None
|
|
965
993
|
result.created_at = None
|
|
@@ -971,11 +999,12 @@ def clone_snapshot_model_instance[SnapshotModelT: SnapshotModelMixin](
|
|
|
971
999
|
model: type[SnapshotModelT],
|
|
972
1000
|
instance: SnapshotModelMixin,
|
|
973
1001
|
*,
|
|
1002
|
+
validate_only: bool = False,
|
|
974
1003
|
clear_meta_fields: bool = True,
|
|
975
|
-
inplace: bool = False,
|
|
976
1004
|
) -> SnapshotModelT:
|
|
977
1005
|
result = model.model_validate(instance)
|
|
978
|
-
|
|
1006
|
+
if validate_only:
|
|
1007
|
+
return instance
|
|
979
1008
|
if clear_meta_fields:
|
|
980
1009
|
result.sqn = None
|
|
981
1010
|
result.created_at = None
|
|
@@ -988,11 +1017,12 @@ def clone_revision_model_instance[RevisionModelT: RevisionModelMixin](
|
|
|
988
1017
|
model: type[RevisionModelT],
|
|
989
1018
|
instance: RevisionModelMixin,
|
|
990
1019
|
*,
|
|
1020
|
+
validate_only: bool = False,
|
|
991
1021
|
clear_meta_fields: bool = True,
|
|
992
|
-
inplace: bool = False,
|
|
993
1022
|
) -> RevisionModelT:
|
|
994
1023
|
result = model.model_validate(instance)
|
|
995
|
-
|
|
1024
|
+
if validate_only:
|
|
1025
|
+
return instance
|
|
996
1026
|
if clear_meta_fields:
|
|
997
1027
|
result.sqn = None
|
|
998
1028
|
result.created_at = None
|
|
@@ -1081,7 +1111,7 @@ def db_update_sequence_model[SequenceModelT: SequenceModelMixin](
|
|
|
1081
1111
|
raise sa_exc.NoResultFound(f"'{model_name_of(model)}' of specified sqn '{sqn}' not found")
|
|
1082
1112
|
|
|
1083
1113
|
db_instance = model_copy_from(db_instance, clone_sequence_model_instance(model, instance), exclude_none=True)
|
|
1084
|
-
|
|
1114
|
+
clone_sequence_model_instance(model, db_instance, validate_only=True)
|
|
1085
1115
|
db.flush()
|
|
1086
1116
|
|
|
1087
1117
|
return db_instance
|
|
@@ -1146,7 +1176,7 @@ def db_update_changing_model[ChangingModelT: ChangingModelMixin](
|
|
|
1146
1176
|
|
|
1147
1177
|
db_instance = model_copy_from(db_instance, clone_changing_model_instance(model, instance), exclude_none=True)
|
|
1148
1178
|
db_instance.updated_at = updated_at
|
|
1149
|
-
|
|
1179
|
+
clone_changing_model_instance(model, db_instance, validate_only=True)
|
|
1150
1180
|
db.flush()
|
|
1151
1181
|
|
|
1152
1182
|
return db_instance
|
|
@@ -1304,13 +1334,14 @@ def db_update_snapshot_model[SnapshotModelT: SnapshotModelMixin](
|
|
|
1304
1334
|
raise sa_exc.NoResultFound(f"active '{model_name_of(model)}' of specified record_sqn '{record_sqn}' not found")
|
|
1305
1335
|
|
|
1306
1336
|
db_instance.expired_at = updated_at
|
|
1307
|
-
|
|
1337
|
+
clone_snapshot_model_instance(model, db_instance, validate_only=True)
|
|
1308
1338
|
db.flush()
|
|
1309
1339
|
|
|
1310
1340
|
db_new_instance = clone_snapshot_model_instance(model, instance)
|
|
1311
1341
|
db_new_instance.record_sqn = record_sqn
|
|
1312
1342
|
db_new_instance.created_at = updated_at
|
|
1313
1343
|
db_new_instance.expired_at = None
|
|
1344
|
+
clone_snapshot_model_instance(model, db_new_instance, validate_only=True)
|
|
1314
1345
|
db.add(db_new_instance)
|
|
1315
1346
|
db.flush()
|
|
1316
1347
|
|
|
@@ -1333,7 +1364,7 @@ def db_expire_snapshot_model[SnapshotModelT: SnapshotModelMixin](
|
|
|
1333
1364
|
raise sa_exc.NoResultFound(f"active '{model_name_of(model)}' of specified record_sqn '{record_sqn}' not found")
|
|
1334
1365
|
|
|
1335
1366
|
db_instance.expired_at = updated_at
|
|
1336
|
-
|
|
1367
|
+
clone_snapshot_model_instance(model, db_instance, validate_only=True)
|
|
1337
1368
|
db.flush()
|
|
1338
1369
|
|
|
1339
1370
|
return db_instance
|
|
@@ -1364,9 +1395,10 @@ def db_activate_snapshot_model[SnapshotModelT: SnapshotModelMixin](
|
|
|
1364
1395
|
db_new_instance.record_sqn = record_sqn
|
|
1365
1396
|
db_new_instance.created_at = db_instance.expired_at
|
|
1366
1397
|
db_new_instance.expired_at = updated_at
|
|
1367
|
-
|
|
1398
|
+
clone_snapshot_model_instance(model, db_new_instance, validate_only=True)
|
|
1368
1399
|
db_new_instance.created_at = updated_at
|
|
1369
1400
|
db_new_instance.expired_at = None
|
|
1401
|
+
clone_snapshot_model_instance(model, db_new_instance, validate_only=True)
|
|
1370
1402
|
db.add(db_new_instance)
|
|
1371
1403
|
db.flush()
|
|
1372
1404
|
|
|
@@ -1529,7 +1561,7 @@ def db_update_revision_model[RevisionModelT: RevisionModelMixin](
|
|
|
1529
1561
|
raise sa_exc.NoResultFound(f"active '{model_name_of(model)}' of specified record_sqn '{record_sqn}' not found")
|
|
1530
1562
|
|
|
1531
1563
|
db_instance.expired_at = updated_at
|
|
1532
|
-
|
|
1564
|
+
clone_revision_model_instance(model, db_instance, validate_only=True)
|
|
1533
1565
|
db.flush()
|
|
1534
1566
|
|
|
1535
1567
|
db_new_instance = clone_revision_model_instance(model, instance)
|
|
@@ -1538,6 +1570,7 @@ def db_update_revision_model[RevisionModelT: RevisionModelMixin](
|
|
|
1538
1570
|
db_new_instance.updated_at = updated_at
|
|
1539
1571
|
db_new_instance.expired_at = None
|
|
1540
1572
|
db_new_instance.revision = db_instance.revision + 1
|
|
1573
|
+
clone_revision_model_instance(model, db_new_instance, validate_only=True)
|
|
1541
1574
|
db.add(db_new_instance)
|
|
1542
1575
|
db.flush()
|
|
1543
1576
|
|
|
@@ -1560,7 +1593,7 @@ def db_expire_revision_model[RevisionModelT: RevisionModelMixin](
|
|
|
1560
1593
|
raise sa_exc.NoResultFound(f"active '{model_name_of(model)}' of specified record_sqn '{record_sqn}' not found")
|
|
1561
1594
|
|
|
1562
1595
|
db_instance.expired_at = updated_at
|
|
1563
|
-
|
|
1596
|
+
clone_revision_model_instance(model, db_instance, validate_only=True)
|
|
1564
1597
|
db.flush()
|
|
1565
1598
|
|
|
1566
1599
|
return db_instance
|
|
@@ -1593,9 +1626,10 @@ def db_activate_revision_model[RevisionModelT: RevisionModelMixin](
|
|
|
1593
1626
|
db_new_instance.updated_at = db_instance.expired_at
|
|
1594
1627
|
db_new_instance.expired_at = updated_at
|
|
1595
1628
|
db_new_instance.revision = db_instance.revision + 1
|
|
1596
|
-
|
|
1629
|
+
clone_revision_model_instance(model, db_new_instance, validate_only=True)
|
|
1597
1630
|
db_new_instance.updated_at = updated_at
|
|
1598
1631
|
db_new_instance.expired_at = None
|
|
1632
|
+
clone_revision_model_instance(model, db_new_instance, validate_only=True)
|
|
1599
1633
|
db.add(db_new_instance)
|
|
1600
1634
|
db.flush()
|
|
1601
1635
|
|
plexus/common/utils/tagutils.py
CHANGED
|
@@ -33,6 +33,7 @@ from plexus.common.resources.tags import predefined_tagset_specs
|
|
|
33
33
|
from plexus.common.utils.datautils import validate_colon_tag, validate_snake_case, validate_vehicle_name
|
|
34
34
|
from plexus.common.utils.datautils import validate_dt_timezone, validate_semver, validate_slash_tag
|
|
35
35
|
from plexus.common.utils.jsonutils import json_datetime_encoder
|
|
36
|
+
from plexus.common.utils.ormutils import SQLiteDateTime
|
|
36
37
|
from plexus.common.utils.ormutils import SequenceModelMixinProtocol
|
|
37
38
|
from plexus.common.utils.ormutils import clone_sequence_model_instance, make_base_model, make_sequence_model_mixin
|
|
38
39
|
from plexus.common.utils.sqlutils import escape_sql_like
|
|
@@ -396,11 +397,11 @@ class TagTarget(BaseModel):
|
|
|
396
397
|
description="Vehicle name associated with the tag record",
|
|
397
398
|
)
|
|
398
399
|
begin_dt: datetime.datetime = Field(
|
|
399
|
-
sa_column=sa.Column(
|
|
400
|
+
sa_column=sa.Column(SQLiteDateTime, nullable=False),
|
|
400
401
|
description="Begin datetime of the target range associated with the tag record",
|
|
401
402
|
)
|
|
402
403
|
end_dt: datetime.datetime = Field(
|
|
403
|
-
sa_column=sa.Column(
|
|
404
|
+
sa_column=sa.Column(SQLiteDateTime, nullable=False),
|
|
404
405
|
description="End datetime of the target range associated with the tag record",
|
|
405
406
|
)
|
|
406
407
|
|
|
@@ -431,13 +432,13 @@ class TagTarget(BaseModel):
|
|
|
431
432
|
@pdt.field_validator("begin_dt", mode="after")
|
|
432
433
|
@classmethod
|
|
433
434
|
def validate_begin_dt(cls, v: datetime.datetime) -> datetime.datetime:
|
|
434
|
-
validate_dt_timezone(v
|
|
435
|
+
validate_dt_timezone(v)
|
|
435
436
|
return v
|
|
436
437
|
|
|
437
438
|
@pdt.field_validator("end_dt", mode="after")
|
|
438
439
|
@classmethod
|
|
439
440
|
def validate_end_dt(cls, v: datetime.datetime) -> datetime.datetime:
|
|
440
|
-
validate_dt_timezone(v
|
|
441
|
+
validate_dt_timezone(v)
|
|
441
442
|
return v
|
|
442
443
|
|
|
443
444
|
@pdt.model_validator(mode="after")
|
|
@@ -461,11 +462,11 @@ class TagRecord(BaseModel):
|
|
|
461
462
|
description="Sequence number of the tag record's target",
|
|
462
463
|
)
|
|
463
464
|
begin_dt: datetime.datetime = Field(
|
|
464
|
-
sa_column=sa.Column(
|
|
465
|
+
sa_column=sa.Column(SQLiteDateTime, nullable=False),
|
|
465
466
|
description="Begin datetime of the tag record",
|
|
466
467
|
)
|
|
467
468
|
end_dt: datetime.datetime = Field(
|
|
468
|
-
sa_column=sa.Column(
|
|
469
|
+
sa_column=sa.Column(SQLiteDateTime, nullable=False),
|
|
469
470
|
description="End datetime of the tag record",
|
|
470
471
|
)
|
|
471
472
|
tagset_namespace: str | None = Field(
|
|
@@ -496,13 +497,13 @@ class TagRecord(BaseModel):
|
|
|
496
497
|
@pdt.field_validator("begin_dt", mode="after")
|
|
497
498
|
@classmethod
|
|
498
499
|
def validate_begin_dt(cls, v: datetime.datetime) -> datetime.datetime:
|
|
499
|
-
validate_dt_timezone(v
|
|
500
|
+
validate_dt_timezone(v)
|
|
500
501
|
return v
|
|
501
502
|
|
|
502
503
|
@pdt.field_validator("end_dt", mode="after")
|
|
503
504
|
@classmethod
|
|
504
505
|
def validate_end_dt(cls, v: datetime.datetime) -> datetime.datetime:
|
|
505
|
-
validate_dt_timezone(v
|
|
506
|
+
validate_dt_timezone(v)
|
|
506
507
|
return v
|
|
507
508
|
|
|
508
509
|
@pdt.field_validator("tagset_namespace", mode="after")
|
|
@@ -571,7 +572,7 @@ if typing.TYPE_CHECKING:
|
|
|
571
572
|
|
|
572
573
|
@singleton
|
|
573
574
|
def tag_cache_file_path() -> pathlib.Path:
|
|
574
|
-
return pathlib.Path.home() / ".local" / "
|
|
575
|
+
return pathlib.Path.home() / ".local" / "plexus" / "tag_cache" / f"{randomizer().random_alphanumeric(7)}.db"
|
|
575
576
|
|
|
576
577
|
|
|
577
578
|
class TagCache(object):
|
|
@@ -595,9 +596,13 @@ class TagCache(object):
|
|
|
595
596
|
|
|
596
597
|
@contextlib.contextmanager
|
|
597
598
|
def make_session(self) -> Generator[sa_orm.Session, None, None]:
|
|
598
|
-
with self.thread_lock:
|
|
599
|
-
|
|
599
|
+
with self.thread_lock, self.conn_maker.make_session(expire_on_commit=False) as session:
|
|
600
|
+
try:
|
|
600
601
|
yield session
|
|
602
|
+
session.commit()
|
|
603
|
+
except Exception:
|
|
604
|
+
session.rollback()
|
|
605
|
+
raise
|
|
601
606
|
|
|
602
607
|
def get_target(self, target: int | str) -> TagTargetTable | None:
|
|
603
608
|
with self.make_session() as session:
|
|
@@ -1019,7 +1024,6 @@ class TargetedTagCache(object):
|
|
|
1019
1024
|
session.add(db_tag_record)
|
|
1020
1025
|
session.commit()
|
|
1021
1026
|
|
|
1022
|
-
session.refresh(db_tag_record)
|
|
1023
1027
|
return chainable(self, db_tag_record)
|
|
1024
1028
|
|
|
1025
1029
|
def add_tag(
|
|
@@ -1104,7 +1108,6 @@ class TargetedTagCache(object):
|
|
|
1104
1108
|
|
|
1105
1109
|
session.commit()
|
|
1106
1110
|
|
|
1107
|
-
session.refresh(db_tag_record)
|
|
1108
1111
|
return chainable(self, db_tag_record)
|
|
1109
1112
|
|
|
1110
1113
|
def remove_tags(
|
|
@@ -1158,7 +1161,7 @@ class TargetedTagCache(object):
|
|
|
1158
1161
|
|
|
1159
1162
|
|
|
1160
1163
|
@memorized
|
|
1161
|
-
def tag_cache(*, identifier: str | None = None, file_path: str | None = None) -> TagCache:
|
|
1164
|
+
def tag_cache(*, identifier: str | None = None, file_path: str | os.PathLike[str] | None = None) -> TagCache:
|
|
1162
1165
|
"""
|
|
1163
1166
|
Get a ``TagCache`` instance associated with the given identifier. If the identifier is ``None``, return a
|
|
1164
1167
|
``TagCache`` instance associated with a default file path. Otherwise, validate the identifier as a snake case
|
plexus/common/utils/testutils.py
CHANGED
|
@@ -116,6 +116,7 @@ def patched_postgresql_session_maker(
|
|
|
116
116
|
base_model: type[SQLModel],
|
|
117
117
|
app: FastAPI,
|
|
118
118
|
session_maker: Callable[[], Generator[sa_orm.Session]],
|
|
119
|
+
**kwargs,
|
|
119
120
|
) -> Callable[[pytest.FixtureRequest], Generator[Callable[[], Iterator[sa_orm.Session]]]]:
|
|
120
121
|
"""
|
|
121
122
|
Create a pytest fixture that provides a patched session maker for PostgreSQL tests.
|
|
@@ -141,7 +142,7 @@ def patched_postgresql_session_maker(
|
|
|
141
142
|
)
|
|
142
143
|
|
|
143
144
|
def make_session_maker() -> Iterator[sa_orm.Session]:
|
|
144
|
-
with cm.make_session(
|
|
145
|
+
with cm.make_session(**kwargs) as db:
|
|
145
146
|
try:
|
|
146
147
|
# language=postgresql
|
|
147
148
|
db.execute(sa.sql.text("SET TIMEZONE TO 'UTC'"))
|
|
@@ -15,15 +15,15 @@ plexus/common/utils/config.py,sha256=uCzSYR9W-vNNZiRJ3FdiExuUazlDXY7xJtJaY11T_bA
|
|
|
15
15
|
plexus/common/utils/datautils.py,sha256=mgnr-dcHpw-Pk3qBud0lC3JX_pv-iKzI8llsPW9Q12g,9275
|
|
16
16
|
plexus/common/utils/dockerutils.py,sha256=WPxQuabRWyyM8wpSSYhb_HZaOw5yZ2TbU2dEQ2xRIlQ,5787
|
|
17
17
|
plexus/common/utils/gisutils.py,sha256=UR3uVoD1nAy0SWJ1AYWCUy94Lo8zNb4nv_JdpcANBDE,11462
|
|
18
|
-
plexus/common/utils/jsonutils.py,sha256
|
|
19
|
-
plexus/common/utils/ormutils.py,sha256=
|
|
18
|
+
plexus/common/utils/jsonutils.py,sha256=-_uKlQMLMgmVO9pB99S45Y_Vufx5dFSq43DIwGz1a54,3328
|
|
19
|
+
plexus/common/utils/ormutils.py,sha256=_kkQLTScYeoAneEdbGvkcsXh1TDja__AUznVkOpRNn0,60393
|
|
20
20
|
plexus/common/utils/pathutils.py,sha256=hGJqSLj08tuOeZ7WeC5d4BtjnPI732BuntVQBQsqOaI,9581
|
|
21
21
|
plexus/common/utils/s3utils.py,sha256=zlO4kGs-c2gUeOfPfiKIE5liQZsbYxqAZYCwA8kL0Lo,36017
|
|
22
22
|
plexus/common/utils/sqlutils.py,sha256=D6kTBjhO5YlNRt3uFlPt6z3uH61m9ajEzPYmsI6NoFc,231
|
|
23
23
|
plexus/common/utils/strutils.py,sha256=O9Inv4ffUTf6Xjc5ftoZwbIua1NeG7itCT9S3zjZxBc,16436
|
|
24
|
-
plexus/common/utils/tagutils.py,sha256=
|
|
25
|
-
plexus/common/utils/testutils.py,sha256=
|
|
26
|
-
plexus_python_common-1.0.
|
|
27
|
-
plexus_python_common-1.0.
|
|
28
|
-
plexus_python_common-1.0.
|
|
29
|
-
plexus_python_common-1.0.
|
|
24
|
+
plexus/common/utils/tagutils.py,sha256=MzsuxBH62lAPuvQL1wx7kKvQHsA5NXYMEPRhSYwb4gA,51077
|
|
25
|
+
plexus/common/utils/testutils.py,sha256=N8ijLu7X-hlQlHzvv0TtSsQpIF4T1hbr-AjkILoV2Ac,6152
|
|
26
|
+
plexus_python_common-1.0.66.dist-info/METADATA,sha256=FrVKPSwnSIbWkpwtHO-PABwKcvEK6Sey8UtP8sRKleg,1481
|
|
27
|
+
plexus_python_common-1.0.66.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
28
|
+
plexus_python_common-1.0.66.dist-info/top_level.txt,sha256=ug_g7CVwaMQuas5UzAXbHUrQvKGCn8ezc6ZNvvRlJOE,7
|
|
29
|
+
plexus_python_common-1.0.66.dist-info/RECORD,,
|
|
File without changes
|
{plexus_python_common-1.0.65.dist-info → plexus_python_common-1.0.66.dist-info}/top_level.txt
RENAMED
|
File without changes
|