plexus-python-common 1.0.70__tar.gz → 1.0.72__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.70 → plexus_python_common-1.0.72}/PKG-INFO +1 -1
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/tagutils.py +268 -125
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus_python_common.egg-info/PKG-INFO +1 -1
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/utils/tagutils_test.py +72 -67
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/.editorconfig +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/.github/workflows/pr.yml +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/.github/workflows/push.yml +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/.gitignore +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/MANIFEST.in +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/README.md +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/VERSION +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/pyproject.toml +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/jsonutils/dummy.0.jsonl +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/jsonutils/dummy.1.jsonl +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/jsonutils/dummy.2.jsonl +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/0-dummy +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/1-dummy +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/2-dummy +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/dummy.0.0.jsonl +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/dummy.0.0.vol-0.jsonl +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/dummy.0.jsonl +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/dummy.1.1.jsonl +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/dummy.1.1.vol-1.jsonl +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/dummy.1.jsonl +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/dummy.2.2.jsonl +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/dummy.2.2.vol-2.jsonl +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/dummy.2.jsonl +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/dummy.csv.part0 +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/dummy.csv.part1 +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/dummy.csv.part2 +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/dummy.txt +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/s3utils/dir.baz/file.bar.baz +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/s3utils/dir.baz/file.foo.bar +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/s3utils/dir.baz/file.foo.baz +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/s3utils/dir.foo/dir.foo.bar/dir.foo.bar.baz/file.foo.bar.baz +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.bar.baz +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.bar +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.baz +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/s3utils/dir.foo/file.bar +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/s3utils/dir.foo/file.baz +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/s3utils/dir.foo/file.foo +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/s3utils_archive/archive.compressed.zip +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/s3utils_archive/archive.uncompressed.zip +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/setup.cfg +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/setup.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/__init__.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/carto/OSMFile.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/carto/OSMNode.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/carto/OSMTags.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/carto/OSMWay.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/carto/__init__.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/resources/__init__.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/resources/tags/__init__.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/resources/tags/unittest-1.0.0.tagset.yaml +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/resources/tags/universal-1.0.0.tagset.yaml +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/__init__.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/apiutils.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/bagutils.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/config.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/datautils.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/dockerutils.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/gisutils.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/jsonutils.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/ormutils.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/pathutils.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/s3utils.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/sqlutils.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/strutils.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/testutils.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus_python_common.egg-info/SOURCES.txt +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus_python_common.egg-info/dependency_links.txt +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus_python_common.egg-info/not-zip-safe +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus_python_common.egg-info/requires.txt +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus_python_common.egg-info/top_level.txt +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/__init__.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/__init__.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/carto/__init__.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/carto/osm_file_test.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/carto/osm_tags_test.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/utils/__init__.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/utils/bagutils_test.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/utils/datautils_test.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/utils/dockerutils_test.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/utils/gisutils_test.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/utils/jsonutils_test.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/utils/ormutils_test.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/utils/pathutils_test.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/utils/s3utils_test.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/utils/strutils_test.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/plexus_tests/common/utils/testutils_test.py +0 -0
- {plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/test/testenv.py +0 -0
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/tagutils.py
RENAMED
|
@@ -33,14 +33,14 @@ 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
|
|
37
|
-
from plexus.common.utils.ormutils import SequenceModelMixinProtocol
|
|
36
|
+
from plexus.common.utils.ormutils import SQLiteDateTime, SequenceModelMixinProtocol
|
|
38
37
|
from plexus.common.utils.ormutils import clone_sequence_model_instance, make_base_model, make_sequence_model_mixin
|
|
39
38
|
from plexus.common.utils.sqlutils import escape_sql_like
|
|
40
39
|
|
|
41
40
|
__all__ = [
|
|
42
41
|
"RichDesc",
|
|
43
42
|
"Tag",
|
|
43
|
+
"BoundTag",
|
|
44
44
|
"Tagset",
|
|
45
45
|
"MutableTagset",
|
|
46
46
|
"populate_tagset",
|
|
@@ -894,7 +894,7 @@ class TagCache(object):
|
|
|
894
894
|
*,
|
|
895
895
|
tagsets: Sequence[Tagset] | None = None,
|
|
896
896
|
tagset_inverted: bool = False,
|
|
897
|
-
):
|
|
897
|
+
) -> Self:
|
|
898
898
|
"""
|
|
899
899
|
Remove tag records from the cache that match the specified filters.
|
|
900
900
|
|
|
@@ -906,6 +906,7 @@ class TagCache(object):
|
|
|
906
906
|
:param tagsets: Filter by tagsets (match tags that are in any of the specified tagsets)
|
|
907
907
|
:param tagset_inverted: Whether to invert the tagset filter (match tags that are NOT in any of the specified
|
|
908
908
|
tagsets)
|
|
909
|
+
:return: Self for chaining
|
|
909
910
|
"""
|
|
910
911
|
with self.make_session() as session:
|
|
911
912
|
query_stmt = session.query(TagRecordTable)
|
|
@@ -930,86 +931,20 @@ class TagCache(object):
|
|
|
930
931
|
query_stmt.delete()
|
|
931
932
|
session.commit()
|
|
932
933
|
|
|
933
|
-
|
|
934
|
-
with self.make_session() as session:
|
|
935
|
-
session.execute(sa.delete(TagRecordTable))
|
|
936
|
-
session.execute(sa.delete(TagTargetTable))
|
|
937
|
-
session.commit()
|
|
938
|
-
|
|
939
|
-
def append_to(self, target_file_path: str, *, overwrite: bool = False):
|
|
940
|
-
target_tag_cache = TagCache(file_path=target_file_path)
|
|
941
|
-
if overwrite:
|
|
942
|
-
target_tag_cache.clear()
|
|
943
|
-
TagCache.copy_to(self, target_tag_cache)
|
|
944
|
-
|
|
945
|
-
def merge_from(self, source_file_path: str, *, overwrite: bool = False):
|
|
946
|
-
source_tag_cache = TagCache(file_path=source_file_path)
|
|
947
|
-
if overwrite:
|
|
948
|
-
self.clear()
|
|
949
|
-
TagCache.copy_to(source_tag_cache, self)
|
|
950
|
-
|
|
951
|
-
@staticmethod
|
|
952
|
-
def copy_to(src: "TagCache", dst: "TagCache"):
|
|
953
|
-
# If src and dst are the same instance or point to the same file path,
|
|
954
|
-
# do nothing to avoid accidentally clearing the cache
|
|
955
|
-
if src == dst or src.file_path == dst.file_path:
|
|
956
|
-
return
|
|
957
|
-
|
|
958
|
-
with src.make_session() as src_session, dst.make_session() as dst_session:
|
|
959
|
-
src_db_tag_targets = src_session.query(TagTargetTable).all()
|
|
960
|
-
dst_db_tag_targets = [
|
|
961
|
-
clone_sequence_model_instance(TagTargetTable, db_tag_target, clear_meta_fields=True)
|
|
962
|
-
for db_tag_target in src_db_tag_targets
|
|
963
|
-
]
|
|
964
|
-
dst_session.add_all(dst_db_tag_targets)
|
|
965
|
-
dst_session.flush() # ensure new sqn values are assigned
|
|
966
|
-
|
|
967
|
-
sqn_map = {src_db_tag_target.sqn: dst_db_tag_target.sqn
|
|
968
|
-
for src_db_tag_target, dst_db_tag_target in zip(src_db_tag_targets, dst_db_tag_targets)}
|
|
969
|
-
|
|
970
|
-
for db_tag_records in batched(src_session.query(TagRecordTable).yield_per(1000), 1000):
|
|
971
|
-
cloned_db_tag_records = []
|
|
972
|
-
for db_tag_record in db_tag_records:
|
|
973
|
-
cloned_db_tag_record = clone_sequence_model_instance(TagRecordTable,
|
|
974
|
-
db_tag_record,
|
|
975
|
-
clear_meta_fields=True)
|
|
976
|
-
try:
|
|
977
|
-
cloned_db_tag_record.target_sqn = sqn_map[db_tag_record.target_sqn]
|
|
978
|
-
except KeyError as e:
|
|
979
|
-
raise ValueError(f"no cloned tag target for target_sqn '{db_tag_record.target_sqn}'") from e
|
|
980
|
-
cloned_db_tag_records.append(cloned_db_tag_record)
|
|
981
|
-
dst_session.add_all(cloned_db_tag_records)
|
|
982
|
-
dst_session.commit()
|
|
983
|
-
|
|
984
|
-
count_tags = count_records
|
|
985
|
-
iter_tags = iter_records
|
|
986
|
-
iter_tag_and_targets = iter_record_and_targets
|
|
987
|
-
remove_tags = remove_records
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
class TargetedTagCache(object):
|
|
991
|
-
def __init__(self, cache: TagCache, tag_target: TagTargetTable):
|
|
992
|
-
self.cache = cache
|
|
993
|
-
self.tag_target = tag_target
|
|
994
|
-
|
|
995
|
-
@contextlib.contextmanager
|
|
996
|
-
def make_session(self) -> Generator[sa_orm.Session, None, None]:
|
|
997
|
-
with self.cache.make_session() as session:
|
|
998
|
-
if not session.query(TagTargetTable).filter(TagTargetTable.sqn == self.tag_target.sqn).first():
|
|
999
|
-
raise ValueError(f"tag target with sqn '{self.tag_target.sqn}' is no longer present in cache")
|
|
1000
|
-
yield session
|
|
934
|
+
return self
|
|
1001
935
|
|
|
1002
|
-
def
|
|
936
|
+
def target_count_records(self, target_sqn: int) -> int:
|
|
1003
937
|
with self.make_session() as session:
|
|
1004
938
|
return (
|
|
1005
939
|
session
|
|
1006
940
|
.query(sa.func.count(TagRecordTable.sqn))
|
|
1007
|
-
.filter(TagRecordTable.target_sqn ==
|
|
941
|
+
.filter(TagRecordTable.target_sqn == target_sqn)
|
|
1008
942
|
.scalar()
|
|
1009
943
|
)
|
|
1010
944
|
|
|
1011
|
-
def
|
|
945
|
+
def target_iter_records(
|
|
1012
946
|
self,
|
|
947
|
+
target_sqn: int,
|
|
1013
948
|
begin_dt: datetime.datetime | None = None,
|
|
1014
949
|
end_dt: datetime.datetime | None = None,
|
|
1015
950
|
tagset_namespace: str | None = None,
|
|
@@ -1025,6 +960,7 @@ class TargetedTagCache(object):
|
|
|
1025
960
|
"""
|
|
1026
961
|
Query tag records in the cache with optional filters.
|
|
1027
962
|
|
|
963
|
+
:param target_sqn: Filter by target sequence number (exact match)
|
|
1028
964
|
:param begin_dt: Filter by begin time (inclusive)
|
|
1029
965
|
:param end_dt: Filter by end time (inclusive)
|
|
1030
966
|
:param tagset_namespace: Filter by tagset namespace (exact match)
|
|
@@ -1040,7 +976,7 @@ class TargetedTagCache(object):
|
|
|
1040
976
|
"""
|
|
1041
977
|
|
|
1042
978
|
with self.make_session() as session:
|
|
1043
|
-
query_stmt = session.query(TagRecordTable).filter(TagRecordTable.target_sqn ==
|
|
979
|
+
query_stmt = session.query(TagRecordTable).filter(TagRecordTable.target_sqn == target_sqn)
|
|
1044
980
|
if begin_dt:
|
|
1045
981
|
query_stmt = query_stmt.filter(TagRecordTable.end_dt >= begin_dt)
|
|
1046
982
|
if end_dt:
|
|
@@ -1068,19 +1004,20 @@ class TargetedTagCache(object):
|
|
|
1068
1004
|
for result in query_stmt.yield_per(batch_size):
|
|
1069
1005
|
yield result
|
|
1070
1006
|
|
|
1071
|
-
def
|
|
1007
|
+
def target_add_record(
|
|
1072
1008
|
self,
|
|
1073
|
-
|
|
1074
|
-
|
|
1009
|
+
target_sqn: int,
|
|
1010
|
+
begin_dt: datetime.datetime,
|
|
1011
|
+
end_dt: datetime.datetime,
|
|
1075
1012
|
tag: str | Tag | BoundTag,
|
|
1076
1013
|
props: JsonType | None = None,
|
|
1077
1014
|
tagset_namespace: str | None = None,
|
|
1078
1015
|
tagset_version: str | None = None,
|
|
1079
1016
|
) -> Chainable[Self, TagRecordTable]:
|
|
1080
1017
|
"""
|
|
1081
|
-
Add a tag record to the cache for the specified time range.
|
|
1082
|
-
default to the target's ``begin_dt`` or ``end_dt`` respectively.
|
|
1018
|
+
Add a tag record to the cache for the specified time range.
|
|
1083
1019
|
|
|
1020
|
+
:param target_sqn: Sequence number of the tag record's target
|
|
1084
1021
|
:param begin_dt: Begin datetime of the tag record
|
|
1085
1022
|
:param end_dt: End datetime of the tag record
|
|
1086
1023
|
:param tag: Tag name or ``Tag``/``BoundTag`` instance to be added. If ``Tag``/``BoundTag`` instance is provided,
|
|
@@ -1091,13 +1028,13 @@ class TargetedTagCache(object):
|
|
|
1091
1028
|
instance will be used.
|
|
1092
1029
|
:param tagset_version: Version of the tagset that the tag belongs to. If the ``tag`` parameter is a ``BoundTag``
|
|
1093
1030
|
instance, this parameter will be ignored and the version from the instance will be used.
|
|
1094
|
-
:return: Self instance for chaining
|
|
1031
|
+
:return: Self instance for chaining along with the added ``TagRecordTable`` instance
|
|
1095
1032
|
"""
|
|
1096
1033
|
with self.make_session() as session:
|
|
1097
1034
|
tag_record = TagRecord(
|
|
1098
|
-
target_sqn=
|
|
1099
|
-
begin_dt=begin_dt
|
|
1100
|
-
end_dt=end_dt
|
|
1035
|
+
target_sqn=target_sqn,
|
|
1036
|
+
begin_dt=begin_dt,
|
|
1037
|
+
end_dt=end_dt,
|
|
1101
1038
|
tagset_namespace=tag.namespace if isinstance(tag, BoundTag) else tagset_namespace,
|
|
1102
1039
|
tagset_version=tag.version if isinstance(tag, BoundTag) else tagset_version,
|
|
1103
1040
|
tag=tag.name if isinstance(tag, Tag) else tag,
|
|
@@ -1109,38 +1046,9 @@ class TargetedTagCache(object):
|
|
|
1109
1046
|
|
|
1110
1047
|
return chainable(self, db_tag_record)
|
|
1111
1048
|
|
|
1112
|
-
def
|
|
1113
|
-
self,
|
|
1114
|
-
tag: str | Tag | BoundTag,
|
|
1115
|
-
props: JsonType | None = None,
|
|
1116
|
-
tagset_namespace: str | None = None,
|
|
1117
|
-
tagset_version: str | None = None,
|
|
1118
|
-
) -> Chainable[Self, TagRecordTable]:
|
|
1119
|
-
"""
|
|
1120
|
-
Add a tag record to the cache for the entire target range.
|
|
1121
|
-
|
|
1122
|
-
:param tag: Tag name or ``Tag``/``BoundTag`` instance to be added. If ``Tag``/``BoundTag`` instance is provided,
|
|
1123
|
-
its name will be used.
|
|
1124
|
-
:param props: Additional properties of the tag record in JSON format (optional)
|
|
1125
|
-
:param tagset_namespace: Namespace of the tagset that the tag belongs to. If the ``tag`` parameter is a
|
|
1126
|
-
``BoundTag`` instance, this parameter will be ignored and the namespace from the
|
|
1127
|
-
instance will be used.
|
|
1128
|
-
:param tagset_version: Version of the tagset that the tag belongs to. If the ``tag`` parameter is a
|
|
1129
|
-
``BoundTag`` instance, this parameter will be ignored and the version from the instance
|
|
1130
|
-
will be used.
|
|
1131
|
-
:return: Self instance for chaining
|
|
1132
|
-
"""
|
|
1133
|
-
return self.add_ranged_record(
|
|
1134
|
-
begin_dt=self.tag_target.begin_dt,
|
|
1135
|
-
end_dt=self.tag_target.end_dt,
|
|
1136
|
-
tag=tag,
|
|
1137
|
-
tagset_namespace=tagset_namespace,
|
|
1138
|
-
tagset_version=tagset_version,
|
|
1139
|
-
props=props,
|
|
1140
|
-
)
|
|
1141
|
-
|
|
1142
|
-
def update_record(
|
|
1049
|
+
def target_update_record(
|
|
1143
1050
|
self,
|
|
1051
|
+
target_sqn: int,
|
|
1144
1052
|
sqn: int,
|
|
1145
1053
|
*,
|
|
1146
1054
|
begin_dt: datetime.datetime | None = None,
|
|
@@ -1154,6 +1062,7 @@ class TargetedTagCache(object):
|
|
|
1154
1062
|
"""
|
|
1155
1063
|
Update a tag record in the cache by its sequence number.
|
|
1156
1064
|
|
|
1065
|
+
:param target_sqn: Sequence number of the tag record's target
|
|
1157
1066
|
:param sqn: Sequence number of the tag record to be updated
|
|
1158
1067
|
:param begin_dt: New begin datetime of the tag record (optional)
|
|
1159
1068
|
:param end_dt: New end datetime of the tag record (optional)
|
|
@@ -1167,10 +1076,15 @@ class TargetedTagCache(object):
|
|
|
1167
1076
|
is a ``BoundTag`` instance, this parameter will be ignored and the version from the
|
|
1168
1077
|
instance will be used.
|
|
1169
1078
|
:param flags: New integer bitmask storing status or metadata flags for this tag record (optional)
|
|
1170
|
-
:return: Self instance for chaining
|
|
1079
|
+
:return: Self instance for chaining along with the updated ``TagRecordTable`` instance
|
|
1171
1080
|
"""
|
|
1172
1081
|
with self.make_session() as session:
|
|
1173
|
-
db_tag_record =
|
|
1082
|
+
db_tag_record = (
|
|
1083
|
+
session
|
|
1084
|
+
.query(TagRecordTable)
|
|
1085
|
+
.filter(TagRecordTable.target_sqn == target_sqn, TagRecordTable.sqn == sqn)
|
|
1086
|
+
.one_or_none()
|
|
1087
|
+
)
|
|
1174
1088
|
if not db_tag_record:
|
|
1175
1089
|
raise ValueError(f"tag record with sqn '{sqn}' not found in cache")
|
|
1176
1090
|
|
|
@@ -1193,8 +1107,9 @@ class TargetedTagCache(object):
|
|
|
1193
1107
|
|
|
1194
1108
|
return chainable(self, db_tag_record)
|
|
1195
1109
|
|
|
1196
|
-
def
|
|
1110
|
+
def target_remove_records(
|
|
1197
1111
|
self,
|
|
1112
|
+
target_sqn: int,
|
|
1198
1113
|
begin_dt: datetime.datetime | None = None,
|
|
1199
1114
|
end_dt: datetime.datetime | None = None,
|
|
1200
1115
|
tagset_namespace: str | None = None,
|
|
@@ -1207,6 +1122,7 @@ class TargetedTagCache(object):
|
|
|
1207
1122
|
"""
|
|
1208
1123
|
Remove tag records from the cache that match the specified filters.
|
|
1209
1124
|
|
|
1125
|
+
:param target_sqn: Filter by target sequence number (exact match)
|
|
1210
1126
|
:param begin_dt: Filter by begin time (inclusive)
|
|
1211
1127
|
:param end_dt: Filter by end time (inclusive)
|
|
1212
1128
|
:param tagset_namespace: Filter by tagset namespace (exact match)
|
|
@@ -1218,7 +1134,7 @@ class TargetedTagCache(object):
|
|
|
1218
1134
|
:return: Self instance for chaining
|
|
1219
1135
|
"""
|
|
1220
1136
|
with self.make_session() as session:
|
|
1221
|
-
query_stmt = session.query(TagRecordTable).filter(TagRecordTable.target_sqn ==
|
|
1137
|
+
query_stmt = session.query(TagRecordTable).filter(TagRecordTable.target_sqn == target_sqn)
|
|
1222
1138
|
if begin_dt:
|
|
1223
1139
|
query_stmt = query_stmt.filter(TagRecordTable.end_dt >= begin_dt)
|
|
1224
1140
|
if end_dt:
|
|
@@ -1242,12 +1158,239 @@ class TargetedTagCache(object):
|
|
|
1242
1158
|
|
|
1243
1159
|
return self
|
|
1244
1160
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1161
|
+
def clear(self):
|
|
1162
|
+
with self.make_session() as session:
|
|
1163
|
+
session.execute(sa.delete(TagRecordTable))
|
|
1164
|
+
session.execute(sa.delete(TagTargetTable))
|
|
1165
|
+
session.commit()
|
|
1166
|
+
|
|
1167
|
+
def append_to(self, target_file_path: str, *, overwrite: bool = False):
|
|
1168
|
+
target_tag_cache = TagCache(file_path=target_file_path)
|
|
1169
|
+
if overwrite:
|
|
1170
|
+
target_tag_cache.clear()
|
|
1171
|
+
TagCache.copy_to(self, target_tag_cache)
|
|
1172
|
+
|
|
1173
|
+
def merge_from(self, source_file_path: str, *, overwrite: bool = False):
|
|
1174
|
+
source_tag_cache = TagCache(file_path=source_file_path)
|
|
1175
|
+
if overwrite:
|
|
1176
|
+
self.clear()
|
|
1177
|
+
TagCache.copy_to(source_tag_cache, self)
|
|
1178
|
+
|
|
1179
|
+
@staticmethod
|
|
1180
|
+
def copy_to(src: "TagCache", dst: "TagCache"):
|
|
1181
|
+
# If src and dst are the same instance or point to the same file path,
|
|
1182
|
+
# do nothing to avoid accidentally clearing the cache
|
|
1183
|
+
if src == dst or src.file_path == dst.file_path:
|
|
1184
|
+
return
|
|
1185
|
+
|
|
1186
|
+
with src.make_session() as src_session, dst.make_session() as dst_session:
|
|
1187
|
+
src_db_tag_targets = src_session.query(TagTargetTable).all()
|
|
1188
|
+
dst_db_tag_targets = [
|
|
1189
|
+
clone_sequence_model_instance(TagTargetTable, db_tag_target, clear_meta_fields=True)
|
|
1190
|
+
for db_tag_target in src_db_tag_targets
|
|
1191
|
+
]
|
|
1192
|
+
dst_session.add_all(dst_db_tag_targets)
|
|
1193
|
+
dst_session.flush() # ensure new sqn values are assigned
|
|
1194
|
+
|
|
1195
|
+
sqn_map = {src_db_tag_target.sqn: dst_db_tag_target.sqn
|
|
1196
|
+
for src_db_tag_target, dst_db_tag_target in zip(src_db_tag_targets, dst_db_tag_targets)}
|
|
1197
|
+
|
|
1198
|
+
for db_tag_records in batched(src_session.query(TagRecordTable).yield_per(1000), 1000):
|
|
1199
|
+
cloned_db_tag_records = []
|
|
1200
|
+
for db_tag_record in db_tag_records:
|
|
1201
|
+
cloned_db_tag_record = clone_sequence_model_instance(TagRecordTable,
|
|
1202
|
+
db_tag_record,
|
|
1203
|
+
clear_meta_fields=True)
|
|
1204
|
+
try:
|
|
1205
|
+
cloned_db_tag_record.target_sqn = sqn_map[db_tag_record.target_sqn]
|
|
1206
|
+
except KeyError as e:
|
|
1207
|
+
raise ValueError(f"no cloned tag target for target_sqn '{db_tag_record.target_sqn}'") from e
|
|
1208
|
+
cloned_db_tag_records.append(cloned_db_tag_record)
|
|
1209
|
+
dst_session.add_all(cloned_db_tag_records)
|
|
1210
|
+
dst_session.commit()
|
|
1211
|
+
|
|
1212
|
+
|
|
1213
|
+
class TargetedTagCache(object):
|
|
1214
|
+
def __init__(self, cache: TagCache, tag_target: TagTargetTable):
|
|
1215
|
+
self.cache = cache
|
|
1216
|
+
self.tag_target = tag_target
|
|
1217
|
+
|
|
1218
|
+
def count_records(self) -> int:
|
|
1219
|
+
return self.cache.target_count_records(self.tag_target.sqn)
|
|
1220
|
+
|
|
1221
|
+
def iter_records(
|
|
1222
|
+
self,
|
|
1223
|
+
begin_dt: datetime.datetime | None = None,
|
|
1224
|
+
end_dt: datetime.datetime | None = None,
|
|
1225
|
+
tagset_namespace: str | None = None,
|
|
1226
|
+
tagset_version: str | None = None,
|
|
1227
|
+
tag_prefix: str | None = None,
|
|
1228
|
+
*,
|
|
1229
|
+
tagsets: Sequence[Tagset] | None = None,
|
|
1230
|
+
tagset_inverted: bool = False,
|
|
1231
|
+
skip: int | None = None,
|
|
1232
|
+
limit: int | None = None,
|
|
1233
|
+
batch_size: int = 1000,
|
|
1234
|
+
) -> Generator[TagRecordTable, None, None]:
|
|
1235
|
+
return self.cache.target_iter_records(
|
|
1236
|
+
target_sqn=self.tag_target.sqn,
|
|
1237
|
+
begin_dt=begin_dt,
|
|
1238
|
+
end_dt=end_dt,
|
|
1239
|
+
tagset_namespace=tagset_namespace,
|
|
1240
|
+
tagset_version=tagset_version,
|
|
1241
|
+
tag_prefix=tag_prefix,
|
|
1242
|
+
tagsets=tagsets,
|
|
1243
|
+
tagset_inverted=tagset_inverted,
|
|
1244
|
+
skip=skip,
|
|
1245
|
+
limit=limit,
|
|
1246
|
+
batch_size=batch_size,
|
|
1247
|
+
)
|
|
1248
|
+
|
|
1249
|
+
def add_ranged_record(
|
|
1250
|
+
self,
|
|
1251
|
+
begin_dt: datetime.datetime | None,
|
|
1252
|
+
end_dt: datetime.datetime | None,
|
|
1253
|
+
tag: str | Tag | BoundTag,
|
|
1254
|
+
props: JsonType | None = None,
|
|
1255
|
+
tagset_namespace: str | None = None,
|
|
1256
|
+
tagset_version: str | None = None,
|
|
1257
|
+
) -> 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
|
+
result = self.cache.target_add_record(
|
|
1275
|
+
target_sqn=self.tag_target.sqn,
|
|
1276
|
+
begin_dt=begin_dt or self.tag_target.begin_dt,
|
|
1277
|
+
end_dt=end_dt or self.tag_target.end_dt,
|
|
1278
|
+
tag=tag,
|
|
1279
|
+
props=props,
|
|
1280
|
+
tagset_namespace=tagset_namespace,
|
|
1281
|
+
tagset_version=tagset_version,
|
|
1282
|
+
)
|
|
1283
|
+
return result.retarget(self)
|
|
1284
|
+
|
|
1285
|
+
def add_record(
|
|
1286
|
+
self,
|
|
1287
|
+
tag: str | Tag | BoundTag,
|
|
1288
|
+
props: JsonType | None = None,
|
|
1289
|
+
tagset_namespace: str | None = None,
|
|
1290
|
+
tagset_version: str | None = None,
|
|
1291
|
+
) -> 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
|
+
result = self.add_ranged_record(
|
|
1307
|
+
begin_dt=self.tag_target.begin_dt,
|
|
1308
|
+
end_dt=self.tag_target.end_dt,
|
|
1309
|
+
tag=tag,
|
|
1310
|
+
tagset_namespace=tagset_namespace,
|
|
1311
|
+
tagset_version=tagset_version,
|
|
1312
|
+
props=props,
|
|
1313
|
+
)
|
|
1314
|
+
return result.retarget(self)
|
|
1315
|
+
|
|
1316
|
+
def update_record(
|
|
1317
|
+
self,
|
|
1318
|
+
sqn: int,
|
|
1319
|
+
*,
|
|
1320
|
+
begin_dt: datetime.datetime | None = None,
|
|
1321
|
+
end_dt: datetime.datetime | None = None,
|
|
1322
|
+
tag: str | Tag | BoundTag | None = None,
|
|
1323
|
+
props: JsonType | None = None,
|
|
1324
|
+
tagset_namespace: str | None = None,
|
|
1325
|
+
tagset_version: str | None = None,
|
|
1326
|
+
flags: int | None = None,
|
|
1327
|
+
) -> 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
|
+
result = self.cache.target_update_record(
|
|
1347
|
+
self.tag_target.sqn,
|
|
1348
|
+
sqn,
|
|
1349
|
+
begin_dt=begin_dt,
|
|
1350
|
+
end_dt=end_dt,
|
|
1351
|
+
tag=tag,
|
|
1352
|
+
props=props,
|
|
1353
|
+
tagset_namespace=tagset_namespace,
|
|
1354
|
+
tagset_version=tagset_version,
|
|
1355
|
+
flags=flags,
|
|
1356
|
+
)
|
|
1357
|
+
return result.retarget(self)
|
|
1358
|
+
|
|
1359
|
+
def remove_records(
|
|
1360
|
+
self,
|
|
1361
|
+
begin_dt: datetime.datetime | None = None,
|
|
1362
|
+
end_dt: datetime.datetime | None = None,
|
|
1363
|
+
tagset_namespace: str | None = None,
|
|
1364
|
+
tagset_version: str | None = None,
|
|
1365
|
+
tag_prefix: str | None = None,
|
|
1366
|
+
*,
|
|
1367
|
+
tagsets: Sequence[Tagset] | None = None,
|
|
1368
|
+
tagset_inverted: bool = False,
|
|
1369
|
+
) -> 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
|
+
self.cache.target_remove_records(
|
|
1384
|
+
self.tag_target.sqn,
|
|
1385
|
+
begin_dt=begin_dt,
|
|
1386
|
+
end_dt=end_dt,
|
|
1387
|
+
tagset_namespace=tagset_namespace,
|
|
1388
|
+
tagset_version=tagset_version,
|
|
1389
|
+
tag_prefix=tag_prefix,
|
|
1390
|
+
tagsets=tagsets,
|
|
1391
|
+
tagset_inverted=tagset_inverted,
|
|
1392
|
+
)
|
|
1393
|
+
return self
|
|
1251
1394
|
|
|
1252
1395
|
|
|
1253
1396
|
@memorized
|
|
@@ -131,7 +131,7 @@ class TagUtilsTest(unittest.TestCase):
|
|
|
131
131
|
for i in range(tag_records_count):
|
|
132
132
|
tag_name = tag_names[i % len(tag_names)]
|
|
133
133
|
tag = tagset.get_bound(tag_name) or tag_name
|
|
134
|
-
target_cache.
|
|
134
|
+
target_cache.add_ranged_record(
|
|
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,
|
|
@@ -150,92 +150,93 @@ class TagUtilsTest(unittest.TestCase):
|
|
|
150
150
|
},
|
|
151
151
|
)
|
|
152
152
|
|
|
153
|
-
self.assertEqual(target_cache.
|
|
154
|
-
self.assertEqual(len(list(target_cache.
|
|
155
|
-
self.assertEqual(len(list(target_cache.
|
|
153
|
+
self.assertEqual(target_cache.count_records(), tag_records_count)
|
|
154
|
+
self.assertEqual(len(list(target_cache.iter_records())), tag_records_count)
|
|
155
|
+
self.assertEqual(len(list(target_cache.iter_records(tagsets=[tagset]))),
|
|
156
156
|
tag_records_count * tagset_tags_count // tags_count)
|
|
157
|
-
self.assertEqual(len(list(target_cache.
|
|
157
|
+
self.assertEqual(len(list(target_cache.iter_records(tagsets=[tagset], tagset_inverted=True))),
|
|
158
158
|
tag_records_count * (tags_count - tagset_tags_count) // tags_count)
|
|
159
|
-
self.assertEqual(len(list(target_cache.
|
|
159
|
+
self.assertEqual(len(list(target_cache.iter_records(tagsets=[tagset], tagset_inverted=False))),
|
|
160
160
|
tag_records_count * tagset_tags_count // tags_count)
|
|
161
|
-
self.assertEqual(len(list(target_cache.
|
|
162
|
-
|
|
161
|
+
self.assertEqual(len(list(target_cache.iter_records(dt_parse_iso("2020-01-01T00:00:00+00:00"),
|
|
162
|
+
dt_parse_iso("2020-01-01T00:01:00+00:00")))),
|
|
163
163
|
60 + 1)
|
|
164
|
-
self.assertEqual(len(list(target_cache.
|
|
165
|
-
|
|
166
|
-
|
|
164
|
+
self.assertEqual(len(list(target_cache.iter_records(dt_parse_iso("2020-01-01T00:00:00+00:00"),
|
|
165
|
+
dt_parse_iso("2020-01-01T00:01:00+00:00"),
|
|
166
|
+
tag_prefix="dummy:foo"))),
|
|
167
167
|
60 // tags_count + 1)
|
|
168
|
-
self.assertEqual(len(list(target_cache.
|
|
169
|
-
|
|
170
|
-
|
|
168
|
+
self.assertEqual(len(list(target_cache.iter_records(dt_parse_iso("2020-01-01T00:00:00+00:00"),
|
|
169
|
+
dt_parse_iso("2020-01-01T00:01:00+00:00"),
|
|
170
|
+
tag_prefix="dummy:bar"))),
|
|
171
171
|
60 // tags_count)
|
|
172
|
-
self.assertEqual(len(list(target_cache.
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
self.assertEqual(len(list(target_cache.iter_records(dt_parse_iso("2020-01-01T00:00:00+00:00"),
|
|
173
|
+
dt_parse_iso("2020-01-01T00:01:00+00:00"),
|
|
174
|
+
tag_prefix="dummy"))),
|
|
175
175
|
60 + 1)
|
|
176
|
-
self.assertEqual(len(list(target_cache.
|
|
176
|
+
self.assertEqual(len(list(target_cache.iter_records(tag_prefix="dummy:foo"))),
|
|
177
177
|
tag_records_count // tags_count)
|
|
178
|
-
self.assertEqual(len(list(target_cache.
|
|
178
|
+
self.assertEqual(len(list(target_cache.iter_records(tag_prefix="dummy:bar"))),
|
|
179
179
|
tag_records_count // tags_count)
|
|
180
|
-
self.assertEqual(len(list(target_cache.
|
|
180
|
+
self.assertEqual(len(list(target_cache.iter_records(tag_prefix="dummy"))), tag_records_count)
|
|
181
181
|
|
|
182
|
-
self.assertEqual(len(list(cache.
|
|
183
|
-
self.assertEqual(len(list(cache.
|
|
184
|
-
self.assertEqual(len(list(cache.
|
|
182
|
+
self.assertEqual(len(list(cache.iter_records())), tag_records_count)
|
|
183
|
+
self.assertEqual(len(list(cache.iter_records(tagsets=[tagset]))), tag_records_count // 2)
|
|
184
|
+
self.assertEqual(len(list(cache.iter_records(tagsets=[tagset], tagset_inverted=True))),
|
|
185
185
|
tag_records_count * (tags_count - tagset_tags_count) // tags_count)
|
|
186
|
-
self.assertEqual(len(list(cache.
|
|
186
|
+
self.assertEqual(len(list(cache.iter_records(tagsets=[tagset], tagset_inverted=False))),
|
|
187
187
|
tag_records_count * tagset_tags_count // tags_count)
|
|
188
|
-
self.assertEqual(len(list(cache.
|
|
189
|
-
|
|
188
|
+
self.assertEqual(len(list(cache.iter_records(dt_parse_iso("2020-01-01T00:00:00+00:00"),
|
|
189
|
+
dt_parse_iso("2020-01-01T00:01:00+00:00")))),
|
|
190
190
|
60 + 1)
|
|
191
|
-
self.assertEqual(len(list(cache.
|
|
192
|
-
|
|
193
|
-
|
|
191
|
+
self.assertEqual(len(list(cache.iter_records(dt_parse_iso("2020-01-01T00:00:00+00:00"),
|
|
192
|
+
dt_parse_iso("2020-01-01T00:01:00+00:00"),
|
|
193
|
+
tag_prefix="dummy:foo"))),
|
|
194
194
|
60 // tags_count + 1)
|
|
195
|
-
self.assertEqual(len(list(cache.
|
|
196
|
-
|
|
197
|
-
|
|
195
|
+
self.assertEqual(len(list(cache.iter_records(dt_parse_iso("2020-01-01T00:00:00+00:00"),
|
|
196
|
+
dt_parse_iso("2020-01-01T00:01:00+00:00"),
|
|
197
|
+
tag_prefix="dummy:bar"))),
|
|
198
198
|
60 // tags_count)
|
|
199
|
-
self.assertEqual(len(list(cache.
|
|
200
|
-
|
|
201
|
-
|
|
199
|
+
self.assertEqual(len(list(cache.iter_records(dt_parse_iso("2020-01-01T00:00:00+00:00"),
|
|
200
|
+
dt_parse_iso("2020-01-01T00:01:00+00:00"),
|
|
201
|
+
tag_prefix="dummy"))),
|
|
202
202
|
60 + 1)
|
|
203
|
-
self.assertEqual(len(list(cache.
|
|
204
|
-
self.assertEqual(len(list(cache.
|
|
205
|
-
self.assertEqual(len(list(cache.
|
|
203
|
+
self.assertEqual(len(list(cache.iter_records(tag_prefix="dummy:foo"))), tag_records_count // tags_count)
|
|
204
|
+
self.assertEqual(len(list(cache.iter_records(tag_prefix="dummy:bar"))), tag_records_count // tags_count)
|
|
205
|
+
self.assertEqual(len(list(cache.iter_records(tag_prefix="dummy"))), tag_records_count)
|
|
206
206
|
|
|
207
|
-
target_cache.
|
|
207
|
+
target_cache.remove_records(dt_parse_iso("2020-01-01T00:00:00+00:00"),
|
|
208
|
+
dt_parse_iso("2020-01-01T00:01:00+00:00"))
|
|
208
209
|
|
|
209
|
-
self.assertEqual(target_cache.
|
|
210
|
-
self.assertEqual(len(list(target_cache.
|
|
211
|
-
self.assertEqual(cache.
|
|
212
|
-
self.assertEqual(len(list(cache.
|
|
210
|
+
self.assertEqual(target_cache.count_records(), tag_records_count - (60 + 1))
|
|
211
|
+
self.assertEqual(len(list(target_cache.iter_records())), tag_records_count - (60 + 1))
|
|
212
|
+
self.assertEqual(cache.count_records(), tag_records_count - (60 + 1))
|
|
213
|
+
self.assertEqual(len(list(cache.iter_records())), tag_records_count - (60 + 1))
|
|
213
214
|
|
|
214
|
-
target_cache.
|
|
215
|
+
target_cache.remove_records(tagsets=[tagset], tagset_inverted=True)
|
|
215
216
|
|
|
216
217
|
self.assertEqual(
|
|
217
|
-
target_cache.
|
|
218
|
+
target_cache.count_records(),
|
|
218
219
|
tag_records_count * tagset_tags_count // tags_count - (60 * tagset_tags_count // tags_count + 1),
|
|
219
220
|
)
|
|
220
221
|
self.assertEqual(
|
|
221
|
-
len(list(target_cache.
|
|
222
|
+
len(list(target_cache.iter_records())),
|
|
222
223
|
tag_records_count * tagset_tags_count // tags_count - (60 * tagset_tags_count // tags_count + 1),
|
|
223
224
|
)
|
|
224
225
|
self.assertEqual(
|
|
225
|
-
cache.
|
|
226
|
+
cache.count_records(),
|
|
226
227
|
tag_records_count * tagset_tags_count // tags_count - (60 * tagset_tags_count // tags_count + 1),
|
|
227
228
|
)
|
|
228
229
|
self.assertEqual(
|
|
229
|
-
len(list(cache.
|
|
230
|
+
len(list(cache.iter_records())),
|
|
230
231
|
tag_records_count * tagset_tags_count // tags_count - (60 * tagset_tags_count // tags_count + 1),
|
|
231
232
|
)
|
|
232
233
|
|
|
233
|
-
target_cache.
|
|
234
|
+
target_cache.remove_records()
|
|
234
235
|
|
|
235
|
-
self.assertEqual(target_cache.
|
|
236
|
-
self.assertEqual(len(list(target_cache.
|
|
237
|
-
self.assertEqual(cache.
|
|
238
|
-
self.assertEqual(len(list(cache.
|
|
236
|
+
self.assertEqual(target_cache.count_records(), 0)
|
|
237
|
+
self.assertEqual(len(list(target_cache.iter_records())), 0)
|
|
238
|
+
self.assertEqual(cache.count_records(), 0)
|
|
239
|
+
self.assertEqual(len(list(cache.iter_records())), 0)
|
|
239
240
|
|
|
240
241
|
def test_tag_cache__multithread(self):
|
|
241
242
|
tag_names = [
|
|
@@ -296,7 +297,7 @@ class TagUtilsTest(unittest.TestCase):
|
|
|
296
297
|
for i in range(tasks_count_per_thread):
|
|
297
298
|
tag_name = tag_names[i % len(tag_names)]
|
|
298
299
|
tag = old_tagset.get_bound(tag_name) or new_tagset.get_bound(tag_name) or tag_name
|
|
299
|
-
target_cache.
|
|
300
|
+
target_cache.add_ranged_record(
|
|
300
301
|
dt_parse_iso("2020-01-01T00:00:00+00:00") + datetime.timedelta(seconds=i),
|
|
301
302
|
dt_parse_iso("2020-01-02T00:00:00+00:00") + datetime.timedelta(seconds=i + 1),
|
|
302
303
|
tag,
|
|
@@ -322,23 +323,27 @@ class TagUtilsTest(unittest.TestCase):
|
|
|
322
323
|
thread.join()
|
|
323
324
|
|
|
324
325
|
for target_cache in target_caches:
|
|
325
|
-
self.assertEqual(target_cache.
|
|
326
|
-
self.assertEqual(len(list(target_cache.
|
|
327
|
-
self.assertEqual(len(list(target_cache.
|
|
326
|
+
self.assertEqual(target_cache.count_records(), tasks_count_per_target_cache)
|
|
327
|
+
self.assertEqual(len(list(target_cache.iter_records())), tasks_count_per_target_cache)
|
|
328
|
+
self.assertEqual(len(list(target_cache.iter_records(tag_prefix="dummy:bar"))),
|
|
328
329
|
tasks_count_per_target_cache // tags_count)
|
|
329
|
-
self.assertEqual(len(list(target_cache.
|
|
330
|
+
self.assertEqual(len(list(target_cache.iter_records(tagset_namespace="tagset"))),
|
|
330
331
|
tasks_count_per_target_cache * tagset_tags_count // tags_count)
|
|
331
|
-
self.assertEqual(
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
self.assertEqual(
|
|
332
|
+
self.assertEqual(
|
|
333
|
+
len(list(target_cache.iter_records(tagset_namespace="tagset", tagset_version="1.0.0"))),
|
|
334
|
+
tasks_count_per_target_cache * old_tagset_tags_count // tags_count,
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
self.assertEqual(cache.count_records(), total_tasks_count)
|
|
338
|
+
self.assertEqual(len(list(cache.iter_record_and_targets())), total_tasks_count)
|
|
339
|
+
self.assertEqual(len(list(cache.iter_record_and_targets(tag_prefix="dummy:bar"))),
|
|
337
340
|
total_tasks_count // tags_count)
|
|
338
|
-
self.assertEqual(len(list(cache.
|
|
341
|
+
self.assertEqual(len(list(cache.iter_record_and_targets(tagset_namespace="tagset"))),
|
|
339
342
|
total_tasks_count * tagset_tags_count // tags_count)
|
|
340
|
-
self.assertEqual(
|
|
341
|
-
|
|
343
|
+
self.assertEqual(
|
|
344
|
+
len(list(cache.iter_record_and_targets(tagset_namespace="tagset", tagset_version="1.0.0"))),
|
|
345
|
+
total_tasks_count * old_tagset_tags_count // tags_count,
|
|
346
|
+
)
|
|
342
347
|
|
|
343
348
|
def test_tag_cache__clone(self):
|
|
344
349
|
tag_names = [
|
|
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.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/0-dummy
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/resources/unittest/pathutils/1-dummy
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/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.70 → plexus_python_common-1.0.72}/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.70 → plexus_python_common-1.0.72}/src/plexus/common/carto/OSMFile.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/carto/OSMNode.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/carto/OSMTags.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/carto/OSMWay.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/carto/__init__.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/resources/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/__init__.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/apiutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/bagutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/config.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/datautils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/dockerutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/gisutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/jsonutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/ormutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/pathutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/s3utils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/sqlutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/src/plexus/common/utils/strutils.py
RENAMED
|
File without changes
|
{plexus_python_common-1.0.70 → plexus_python_common-1.0.72}/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.70 → plexus_python_common-1.0.72}/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
|