plexus-python-common 1.0.72__tar.gz → 1.0.73__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.
Files changed (91) hide show
  1. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/PKG-INFO +1 -1
  2. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/utils/tagutils.py +68 -75
  3. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus_python_common.egg-info/PKG-INFO +1 -1
  4. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/utils/tagutils_test.py +10 -8
  5. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/.editorconfig +0 -0
  6. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/.github/workflows/pr.yml +0 -0
  7. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/.github/workflows/push.yml +0 -0
  8. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/.gitignore +0 -0
  9. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/MANIFEST.in +0 -0
  10. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/README.md +0 -0
  11. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/VERSION +0 -0
  12. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/pyproject.toml +0 -0
  13. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/jsonutils/dummy.0.jsonl +0 -0
  14. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/jsonutils/dummy.1.jsonl +0 -0
  15. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/jsonutils/dummy.2.jsonl +0 -0
  16. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/0-dummy +0 -0
  17. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/1-dummy +0 -0
  18. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/2-dummy +0 -0
  19. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/dummy.0.0.jsonl +0 -0
  20. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/dummy.0.0.vol-0.jsonl +0 -0
  21. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/dummy.0.jsonl +0 -0
  22. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/dummy.1.1.jsonl +0 -0
  23. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/dummy.1.1.vol-1.jsonl +0 -0
  24. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/dummy.1.jsonl +0 -0
  25. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/dummy.2.2.jsonl +0 -0
  26. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/dummy.2.2.vol-2.jsonl +0 -0
  27. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/dummy.2.jsonl +0 -0
  28. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/dummy.csv.part0 +0 -0
  29. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/dummy.csv.part1 +0 -0
  30. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/dummy.csv.part2 +0 -0
  31. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/pathutils/dummy.txt +0 -0
  32. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/s3utils/dir.baz/file.bar.baz +0 -0
  33. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/s3utils/dir.baz/file.foo.bar +0 -0
  34. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/s3utils/dir.baz/file.foo.baz +0 -0
  35. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/s3utils/dir.foo/dir.foo.bar/dir.foo.bar.baz/file.foo.bar.baz +0 -0
  36. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.bar.baz +0 -0
  37. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.bar +0 -0
  38. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.baz +0 -0
  39. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/s3utils/dir.foo/file.bar +0 -0
  40. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/s3utils/dir.foo/file.baz +0 -0
  41. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/s3utils/dir.foo/file.foo +0 -0
  42. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/s3utils_archive/archive.compressed.zip +0 -0
  43. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/resources/unittest/s3utils_archive/archive.uncompressed.zip +0 -0
  44. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/setup.cfg +0 -0
  45. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/setup.py +0 -0
  46. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/__init__.py +0 -0
  47. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/carto/OSMFile.py +0 -0
  48. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/carto/OSMNode.py +0 -0
  49. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/carto/OSMTags.py +0 -0
  50. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/carto/OSMWay.py +0 -0
  51. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/carto/__init__.py +0 -0
  52. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/resources/__init__.py +0 -0
  53. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/resources/tags/__init__.py +0 -0
  54. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/resources/tags/unittest-1.0.0.tagset.yaml +0 -0
  55. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/resources/tags/universal-1.0.0.tagset.yaml +0 -0
  56. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/utils/__init__.py +0 -0
  57. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/utils/apiutils.py +0 -0
  58. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/utils/bagutils.py +0 -0
  59. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/utils/config.py +0 -0
  60. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/utils/datautils.py +0 -0
  61. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/utils/dockerutils.py +0 -0
  62. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/utils/gisutils.py +0 -0
  63. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/utils/jsonutils.py +0 -0
  64. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/utils/ormutils.py +0 -0
  65. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/utils/pathutils.py +0 -0
  66. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/utils/s3utils.py +0 -0
  67. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/utils/sqlutils.py +0 -0
  68. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/utils/strutils.py +0 -0
  69. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus/common/utils/testutils.py +0 -0
  70. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus_python_common.egg-info/SOURCES.txt +0 -0
  71. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus_python_common.egg-info/dependency_links.txt +0 -0
  72. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus_python_common.egg-info/not-zip-safe +0 -0
  73. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus_python_common.egg-info/requires.txt +0 -0
  74. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/src/plexus_python_common.egg-info/top_level.txt +0 -0
  75. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/__init__.py +0 -0
  76. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/__init__.py +0 -0
  77. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/carto/__init__.py +0 -0
  78. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/carto/osm_file_test.py +0 -0
  79. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/carto/osm_tags_test.py +0 -0
  80. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/utils/__init__.py +0 -0
  81. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/utils/bagutils_test.py +0 -0
  82. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/utils/datautils_test.py +0 -0
  83. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/utils/dockerutils_test.py +0 -0
  84. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/utils/gisutils_test.py +0 -0
  85. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/utils/jsonutils_test.py +0 -0
  86. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/utils/ormutils_test.py +0 -0
  87. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/utils/pathutils_test.py +0 -0
  88. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/utils/s3utils_test.py +0 -0
  89. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/utils/strutils_test.py +0 -0
  90. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/plexus_tests/common/utils/testutils_test.py +0 -0
  91. {plexus_python_common-1.0.72 → plexus_python_common-1.0.73}/test/testenv.py +0 -0
@@ -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.73
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Programming Language :: Python :: 3.13
@@ -84,11 +84,11 @@ class Tag(object):
84
84
  def unbind(self) -> Self:
85
85
  return self
86
86
 
87
- def validate(self, props: JsonType | None, *, raise_on_error: bool = False) -> bool:
88
- if self.schema is None or props is None:
87
+ def validate(self, features: JsonType | None, *, raise_on_error: bool = False) -> bool:
88
+ if self.schema is None or features is None:
89
89
  return True
90
90
  try:
91
- jsonschema.Draft7Validator(self.schema).validate(props)
91
+ jsonschema.Draft7Validator(self.schema).validate(features)
92
92
  return True
93
93
  except (jsonschema.ValidationError, jsonschema.SchemaError):
94
94
  if raise_on_error:
@@ -178,9 +178,9 @@ class Tagset(Sequence[Tag], Mapping[str, Tag]):
178
178
  return []
179
179
  return list(dicttree_lineage(self.tags_tree, child.tag_parts[:-1]))
180
180
 
181
- def validate(self, tag_name: str, props: JsonType | None, *, raise_on_error: bool = False) -> bool:
181
+ def validate(self, tag_name: str, features: JsonType | None, *, raise_on_error: bool = False) -> bool:
182
182
  tag = self.get(tag_name)
183
- return False if tag is None else tag.validate(props, raise_on_error=raise_on_error)
183
+ return False if tag is None else tag.validate(features, raise_on_error=raise_on_error)
184
184
 
185
185
 
186
186
  class MutableTagset(Tagset):
@@ -491,6 +491,11 @@ def make_tag_record_model_mixin() -> type[pdt.BaseModel]:
491
491
  sa_column=sa.Column(sa_sqlite.VARCHAR(256), nullable=False),
492
492
  description="Tag name",
493
493
  )
494
+ features: JsonType | None = Field(
495
+ sa_column=sa.Column(sa_sqlite.JSON, nullable=True),
496
+ default=None,
497
+ description="Tag features in JSON format, which can be used for storing preprocessed information of the tag record to facilitate querying and filtering",
498
+ )
494
499
  props: JsonType | None = Field(
495
500
  sa_column=sa.Column(sa_sqlite.JSON, nullable=True),
496
501
  default=None,
@@ -592,6 +597,7 @@ if typing.TYPE_CHECKING:
592
597
  tagset_namespace: sa_orm.Mapped[str | None] = ...
593
598
  tagset_version: sa_orm.Mapped[str | None] = ...
594
599
  tag: sa_orm.Mapped[str] = ...
600
+ features: sa_orm.Mapped[JsonType | None] = ...
595
601
  props: sa_orm.Mapped[JsonType | None] = ...
596
602
  flags: sa_orm.Mapped[int] = ...
597
603
 
@@ -676,7 +682,21 @@ class TagCache(object):
676
682
  begin_dt: datetime.datetime,
677
683
  end_dt: datetime.datetime,
678
684
  props: JsonType | None = None,
679
- ) -> TagTargetTable:
685
+ ) -> Chainable[Self, TagTargetTable]:
686
+ """
687
+ Create a new tag target and add it to the cache.
688
+
689
+ :param identifier: Identifier of the tag target, which should be unique across the cache. It is recommended
690
+ to use a slash tag (e.g. "dummy_name/dummy_name") to ensure uniqueness and facilitate
691
+ organization, but other formats are also allowed as long as they are valid slash tags.
692
+ :param tagger_name: Name of the tagger creating the tag target.
693
+ :param tagger_version: Version of the tagger creating the tag target.
694
+ :param vehicle_name: Name of the vehicle associated with the tag target.
695
+ :param begin_dt: Start datetime for the tag target's validity period.
696
+ :param end_dt: End datetime for the tag target's validity period.
697
+ :param props: Additional properties for the tag target.
698
+ :return: Self instance for chaining along with the added ``TagTargetTable`` instance
699
+ """
680
700
  with self.make_session() as session:
681
701
  tag_target = TagTarget(
682
702
  identifier=identifier,
@@ -691,7 +711,7 @@ class TagCache(object):
691
711
  session.add(db_tag_target)
692
712
  session.commit()
693
713
 
694
- return self.get_target(identifier)
714
+ return chainable(self, db_tag_target)
695
715
 
696
716
  def remove_targets(
697
717
  self,
@@ -701,7 +721,23 @@ class TagCache(object):
701
721
  vehicle_name: str | None = None,
702
722
  begin_dt: datetime.datetime | None = None,
703
723
  end_dt: datetime.datetime | None = None,
724
+ *,
725
+ cascade_records: bool = True,
704
726
  ):
727
+ """
728
+ Remove tag targets from the cache that match the specified filters.
729
+
730
+ :param identifier: Filter by target identifier (exact match)
731
+ :param tagger_name: Filter by tagger name (exact match)
732
+ :param tagger_version: Filter by tagger version (exact match)
733
+ :param vehicle_name: Filter by vehicle name (exact match)
734
+ :param begin_dt: Filter by begin time (inclusive)
735
+ :param end_dt: Filter by end time (inclusive)
736
+ :param cascade_records: Whether to also remove tag records that are associated with the removed targets.
737
+ If False, the tag records will be kept but become orphaned (i.e. their ``target_sqn``
738
+ will not have a corresponding target in the cache).
739
+ :return: Self for chaining
740
+ """
705
741
  with self.make_session() as session:
706
742
  query_stmt = session.query(TagTargetTable)
707
743
  if identifier:
@@ -720,13 +756,16 @@ class TagCache(object):
720
756
  query_stmt.delete()
721
757
  session.commit()
722
758
 
723
- (
724
- session
725
- .query(TagRecordTable)
726
- .filter(TagRecordTable.target_sqn.notin_(session.query(TagTargetTable.sqn)))
727
- .delete()
728
- )
729
- session.commit()
759
+ if cascade_records:
760
+ (
761
+ session
762
+ .query(TagRecordTable)
763
+ .filter(TagRecordTable.target_sqn.notin_(session.query(TagTargetTable.sqn)))
764
+ .delete()
765
+ )
766
+ session.commit()
767
+
768
+ return self
730
769
 
731
770
  def with_target(self, target: int | str) -> "TargetedTagCache":
732
771
  db_tag_target = self.get_target(target)
@@ -1010,6 +1049,7 @@ class TagCache(object):
1010
1049
  begin_dt: datetime.datetime,
1011
1050
  end_dt: datetime.datetime,
1012
1051
  tag: str | Tag | BoundTag,
1052
+ features: JsonType | None = None,
1013
1053
  props: JsonType | None = None,
1014
1054
  tagset_namespace: str | None = None,
1015
1055
  tagset_version: str | None = None,
@@ -1022,6 +1062,8 @@ class TagCache(object):
1022
1062
  :param end_dt: End datetime of the tag record
1023
1063
  :param tag: Tag name or ``Tag``/``BoundTag`` instance to be added. If ``Tag``/``BoundTag`` instance is provided,
1024
1064
  its name will be used.
1065
+ :param features: Additional tag features of the tag record in JSON format (optional), which can be used for
1066
+ storing preprocessed information of the tag record to facilitate querying and filtering.
1025
1067
  :param props: Additional properties of the tag record in JSON format (optional)
1026
1068
  :param tagset_namespace: Namespace of the tagset that the tag belongs to. If the ``tag`` parameter is a
1027
1069
  ``BoundTag`` instance, this parameter will be ignored and the namespace from the
@@ -1038,6 +1080,7 @@ class TagCache(object):
1038
1080
  tagset_namespace=tag.namespace if isinstance(tag, BoundTag) else tagset_namespace,
1039
1081
  tagset_version=tag.version if isinstance(tag, BoundTag) else tagset_version,
1040
1082
  tag=tag.name if isinstance(tag, Tag) else tag,
1083
+ features=features,
1041
1084
  props=props,
1042
1085
  )
1043
1086
  db_tag_record = clone_sequence_model_instance(TagRecordTable, tag_record)
@@ -1054,6 +1097,7 @@ class TagCache(object):
1054
1097
  begin_dt: datetime.datetime | None = None,
1055
1098
  end_dt: datetime.datetime | None = None,
1056
1099
  tag: str | Tag | BoundTag | None = None,
1100
+ features: JsonType | None = None,
1057
1101
  props: JsonType | None = None,
1058
1102
  tagset_namespace: str | None = None,
1059
1103
  tagset_version: str | None = None,
@@ -1068,6 +1112,8 @@ class TagCache(object):
1068
1112
  :param end_dt: New end datetime of the tag record (optional)
1069
1113
  :param tag: New tag name or ``Tag``/``BoundTag`` instance to be updated (optional). If ``Tag``/``BoundTag``
1070
1114
  instance is provided, its name will be used.
1115
+ :param features: Additional tag features of the tag record in JSON format (optional), which can be used for
1116
+ storing preprocessed information of the tag record to facilitate querying and filtering.
1071
1117
  :param props: New additional properties of the tag record in JSON format (optional)
1072
1118
  :param tagset_namespace: New namespace of the tagset that the tag belongs to (optional). If the ``tag``
1073
1119
  parameter is a ``BoundTag`` instance, this parameter will be ignored and the namespace
@@ -1098,6 +1144,8 @@ class TagCache(object):
1098
1144
  db_tag_record.tagset_version = tag.version if isinstance(tag, BoundTag) else tagset_version
1099
1145
  if tag is not None:
1100
1146
  db_tag_record.tag = tag.name if isinstance(tag, Tag) else tag
1147
+ if features is not None:
1148
+ db_tag_record.features = features
1101
1149
  if props is not None:
1102
1150
  db_tag_record.props = props
1103
1151
  if flags is not None:
@@ -1251,31 +1299,17 @@ class TargetedTagCache(object):
1251
1299
  begin_dt: datetime.datetime | None,
1252
1300
  end_dt: datetime.datetime | None,
1253
1301
  tag: str | Tag | BoundTag,
1302
+ features: JsonType | None = None,
1254
1303
  props: JsonType | None = None,
1255
1304
  tagset_namespace: str | None = None,
1256
1305
  tagset_version: str | None = None,
1257
1306
  ) -> 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
1307
  result = self.cache.target_add_record(
1275
1308
  target_sqn=self.tag_target.sqn,
1276
1309
  begin_dt=begin_dt or self.tag_target.begin_dt,
1277
1310
  end_dt=end_dt or self.tag_target.end_dt,
1278
1311
  tag=tag,
1312
+ features=features,
1279
1313
  props=props,
1280
1314
  tagset_namespace=tagset_namespace,
1281
1315
  tagset_version=tagset_version,
@@ -1285,28 +1319,16 @@ class TargetedTagCache(object):
1285
1319
  def add_record(
1286
1320
  self,
1287
1321
  tag: str | Tag | BoundTag,
1322
+ features: JsonType | None = None,
1288
1323
  props: JsonType | None = None,
1289
1324
  tagset_namespace: str | None = None,
1290
1325
  tagset_version: str | None = None,
1291
1326
  ) -> 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
1327
  result = self.add_ranged_record(
1307
1328
  begin_dt=self.tag_target.begin_dt,
1308
1329
  end_dt=self.tag_target.end_dt,
1309
1330
  tag=tag,
1331
+ features=features,
1310
1332
  tagset_namespace=tagset_namespace,
1311
1333
  tagset_version=tagset_version,
1312
1334
  props=props,
@@ -1320,35 +1342,19 @@ class TargetedTagCache(object):
1320
1342
  begin_dt: datetime.datetime | None = None,
1321
1343
  end_dt: datetime.datetime | None = None,
1322
1344
  tag: str | Tag | BoundTag | None = None,
1345
+ features: JsonType | None = None,
1323
1346
  props: JsonType | None = None,
1324
1347
  tagset_namespace: str | None = None,
1325
1348
  tagset_version: str | None = None,
1326
1349
  flags: int | None = None,
1327
1350
  ) -> 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
1351
  result = self.cache.target_update_record(
1347
1352
  self.tag_target.sqn,
1348
1353
  sqn,
1349
1354
  begin_dt=begin_dt,
1350
1355
  end_dt=end_dt,
1351
1356
  tag=tag,
1357
+ features=features,
1352
1358
  props=props,
1353
1359
  tagset_namespace=tagset_namespace,
1354
1360
  tagset_version=tagset_version,
@@ -1367,19 +1373,6 @@ class TargetedTagCache(object):
1367
1373
  tagsets: Sequence[Tagset] | None = None,
1368
1374
  tagset_inverted: bool = False,
1369
1375
  ) -> 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
1376
  self.cache.target_remove_records(
1384
1377
  self.tag_target.sqn,
1385
1378
  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.73
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Programming Language :: Python :: 3.13
@@ -86,15 +86,15 @@ class TagUtilsTest(unittest.TestCase):
86
86
 
87
87
  @ddt.idata(data_tag_validate)
88
88
  @ddt.unpack
89
- def test_tagset_validate(self, tag: str, props: JsonObject, should_pass: bool):
89
+ def test_tagset_validate(self, tag: str, features: JsonObject, should_pass: bool):
90
90
  tagset = predefined_tagsets().get("unittest")
91
91
 
92
92
  if should_pass:
93
- self.assertTrue(tagset.validate(tag, props))
93
+ self.assertTrue(tagset.validate(tag, features))
94
94
  else:
95
- self.assertFalse(tagset.validate(tag, props))
95
+ self.assertFalse(tagset.validate(tag, features))
96
96
  with self.assertRaises(Exception):
97
- tagset.validate(tag, props, raise_on_error=True)
97
+ tagset.validate(tag, features, raise_on_error=True)
98
98
 
99
99
  def test_tag_cache(self):
100
100
  tag_names = [
@@ -122,7 +122,7 @@ class TagUtilsTest(unittest.TestCase):
122
122
  "dummy_vehicle",
123
123
  dt_parse_iso("2020-01-01T00:00:00+00:00"),
124
124
  dt_parse_iso("2020-01-01T01:00:00+00:00"),
125
- {"dummy_target_prop": "dummy_value"})
125
+ props={"dummy_target_prop": "dummy_value"})
126
126
 
127
127
  target_cache = cache.with_target("awesome_tagger/20200101_000000/dummy_vehicle/0")
128
128
 
@@ -135,7 +135,7 @@ class TagUtilsTest(unittest.TestCase):
135
135
  dt_parse_iso("2020-01-01T00:00:00+00:00") + datetime.timedelta(seconds=i),
136
136
  dt_parse_iso("2020-01-02T00:00:00+00:00") + datetime.timedelta(seconds=i + 1),
137
137
  tag,
138
- props={
138
+ features={
139
139
  "dummy_int": 1,
140
140
  "dummy_float": 1.0e-1,
141
141
  "dummy_bool": True,
@@ -148,6 +148,7 @@ class TagUtilsTest(unittest.TestCase):
148
148
  "dummy_str": "dummy_string",
149
149
  },
150
150
  },
151
+ props={"dummy_record_prop": "dummy_value"},
151
152
  )
152
153
 
153
154
  self.assertEqual(target_cache.count_records(), tag_records_count)
@@ -277,7 +278,7 @@ class TagUtilsTest(unittest.TestCase):
277
278
  "dummy_vehicle",
278
279
  dt_parse_iso("2020-01-01T00:00:00+00:00"),
279
280
  dt_parse_iso("2020-01-01T01:00:00+00:00"),
280
- {"dummy_target_prop": "dummy_value"})
281
+ props={"dummy_target_prop": "dummy_value"})
281
282
 
282
283
  target_caches = [cache.with_target(f"concurrent_tagger/20200101_000000/dummy_vehicle/{i}")
283
284
  for i in range(target_caches_count)]
@@ -301,7 +302,7 @@ class TagUtilsTest(unittest.TestCase):
301
302
  dt_parse_iso("2020-01-01T00:00:00+00:00") + datetime.timedelta(seconds=i),
302
303
  dt_parse_iso("2020-01-02T00:00:00+00:00") + datetime.timedelta(seconds=i + 1),
303
304
  tag,
304
- props={
305
+ features={
305
306
  "dummy_int": 1,
306
307
  "dummy_float": 1.0e-1,
307
308
  "dummy_bool": True,
@@ -314,6 +315,7 @@ class TagUtilsTest(unittest.TestCase):
314
315
  "dummy_str": "dummy_string",
315
316
  },
316
317
  },
318
+ props={"dummy_record_prop": "dummy_value"},
317
319
  )
318
320
 
319
321
  threads = [threading.Thread(target=worker, args=(tid,)) for tid in range(total_threads_count)]