plexus-python-common 1.0.72__py3-none-any.whl → 1.0.74__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.
@@ -38,6 +38,8 @@ from plexus.common.utils.ormutils import clone_sequence_model_instance, make_bas
38
38
  from plexus.common.utils.sqlutils import escape_sql_like
39
39
 
40
40
  __all__ = [
41
+ "versioned_identifier",
42
+ "split_versioned_identifier",
41
43
  "RichDesc",
42
44
  "Tag",
43
45
  "BoundTag",
@@ -60,6 +62,21 @@ __all__ = [
60
62
  ]
61
63
 
62
64
 
65
+ def versioned_identifier(identifier: str | None, version: str | None) -> str | None:
66
+ if identifier is None or version is None:
67
+ return identifier
68
+ return f"{identifier}@{version}"
69
+
70
+
71
+ def split_versioned_identifier(s: str | None) -> tuple[str | None, str | None]:
72
+ if s is None:
73
+ return None, None
74
+ if "@" not in s:
75
+ return s, None
76
+ identifier, version = s.rsplit("@", 1)
77
+ return identifier, version
78
+
79
+
63
80
  @dataclasses.dataclass(frozen=True, eq=True, order=True)
64
81
  class RichDesc(object):
65
82
  type: str
@@ -84,11 +101,11 @@ class Tag(object):
84
101
  def unbind(self) -> Self:
85
102
  return self
86
103
 
87
- def validate(self, props: JsonType | None, *, raise_on_error: bool = False) -> bool:
88
- if self.schema is None or props is None:
104
+ def validate(self, features: JsonType | None, *, raise_on_error: bool = False) -> bool:
105
+ if self.schema is None or features is None:
89
106
  return True
90
107
  try:
91
- jsonschema.Draft7Validator(self.schema).validate(props)
108
+ jsonschema.Draft7Validator(self.schema).validate(features)
92
109
  return True
93
110
  except (jsonschema.ValidationError, jsonschema.SchemaError):
94
111
  if raise_on_error:
@@ -178,9 +195,9 @@ class Tagset(Sequence[Tag], Mapping[str, Tag]):
178
195
  return []
179
196
  return list(dicttree_lineage(self.tags_tree, child.tag_parts[:-1]))
180
197
 
181
- def validate(self, tag_name: str, props: JsonType | None, *, raise_on_error: bool = False) -> bool:
198
+ def validate(self, tag_name: str, features: JsonType | None, *, raise_on_error: bool = False) -> bool:
182
199
  tag = self.get(tag_name)
183
- return False if tag is None else tag.validate(props, raise_on_error=raise_on_error)
200
+ return False if tag is None else tag.validate(features, raise_on_error=raise_on_error)
184
201
 
185
202
 
186
203
  class MutableTagset(Tagset):
@@ -331,7 +348,7 @@ def predefined_tagsets() -> dict[str, Tagset]:
331
348
  else:
332
349
  latest_targets[tagset.namespace] = (version, tagset)
333
350
 
334
- tagsets[f"{tagset.namespace}:{tagset.version}"] = tagset
351
+ tagsets[versioned_identifier(tagset.namespace, tagset.version)] = tagset
335
352
 
336
353
  for _, tagset in latest_targets.values():
337
354
  tagsets[tagset.namespace] = tagset
@@ -491,6 +508,11 @@ def make_tag_record_model_mixin() -> type[pdt.BaseModel]:
491
508
  sa_column=sa.Column(sa_sqlite.VARCHAR(256), nullable=False),
492
509
  description="Tag name",
493
510
  )
511
+ features: JsonType | None = Field(
512
+ sa_column=sa.Column(sa_sqlite.JSON, nullable=True),
513
+ default=None,
514
+ description="Tag features in JSON format, which can be used for storing preprocessed information of the tag record to facilitate querying and filtering",
515
+ )
494
516
  props: JsonType | None = Field(
495
517
  sa_column=sa.Column(sa_sqlite.JSON, nullable=True),
496
518
  default=None,
@@ -592,6 +614,7 @@ if typing.TYPE_CHECKING:
592
614
  tagset_namespace: sa_orm.Mapped[str | None] = ...
593
615
  tagset_version: sa_orm.Mapped[str | None] = ...
594
616
  tag: sa_orm.Mapped[str] = ...
617
+ features: sa_orm.Mapped[JsonType | None] = ...
595
618
  props: sa_orm.Mapped[JsonType | None] = ...
596
619
  flags: sa_orm.Mapped[int] = ...
597
620
 
@@ -676,7 +699,21 @@ class TagCache(object):
676
699
  begin_dt: datetime.datetime,
677
700
  end_dt: datetime.datetime,
678
701
  props: JsonType | None = None,
679
- ) -> TagTargetTable:
702
+ ) -> Chainable[Self, TagTargetTable]:
703
+ """
704
+ Create a new tag target and add it to the cache.
705
+
706
+ :param identifier: Identifier of the tag target, which should be unique across the cache. It is recommended
707
+ to use a slash tag (e.g. "dummy_name/dummy_name") to ensure uniqueness and facilitate
708
+ organization, but other formats are also allowed as long as they are valid slash tags.
709
+ :param tagger_name: Name of the tagger creating the tag target.
710
+ :param tagger_version: Version of the tagger creating the tag target.
711
+ :param vehicle_name: Name of the vehicle associated with the tag target.
712
+ :param begin_dt: Start datetime for the tag target's validity period.
713
+ :param end_dt: End datetime for the tag target's validity period.
714
+ :param props: Additional properties for the tag target.
715
+ :return: Self instance for chaining along with the added ``TagTargetTable`` instance
716
+ """
680
717
  with self.make_session() as session:
681
718
  tag_target = TagTarget(
682
719
  identifier=identifier,
@@ -691,7 +728,7 @@ class TagCache(object):
691
728
  session.add(db_tag_target)
692
729
  session.commit()
693
730
 
694
- return self.get_target(identifier)
731
+ return chainable(self, db_tag_target)
695
732
 
696
733
  def remove_targets(
697
734
  self,
@@ -701,7 +738,23 @@ class TagCache(object):
701
738
  vehicle_name: str | None = None,
702
739
  begin_dt: datetime.datetime | None = None,
703
740
  end_dt: datetime.datetime | None = None,
741
+ *,
742
+ cascade_records: bool = True,
704
743
  ):
744
+ """
745
+ Remove tag targets from the cache that match the specified filters.
746
+
747
+ :param identifier: Filter by target identifier (exact match)
748
+ :param tagger_name: Filter by tagger name (exact match)
749
+ :param tagger_version: Filter by tagger version (exact match)
750
+ :param vehicle_name: Filter by vehicle name (exact match)
751
+ :param begin_dt: Filter by begin time (inclusive)
752
+ :param end_dt: Filter by end time (inclusive)
753
+ :param cascade_records: Whether to also remove tag records that are associated with the removed targets.
754
+ If False, the tag records will be kept but become orphaned (i.e. their ``target_sqn``
755
+ will not have a corresponding target in the cache).
756
+ :return: Self for chaining
757
+ """
705
758
  with self.make_session() as session:
706
759
  query_stmt = session.query(TagTargetTable)
707
760
  if identifier:
@@ -720,13 +773,16 @@ class TagCache(object):
720
773
  query_stmt.delete()
721
774
  session.commit()
722
775
 
723
- (
724
- session
725
- .query(TagRecordTable)
726
- .filter(TagRecordTable.target_sqn.notin_(session.query(TagTargetTable.sqn)))
727
- .delete()
728
- )
729
- session.commit()
776
+ if cascade_records:
777
+ (
778
+ session
779
+ .query(TagRecordTable)
780
+ .filter(TagRecordTable.target_sqn.notin_(session.query(TagTargetTable.sqn)))
781
+ .delete()
782
+ )
783
+ session.commit()
784
+
785
+ return self
730
786
 
731
787
  def with_target(self, target: int | str) -> "TargetedTagCache":
732
788
  db_tag_target = self.get_target(target)
@@ -1010,6 +1066,7 @@ class TagCache(object):
1010
1066
  begin_dt: datetime.datetime,
1011
1067
  end_dt: datetime.datetime,
1012
1068
  tag: str | Tag | BoundTag,
1069
+ features: JsonType | None = None,
1013
1070
  props: JsonType | None = None,
1014
1071
  tagset_namespace: str | None = None,
1015
1072
  tagset_version: str | None = None,
@@ -1022,6 +1079,8 @@ class TagCache(object):
1022
1079
  :param end_dt: End datetime of the tag record
1023
1080
  :param tag: Tag name or ``Tag``/``BoundTag`` instance to be added. If ``Tag``/``BoundTag`` instance is provided,
1024
1081
  its name will be used.
1082
+ :param features: Additional tag features of the tag record in JSON format (optional), which can be used for
1083
+ storing preprocessed information of the tag record to facilitate querying and filtering.
1025
1084
  :param props: Additional properties of the tag record in JSON format (optional)
1026
1085
  :param tagset_namespace: Namespace of the tagset that the tag belongs to. If the ``tag`` parameter is a
1027
1086
  ``BoundTag`` instance, this parameter will be ignored and the namespace from the
@@ -1038,6 +1097,7 @@ class TagCache(object):
1038
1097
  tagset_namespace=tag.namespace if isinstance(tag, BoundTag) else tagset_namespace,
1039
1098
  tagset_version=tag.version if isinstance(tag, BoundTag) else tagset_version,
1040
1099
  tag=tag.name if isinstance(tag, Tag) else tag,
1100
+ features=features,
1041
1101
  props=props,
1042
1102
  )
1043
1103
  db_tag_record = clone_sequence_model_instance(TagRecordTable, tag_record)
@@ -1054,6 +1114,7 @@ class TagCache(object):
1054
1114
  begin_dt: datetime.datetime | None = None,
1055
1115
  end_dt: datetime.datetime | None = None,
1056
1116
  tag: str | Tag | BoundTag | None = None,
1117
+ features: JsonType | None = None,
1057
1118
  props: JsonType | None = None,
1058
1119
  tagset_namespace: str | None = None,
1059
1120
  tagset_version: str | None = None,
@@ -1068,6 +1129,8 @@ class TagCache(object):
1068
1129
  :param end_dt: New end datetime of the tag record (optional)
1069
1130
  :param tag: New tag name or ``Tag``/``BoundTag`` instance to be updated (optional). If ``Tag``/``BoundTag``
1070
1131
  instance is provided, its name will be used.
1132
+ :param features: Additional tag features of the tag record in JSON format (optional), which can be used for
1133
+ storing preprocessed information of the tag record to facilitate querying and filtering.
1071
1134
  :param props: New additional properties of the tag record in JSON format (optional)
1072
1135
  :param tagset_namespace: New namespace of the tagset that the tag belongs to (optional). If the ``tag``
1073
1136
  parameter is a ``BoundTag`` instance, this parameter will be ignored and the namespace
@@ -1098,6 +1161,8 @@ class TagCache(object):
1098
1161
  db_tag_record.tagset_version = tag.version if isinstance(tag, BoundTag) else tagset_version
1099
1162
  if tag is not None:
1100
1163
  db_tag_record.tag = tag.name if isinstance(tag, Tag) else tag
1164
+ if features is not None:
1165
+ db_tag_record.features = features
1101
1166
  if props is not None:
1102
1167
  db_tag_record.props = props
1103
1168
  if flags is not None:
@@ -1251,31 +1316,17 @@ class TargetedTagCache(object):
1251
1316
  begin_dt: datetime.datetime | None,
1252
1317
  end_dt: datetime.datetime | None,
1253
1318
  tag: str | Tag | BoundTag,
1319
+ features: JsonType | None = None,
1254
1320
  props: JsonType | None = None,
1255
1321
  tagset_namespace: str | None = None,
1256
1322
  tagset_version: str | None = None,
1257
1323
  ) -> Chainable[Self, TagRecordTable]:
1258
- """
1259
- Add a tag record to the cache for the specified time range. If ``begin_dt`` or ``end_dt`` is None, it will
1260
- default to the target's ``begin_dt`` or ``end_dt`` respectively.
1261
-
1262
- :param begin_dt: Begin datetime of the tag record
1263
- :param end_dt: End datetime of the tag record
1264
- :param tag: Tag name or ``Tag``/``BoundTag`` instance to be added. If ``Tag``/``BoundTag`` instance is provided,
1265
- its name will be used.
1266
- :param props: Additional properties of the tag record in JSON format (optional)
1267
- :param tagset_namespace: Namespace of the tagset that the tag belongs to. If the ``tag`` parameter is a
1268
- ``BoundTag`` instance, this parameter will be ignored and the namespace from the
1269
- instance will be used.
1270
- :param tagset_version: Version of the tagset that the tag belongs to. If the ``tag`` parameter is a ``BoundTag``
1271
- instance, this parameter will be ignored and the version from the instance will be used.
1272
- :return: Self instance for chaining along with the added ``TagRecordTable`` instance
1273
- """
1274
1324
  result = self.cache.target_add_record(
1275
1325
  target_sqn=self.tag_target.sqn,
1276
1326
  begin_dt=begin_dt or self.tag_target.begin_dt,
1277
1327
  end_dt=end_dt or self.tag_target.end_dt,
1278
1328
  tag=tag,
1329
+ features=features,
1279
1330
  props=props,
1280
1331
  tagset_namespace=tagset_namespace,
1281
1332
  tagset_version=tagset_version,
@@ -1285,28 +1336,16 @@ class TargetedTagCache(object):
1285
1336
  def add_record(
1286
1337
  self,
1287
1338
  tag: str | Tag | BoundTag,
1339
+ features: JsonType | None = None,
1288
1340
  props: JsonType | None = None,
1289
1341
  tagset_namespace: str | None = None,
1290
1342
  tagset_version: str | None = None,
1291
1343
  ) -> Chainable[Self, TagRecordTable]:
1292
- """
1293
- Add a tag record to the cache for the entire target range.
1294
-
1295
- :param tag: Tag name or ``Tag``/``BoundTag`` instance to be added. If ``Tag``/``BoundTag`` instance is provided,
1296
- its name will be used.
1297
- :param props: Additional properties of the tag record in JSON format (optional)
1298
- :param tagset_namespace: Namespace of the tagset that the tag belongs to. If the ``tag`` parameter is a
1299
- ``BoundTag`` instance, this parameter will be ignored and the namespace from the
1300
- instance will be used.
1301
- :param tagset_version: Version of the tagset that the tag belongs to. If the ``tag`` parameter is a
1302
- ``BoundTag`` instance, this parameter will be ignored and the version from the instance
1303
- will be used.
1304
- :return: Self instance for chaining along with the added ``TagRecordTable`` instance
1305
- """
1306
1344
  result = self.add_ranged_record(
1307
1345
  begin_dt=self.tag_target.begin_dt,
1308
1346
  end_dt=self.tag_target.end_dt,
1309
1347
  tag=tag,
1348
+ features=features,
1310
1349
  tagset_namespace=tagset_namespace,
1311
1350
  tagset_version=tagset_version,
1312
1351
  props=props,
@@ -1320,35 +1359,19 @@ class TargetedTagCache(object):
1320
1359
  begin_dt: datetime.datetime | None = None,
1321
1360
  end_dt: datetime.datetime | None = None,
1322
1361
  tag: str | Tag | BoundTag | None = None,
1362
+ features: JsonType | None = None,
1323
1363
  props: JsonType | None = None,
1324
1364
  tagset_namespace: str | None = None,
1325
1365
  tagset_version: str | None = None,
1326
1366
  flags: int | None = None,
1327
1367
  ) -> Chainable[Self, TagRecordTable]:
1328
- """
1329
- Update a tag record in the cache by its sequence number.
1330
-
1331
- :param sqn: Sequence number of the tag record to be updated
1332
- :param begin_dt: New begin datetime of the tag record (optional)
1333
- :param end_dt: New end datetime of the tag record (optional)
1334
- :param tag: New tag name or ``Tag``/``BoundTag`` instance to be updated (optional). If ``Tag``/``BoundTag``
1335
- instance is provided, its name will be used.
1336
- :param props: New additional properties of the tag record in JSON format (optional)
1337
- :param tagset_namespace: New namespace of the tagset that the tag belongs to (optional). If the ``tag``
1338
- parameter is a ``BoundTag`` instance, this parameter will be ignored and the namespace
1339
- from the instance will be used.
1340
- :param tagset_version: New version of the tagset that the tag belongs to (optional). If the ``tag`` parameter
1341
- is a ``BoundTag`` instance, this parameter will be ignored and the version from the
1342
- instance will be used.
1343
- :param flags: New integer bitmask storing status or metadata flags for this tag record (optional)
1344
- :return: Self instance for chaining along with the updated ``TagRecordTable`` instance
1345
- """
1346
1368
  result = self.cache.target_update_record(
1347
1369
  self.tag_target.sqn,
1348
1370
  sqn,
1349
1371
  begin_dt=begin_dt,
1350
1372
  end_dt=end_dt,
1351
1373
  tag=tag,
1374
+ features=features,
1352
1375
  props=props,
1353
1376
  tagset_namespace=tagset_namespace,
1354
1377
  tagset_version=tagset_version,
@@ -1367,19 +1390,6 @@ class TargetedTagCache(object):
1367
1390
  tagsets: Sequence[Tagset] | None = None,
1368
1391
  tagset_inverted: bool = False,
1369
1392
  ) -> Self:
1370
- """
1371
- Remove tag records from the cache that match the specified filters.
1372
-
1373
- :param begin_dt: Filter by begin time (inclusive)
1374
- :param end_dt: Filter by end time (inclusive)
1375
- :param tagset_namespace: Filter by tagset namespace (exact match)
1376
- :param tagset_version: Filter by tagset version (exact match)
1377
- :param tag_prefix: Filter by tag name prefix, e.g. "dummy_tag:" to match all tags starting with "dummy_tag:"
1378
- :param tagsets: Filter by tagsets (match tags that are in any of the specified tagsets)
1379
- :param tagset_inverted: Whether to invert the tagset filter (match tags that are NOT in any of the specified
1380
- tagsets)
1381
- :return: Self instance for chaining
1382
- """
1383
1393
  self.cache.target_remove_records(
1384
1394
  self.tag_target.sqn,
1385
1395
  begin_dt=begin_dt,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plexus-python-common
3
- Version: 1.0.72
3
+ Version: 1.0.74
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Programming Language :: Python :: 3.13
@@ -21,9 +21,9 @@ plexus/common/utils/pathutils.py,sha256=hGJqSLj08tuOeZ7WeC5d4BtjnPI732BuntVQBQsq
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=U5JGeMl9MHXthauk89MWzxNeDZ665S28uaJVfcndolU,62213
24
+ plexus/common/utils/tagutils.py,sha256=4r-g4JQ_zmJI4ttJHvlKq-iQuqA6GSPb3PQwaJfnBkg,61632
25
25
  plexus/common/utils/testutils.py,sha256=N8ijLu7X-hlQlHzvv0TtSsQpIF4T1hbr-AjkILoV2Ac,6152
26
- plexus_python_common-1.0.72.dist-info/METADATA,sha256=a6Gp00ANkZ9HsHTIIiTXzLkX0pGKcV0fJbtheMKb-GA,1481
27
- plexus_python_common-1.0.72.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
28
- plexus_python_common-1.0.72.dist-info/top_level.txt,sha256=ug_g7CVwaMQuas5UzAXbHUrQvKGCn8ezc6ZNvvRlJOE,7
29
- plexus_python_common-1.0.72.dist-info/RECORD,,
26
+ plexus_python_common-1.0.74.dist-info/METADATA,sha256=2RyK_d-GgT_5C4ojTgb5ONTTE0Oi11FB7Mz1Ub7ssyo,1481
27
+ plexus_python_common-1.0.74.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
28
+ plexus_python_common-1.0.74.dist-info/top_level.txt,sha256=ug_g7CVwaMQuas5UzAXbHUrQvKGCn8ezc6ZNvvRlJOE,7
29
+ plexus_python_common-1.0.74.dist-info/RECORD,,