plexus-python-common 1.0.48__tar.gz → 1.0.49__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 (93) hide show
  1. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/PKG-INFO +1 -1
  2. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/utils/tagutils.py +95 -27
  3. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus_python_common.egg-info/PKG-INFO +1 -1
  4. plexus_python_common-1.0.49/test/plexus_tests/common/utils/tagutils_test.py +104 -0
  5. plexus_python_common-1.0.48/test/plexus_tests/common/utils/tagutils_test.py +0 -94
  6. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/.editorconfig +0 -0
  7. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/.github/workflows/pr.yml +0 -0
  8. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/.github/workflows/push.yml +0 -0
  9. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/.gitignore +0 -0
  10. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/MANIFEST.in +0 -0
  11. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/README.md +0 -0
  12. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/VERSION +0 -0
  13. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/pyproject.toml +0 -0
  14. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/jsonutils/dummy.0.jsonl +0 -0
  15. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/jsonutils/dummy.1.jsonl +0 -0
  16. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/jsonutils/dummy.2.jsonl +0 -0
  17. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/0-dummy +0 -0
  18. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/1-dummy +0 -0
  19. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/2-dummy +0 -0
  20. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/dummy.0.0.jsonl +0 -0
  21. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/dummy.0.0.vol-0.jsonl +0 -0
  22. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/dummy.0.jsonl +0 -0
  23. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/dummy.1.1.jsonl +0 -0
  24. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/dummy.1.1.vol-1.jsonl +0 -0
  25. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/dummy.1.jsonl +0 -0
  26. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/dummy.2.2.jsonl +0 -0
  27. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/dummy.2.2.vol-2.jsonl +0 -0
  28. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/dummy.2.jsonl +0 -0
  29. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/dummy.csv.part0 +0 -0
  30. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/dummy.csv.part1 +0 -0
  31. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/dummy.csv.part2 +0 -0
  32. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/pathutils/dummy.txt +0 -0
  33. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/s3utils/dir.baz/file.bar.baz +0 -0
  34. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/s3utils/dir.baz/file.foo.bar +0 -0
  35. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/s3utils/dir.baz/file.foo.baz +0 -0
  36. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/s3utils/dir.foo/dir.foo.bar/dir.foo.bar.baz/file.foo.bar.baz +0 -0
  37. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.bar.baz +0 -0
  38. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.bar +0 -0
  39. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/s3utils/dir.foo/dir.foo.bar/file.foo.baz +0 -0
  40. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/s3utils/dir.foo/file.bar +0 -0
  41. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/s3utils/dir.foo/file.baz +0 -0
  42. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/s3utils/dir.foo/file.foo +0 -0
  43. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/s3utils_archive/archive.compressed.zip +0 -0
  44. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/resources/unittest/s3utils_archive/archive.uncompressed.zip +0 -0
  45. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/setup.cfg +0 -0
  46. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/setup.py +0 -0
  47. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/__init__.py +0 -0
  48. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/carto/OSMFile.py +0 -0
  49. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/carto/OSMNode.py +0 -0
  50. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/carto/OSMTags.py +0 -0
  51. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/carto/OSMWay.py +0 -0
  52. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/carto/__init__.py +0 -0
  53. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/pose.py +0 -0
  54. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/proj.py +0 -0
  55. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/resources/__init__.py +0 -0
  56. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/resources/tags/__init__.py +0 -0
  57. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/resources/tags/universal.tagset.yaml +0 -0
  58. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/utils/__init__.py +0 -0
  59. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/utils/apiutils.py +0 -0
  60. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/utils/bagutils.py +0 -0
  61. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/utils/config.py +0 -0
  62. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/utils/datautils.py +0 -0
  63. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/utils/dockerutils.py +0 -0
  64. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/utils/jsonutils.py +0 -0
  65. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/utils/ormutils.py +0 -0
  66. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/utils/pathutils.py +0 -0
  67. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/utils/s3utils.py +0 -0
  68. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/utils/sqlutils.py +0 -0
  69. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/utils/strutils.py +0 -0
  70. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus/common/utils/testutils.py +0 -0
  71. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus_python_common.egg-info/SOURCES.txt +0 -0
  72. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus_python_common.egg-info/dependency_links.txt +0 -0
  73. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus_python_common.egg-info/not-zip-safe +0 -0
  74. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus_python_common.egg-info/requires.txt +0 -0
  75. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/src/plexus_python_common.egg-info/top_level.txt +0 -0
  76. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/__init__.py +0 -0
  77. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/__init__.py +0 -0
  78. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/carto/__init__.py +0 -0
  79. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/carto/osm_file_test.py +0 -0
  80. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/carto/osm_tags_test.py +0 -0
  81. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/pose_test.py +0 -0
  82. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/proj_test.py +0 -0
  83. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/utils/__init__.py +0 -0
  84. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/utils/bagutils_test.py +0 -0
  85. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/utils/datautils_test.py +0 -0
  86. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/utils/dockerutils_test.py +0 -0
  87. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/utils/jsonutils_test.py +0 -0
  88. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/utils/ormutils_test.py +0 -0
  89. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/utils/pathutils_test.py +0 -0
  90. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/utils/s3utils_test.py +0 -0
  91. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/utils/strutils_test.py +0 -0
  92. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/test/plexus_tests/common/utils/testutils_test.py +0 -0
  93. {plexus_python_common-1.0.48 → plexus_python_common-1.0.49}/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.48
3
+ Version: 1.0.49
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Programming Language :: Python :: 3.13
@@ -36,6 +36,7 @@ __all__ = [
36
36
  "RichDesc",
37
37
  "Tag",
38
38
  "Tagset",
39
+ "MutableTagset",
39
40
  "populate_tagset",
40
41
  "predefined_tagsets",
41
42
  "render_tagset_markdown_readme",
@@ -132,8 +133,13 @@ class Tag(object):
132
133
  def parent_tag_name(self) -> str | None:
133
134
  return head_or_none(self.name.rsplit(":", 1))
134
135
 
135
- def populate(self, vehicle_name: str, begin_dt: datetime.datetime, end_dt: datetime.datetime,
136
- props: JsonType) -> TagRecord:
136
+ def populate(
137
+ self,
138
+ vehicle_name: str,
139
+ begin_dt: datetime.datetime,
140
+ end_dt: datetime.datetime,
141
+ props: JsonType,
142
+ ) -> TagRecord:
137
143
  return TagRecord(
138
144
  vehicle_name=vehicle_name,
139
145
  begin_dt=begin_dt,
@@ -175,11 +181,49 @@ class Tagset(Sequence[Tag], Mapping[str, Tag]):
175
181
  tag_name = item.name if isinstance(item, Tag) else item
176
182
  return self.tags_dict.get(tag_name)
177
183
 
184
+ def clone(self) -> Self:
185
+ return clone_tagset(self)
186
+
187
+ def mutable(self):
188
+ return clone_mutable_tagset(self)
189
+
190
+ def frozen(self):
191
+ return self.clone()
192
+
178
193
  @property
179
194
  def tag_names(self) -> list[str]:
180
195
  return list(self.tags_dict.keys())
181
196
 
182
- def add(self, tag: Tag) -> None:
197
+ def child_tags(self, parent: str | Tag) -> list[Tag]:
198
+ if parent is None:
199
+ return []
200
+ if isinstance(parent, str):
201
+ return self.child_tags(self.get(parent))
202
+
203
+ subtree = dicttree_subtree(self.tags_tree, parent.tag_parts)
204
+ return list(dicttree_children(subtree)) if subtree else []
205
+
206
+ def parent_tags(self, child: str | Tag) -> list[Tag]:
207
+ if child is None:
208
+ return []
209
+ if isinstance(child, str):
210
+ return self.parent_tags(self.get(child))
211
+
212
+ return list(dicttree_lineage(self.tags_tree, child.tag_parts[:-1]))
213
+
214
+
215
+ class MutableTagset(Tagset):
216
+
217
+ def clone(self) -> Self:
218
+ return clone_mutable_tagset(self)
219
+
220
+ def mutable(self):
221
+ return self.clone()
222
+
223
+ def frozen(self):
224
+ return clone_tagset(self)
225
+
226
+ def add(self, tag: Tag) -> Self:
183
227
  if tag.name in self.tags_dict:
184
228
  raise ValueError(f"duplicate tag name '{tag.name}'")
185
229
 
@@ -188,7 +232,9 @@ class Tagset(Sequence[Tag], Mapping[str, Tag]):
188
232
 
189
233
  dicttree_add(self.tags_tree, tag.tag_parts, tag, create_prefix=True)
190
234
 
191
- def remove(self, tag_name: str) -> None:
235
+ return self
236
+
237
+ def remove(self, tag_name: str) -> Self:
192
238
  tag = self.get(tag_name)
193
239
  if tag is None:
194
240
  raise ValueError(f"tag '{tag_name}' not found")
@@ -198,22 +244,23 @@ class Tagset(Sequence[Tag], Mapping[str, Tag]):
198
244
 
199
245
  dicttree_remove(self.tags_tree, tag.tag_parts, recursive=True)
200
246
 
201
- def child_tags(self, parent: str | Tag) -> list[Tag]:
202
- if parent is None:
203
- return []
204
- if isinstance(parent, str):
205
- return self.child_tags(self.get(parent))
247
+ return self
206
248
 
207
- subtree = dicttree_subtree(self.tags_tree, parent.tag_parts)
208
- return list(dicttree_children(subtree)) if subtree else []
209
249
 
210
- def parent_tags(self, child: str | Tag) -> list[Tag]:
211
- if child is None:
212
- return []
213
- if isinstance(child, str):
214
- return self.parent_tags(self.get(child))
250
+ def clone_tagset(tagset: Tagset) -> Tagset:
251
+ tagset = clone_mutable_tagset(tagset)
252
+ new_tagset = Tagset(namespace=tagset.namespace, desc=tagset.desc)
253
+ new_tagset.tags = tagset.tags
254
+ new_tagset.tags_dict = tagset.tags_dict
255
+ new_tagset.tags_tree = tagset.tags_tree
256
+ return new_tagset
215
257
 
216
- return list(dicttree_lineage(self.tags_tree, child.tag_parts[:-1]))
258
+
259
+ def clone_mutable_tagset(tagset: Tagset) -> MutableTagset:
260
+ new_tagset = MutableTagset(namespace=tagset.namespace, desc=tagset.desc)
261
+ for tag in tagset.tags:
262
+ new_tagset.add(tag)
263
+ return new_tagset
217
264
 
218
265
 
219
266
  def populate_tagset(tagset_spec: JsonObject) -> Tagset:
@@ -268,12 +315,12 @@ def populate_tagset(tagset_spec: JsonObject) -> Tagset:
268
315
  if tags is None:
269
316
  raise ValueError("missing '$tags' in tagset spec")
270
317
 
271
- tagset = Tagset(namespace=namespace, desc=desc)
318
+ tagset = MutableTagset(namespace=namespace, desc=desc)
272
319
 
273
320
  for tag in validate_and_collect("", tags):
274
321
  tagset.add(tag)
275
322
 
276
- return tagset
323
+ return tagset.frozen()
277
324
 
278
325
 
279
326
  @singleton
@@ -330,25 +377,34 @@ def tag_cache_file_path() -> pathlib.Path:
330
377
 
331
378
 
332
379
  class TagCache(object):
333
- def __init__(self, *, file_path: str | os.PathLike[str] | None = None, fail_if_exists: bool = False):
380
+ def __init__(
381
+ self,
382
+ *,
383
+ file_path: str | os.PathLike[str] | None = None,
384
+ fail_if_exists: bool = False,
385
+ ):
334
386
  self.file_path = pathlib.Path(file_path or tag_cache_file_path())
335
387
  if fail_if_exists and self.file_path.exists():
336
388
  raise FileExistsError(f"tag cache file '{str(self.file_path)}' already exists")
337
389
  self.file_path.parent.mkdir(parents=True, exist_ok=True)
390
+
338
391
  self.conn_maker = ConnectionMaker.from_url(f"sqlite:///{str(self.file_path.absolute())}",
339
392
  engine_opts=dict(connect_args={"check_same_thread": False}))
340
393
  BaseModel.metadata.create_all(self.conn_maker.engine)
341
394
 
342
395
  def query(
343
396
  self,
344
- vehicle_name: str,
397
+ vehicle_name: str | None = None,
345
398
  begin_time: datetime.datetime | None = None,
346
399
  end_time: datetime.datetime | None = None,
347
400
  tag_pattern: str | None = None,
348
- ) -> list[TagRecordTable]:
401
+ *,
402
+ tagsets: Sequence[Tagset] | None = None,
403
+ ) -> Generator[TagRecordTable]:
349
404
  with self.conn_maker.make_session() as session:
350
- query = session.query(TagRecordTable).where(TagRecordTable.vehicle_name == vehicle_name)
351
-
405
+ query = session.query(TagRecordTable)
406
+ if vehicle_name:
407
+ query = query.filter(TagRecordTable.vehicle_name == vehicle_name)
352
408
  if begin_time:
353
409
  query = query.filter(TagRecordTable.end_dt >= begin_time)
354
410
  if end_time:
@@ -356,7 +412,15 @@ class TagCache(object):
356
412
  if tag_pattern:
357
413
  query = query.filter(TagRecordTable.tag.like(f"{escape_sql_like(tag_pattern)}%", escape="\\"))
358
414
 
359
- return query.all()
415
+ if not tagsets:
416
+ yield from query.all()
417
+ else:
418
+ yield from (db_tag_record for db_tag_record in query.all()
419
+ if any(db_tag_record.tag in tagset for tagset in tagsets))
420
+
421
+ def undefined(self, tagsets: Sequence[Tagset]) -> Generator[TagRecordTable, None, None]:
422
+ yield from (db_tag_record for db_tag_record in self.query()
423
+ if all(db_tag_record.tag not in tagset for tagset in tagsets))
360
424
 
361
425
  def add(
362
426
  self,
@@ -365,7 +429,7 @@ class TagCache(object):
365
429
  end_time: datetime.datetime,
366
430
  tag: str | Tag,
367
431
  props: JsonType | None = None,
368
- ):
432
+ ) -> Self:
369
433
  with self.conn_maker.make_session() as session:
370
434
  tag_record = TagRecord(
371
435
  vehicle_name=vehicle_name,
@@ -377,7 +441,9 @@ class TagCache(object):
377
441
  session.add(clone_sequence_model_instance(TagRecordTable, tag_record))
378
442
  session.commit()
379
443
 
380
- def remove(self, vehicle_name: str, begin_time: datetime.datetime, end_time: datetime.datetime):
444
+ return self
445
+
446
+ def remove(self, vehicle_name: str, begin_time: datetime.datetime, end_time: datetime.datetime) -> Self:
381
447
  with self.conn_maker.make_session() as session:
382
448
  session.execute(
383
449
  sa
@@ -390,6 +456,8 @@ class TagCache(object):
390
456
  )
391
457
  session.commit()
392
458
 
459
+ return self
460
+
393
461
  def clear(self):
394
462
  with self.conn_maker.make_session() as session:
395
463
  session.execute(sa.delete(TagRecordTable))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plexus-python-common
3
- Version: 1.0.48
3
+ Version: 1.0.49
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,104 @@
1
+ import datetime
2
+ import unittest
3
+
4
+ import ddt
5
+ from iker.common.utils.dtutils import dt_parse_iso
6
+
7
+ from plexus.common.utils.tagutils import MutableTagset, Tag, TagCache, Tagset
8
+ from plexus.common.utils.tagutils import predefined_tagsets, render_tagset_markdown_readme
9
+ from plexus.common.utils.tagutils import tag_cache_file_path
10
+
11
+
12
+ @ddt.ddt
13
+ class TagUtilsTest(unittest.TestCase):
14
+
15
+ def test_predefined_tagsets(self):
16
+ tagsets = predefined_tagsets()
17
+ for _, tagset in tagsets.items():
18
+ self.assertIsInstance(tagset, Tagset)
19
+ self.assertNotIsInstance(tagset, MutableTagset)
20
+
21
+ for tag in tagset:
22
+ self.assertIn(tag, tagset)
23
+ self.assertIn(tag.name, tagset)
24
+ self.assertEqual(tag, tagset.get(tag))
25
+ self.assertEqual(tag, tagset.get(tag.name))
26
+
27
+ markdown = render_tagset_markdown_readme(tagset)
28
+ self.assertIsInstance(markdown, str)
29
+
30
+ print(markdown)
31
+
32
+ def test_tag_cache(self):
33
+ tag_cache = TagCache()
34
+
35
+ self.assertEqual(tag_cache.file_path, tag_cache_file_path())
36
+ self.assertTrue(tag_cache.file_path.exists())
37
+
38
+ self.assertEqual(len(list(tag_cache.query("dummy_vehicle"))), 0)
39
+
40
+ tagset = MutableTagset(namespace="tagset", desc="A dummy tagset for testing")
41
+
42
+ tagset.add(Tag(name="dummy:foo", desc="A dummy tag for testing"))
43
+ tagset.add(Tag(name="dummy:bar", desc="A dummy tag for testing"))
44
+
45
+ tags = [
46
+ "dummy:foo",
47
+ "dummy:bar",
48
+ "dummy:baz",
49
+ "dummy:qux",
50
+ ]
51
+ for i in range(1000):
52
+ tag_cache.add(
53
+ "dummy_vehicle",
54
+ dt_parse_iso("2020-01-01T00:00:00.000000+00:00") + datetime.timedelta(seconds=i),
55
+ dt_parse_iso("2021-01-01T00:00:00.000000+00:00") + datetime.timedelta(seconds=i + 1),
56
+ tags[i % len(tags)],
57
+ )
58
+
59
+ self.assertEqual(len(list(tag_cache.query())), 1000)
60
+ self.assertEqual(len(list(tag_cache.query("dummy_vehicle"))), 1000)
61
+ self.assertEqual(len(list(tag_cache.query(tagsets=[tagset]))), 500)
62
+ self.assertEqual(
63
+ len(list(tag_cache.query("dummy_vehicle",
64
+ dt_parse_iso("2020-01-01T00:00:00.000000+00:00"),
65
+ dt_parse_iso("2020-01-01T00:01:00.000000+00:00")))),
66
+ 61,
67
+ )
68
+ self.assertEqual(
69
+ len(list(tag_cache.query("dummy_vehicle",
70
+ dt_parse_iso("2020-01-01T00:00:00.000000+00:00"),
71
+ dt_parse_iso("2020-01-01T00:01:00.000000+00:00"),
72
+ tag_pattern="dummy:foo"))),
73
+ 16,
74
+ )
75
+ self.assertEqual(
76
+ len(list(tag_cache.query("dummy_vehicle",
77
+ dt_parse_iso("2020-01-01T00:00:00.000000+00:00"),
78
+ dt_parse_iso("2020-01-01T00:01:00.000000+00:00"),
79
+ tag_pattern="dummy:bar"))),
80
+ 15,
81
+ )
82
+ self.assertEqual(
83
+ len(list(tag_cache.query("dummy_vehicle",
84
+ dt_parse_iso("2020-01-01T00:00:00.000000+00:00"),
85
+ dt_parse_iso("2020-01-01T00:01:00.000000+00:00"),
86
+ tag_pattern="dummy"))),
87
+ 61,
88
+ )
89
+ self.assertEqual(len(list(tag_cache.query("dummy_vehicle", tag_pattern="dummy:foo"))), 250)
90
+ self.assertEqual(len(list(tag_cache.query("dummy_vehicle", tag_pattern="dummy:bar"))), 250)
91
+ self.assertEqual(len(list(tag_cache.query("dummy_vehicle", tag_pattern="dummy"))), 1000)
92
+ self.assertEqual(len(list(tag_cache.query("another_dummy_vehicle"))), 0)
93
+
94
+ self.assertEqual(len(list(tag_cache.undefined([tagset]))), 500)
95
+
96
+ tag_cache.remove("dummy_vehicle",
97
+ dt_parse_iso("2020-01-01T00:00:00.000000+00:00"),
98
+ dt_parse_iso("2020-01-01T00:01:00.000000+00:00"))
99
+
100
+ self.assertEqual(len(list(tag_cache.query("dummy_vehicle"))), 939)
101
+
102
+ tag_cache.clear()
103
+
104
+ self.assertEqual(len(list(tag_cache.query("dummy_vehicle"))), 0)
@@ -1,94 +0,0 @@
1
- import datetime
2
- import unittest
3
-
4
- import ddt
5
- from iker.common.utils.dtutils import dt_parse_iso
6
-
7
- from plexus.common.utils.tagutils import TagCache, Tagset
8
- from plexus.common.utils.tagutils import predefined_tagsets, render_tagset_markdown_readme
9
- from plexus.common.utils.tagutils import tag_cache_file_path
10
-
11
-
12
- @ddt.ddt
13
- class TagUtilsTest(unittest.TestCase):
14
-
15
- def test_predefined_tagsets(self):
16
- tagsets = predefined_tagsets()
17
- for _, tagset in tagsets.items():
18
- self.assertIsInstance(tagset, Tagset)
19
-
20
- for tag in tagset:
21
- self.assertIn(tag, tagset)
22
- self.assertIn(tag.name, tagset)
23
- self.assertEqual(tag, tagset.get(tag))
24
- self.assertEqual(tag, tagset.get(tag.name))
25
-
26
- markdown = render_tagset_markdown_readme(tagset)
27
- self.assertIsInstance(markdown, str)
28
-
29
- print(markdown)
30
-
31
- def test_tag_cache(self):
32
- tag_cache = TagCache()
33
-
34
- self.assertEqual(tag_cache.file_path, tag_cache_file_path())
35
- self.assertTrue(tag_cache.file_path.exists())
36
-
37
- self.assertEqual(len(tag_cache.query("dummy_vehicle")), 0)
38
-
39
- tags = [
40
- "dummy:foo",
41
- "dummy:bar",
42
- "dummy:baz",
43
- "dummy:qux",
44
- ]
45
- for i in range(1000):
46
- tag_cache.add(
47
- "dummy_vehicle",
48
- dt_parse_iso("2020-01-01T00:00:00.000000+00:00") + datetime.timedelta(seconds=i),
49
- dt_parse_iso("2021-01-01T00:00:00.000000+00:00") + datetime.timedelta(seconds=i + 1),
50
- tags[i % len(tags)],
51
- )
52
-
53
- self.assertEqual(len(tag_cache.query("dummy_vehicle")), 1000)
54
- self.assertEqual(
55
- len(tag_cache.query("dummy_vehicle",
56
- dt_parse_iso("2020-01-01T00:00:00.000000+00:00"),
57
- dt_parse_iso("2020-01-01T00:01:00.000000+00:00"))),
58
- 61,
59
- )
60
- self.assertEqual(
61
- len(tag_cache.query("dummy_vehicle",
62
- dt_parse_iso("2020-01-01T00:00:00.000000+00:00"),
63
- dt_parse_iso("2020-01-01T00:01:00.000000+00:00"),
64
- tag_pattern="dummy:foo")),
65
- 16,
66
- )
67
- self.assertEqual(
68
- len(tag_cache.query("dummy_vehicle",
69
- dt_parse_iso("2020-01-01T00:00:00.000000+00:00"),
70
- dt_parse_iso("2020-01-01T00:01:00.000000+00:00"),
71
- tag_pattern="dummy:bar")),
72
- 15,
73
- )
74
- self.assertEqual(
75
- len(tag_cache.query("dummy_vehicle",
76
- dt_parse_iso("2020-01-01T00:00:00.000000+00:00"),
77
- dt_parse_iso("2020-01-01T00:01:00.000000+00:00"),
78
- tag_pattern="dummy")),
79
- 61,
80
- )
81
- self.assertEqual(len(tag_cache.query("dummy_vehicle", tag_pattern="dummy:foo")), 250)
82
- self.assertEqual(len(tag_cache.query("dummy_vehicle", tag_pattern="dummy:bar")), 250)
83
- self.assertEqual(len(tag_cache.query("dummy_vehicle", tag_pattern="dummy")), 1000)
84
- self.assertEqual(len(tag_cache.query("another_dummy_vehicle")), 0)
85
-
86
- tag_cache.remove("dummy_vehicle",
87
- dt_parse_iso("2020-01-01T00:00:00.000000+00:00"),
88
- dt_parse_iso("2020-01-01T00:01:00.000000+00:00"))
89
-
90
- self.assertEqual(len(tag_cache.query("dummy_vehicle")), 939)
91
-
92
- tag_cache.clear()
93
-
94
- self.assertEqual(len(tag_cache.query("dummy_vehicle")), 0)