plexus-python-common 1.0.72__tar.gz → 1.0.74__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.
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/PKG-INFO +1 -1
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/tagutils.py +86 -76
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus_python_common.egg-info/PKG-INFO +1 -1
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/utils/tagutils_test.py +13 -9
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/.editorconfig +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/.github/workflows/pr.yml +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/.github/workflows/push.yml +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/.gitignore +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/MANIFEST.in +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/README.md +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/VERSION +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/pyproject.toml +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/jsonutils/dummy.0.jsonl +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/jsonutils/dummy.1.jsonl +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/jsonutils/dummy.2.jsonl +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/0-dummy +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/1-dummy +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/2-dummy +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/dummy.0.0.jsonl +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/dummy.0.0.vol-0.jsonl +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/dummy.0.jsonl +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/dummy.1.1.jsonl +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/dummy.1.1.vol-1.jsonl +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/dummy.1.jsonl +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/dummy.2.2.jsonl +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/dummy.2.2.vol-2.jsonl +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/dummy.2.jsonl +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/dummy.csv.part0 +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/dummy.csv.part1 +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/dummy.csv.part2 +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/dummy.txt +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/s3utils/dir.baz/file.bar.baz +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/s3utils/dir.baz/file.foo.bar +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/s3utils/dir.baz/file.foo.baz +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/s3utils/dir.foo/dir.foo.bar/dir.foo.bar.baz/file.foo.bar.baz +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.bar.baz +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.bar +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.baz +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/s3utils/dir.foo/file.bar +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/s3utils/dir.foo/file.baz +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/s3utils/dir.foo/file.foo +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/s3utils_archive/archive.compressed.zip +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/s3utils_archive/archive.uncompressed.zip +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/setup.cfg +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/setup.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/__init__.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/carto/OSMFile.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/carto/OSMNode.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/carto/OSMTags.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/carto/OSMWay.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/carto/__init__.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/resources/__init__.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/resources/tags/__init__.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/resources/tags/unittest-1.0.0.tagset.yaml +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/resources/tags/universal-1.0.0.tagset.yaml +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/__init__.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/apiutils.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/bagutils.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/config.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/datautils.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/dockerutils.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/gisutils.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/jsonutils.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/ormutils.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/pathutils.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/s3utils.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/sqlutils.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/strutils.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/testutils.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus_python_common.egg-info/SOURCES.txt +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus_python_common.egg-info/dependency_links.txt +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus_python_common.egg-info/not-zip-safe +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus_python_common.egg-info/requires.txt +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus_python_common.egg-info/top_level.txt +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/__init__.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/__init__.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/carto/__init__.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/carto/osm_file_test.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/carto/osm_tags_test.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/utils/__init__.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/utils/bagutils_test.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/utils/datautils_test.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/utils/dockerutils_test.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/utils/gisutils_test.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/utils/jsonutils_test.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/utils/ormutils_test.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/utils/pathutils_test.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/utils/s3utils_test.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/utils/strutils_test.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/utils/testutils_test.py +0 -0
- {plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/testenv.py +0 -0
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/tagutils.py
RENAMED
|
@@ -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,
|
|
88
|
-
if self.schema is None or
|
|
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(
|
|
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,
|
|
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(
|
|
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[
|
|
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
|
|
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
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
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,
|
|
@@ -13,6 +13,7 @@ from plexus.common.utils.tagutils import MutableTagset, Tag, TagCache, Tagset
|
|
|
13
13
|
from plexus.common.utils.tagutils import populate_clip_ranges
|
|
14
14
|
from plexus.common.utils.tagutils import predefined_tagsets, render_tagset_markdown_readme
|
|
15
15
|
from plexus.common.utils.tagutils import tag_cache_file_path
|
|
16
|
+
from plexus.common.utils.tagutils import versioned_identifier
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
@ddt.ddt
|
|
@@ -46,7 +47,8 @@ class TagUtilsTest(unittest.TestCase):
|
|
|
46
47
|
|
|
47
48
|
print(markdown)
|
|
48
49
|
|
|
49
|
-
self.assertEqual(predefined_tagsets().get("unittest"),
|
|
50
|
+
self.assertEqual(predefined_tagsets().get("unittest"),
|
|
51
|
+
predefined_tagsets().get(versioned_identifier("unittest", "1.0.0")))
|
|
50
52
|
|
|
51
53
|
data_tag_validate = [
|
|
52
54
|
("level_1_tag", {"dummy_property": "dummy_value"}, True,),
|
|
@@ -86,15 +88,15 @@ class TagUtilsTest(unittest.TestCase):
|
|
|
86
88
|
|
|
87
89
|
@ddt.idata(data_tag_validate)
|
|
88
90
|
@ddt.unpack
|
|
89
|
-
def test_tagset_validate(self, tag: str,
|
|
91
|
+
def test_tagset_validate(self, tag: str, features: JsonObject, should_pass: bool):
|
|
90
92
|
tagset = predefined_tagsets().get("unittest")
|
|
91
93
|
|
|
92
94
|
if should_pass:
|
|
93
|
-
self.assertTrue(tagset.validate(tag,
|
|
95
|
+
self.assertTrue(tagset.validate(tag, features))
|
|
94
96
|
else:
|
|
95
|
-
self.assertFalse(tagset.validate(tag,
|
|
97
|
+
self.assertFalse(tagset.validate(tag, features))
|
|
96
98
|
with self.assertRaises(Exception):
|
|
97
|
-
tagset.validate(tag,
|
|
99
|
+
tagset.validate(tag, features, raise_on_error=True)
|
|
98
100
|
|
|
99
101
|
def test_tag_cache(self):
|
|
100
102
|
tag_names = [
|
|
@@ -122,7 +124,7 @@ class TagUtilsTest(unittest.TestCase):
|
|
|
122
124
|
"dummy_vehicle",
|
|
123
125
|
dt_parse_iso("2020-01-01T00:00:00+00:00"),
|
|
124
126
|
dt_parse_iso("2020-01-01T01:00:00+00:00"),
|
|
125
|
-
{"dummy_target_prop": "dummy_value"})
|
|
127
|
+
props={"dummy_target_prop": "dummy_value"})
|
|
126
128
|
|
|
127
129
|
target_cache = cache.with_target("awesome_tagger/20200101_000000/dummy_vehicle/0")
|
|
128
130
|
|
|
@@ -135,7 +137,7 @@ class TagUtilsTest(unittest.TestCase):
|
|
|
135
137
|
dt_parse_iso("2020-01-01T00:00:00+00:00") + datetime.timedelta(seconds=i),
|
|
136
138
|
dt_parse_iso("2020-01-02T00:00:00+00:00") + datetime.timedelta(seconds=i + 1),
|
|
137
139
|
tag,
|
|
138
|
-
|
|
140
|
+
features={
|
|
139
141
|
"dummy_int": 1,
|
|
140
142
|
"dummy_float": 1.0e-1,
|
|
141
143
|
"dummy_bool": True,
|
|
@@ -148,6 +150,7 @@ class TagUtilsTest(unittest.TestCase):
|
|
|
148
150
|
"dummy_str": "dummy_string",
|
|
149
151
|
},
|
|
150
152
|
},
|
|
153
|
+
props={"dummy_record_prop": "dummy_value"},
|
|
151
154
|
)
|
|
152
155
|
|
|
153
156
|
self.assertEqual(target_cache.count_records(), tag_records_count)
|
|
@@ -277,7 +280,7 @@ class TagUtilsTest(unittest.TestCase):
|
|
|
277
280
|
"dummy_vehicle",
|
|
278
281
|
dt_parse_iso("2020-01-01T00:00:00+00:00"),
|
|
279
282
|
dt_parse_iso("2020-01-01T01:00:00+00:00"),
|
|
280
|
-
{"dummy_target_prop": "dummy_value"})
|
|
283
|
+
props={"dummy_target_prop": "dummy_value"})
|
|
281
284
|
|
|
282
285
|
target_caches = [cache.with_target(f"concurrent_tagger/20200101_000000/dummy_vehicle/{i}")
|
|
283
286
|
for i in range(target_caches_count)]
|
|
@@ -301,7 +304,7 @@ class TagUtilsTest(unittest.TestCase):
|
|
|
301
304
|
dt_parse_iso("2020-01-01T00:00:00+00:00") + datetime.timedelta(seconds=i),
|
|
302
305
|
dt_parse_iso("2020-01-02T00:00:00+00:00") + datetime.timedelta(seconds=i + 1),
|
|
303
306
|
tag,
|
|
304
|
-
|
|
307
|
+
features={
|
|
305
308
|
"dummy_int": 1,
|
|
306
309
|
"dummy_float": 1.0e-1,
|
|
307
310
|
"dummy_bool": True,
|
|
@@ -314,6 +317,7 @@ class TagUtilsTest(unittest.TestCase):
|
|
|
314
317
|
"dummy_str": "dummy_string",
|
|
315
318
|
},
|
|
316
319
|
},
|
|
320
|
+
props={"dummy_record_prop": "dummy_value"},
|
|
317
321
|
)
|
|
318
322
|
|
|
319
323
|
threads = [threading.Thread(target=worker, args=(tid,)) for tid in range(total_threads_count)]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/0-dummy
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/1-dummy
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/2-dummy
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/resources/unittest/pathutils/dummy.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/carto/OSMFile.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/carto/OSMNode.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/carto/OSMTags.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/carto/OSMWay.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/carto/__init__.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/resources/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/__init__.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/apiutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/bagutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/config.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/datautils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/dockerutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/gisutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/jsonutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/ormutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/pathutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/s3utils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/sqlutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/strutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/src/plexus/common/utils/testutils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plexus_python_common-1.0.72 → plexus_python_common-1.0.74}/test/plexus_tests/common/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|