streamlit-octostar-utils 0.5.0.dev1__tar.gz → 0.5.0.dev2__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.
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/PKG-INFO +1 -1
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/pyproject.toml +1 -1
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/nifi.py +210 -17
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/LICENSE +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/README.md +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/__init__.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/__init__.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/celery.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/contents.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/fastapi.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/parallelism.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/parser/__init__.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/parser/combine_fields.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/parser/entities_parser.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/parser/generics.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/parser/info.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/parser/linkchart_functions.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/parser/matches.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/parser/parameters.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/parser/rules.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/api_crafter/parser/signals.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/core/__init__.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/core/dict.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/core/filetypes.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/core/threading/__init__.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/core/threading/key_queue.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/core/timestamp.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/nlp/__init__.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/nlp/custom_recognizers.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/nlp/language.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/nlp/ner.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/octostar/__init__.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/octostar/client.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/octostar/context.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/octostar/permissions.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/ontology/__init__.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/ontology/inheritance.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/ontology/relationships.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/ontology/validation.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/style/__init__.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/style/common.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/threading/__init__.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/threading/async_task_manager.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/threading/session_callback_manager.py +0 -0
- {streamlit_octostar_utils-0.5.0.dev1 → streamlit_octostar_utils-0.5.0.dev2}/streamlit_octostar_utils/threading/session_state_hot_swapper.py +0 -0
|
@@ -238,6 +238,156 @@ class NifiFragmenter(object):
|
|
|
238
238
|
pointer.get("merge_params") or {}, defragmenter_config, lambda _, v2: v2
|
|
239
239
|
)
|
|
240
240
|
|
|
241
|
+
_REQUIRED_FRAGMENT_FIELDS = ("index", "count", "identifier")
|
|
242
|
+
|
|
243
|
+
@staticmethod
|
|
244
|
+
def get_fragment_info(entity, fragmenter_keylist):
|
|
245
|
+
"""Read fragment metadata (identifier, count, index, root_uid, merge_params)
|
|
246
|
+
for a given fragmenter level. Read-only -- does not mutate the entity.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
entity: A NifiEntity or NifiEntityProxy.
|
|
250
|
+
fragmenter_keylist: Dot-separated key path into the fragment config
|
|
251
|
+
(e.g. "document_pages" or "audio_split").
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
dict with keys like identifier, count, index, root_uid, merge_params.
|
|
255
|
+
Empty dict if fragmenter_keylist is empty or intermediate keys are
|
|
256
|
+
missing (entity not fragmented at this level).
|
|
257
|
+
|
|
258
|
+
Raises:
|
|
259
|
+
KeyError: If the final fragment key is missing from the config.
|
|
260
|
+
ValueError: If the fragment info exists but lacks required fields
|
|
261
|
+
(index, count, identifier).
|
|
262
|
+
"""
|
|
263
|
+
if not fragmenter_keylist:
|
|
264
|
+
return {}
|
|
265
|
+
pointer = entity.request["config"]["fragment"]
|
|
266
|
+
for k in fragmenter_keylist.split(".")[:-1]:
|
|
267
|
+
if not pointer.get(k):
|
|
268
|
+
return {}
|
|
269
|
+
pointer = pointer[k]
|
|
270
|
+
info = pointer[fragmenter_keylist.split(".")[-1]]
|
|
271
|
+
missing = [f for f in NifiFragmenter._REQUIRED_FRAGMENT_FIELDS if f not in info]
|
|
272
|
+
if missing:
|
|
273
|
+
raise RuntimeError(
|
|
274
|
+
f"Fragment info for '{fragmenter_keylist}' is missing required "
|
|
275
|
+
f"field(s): {', '.join(missing)}"
|
|
276
|
+
)
|
|
277
|
+
return info
|
|
278
|
+
|
|
279
|
+
@staticmethod
|
|
280
|
+
def identify_fragment_groups(nifi_batches):
|
|
281
|
+
"""Find all fragmented entities grouped by their active fragmenter level.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
nifi_batches: List of NifiEntityBatch objects.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
dict mapping fragmenter_keylist to list of entities at that level.
|
|
288
|
+
Empty dict if no fragments found. Callers use get_fragment_info()
|
|
289
|
+
to fetch metadata per entity, and filter by index==0 to find roots.
|
|
290
|
+
"""
|
|
291
|
+
all_entities = list(itertools.chain(*[b.entities for b in nifi_batches]))
|
|
292
|
+
groups = {}
|
|
293
|
+
for e in all_entities:
|
|
294
|
+
stack = e.request["config"].get("fragment", {}).get("fragments_stack", [])
|
|
295
|
+
if stack:
|
|
296
|
+
groups.setdefault(stack[0], []).append(e)
|
|
297
|
+
return groups
|
|
298
|
+
|
|
299
|
+
@staticmethod
|
|
300
|
+
def build_fragment_tree_from_children_entities(root_entity, fragmenter_keylist):
|
|
301
|
+
"""Recursively build a tree from a root fragment entity by walking
|
|
302
|
+
its children_entities.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
root_entity: The root entity (index 0) to start from.
|
|
306
|
+
fragmenter_keylist: The fragmenter level to build for.
|
|
307
|
+
|
|
308
|
+
Returns:
|
|
309
|
+
Nested dict with keys:
|
|
310
|
+
"entity": NifiEntity/NifiEntityProxy
|
|
311
|
+
"index": int
|
|
312
|
+
"merge_params": dict or None
|
|
313
|
+
"children": list of child trees
|
|
314
|
+
"""
|
|
315
|
+
info = NifiFragmenter.get_fragment_info(root_entity, fragmenter_keylist)
|
|
316
|
+
child_fragments = []
|
|
317
|
+
for e in root_entity.children_entities:
|
|
318
|
+
try:
|
|
319
|
+
child_info = NifiFragmenter.get_fragment_info(e, fragmenter_keylist)
|
|
320
|
+
if child_info:
|
|
321
|
+
child_fragments.append(e)
|
|
322
|
+
except (AttributeError, KeyError):
|
|
323
|
+
pass
|
|
324
|
+
return {
|
|
325
|
+
"entity": root_entity,
|
|
326
|
+
"index": info.get("index"),
|
|
327
|
+
"merge_params": info.get("merge_params"),
|
|
328
|
+
"children": [
|
|
329
|
+
NifiFragmenter.build_fragment_tree_from_children_entities(child, fragmenter_keylist)
|
|
330
|
+
for child in child_fragments
|
|
331
|
+
],
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
@staticmethod
|
|
335
|
+
def extract_tree_entities(tree):
|
|
336
|
+
"""Flatten a fragment tree into a list of all entities (pre-order).
|
|
337
|
+
|
|
338
|
+
Args:
|
|
339
|
+
tree: Fragment tree node (from build_fragment_tree_from_children_entities).
|
|
340
|
+
|
|
341
|
+
Returns:
|
|
342
|
+
List of entities in pre-order traversal.
|
|
343
|
+
"""
|
|
344
|
+
entities = [tree["entity"]]
|
|
345
|
+
for child in tree.get("children", []):
|
|
346
|
+
entities.extend(NifiFragmenter.extract_tree_entities(child))
|
|
347
|
+
return entities
|
|
348
|
+
|
|
349
|
+
@staticmethod
|
|
350
|
+
def iterate_fragments_tree(tree, order="post"):
|
|
351
|
+
"""Yield tree nodes in traversal order.
|
|
352
|
+
|
|
353
|
+
Args:
|
|
354
|
+
tree: Fragment tree node (from build_fragment_tree_from_children_entities).
|
|
355
|
+
order: "post" (children first, default) or "pre" (parent first).
|
|
356
|
+
|
|
357
|
+
Yields:
|
|
358
|
+
dict nodes with "entity", "index", "merge_params", "children" keys.
|
|
359
|
+
"""
|
|
360
|
+
children = sorted(tree.get("children", []), key=lambda x: x["index"])
|
|
361
|
+
if order == "pre":
|
|
362
|
+
yield tree
|
|
363
|
+
for child in children:
|
|
364
|
+
yield from NifiFragmenter.iterate_fragments_tree(child, order)
|
|
365
|
+
if order == "post":
|
|
366
|
+
yield tree
|
|
367
|
+
|
|
368
|
+
@staticmethod
|
|
369
|
+
def reduce_fragments_tree(tree, leaf_fn, parent_fn):
|
|
370
|
+
"""Bottom-up tree reduction. Processes leaves first, then folds results up.
|
|
371
|
+
|
|
372
|
+
Args:
|
|
373
|
+
tree: Fragment tree node (from build_fragment_tree_from_children_entities).
|
|
374
|
+
leaf_fn: Callable(node) -> result, called on nodes with no children.
|
|
375
|
+
parent_fn: Callable(node, child_results) -> result, called on
|
|
376
|
+
nodes with children. child_results is a list of results from
|
|
377
|
+
child nodes, sorted by index.
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
The result from the root node.
|
|
381
|
+
"""
|
|
382
|
+
children = sorted(tree.get("children", []), key=lambda x: x["index"])
|
|
383
|
+
if not children:
|
|
384
|
+
return leaf_fn(tree)
|
|
385
|
+
child_results = [
|
|
386
|
+
NifiFragmenter.reduce_fragments_tree(child, leaf_fn, parent_fn)
|
|
387
|
+
for child in children
|
|
388
|
+
]
|
|
389
|
+
return parent_fn(tree, child_results)
|
|
390
|
+
|
|
241
391
|
|
|
242
392
|
class NifiEntityBatch(object):
|
|
243
393
|
def __init__(self, entities, config, config_key):
|
|
@@ -777,25 +927,68 @@ class NifiEntity(object):
|
|
|
777
927
|
entity_type = self.record["entity_type"]
|
|
778
928
|
return entity_type == type or type in self.request["ontology_info"]["parents"]
|
|
779
929
|
|
|
780
|
-
def is_fragmented(self) -> bool:
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
930
|
+
def is_fragmented(self, fragment_name_or_idx=None) -> bool:
|
|
931
|
+
"""Check whether this entity is part of a fragmentation.
|
|
932
|
+
|
|
933
|
+
Args:
|
|
934
|
+
fragment_name_or_idx: If None (default), returns True if the entity
|
|
935
|
+
belongs to any fragmentation level. If an int, checks whether the
|
|
936
|
+
fragments_stack has an entry at that index. If a string, checks
|
|
937
|
+
whether that fragmenter keylist is present in the stack.
|
|
938
|
+
|
|
939
|
+
Returns:
|
|
940
|
+
True if the entity is fragmented (at the specified level, if given).
|
|
941
|
+
"""
|
|
942
|
+
stack = self.request["config"].get("fragment", {}).get("fragments_stack", [])
|
|
943
|
+
if fragment_name_or_idx is None:
|
|
944
|
+
return bool(stack)
|
|
945
|
+
if isinstance(fragment_name_or_idx, int):
|
|
946
|
+
return abs(fragment_name_or_idx) <= len(stack)
|
|
947
|
+
return fragment_name_or_idx in stack
|
|
948
|
+
|
|
949
|
+
def is_root_fragment(self, fragment_name_or_idx=-1, recurse=True) -> bool:
|
|
950
|
+
"""Check whether this entity is a root fragment (index == 0).
|
|
951
|
+
|
|
952
|
+
Args:
|
|
953
|
+
fragment_name_or_idx: Which fragmentation level to check. An int
|
|
954
|
+
indexes into fragments_stack (default -1 = oldest level),
|
|
955
|
+
a string matches by fragmenter keylist name.
|
|
956
|
+
recurse: If True (default), check from the starting level towards
|
|
957
|
+
index 0 (most recent) and return True only if the entity is
|
|
958
|
+
root at every checked level. If False, only check the single
|
|
959
|
+
specified level.
|
|
960
|
+
|
|
961
|
+
Returns:
|
|
962
|
+
True if the entity is a root fragment at the specified level(s),
|
|
963
|
+
or if the entity is not fragmented at all.
|
|
964
|
+
"""
|
|
795
965
|
if not self.is_fragmented():
|
|
796
966
|
return True
|
|
797
|
-
|
|
798
|
-
|
|
967
|
+
fragments_stack = self.request["config"]["fragment"]["fragments_stack"]
|
|
968
|
+
|
|
969
|
+
if isinstance(fragment_name_or_idx, int):
|
|
970
|
+
try:
|
|
971
|
+
resolved = (
|
|
972
|
+
fragment_name_or_idx
|
|
973
|
+
if fragment_name_or_idx >= 0
|
|
974
|
+
else len(fragments_stack) + fragment_name_or_idx
|
|
975
|
+
)
|
|
976
|
+
key = fragments_stack[resolved]
|
|
977
|
+
except (IndexError, ValueError):
|
|
978
|
+
return True
|
|
979
|
+
else:
|
|
980
|
+
key = fragment_name_or_idx
|
|
981
|
+
if key not in fragments_stack:
|
|
982
|
+
return True
|
|
983
|
+
resolved = fragments_stack.index(key)
|
|
984
|
+
|
|
985
|
+
if recurse:
|
|
986
|
+
keys_to_check = fragments_stack[:resolved + 1]
|
|
987
|
+
return all(
|
|
988
|
+
NifiFragmenter.get_fragment_info(self, k).get("index", 0) == 0
|
|
989
|
+
for k in keys_to_check
|
|
990
|
+
)
|
|
991
|
+
return NifiFragmenter.get_fragment_info(self, key).get("index", 0) == 0
|
|
799
992
|
|
|
800
993
|
def get_fragment_root_uid(self, fragment_name_or_idx) -> str:
|
|
801
994
|
fragment_config = self.request.get("config", {}).get("fragment", {})
|
|
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
|
|
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
|
|
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
|