plexus-python-common 1.0.53__tar.gz → 1.0.54__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 (92) hide show
  1. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/PKG-INFO +1 -1
  2. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/utils/datautils.py +3 -1
  3. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/utils/tagutils.py +36 -24
  4. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus_python_common.egg-info/PKG-INFO +1 -1
  5. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/utils/tagutils_test.py +152 -0
  6. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/.editorconfig +0 -0
  7. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/.github/workflows/pr.yml +0 -0
  8. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/.github/workflows/push.yml +0 -0
  9. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/.gitignore +0 -0
  10. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/MANIFEST.in +0 -0
  11. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/README.md +0 -0
  12. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/VERSION +0 -0
  13. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/pyproject.toml +0 -0
  14. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/jsonutils/dummy.0.jsonl +0 -0
  15. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/jsonutils/dummy.1.jsonl +0 -0
  16. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/jsonutils/dummy.2.jsonl +0 -0
  17. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/0-dummy +0 -0
  18. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/1-dummy +0 -0
  19. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/2-dummy +0 -0
  20. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/dummy.0.0.jsonl +0 -0
  21. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/dummy.0.0.vol-0.jsonl +0 -0
  22. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/dummy.0.jsonl +0 -0
  23. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/dummy.1.1.jsonl +0 -0
  24. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/dummy.1.1.vol-1.jsonl +0 -0
  25. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/dummy.1.jsonl +0 -0
  26. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/dummy.2.2.jsonl +0 -0
  27. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/dummy.2.2.vol-2.jsonl +0 -0
  28. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/dummy.2.jsonl +0 -0
  29. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/dummy.csv.part0 +0 -0
  30. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/dummy.csv.part1 +0 -0
  31. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/dummy.csv.part2 +0 -0
  32. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/pathutils/dummy.txt +0 -0
  33. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/s3utils/dir.baz/file.bar.baz +0 -0
  34. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/s3utils/dir.baz/file.foo.bar +0 -0
  35. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/s3utils/dir.baz/file.foo.baz +0 -0
  36. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/s3utils/dir.foo/dir.foo.bar/dir.foo.bar.baz/file.foo.bar.baz +0 -0
  37. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.bar.baz +0 -0
  38. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.bar +0 -0
  39. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.baz +0 -0
  40. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/s3utils/dir.foo/file.bar +0 -0
  41. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/s3utils/dir.foo/file.baz +0 -0
  42. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/s3utils/dir.foo/file.foo +0 -0
  43. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/s3utils_archive/archive.compressed.zip +0 -0
  44. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/resources/unittest/s3utils_archive/archive.uncompressed.zip +0 -0
  45. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/setup.cfg +0 -0
  46. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/setup.py +0 -0
  47. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/__init__.py +0 -0
  48. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/carto/OSMFile.py +0 -0
  49. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/carto/OSMNode.py +0 -0
  50. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/carto/OSMTags.py +0 -0
  51. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/carto/OSMWay.py +0 -0
  52. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/carto/__init__.py +0 -0
  53. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/pose.py +0 -0
  54. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/proj.py +0 -0
  55. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/resources/__init__.py +0 -0
  56. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/resources/tags/__init__.py +0 -0
  57. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/resources/tags/universal.tagset.yaml +0 -0
  58. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/utils/__init__.py +0 -0
  59. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/utils/apiutils.py +0 -0
  60. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/utils/bagutils.py +0 -0
  61. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/utils/config.py +0 -0
  62. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/utils/dockerutils.py +0 -0
  63. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/utils/jsonutils.py +0 -0
  64. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/utils/ormutils.py +0 -0
  65. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/utils/pathutils.py +0 -0
  66. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/utils/s3utils.py +0 -0
  67. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/utils/sqlutils.py +0 -0
  68. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/utils/strutils.py +0 -0
  69. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus/common/utils/testutils.py +0 -0
  70. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus_python_common.egg-info/SOURCES.txt +0 -0
  71. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus_python_common.egg-info/dependency_links.txt +0 -0
  72. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus_python_common.egg-info/not-zip-safe +0 -0
  73. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus_python_common.egg-info/requires.txt +0 -0
  74. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/src/plexus_python_common.egg-info/top_level.txt +0 -0
  75. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/__init__.py +0 -0
  76. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/__init__.py +0 -0
  77. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/carto/__init__.py +0 -0
  78. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/carto/osm_file_test.py +0 -0
  79. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/carto/osm_tags_test.py +0 -0
  80. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/pose_test.py +0 -0
  81. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/proj_test.py +0 -0
  82. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/utils/__init__.py +0 -0
  83. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/utils/bagutils_test.py +0 -0
  84. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/utils/datautils_test.py +0 -0
  85. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/utils/dockerutils_test.py +0 -0
  86. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/utils/jsonutils_test.py +0 -0
  87. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/utils/ormutils_test.py +0 -0
  88. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/utils/pathutils_test.py +0 -0
  89. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/utils/s3utils_test.py +0 -0
  90. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/utils/strutils_test.py +0 -0
  91. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/test/plexus_tests/common/utils/testutils_test.py +0 -0
  92. {plexus_python_common-1.0.53 → plexus_python_common-1.0.54}/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.53
3
+ Version: 1.0.54
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Programming Language :: Python :: 3.13
@@ -118,7 +118,9 @@ validate_vehicle_name = make_validate_parse_string(parse_vehicle_name)
118
118
  validate_bag_name = make_validate_parse_string(parse_bag_name)
119
119
 
120
120
 
121
- def validate_dt_timezone(dt: datetime.datetime):
121
+ def validate_dt_timezone(dt: datetime.datetime, *, allow_naive: bool = False):
122
+ if allow_naive and dt.tzinfo is None:
123
+ return
122
124
  if dt.tzinfo != datetime.timezone.utc:
123
125
  raise ValueError(f"dt '{dt}' is not in UTC")
124
126
 
@@ -348,13 +348,13 @@ class TagTargetInfo(BaseModel):
348
348
  @pdt.field_validator("begin_dt", mode="after")
349
349
  @classmethod
350
350
  def validate_begin_dt(cls, v: datetime.datetime) -> datetime.datetime:
351
- validate_dt_timezone(v)
351
+ validate_dt_timezone(v, allow_naive=True)
352
352
  return v
353
353
 
354
354
  @pdt.field_validator("end_dt", mode="after")
355
355
  @classmethod
356
356
  def validate_end_dt(cls, v: datetime.datetime) -> datetime.datetime:
357
- validate_dt_timezone(v)
357
+ validate_dt_timezone(v, allow_naive=True)
358
358
  return v
359
359
 
360
360
  @pdt.model_validator(mode="after")
@@ -390,13 +390,13 @@ class TagRecord(BaseModel):
390
390
  @pdt.field_validator("begin_dt", mode="after")
391
391
  @classmethod
392
392
  def validate_begin_dt(cls, v: datetime.datetime) -> datetime.datetime:
393
- validate_dt_timezone(v)
393
+ validate_dt_timezone(v, allow_naive=True)
394
394
  return v
395
395
 
396
396
  @pdt.field_validator("end_dt", mode="after")
397
397
  @classmethod
398
398
  def validate_end_dt(cls, v: datetime.datetime) -> datetime.datetime:
399
- validate_dt_timezone(v)
399
+ validate_dt_timezone(v, allow_naive=True)
400
400
  return v
401
401
 
402
402
  @pdt.model_validator(mode="after")
@@ -480,7 +480,7 @@ class TagCache(object):
480
480
  vehicle_name: str | None = None,
481
481
  begin_dt: datetime.datetime | None = None,
482
482
  end_dt: datetime.datetime | None = None,
483
- ) -> Generator[TagTargetInfoTable, None, None]:
483
+ ) -> list[TagTargetInfoTable]:
484
484
  with self.make_session() as session:
485
485
  query = session.query(TagTargetInfoTable)
486
486
  if name:
@@ -496,7 +496,7 @@ class TagCache(object):
496
496
  if end_dt:
497
497
  query = query.filter(TagTargetInfoTable.begin_dt <= end_dt)
498
498
 
499
- yield from query.all()
499
+ return query.all()
500
500
 
501
501
  def add_target(
502
502
  self,
@@ -724,35 +724,47 @@ class TagCache(object):
724
724
  target_tag_cache = TagCache(file_path=target_file_path)
725
725
  if overwrite:
726
726
  target_tag_cache.clear()
727
- TagCache.clone_to(self, target_tag_cache)
727
+ TagCache.copy_to(self, target_tag_cache)
728
728
 
729
729
  def merge_from(self, source_file_path: str, *, overwrite: bool = False):
730
730
  source_tag_cache = TagCache(file_path=source_file_path)
731
731
  if overwrite:
732
732
  self.clear()
733
- TagCache.clone_to(source_tag_cache, self)
733
+ TagCache.copy_to(source_tag_cache, self)
734
734
 
735
735
  @staticmethod
736
- def clone_to(source: "TagCache", target: "TagCache"):
737
- if source == target:
736
+ def copy_to(src: "TagCache", dst: "TagCache"):
737
+ # If src and dst are the same instance or point to the same file path,
738
+ # do nothing to avoid accidentally clearing the cache
739
+ if src == dst or src.file_path == dst.file_path:
738
740
  return
739
741
 
740
- target.clear()
741
- with source.make_session() as source_session, target.make_session() as target_session:
742
- target_session.add_all(
743
- [clone_sequence_model_instance(TagTargetInfoTable, db_tag_target_info, clear_meta_fields=True)
744
- for db_tag_target_info in source_session.query(TagTargetInfoTable).all()],
745
- )
746
- for results in batched(source_session.query(TagRecordTable).yield_per(1000), 1000):
747
- target_session.add_all(
748
- [clone_sequence_model_instance(TagRecordTable, db_tag_record, clear_meta_fields=True)
749
- for db_tag_record in results],
750
- )
751
- target_session.commit()
742
+ with src.make_session() as src_session, dst.make_session() as dst_session:
743
+ src_targets = src_session.query(TagTargetInfoTable).all()
744
+ dst_targets = [
745
+ clone_sequence_model_instance(TagTargetInfoTable, db_tag_target_info, clear_meta_fields=True)
746
+ for db_tag_target_info in src_targets
747
+ ]
748
+ dst_session.add_all(dst_targets)
749
+ dst_session.flush() # ensure new sqn values are assigned
750
+
751
+ sqn_map = {src_target.sqn: dst_target.sqn for src_target, dst_target in zip(src_targets, dst_targets)}
752
+
753
+ for results in batched(src_session.query(TagRecordTable).yield_per(1000), 1000):
754
+ clones = []
755
+ for db_tag_record in results:
756
+ cloned = clone_sequence_model_instance(TagRecordTable, db_tag_record, clear_meta_fields=True)
757
+ try:
758
+ cloned.target_sqn = sqn_map[db_tag_record.target_sqn]
759
+ except KeyError as e:
760
+ raise ValueError(f"no cloned target for target_sqn '{db_tag_record.target_sqn}'") from e
761
+ clones.append(cloned)
762
+ dst_session.add_all(clones)
763
+ dst_session.commit()
752
764
 
753
765
 
754
766
  class TargetedTagCache(object):
755
- def __init__(self, cache: "TagCache", target_info: TagTargetInfoTable):
767
+ def __init__(self, cache: TagCache, target_info: TagTargetInfoTable):
756
768
  self.target_info = target_info
757
769
  self.cache = cache
758
770
 
@@ -844,7 +856,7 @@ class TargetedTagCache(object):
844
856
  :param props: Additional properties of the tag record in JSON format (optional)
845
857
  :return: Self instance for chaining
846
858
  """
847
- return self.add_ranged(
859
+ return self.add_ranged_tag(
848
860
  begin_dt=self.target_info.begin_dt,
849
861
  end_dt=self.target_info.end_dt,
850
862
  tag=tag,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plexus-python-common
3
- Version: 1.0.53
3
+ Version: 1.0.54
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Programming Language :: Python :: 3.13
@@ -196,3 +196,155 @@ class TagUtilsTest(unittest.TestCase):
196
196
  self.assertEqual(len(list(cache.iter_tag_and_targets())), total_tasks_count)
197
197
  self.assertEqual(len(list(cache.iter_tag_and_targets(tag_pattern="dummy:bar"))),
198
198
  total_tasks_count // len(tags))
199
+
200
+ def test_tag_cache__clone(self):
201
+ tagset = MutableTagset(namespace="tagset", desc="A dummy tagset for testing")
202
+ tagset.add(Tag(name="dummy:foo", desc="A dummy tag for testing"))
203
+ tagset.add(Tag(name="dummy:bar", desc="Another dummy tag for testing"))
204
+
205
+ tags = [
206
+ "dummy:foo",
207
+ "dummy:bar",
208
+ "dummy:baz",
209
+ "dummy:qux",
210
+ ]
211
+
212
+ with tempfile.TemporaryDirectory() as temp_directory:
213
+ temp_directory = pathlib.Path(temp_directory)
214
+
215
+ src_cache = TagCache(file_path=temp_directory / "src_tag_cache.db")
216
+
217
+ src_cache.add_target("awesome_tagger/20200101_000000/dummy_vehicle/0",
218
+ "awesome_tagger",
219
+ "1.0.0",
220
+ "dummy_vehicle",
221
+ dt_parse_iso("2020-01-01T00:00:00+00:00"),
222
+ dt_parse_iso("2020-01-01T01:00:00+00:00"))
223
+
224
+ src_target_cache = src_cache.with_target("awesome_tagger/20200101_000000/dummy_vehicle/0")
225
+
226
+ tags_count = 1000
227
+
228
+ for i in range(tags_count):
229
+ src_target_cache.add_tag(tags[i % len(tags)])
230
+
231
+ dst_cache = TagCache(file_path=temp_directory / "dst_tag_cache.db")
232
+
233
+ TagCache.copy_to(src_cache, dst_cache)
234
+
235
+ for i in range(tags_count):
236
+ src_target_cache.add_tag(tags[i % len(tags)])
237
+
238
+ dst_target_cache = dst_cache.with_target("awesome_tagger/20200101_000000/dummy_vehicle/0")
239
+
240
+ self.assertEqual(len(list(src_target_cache.iter_tags())), tags_count * 2)
241
+ self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset]))), tags_count * 2 // 2)
242
+ self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=True))),
243
+ tags_count * 2 // 2)
244
+ self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=False))),
245
+ tags_count * 2 // 2)
246
+
247
+ self.assertEqual(len(list(dst_target_cache.iter_tags())), tags_count)
248
+ self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset]))), tags_count // 2)
249
+ self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=True))),
250
+ tags_count // 2)
251
+ self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=False))),
252
+ tags_count // 2)
253
+
254
+ def test_tag_cache__clone_same_file(self):
255
+ tagset = MutableTagset(namespace="tagset", desc="A dummy tagset for testing")
256
+ tagset.add(Tag(name="dummy:foo", desc="A dummy tag for testing"))
257
+ tagset.add(Tag(name="dummy:bar", desc="Another dummy tag for testing"))
258
+
259
+ tags = [
260
+ "dummy:foo",
261
+ "dummy:bar",
262
+ "dummy:baz",
263
+ "dummy:qux",
264
+ ]
265
+
266
+ # Clone to the same file path should not cause any issue, and the cloned cache should be able to read
267
+ # the tags added to the source cache after cloning.
268
+ with tempfile.TemporaryDirectory() as temp_directory:
269
+ temp_directory = pathlib.Path(temp_directory)
270
+
271
+ src_cache = TagCache(file_path=temp_directory / "tag_cache.db")
272
+
273
+ src_cache.add_target("awesome_tagger/20200101_000000/dummy_vehicle/0",
274
+ "awesome_tagger",
275
+ "1.0.0",
276
+ "dummy_vehicle",
277
+ dt_parse_iso("2020-01-01T00:00:00+00:00"),
278
+ dt_parse_iso("2020-01-01T01:00:00+00:00"))
279
+
280
+ src_target_cache = src_cache.with_target("awesome_tagger/20200101_000000/dummy_vehicle/0")
281
+
282
+ tags_count = 1000
283
+
284
+ for i in range(tags_count):
285
+ src_target_cache.add_tag(tags[i % len(tags)])
286
+
287
+ dst_cache = TagCache(file_path=temp_directory / "tag_cache.db")
288
+
289
+ TagCache.copy_to(src_cache, dst_cache)
290
+
291
+ for i in range(tags_count):
292
+ src_target_cache.add_tag(tags[i % len(tags)])
293
+
294
+ dst_target_cache = dst_cache.with_target("awesome_tagger/20200101_000000/dummy_vehicle/0")
295
+
296
+ self.assertEqual(len(list(src_target_cache.iter_tags())), tags_count * 2)
297
+ self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset]))), tags_count * 2 // 2)
298
+ self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=True))),
299
+ tags_count * 2 // 2)
300
+ self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=False))),
301
+ tags_count * 2 // 2)
302
+
303
+ self.assertEqual(len(list(dst_target_cache.iter_tags())), tags_count * 2)
304
+ self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset]))), tags_count * 2 // 2)
305
+ self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=True))),
306
+ tags_count * 2 // 2)
307
+ self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=False))),
308
+ tags_count * 2 // 2)
309
+
310
+ with tempfile.TemporaryDirectory() as temp_directory:
311
+ temp_directory = pathlib.Path(temp_directory)
312
+
313
+ src_cache = TagCache(file_path=temp_directory / "tag_cache.db")
314
+
315
+ src_cache.add_target("awesome_tagger/20200101_000000/dummy_vehicle/0",
316
+ "awesome_tagger",
317
+ "1.0.0",
318
+ "dummy_vehicle",
319
+ dt_parse_iso("2020-01-01T00:00:00+00:00"),
320
+ dt_parse_iso("2020-01-01T01:00:00+00:00"))
321
+
322
+ src_target_cache = src_cache.with_target("awesome_tagger/20200101_000000/dummy_vehicle/0")
323
+
324
+ tags_count = 1000
325
+
326
+ for i in range(tags_count):
327
+ src_target_cache.add_tag(tags[i % len(tags)])
328
+
329
+ dst_cache = src_cache
330
+
331
+ TagCache.copy_to(src_cache, dst_cache)
332
+
333
+ for i in range(tags_count):
334
+ src_target_cache.add_tag(tags[i % len(tags)])
335
+
336
+ dst_target_cache = dst_cache.with_target("awesome_tagger/20200101_000000/dummy_vehicle/0")
337
+
338
+ self.assertEqual(len(list(src_target_cache.iter_tags())), tags_count * 2)
339
+ self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset]))), tags_count * 2 // 2)
340
+ self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=True))),
341
+ tags_count * 2 // 2)
342
+ self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=False))),
343
+ tags_count * 2 // 2)
344
+
345
+ self.assertEqual(len(list(dst_target_cache.iter_tags())), tags_count * 2)
346
+ self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset]))), tags_count * 2 // 2)
347
+ self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=True))),
348
+ tags_count * 2 // 2)
349
+ self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=False))),
350
+ tags_count * 2 // 2)