plexus-python-common 1.0.57__tar.gz → 1.0.58__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 (94) hide show
  1. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/PKG-INFO +1 -1
  2. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/utils/tagutils.py +6 -5
  3. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus_python_common.egg-info/PKG-INFO +1 -1
  4. plexus_python_common-1.0.58/test/plexus_tests/common/utils/jsonutils_test.py +37 -0
  5. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/utils/tagutils_test.py +164 -92
  6. plexus_python_common-1.0.57/test/plexus_tests/common/utils/jsonutils_test.py +0 -15
  7. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/.editorconfig +0 -0
  8. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/.github/workflows/pr.yml +0 -0
  9. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/.github/workflows/push.yml +0 -0
  10. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/.gitignore +0 -0
  11. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/MANIFEST.in +0 -0
  12. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/README.md +0 -0
  13. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/VERSION +0 -0
  14. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/pyproject.toml +0 -0
  15. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/jsonutils/dummy.0.jsonl +0 -0
  16. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/jsonutils/dummy.1.jsonl +0 -0
  17. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/jsonutils/dummy.2.jsonl +0 -0
  18. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/0-dummy +0 -0
  19. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/1-dummy +0 -0
  20. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/2-dummy +0 -0
  21. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/dummy.0.0.jsonl +0 -0
  22. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/dummy.0.0.vol-0.jsonl +0 -0
  23. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/dummy.0.jsonl +0 -0
  24. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/dummy.1.1.jsonl +0 -0
  25. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/dummy.1.1.vol-1.jsonl +0 -0
  26. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/dummy.1.jsonl +0 -0
  27. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/dummy.2.2.jsonl +0 -0
  28. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/dummy.2.2.vol-2.jsonl +0 -0
  29. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/dummy.2.jsonl +0 -0
  30. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/dummy.csv.part0 +0 -0
  31. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/dummy.csv.part1 +0 -0
  32. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/dummy.csv.part2 +0 -0
  33. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/pathutils/dummy.txt +0 -0
  34. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/s3utils/dir.baz/file.bar.baz +0 -0
  35. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/s3utils/dir.baz/file.foo.bar +0 -0
  36. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/s3utils/dir.baz/file.foo.baz +0 -0
  37. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/s3utils/dir.foo/dir.foo.bar/dir.foo.bar.baz/file.foo.bar.baz +0 -0
  38. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.bar.baz +0 -0
  39. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.bar +0 -0
  40. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.baz +0 -0
  41. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/s3utils/dir.foo/file.bar +0 -0
  42. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/s3utils/dir.foo/file.baz +0 -0
  43. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/s3utils/dir.foo/file.foo +0 -0
  44. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/s3utils_archive/archive.compressed.zip +0 -0
  45. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/resources/unittest/s3utils_archive/archive.uncompressed.zip +0 -0
  46. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/setup.cfg +0 -0
  47. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/setup.py +0 -0
  48. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/__init__.py +0 -0
  49. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/carto/OSMFile.py +0 -0
  50. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/carto/OSMNode.py +0 -0
  51. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/carto/OSMTags.py +0 -0
  52. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/carto/OSMWay.py +0 -0
  53. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/carto/__init__.py +0 -0
  54. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/pose.py +0 -0
  55. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/proj.py +0 -0
  56. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/resources/__init__.py +0 -0
  57. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/resources/tags/__init__.py +0 -0
  58. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/resources/tags/unittest-1.0.0.tagset.yaml +0 -0
  59. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/resources/tags/universal-1.0.0.tagset.yaml +0 -0
  60. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/utils/__init__.py +0 -0
  61. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/utils/apiutils.py +0 -0
  62. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/utils/bagutils.py +0 -0
  63. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/utils/config.py +0 -0
  64. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/utils/datautils.py +0 -0
  65. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/utils/dockerutils.py +0 -0
  66. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/utils/jsonutils.py +0 -0
  67. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/utils/ormutils.py +0 -0
  68. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/utils/pathutils.py +0 -0
  69. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/utils/s3utils.py +0 -0
  70. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/utils/sqlutils.py +0 -0
  71. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/utils/strutils.py +0 -0
  72. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus/common/utils/testutils.py +0 -0
  73. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus_python_common.egg-info/SOURCES.txt +0 -0
  74. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus_python_common.egg-info/dependency_links.txt +0 -0
  75. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus_python_common.egg-info/not-zip-safe +0 -0
  76. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus_python_common.egg-info/requires.txt +0 -0
  77. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/src/plexus_python_common.egg-info/top_level.txt +0 -0
  78. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/__init__.py +0 -0
  79. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/__init__.py +0 -0
  80. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/carto/__init__.py +0 -0
  81. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/carto/osm_file_test.py +0 -0
  82. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/carto/osm_tags_test.py +0 -0
  83. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/pose_test.py +0 -0
  84. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/proj_test.py +0 -0
  85. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/utils/__init__.py +0 -0
  86. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/utils/bagutils_test.py +0 -0
  87. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/utils/datautils_test.py +0 -0
  88. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/utils/dockerutils_test.py +0 -0
  89. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/utils/ormutils_test.py +0 -0
  90. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/utils/pathutils_test.py +0 -0
  91. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/utils/s3utils_test.py +0 -0
  92. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/utils/strutils_test.py +0 -0
  93. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/test/plexus_tests/common/utils/testutils_test.py +0 -0
  94. {plexus_python_common-1.0.57 → plexus_python_common-1.0.58}/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.57
3
+ Version: 1.0.58
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Programming Language :: Python :: 3.13
@@ -69,7 +69,8 @@ class Tag(object):
69
69
 
70
70
  @property
71
71
  def parent_tag_name(self) -> str | None:
72
- return head_or_none(self.name.rsplit(":", 1))
72
+ name = head_or_none(self.name.rsplit(":", 1))
73
+ return None if is_blank(name) or name == self.name else name
73
74
 
74
75
  def unbind(self) -> Self:
75
76
  return self
@@ -155,18 +156,18 @@ class Tagset(Sequence[Tag], Mapping[str, Tag]):
155
156
  def tag_names(self) -> list[str]:
156
157
  return list(self.tags_dict.keys())
157
158
 
158
- def child_tags(self, parent: str | Tag | BoundTag) -> list[BoundTag]:
159
+ def child_tags(self, parent: str | Tag | BoundTag) -> list[Tag]:
159
160
  parent = self.get(parent)
160
161
  if parent is None:
161
162
  return []
162
163
  subtree = dicttree_subtree(self.tags_tree, parent.tag_parts)
163
- return list(self.bind(tag) for tag in dicttree_children(subtree)) if subtree else []
164
+ return list(dicttree_children(subtree)) if subtree else []
164
165
 
165
- def parent_tags(self, child: str | Tag | BoundTag) -> list[BoundTag]:
166
+ def parent_tags(self, child: str | Tag | BoundTag) -> list[Tag]:
166
167
  child = self.get(child)
167
168
  if child is None:
168
169
  return []
169
- return list(self.bind(tag) for tag in dicttree_lineage(self.tags_tree, child.tag_parts[:-1]))
170
+ return list(dicttree_lineage(self.tags_tree, child.tag_parts[:-1]))
170
171
 
171
172
  def validate(self, tag_name: str, props: JsonType | None, *, raise_on_error: bool = False) -> bool:
172
173
  tag = self.get(tag_name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plexus-python-common
3
- Version: 1.0.57
3
+ Version: 1.0.58
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Programming Language :: Python :: 3.13
@@ -0,0 +1,37 @@
1
+ import os.path
2
+ import unittest
3
+
4
+ import ddt
5
+ from iker.common.utils.dtutils import dt_parse_iso
6
+
7
+ from plexus.common.utils.jsonutils import json_dumps, json_loads
8
+ from plexus.common.utils.jsonutils import read_chunked_jsonl
9
+ from testenv import resources_directory
10
+
11
+
12
+ @ddt.ddt
13
+ class JsonUtilsTest(unittest.TestCase):
14
+
15
+ def test_json_loads_dumps(self):
16
+ data = {
17
+ "int": 123,
18
+ "float": 123.456,
19
+ "string": "dummy_string",
20
+ "boolean": True,
21
+ "null": None,
22
+ "datetime": dt_parse_iso("2024-01-01T00:00:00.000000+00:00"),
23
+ "list": [123, 123.456, "dummy_string", True, None, dt_parse_iso("2024-01-01T00:00:00.000000+00:00")],
24
+ "dict": {
25
+ "int": 123,
26
+ "float": 123.456,
27
+ "string": "dummy_string",
28
+ "boolean": True,
29
+ "null": None,
30
+ "datetime": dt_parse_iso("2024-01-01T00:00:00.000000+00:00"),
31
+ },
32
+ }
33
+ self.assertEqual(data, json_loads(json_dumps(data)))
34
+
35
+ def test_read_chunked_jsonl(self):
36
+ for data, path in read_chunked_jsonl(str(resources_directory / "unittest" / "jsonutils" / "dummy.{{}}.jsonl")):
37
+ self.assertEqual(data["file"], os.path.basename(path))
@@ -6,6 +6,7 @@ import unittest
6
6
 
7
7
  import ddt
8
8
  from iker.common.utils.dtutils import dt_parse_iso
9
+ from iker.common.utils.iterutils import last
9
10
  from iker.common.utils.jsonutils import JsonObject
10
11
 
11
12
  from plexus.common.utils.tagutils import MutableTagset, Tag, TagCache, Tagset
@@ -25,8 +26,19 @@ class TagUtilsTest(unittest.TestCase):
25
26
  for tag in tagset:
26
27
  self.assertIn(tag, tagset)
27
28
  self.assertIn(tag.name, tagset)
28
- self.assertEqual(tag.name, tagset.get(tag).name)
29
- self.assertEqual(tag.name, tagset.get(tag.name).name)
29
+ self.assertEqual(tag, tagset.get(tag))
30
+ self.assertEqual(tag.name, tagset.get_bound(tag).name)
31
+ self.assertEqual(tag, tagset.get_bound(tag).unbind())
32
+
33
+ if tag.parent_tag_name is not None:
34
+ self.assertIn(tag.parent_tag_name, tagset)
35
+ self.assertEqual(tag.parent_tag_name, tagset.get(tag.parent_tag_name).name)
36
+ self.assertEqual(last(tagset.parent_tags(tag)), tagset.get(tag.parent_tag_name))
37
+
38
+ for child_tag in tagset.child_tags(tag):
39
+ self.assertIn(child_tag, tagset)
40
+ self.assertIn(child_tag.name, tagset)
41
+ self.assertIn(tag, tagset.parent_tags(child_tag))
30
42
 
31
43
  markdown = render_tagset_markdown_readme(tagset)
32
44
  self.assertIsInstance(markdown, str)
@@ -84,17 +96,20 @@ class TagUtilsTest(unittest.TestCase):
84
96
  tagset.validate(tag, props, raise_on_error=True)
85
97
 
86
98
  def test_tag_cache(self):
87
- tagset = MutableTagset(namespace="tagset", version="1.0.0", desc="A dummy tagset for testing")
88
- tagset.add(Tag(name="dummy:foo", desc="A dummy tag for testing"))
89
- tagset.add(Tag(name="dummy:bar", desc="Another dummy tag for testing"))
90
-
91
- tags = [
99
+ tag_names = [
92
100
  "dummy:foo",
93
101
  "dummy:bar",
94
102
  "dummy:baz",
95
103
  "dummy:qux",
96
104
  ]
97
105
 
106
+ tagset = MutableTagset(namespace="tagset", version="1.0.0", desc="A dummy tagset for testing")
107
+ tagset.add(Tag(name="dummy:foo", desc="A dummy tag for testing"))
108
+ tagset.add(Tag(name="dummy:bar", desc="Another dummy tag for testing"))
109
+
110
+ tags_count = len(tag_names)
111
+ tagset_tags_count = sum(1 for tag_name in tag_names if tag_name in tagset)
112
+
98
113
  cache = TagCache()
99
114
 
100
115
  self.assertEqual(cache.file_path, tag_cache_file_path())
@@ -109,72 +124,85 @@ class TagUtilsTest(unittest.TestCase):
109
124
 
110
125
  target_cache = cache.with_target("awesome_tagger/20200101_000000/dummy_vehicle/0")
111
126
 
112
- tags_count = 1000
127
+ tag_records_count = 1000
113
128
 
114
- for i in range(tags_count):
129
+ for i in range(tag_records_count):
130
+ tag_name = tag_names[i % len(tag_names)]
131
+ tag = tagset.get_bound(tag_name) or tag_name
115
132
  target_cache.add_ranged_tag(
116
133
  dt_parse_iso("2020-01-01T00:00:00+00:00") + datetime.timedelta(seconds=i),
117
134
  dt_parse_iso("2020-01-02T00:00:00+00:00") + datetime.timedelta(seconds=i + 1),
118
- tags[i % len(tags)],
135
+ tag,
119
136
  )
120
137
 
121
- self.assertEqual(len(list(target_cache.iter_tags())), tags_count)
122
- self.assertEqual(len(list(target_cache.iter_tags(tagsets=[tagset]))), tags_count // 2)
123
- self.assertEqual(len(list(target_cache.iter_tags(tagsets=[tagset], tagset_inverted=True))), tags_count // 2)
124
- self.assertEqual(len(list(target_cache.iter_tags(tagsets=[tagset], tagset_inverted=False))), tags_count // 2)
138
+ self.assertEqual(len(list(target_cache.iter_tags())), tag_records_count)
139
+ self.assertEqual(len(list(target_cache.iter_tags(tagsets=[tagset]))),
140
+ tag_records_count * tagset_tags_count // tags_count)
141
+ self.assertEqual(len(list(target_cache.iter_tags(tagsets=[tagset], tagset_inverted=True))),
142
+ tag_records_count * (tags_count - tagset_tags_count) // tags_count)
143
+ self.assertEqual(len(list(target_cache.iter_tags(tagsets=[tagset], tagset_inverted=False))),
144
+ tag_records_count * tagset_tags_count // tags_count)
125
145
  self.assertEqual(len(list(target_cache.iter_tags(dt_parse_iso("2020-01-01T00:00:00+00:00"),
126
146
  dt_parse_iso("2020-01-01T00:01:00+00:00")))),
127
147
  60 + 1)
128
148
  self.assertEqual(len(list(target_cache.iter_tags(dt_parse_iso("2020-01-01T00:00:00+00:00"),
129
149
  dt_parse_iso("2020-01-01T00:01:00+00:00"),
130
150
  tag_prefix="dummy:foo"))),
131
- 60 // len(tags) + 1)
151
+ 60 // tags_count + 1)
132
152
  self.assertEqual(len(list(target_cache.iter_tags(dt_parse_iso("2020-01-01T00:00:00+00:00"),
133
153
  dt_parse_iso("2020-01-01T00:01:00+00:00"),
134
154
  tag_prefix="dummy:bar"))),
135
- 60 // len(tags))
155
+ 60 // tags_count)
136
156
  self.assertEqual(len(list(target_cache.iter_tags(dt_parse_iso("2020-01-01T00:00:00+00:00"),
137
157
  dt_parse_iso("2020-01-01T00:01:00+00:00"),
138
158
  tag_prefix="dummy"))),
139
159
  60 + 1)
140
160
  self.assertEqual(len(list(target_cache.iter_tags(tag_prefix="dummy:foo"))),
141
- tags_count // len(tags))
161
+ tag_records_count // tags_count)
142
162
  self.assertEqual(len(list(target_cache.iter_tags(tag_prefix="dummy:bar"))),
143
- tags_count // len(tags))
144
- self.assertEqual(len(list(target_cache.iter_tags(tag_prefix="dummy"))), tags_count)
145
-
146
- self.assertEqual(len(list(cache.iter_tags())), tags_count)
147
- self.assertEqual(len(list(cache.iter_tags(tagsets=[tagset]))), tags_count // 2)
148
- self.assertEqual(len(list(cache.iter_tags(tagsets=[tagset], tagset_inverted=True))), tags_count // 2)
149
- self.assertEqual(len(list(cache.iter_tags(tagsets=[tagset], tagset_inverted=False))), tags_count // 2)
163
+ tag_records_count // tags_count)
164
+ self.assertEqual(len(list(target_cache.iter_tags(tag_prefix="dummy"))), tag_records_count)
165
+
166
+ self.assertEqual(len(list(cache.iter_tags())), tag_records_count)
167
+ self.assertEqual(len(list(cache.iter_tags(tagsets=[tagset]))), tag_records_count // 2)
168
+ self.assertEqual(len(list(cache.iter_tags(tagsets=[tagset], tagset_inverted=True))),
169
+ tag_records_count * (tags_count - tagset_tags_count) // tags_count)
170
+ self.assertEqual(len(list(cache.iter_tags(tagsets=[tagset], tagset_inverted=False))),
171
+ tag_records_count * tagset_tags_count // tags_count)
150
172
  self.assertEqual(len(list(cache.iter_tags(dt_parse_iso("2020-01-01T00:00:00+00:00"),
151
173
  dt_parse_iso("2020-01-01T00:01:00+00:00")))),
152
174
  60 + 1)
153
175
  self.assertEqual(len(list(cache.iter_tags(dt_parse_iso("2020-01-01T00:00:00+00:00"),
154
176
  dt_parse_iso("2020-01-01T00:01:00+00:00"),
155
177
  tag_prefix="dummy:foo"))),
156
- 60 // len(tags) + 1)
178
+ 60 // tags_count + 1)
157
179
  self.assertEqual(len(list(cache.iter_tags(dt_parse_iso("2020-01-01T00:00:00+00:00"),
158
180
  dt_parse_iso("2020-01-01T00:01:00+00:00"),
159
181
  tag_prefix="dummy:bar"))),
160
- 60 // len(tags))
182
+ 60 // tags_count)
161
183
  self.assertEqual(len(list(cache.iter_tags(dt_parse_iso("2020-01-01T00:00:00+00:00"),
162
184
  dt_parse_iso("2020-01-01T00:01:00+00:00"),
163
185
  tag_prefix="dummy"))),
164
186
  60 + 1)
165
- self.assertEqual(len(list(cache.iter_tags(tag_prefix="dummy:foo"))), tags_count // len(tags))
166
- self.assertEqual(len(list(cache.iter_tags(tag_prefix="dummy:bar"))), tags_count // len(tags))
167
- self.assertEqual(len(list(cache.iter_tags(tag_prefix="dummy"))), tags_count)
187
+ self.assertEqual(len(list(cache.iter_tags(tag_prefix="dummy:foo"))), tag_records_count // tags_count)
188
+ self.assertEqual(len(list(cache.iter_tags(tag_prefix="dummy:bar"))), tag_records_count // tags_count)
189
+ self.assertEqual(len(list(cache.iter_tags(tag_prefix="dummy"))), tag_records_count)
168
190
 
169
191
  target_cache.remove_tags(dt_parse_iso("2020-01-01T00:00:00+00:00"), dt_parse_iso("2020-01-01T00:01:00+00:00"))
170
192
 
171
- self.assertEqual(len(list(target_cache.iter_tags())), tags_count - (60 + 1))
172
- self.assertEqual(len(list(cache.iter_tags())), tags_count - (60 + 1))
193
+ self.assertEqual(len(list(target_cache.iter_tags())), tag_records_count - (60 + 1))
194
+ self.assertEqual(len(list(cache.iter_tags())), tag_records_count - (60 + 1))
173
195
 
174
196
  target_cache.remove_tags(tagsets=[tagset], tagset_inverted=True)
175
197
 
176
- self.assertEqual(len(list(target_cache.iter_tags())), tags_count // 2 - (60 // 2 + 1))
177
- self.assertEqual(len(list(cache.iter_tags())), tags_count // 2 - (60 // 2 + 1))
198
+ self.assertEqual(
199
+ len(list(target_cache.iter_tags())),
200
+ tag_records_count * tagset_tags_count // tags_count - (60 * tagset_tags_count // tags_count + 1),
201
+ )
202
+ self.assertEqual(
203
+ len(list(cache.iter_tags())),
204
+ tag_records_count * tagset_tags_count // tags_count - (60 * tagset_tags_count // tags_count + 1),
205
+ )
178
206
 
179
207
  target_cache.remove_tags()
180
208
 
@@ -182,17 +210,27 @@ class TagUtilsTest(unittest.TestCase):
182
210
  self.assertEqual(len(list(cache.iter_tags())), 0)
183
211
 
184
212
  def test_tag_cache__multithread(self):
185
- tagset = MutableTagset(namespace="tagset", version="1.0.0", desc="A dummy tagset for testing")
186
- tagset.add(Tag(name="dummy:foo", desc="A dummy tag for testing"))
187
- tagset.add(Tag(name="dummy:bar", desc="Another dummy tag for testing"))
188
-
189
- tags = [
213
+ tag_names = [
190
214
  "dummy:foo",
191
215
  "dummy:bar",
192
216
  "dummy:baz",
193
217
  "dummy:qux",
194
218
  ]
195
219
 
220
+ old_tagset = MutableTagset(namespace="tagset", version="1.0.0", desc="A dummy tagset for testing")
221
+ old_tagset.add(Tag(name="dummy:foo", desc="A dummy tag for testing"))
222
+ old_tagset.add(Tag(name="dummy:bar", desc="Another dummy tag for testing"))
223
+
224
+ new_tagset = MutableTagset(namespace="tagset", version="1.1.0", desc="Updated dummy tagset for testing")
225
+ new_tagset.add(Tag(name="dummy:foo", desc="A dummy tag for testing"))
226
+ new_tagset.add(Tag(name="dummy:bar", desc="Another dummy tag for testing"))
227
+ new_tagset.add(Tag(name="dummy:baz", desc="Updated dummy tag for testing"))
228
+ new_tagset.remove("dummy:bar")
229
+
230
+ tags_count = len(tag_names)
231
+ tagset_tags_count = sum(1 for tag_name in tag_names if tag_name in old_tagset or tag_name in new_tagset)
232
+ old_tagset_tags_count = sum(1 for tag_name in tag_names if tag_name in old_tagset)
233
+
196
234
  with tempfile.TemporaryDirectory() as temp_directory:
197
235
  temp_directory = pathlib.Path(temp_directory)
198
236
 
@@ -223,14 +261,16 @@ class TagUtilsTest(unittest.TestCase):
223
261
  start_barrier = threading.Barrier(total_threads_count)
224
262
 
225
263
  def worker(tid):
226
- tag_cache = target_caches[tid % target_caches_count]
264
+ target_cache = target_caches[tid % target_caches_count]
227
265
 
228
266
  start_barrier.wait()
229
267
  for i in range(tasks_count_per_thread):
230
- tag_cache.add_ranged_tag(
268
+ tag_name = tag_names[i % len(tag_names)]
269
+ tag = old_tagset.get_bound(tag_name) or new_tagset.get_bound(tag_name) or tag_name
270
+ target_cache.add_ranged_tag(
231
271
  dt_parse_iso("2020-01-01T00:00:00+00:00") + datetime.timedelta(seconds=i),
232
272
  dt_parse_iso("2020-01-02T00:00:00+00:00") + datetime.timedelta(seconds=i + 1),
233
- tags[i % len(tags)],
273
+ tag,
234
274
  )
235
275
 
236
276
  threads = [threading.Thread(target=worker, args=(tid,)) for tid in range(total_threads_count)]
@@ -242,24 +282,35 @@ class TagUtilsTest(unittest.TestCase):
242
282
  for target_cache in target_caches:
243
283
  self.assertEqual(len(list(target_cache.iter_tags())), tasks_count_per_target_cache)
244
284
  self.assertEqual(len(list(target_cache.iter_tags(tag_prefix="dummy:bar"))),
245
- tasks_count_per_target_cache // len(tags))
285
+ tasks_count_per_target_cache // tags_count)
286
+ self.assertEqual(len(list(target_cache.iter_tags(tagset_namespace="tagset"))),
287
+ tasks_count_per_target_cache * tagset_tags_count // tags_count)
288
+ self.assertEqual(len(list(target_cache.iter_tags(tagset_namespace="tagset", tagset_version="1.0.0"))),
289
+ tasks_count_per_target_cache * old_tagset_tags_count // tags_count)
246
290
 
247
291
  self.assertEqual(len(list(cache.iter_tag_and_targets())), total_tasks_count)
248
292
  self.assertEqual(len(list(cache.iter_tag_and_targets(tag_prefix="dummy:bar"))),
249
- total_tasks_count // len(tags))
293
+ total_tasks_count // tags_count)
294
+ self.assertEqual(len(list(cache.iter_tag_and_targets(tagset_namespace="tagset"))),
295
+ total_tasks_count * tagset_tags_count // tags_count)
296
+ self.assertEqual(len(list(cache.iter_tag_and_targets(tagset_namespace="tagset", tagset_version="1.0.0"))),
297
+ total_tasks_count * old_tagset_tags_count // tags_count)
250
298
 
251
299
  def test_tag_cache__clone(self):
252
- tagset = MutableTagset(namespace="tagset", version="1.0.0", desc="A dummy tagset for testing")
253
- tagset.add(Tag(name="dummy:foo", desc="A dummy tag for testing"))
254
- tagset.add(Tag(name="dummy:bar", desc="Another dummy tag for testing"))
255
-
256
- tags = [
300
+ tag_names = [
257
301
  "dummy:foo",
258
302
  "dummy:bar",
259
303
  "dummy:baz",
260
304
  "dummy:qux",
261
305
  ]
262
306
 
307
+ tagset = MutableTagset(namespace="tagset", version="1.0.0", desc="A dummy tagset for testing")
308
+ tagset.add(Tag(name="dummy:foo", desc="A dummy tag for testing"))
309
+ tagset.add(Tag(name="dummy:bar", desc="Another dummy tag for testing"))
310
+
311
+ tags_count = len(tag_names)
312
+ tagset_tags_count = sum(1 for tag_name in tag_names if tag_name in tagset)
313
+
263
314
  with tempfile.TemporaryDirectory() as temp_directory:
264
315
  temp_directory = pathlib.Path(temp_directory)
265
316
 
@@ -274,46 +325,55 @@ class TagUtilsTest(unittest.TestCase):
274
325
 
275
326
  src_target_cache = src_cache.with_target("awesome_tagger/20200101_000000/dummy_vehicle/0")
276
327
 
277
- tags_count = 1000
328
+ tag_records_count = 1000
278
329
 
279
- for i in range(tags_count):
280
- src_target_cache.add_tag(tags[i % len(tags)])
330
+ for i in range(tag_records_count):
331
+ tag_name = tag_names[i % len(tag_names)]
332
+ tag = tagset.get_bound(tag_name) or tag_name
333
+ src_target_cache.add_tag(tag)
281
334
 
282
335
  dst_cache = TagCache(file_path=temp_directory / "dst_tag_cache.db")
283
336
 
284
337
  TagCache.copy_to(src_cache, dst_cache)
285
338
 
286
- for i in range(tags_count):
287
- src_target_cache.add_tag(tags[i % len(tags)])
339
+ for i in range(tag_records_count):
340
+ tag_name = tag_names[i % len(tag_names)]
341
+ tag = tagset.get_bound(tag_name) or tag_name
342
+ src_target_cache.add_tag(tag)
288
343
 
289
344
  dst_target_cache = dst_cache.with_target("awesome_tagger/20200101_000000/dummy_vehicle/0")
290
345
 
291
- self.assertEqual(len(list(src_target_cache.iter_tags())), tags_count * 2)
292
- self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset]))), tags_count * 2 // 2)
346
+ self.assertEqual(len(list(src_target_cache.iter_tags())), tag_records_count * 2)
347
+ self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset]))),
348
+ tag_records_count * 2 * tagset_tags_count // tags_count)
293
349
  self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=True))),
294
- tags_count * 2 // 2)
350
+ tag_records_count * 2 * (tags_count - tagset_tags_count) // tags_count)
295
351
  self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=False))),
296
- tags_count * 2 // 2)
352
+ tag_records_count * 2 * tagset_tags_count // tags_count)
297
353
 
298
- self.assertEqual(len(list(dst_target_cache.iter_tags())), tags_count)
299
- self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset]))), tags_count // 2)
354
+ self.assertEqual(len(list(dst_target_cache.iter_tags())), tag_records_count)
355
+ self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset]))),
356
+ tag_records_count * tagset_tags_count // tags_count)
300
357
  self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=True))),
301
- tags_count // 2)
358
+ tag_records_count * (tags_count - tagset_tags_count) // tags_count)
302
359
  self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=False))),
303
- tags_count // 2)
360
+ tag_records_count * tagset_tags_count // tags_count)
304
361
 
305
362
  def test_tag_cache__clone_same_file(self):
306
- tagset = MutableTagset(namespace="tagset", version="1.0.0", desc="A dummy tagset for testing")
307
- tagset.add(Tag(name="dummy:foo", desc="A dummy tag for testing"))
308
- tagset.add(Tag(name="dummy:bar", desc="Another dummy tag for testing"))
309
-
310
- tags = [
363
+ tag_names = [
311
364
  "dummy:foo",
312
365
  "dummy:bar",
313
366
  "dummy:baz",
314
367
  "dummy:qux",
315
368
  ]
316
369
 
370
+ tagset = MutableTagset(namespace="tagset", version="1.0.0", desc="A dummy tagset for testing")
371
+ tagset.add(Tag(name="dummy:foo", desc="A dummy tag for testing"))
372
+ tagset.add(Tag(name="dummy:bar", desc="Another dummy tag for testing"))
373
+
374
+ tags_count = len(tag_names)
375
+ tagset_tags_count = sum(1 for tag_name in tag_names if tag_name in tagset)
376
+
317
377
  # Clone to the same file path should not cause any issue, and the cloned cache should be able to read
318
378
  # the tags added to the source cache after cloning.
319
379
  with tempfile.TemporaryDirectory() as temp_directory:
@@ -330,33 +390,39 @@ class TagUtilsTest(unittest.TestCase):
330
390
 
331
391
  src_target_cache = src_cache.with_target("awesome_tagger/20200101_000000/dummy_vehicle/0")
332
392
 
333
- tags_count = 1000
393
+ tag_records_count = 1000
334
394
 
335
- for i in range(tags_count):
336
- src_target_cache.add_tag(tags[i % len(tags)])
395
+ for i in range(tag_records_count):
396
+ tag_name = tag_names[i % len(tag_names)]
397
+ tag = tagset.get_bound(tag_name) or tag_name
398
+ src_target_cache.add_tag(tag)
337
399
 
338
400
  dst_cache = TagCache(file_path=temp_directory / "tag_cache.db")
339
401
 
340
402
  TagCache.copy_to(src_cache, dst_cache)
341
403
 
342
- for i in range(tags_count):
343
- src_target_cache.add_tag(tags[i % len(tags)])
404
+ for i in range(tag_records_count):
405
+ tag_name = tag_names[i % len(tag_names)]
406
+ tag = tagset.get_bound(tag_name) or tag_name
407
+ src_target_cache.add_tag(tag)
344
408
 
345
409
  dst_target_cache = dst_cache.with_target("awesome_tagger/20200101_000000/dummy_vehicle/0")
346
410
 
347
- self.assertEqual(len(list(src_target_cache.iter_tags())), tags_count * 2)
348
- self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset]))), tags_count * 2 // 2)
411
+ self.assertEqual(len(list(src_target_cache.iter_tags())), tag_records_count * 2)
412
+ self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset]))),
413
+ tag_records_count * 2 * tagset_tags_count // tags_count)
349
414
  self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=True))),
350
- tags_count * 2 // 2)
415
+ tag_records_count * 2 * (tags_count - tagset_tags_count) // tags_count)
351
416
  self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=False))),
352
- tags_count * 2 // 2)
417
+ tag_records_count * 2 * tagset_tags_count // tags_count)
353
418
 
354
- self.assertEqual(len(list(dst_target_cache.iter_tags())), tags_count * 2)
355
- self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset]))), tags_count * 2 // 2)
419
+ self.assertEqual(len(list(dst_target_cache.iter_tags())), tag_records_count * 2)
420
+ self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset]))),
421
+ tag_records_count * 2 * tagset_tags_count // tags_count)
356
422
  self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=True))),
357
- tags_count * 2 // 2)
423
+ tag_records_count * 2 * (tags_count - tagset_tags_count) // tags_count)
358
424
  self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=False))),
359
- tags_count * 2 // 2)
425
+ tag_records_count * 2 * tagset_tags_count // tags_count)
360
426
 
361
427
  with tempfile.TemporaryDirectory() as temp_directory:
362
428
  temp_directory = pathlib.Path(temp_directory)
@@ -372,30 +438,36 @@ class TagUtilsTest(unittest.TestCase):
372
438
 
373
439
  src_target_cache = src_cache.with_target("awesome_tagger/20200101_000000/dummy_vehicle/0")
374
440
 
375
- tags_count = 1000
441
+ tag_records_count = 1000
376
442
 
377
- for i in range(tags_count):
378
- src_target_cache.add_tag(tags[i % len(tags)])
443
+ for i in range(tag_records_count):
444
+ tag_name = tag_names[i % len(tag_names)]
445
+ tag = tagset.get_bound(tag_name) or tag_name
446
+ src_target_cache.add_tag(tag)
379
447
 
380
448
  dst_cache = src_cache
381
449
 
382
450
  TagCache.copy_to(src_cache, dst_cache)
383
451
 
384
- for i in range(tags_count):
385
- src_target_cache.add_tag(tags[i % len(tags)])
452
+ for i in range(tag_records_count):
453
+ tag_name = tag_names[i % len(tag_names)]
454
+ tag = tagset.get_bound(tag_name) or tag_name
455
+ src_target_cache.add_tag(tag)
386
456
 
387
457
  dst_target_cache = dst_cache.with_target("awesome_tagger/20200101_000000/dummy_vehicle/0")
388
458
 
389
- self.assertEqual(len(list(src_target_cache.iter_tags())), tags_count * 2)
390
- self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset]))), tags_count * 2 // 2)
459
+ self.assertEqual(len(list(src_target_cache.iter_tags())), tag_records_count * 2)
460
+ self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset]))),
461
+ tag_records_count * 2 * tagset_tags_count // tags_count)
391
462
  self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=True))),
392
- tags_count * 2 // 2)
463
+ tag_records_count * 2 * (tags_count - tagset_tags_count) // tags_count)
393
464
  self.assertEqual(len(list(src_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=False))),
394
- tags_count * 2 // 2)
465
+ tag_records_count * 2 * tagset_tags_count // tags_count)
395
466
 
396
- self.assertEqual(len(list(dst_target_cache.iter_tags())), tags_count * 2)
397
- self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset]))), tags_count * 2 // 2)
467
+ self.assertEqual(len(list(dst_target_cache.iter_tags())), tag_records_count * 2)
468
+ self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset]))),
469
+ tag_records_count * 2 * tagset_tags_count // tags_count)
398
470
  self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=True))),
399
- tags_count * 2 // 2)
471
+ tag_records_count * 2 * (tags_count - tagset_tags_count) // tags_count)
400
472
  self.assertEqual(len(list(dst_target_cache.iter_tags(tagsets=[tagset], tagset_inverted=False))),
401
- tags_count * 2 // 2)
473
+ tag_records_count * 2 * tagset_tags_count // tags_count)
@@ -1,15 +0,0 @@
1
- import os.path
2
- import unittest
3
-
4
- import ddt
5
-
6
- from plexus.common.utils.jsonutils import read_chunked_jsonl
7
- from testenv import resources_directory
8
-
9
-
10
- @ddt.ddt
11
- class JsonUtilsTest(unittest.TestCase):
12
-
13
- def test_read_chunked_jsonl(self):
14
- for data, path in read_chunked_jsonl(str(resources_directory / "unittest" / "jsonutils" / "dummy.{{}}.jsonl")):
15
- self.assertEqual(data["file"], os.path.basename(path))