streamlit-octostar-utils 0.4.2.dev1__py3-none-any.whl → 0.4.2.dev2__py3-none-any.whl
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/api_crafter/contents.py +184 -30
- streamlit_octostar_utils/api_crafter/nifi.py +23 -9
- {streamlit_octostar_utils-0.4.2.dev1.dist-info → streamlit_octostar_utils-0.4.2.dev2.dist-info}/METADATA +1 -1
- {streamlit_octostar_utils-0.4.2.dev1.dist-info → streamlit_octostar_utils-0.4.2.dev2.dist-info}/RECORD +6 -6
- {streamlit_octostar_utils-0.4.2.dev1.dist-info → streamlit_octostar_utils-0.4.2.dev2.dist-info}/WHEEL +0 -0
- {streamlit_octostar_utils-0.4.2.dev1.dist-info → streamlit_octostar_utils-0.4.2.dev2.dist-info}/licenses/LICENSE +0 -0
|
@@ -11,6 +11,7 @@ Provides a FileIO-like interface for handling entity contents with support for:
|
|
|
11
11
|
Storage Backends:
|
|
12
12
|
- MemoryContents: In-memory buffer (like BytesIO)
|
|
13
13
|
- WorkspaceAttachmentContents: Octostar workspace attachments with HTTP Range support
|
|
14
|
+
- TemporaryAttachmentContents: Octostar temporary blob storage (user temp bucket)
|
|
14
15
|
"""
|
|
15
16
|
|
|
16
17
|
from abc import ABC, abstractmethod
|
|
@@ -29,6 +30,7 @@ class ContentsLocation(Enum):
|
|
|
29
30
|
"""Enumeration of supported content storage locations."""
|
|
30
31
|
MEMORY = "memory"
|
|
31
32
|
WORKSPACE_ATTACHMENT = "workspace_attachment"
|
|
33
|
+
TEMPORARY_ATTACHMENT = "temporary_attachment"
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
class Contents(ABC):
|
|
@@ -42,12 +44,10 @@ class Contents(ABC):
|
|
|
42
44
|
|
|
43
45
|
def __init__(
|
|
44
46
|
self,
|
|
45
|
-
mode: str = "rb",
|
|
46
47
|
entity_type: Optional[str] = None,
|
|
47
48
|
filetype: Optional[str] = None,
|
|
48
49
|
**kwargs
|
|
49
50
|
):
|
|
50
|
-
self._mode = mode
|
|
51
51
|
self._entity_type = entity_type
|
|
52
52
|
self._filetype = filetype
|
|
53
53
|
self._closed = False
|
|
@@ -105,15 +105,12 @@ class Contents(ABC):
|
|
|
105
105
|
pass
|
|
106
106
|
|
|
107
107
|
def readable(self) -> bool:
|
|
108
|
-
|
|
109
|
-
return 'r' in self._mode or '+' in self._mode
|
|
108
|
+
return True
|
|
110
109
|
|
|
111
110
|
def writable(self) -> bool:
|
|
112
|
-
|
|
113
|
-
return 'w' in self._mode or 'a' in self._mode or '+' in self._mode
|
|
111
|
+
return True
|
|
114
112
|
|
|
115
113
|
def seekable(self) -> bool:
|
|
116
|
-
"""Check if stream is seekable."""
|
|
117
114
|
return True
|
|
118
115
|
|
|
119
116
|
@abstractmethod
|
|
@@ -126,16 +123,16 @@ class Contents(ABC):
|
|
|
126
123
|
"""Close the stream and release resources."""
|
|
127
124
|
self._closed = True
|
|
128
125
|
|
|
126
|
+
@abstractmethod
|
|
127
|
+
def delete(self):
|
|
128
|
+
"""Delete the contents from their storage backend."""
|
|
129
|
+
pass
|
|
130
|
+
|
|
129
131
|
@property
|
|
130
132
|
def closed(self) -> bool:
|
|
131
133
|
"""Check if stream is closed."""
|
|
132
134
|
return self._closed
|
|
133
135
|
|
|
134
|
-
@property
|
|
135
|
-
def mode(self) -> str:
|
|
136
|
-
"""Get the file mode."""
|
|
137
|
-
return self._mode
|
|
138
|
-
|
|
139
136
|
@abstractmethod
|
|
140
137
|
def truncate(self, size: Optional[int] = None) -> int:
|
|
141
138
|
"""
|
|
@@ -286,6 +283,8 @@ class Contents(ABC):
|
|
|
286
283
|
return MemoryContents._from_locator(locator)
|
|
287
284
|
case ContentsLocation.WORKSPACE_ATTACHMENT.value:
|
|
288
285
|
return WorkspaceAttachmentContents._from_locator(locator, client)
|
|
286
|
+
case ContentsLocation.TEMPORARY_ATTACHMENT.value:
|
|
287
|
+
return TemporaryAttachmentContents._from_locator(locator, client)
|
|
289
288
|
case _:
|
|
290
289
|
raise ValueError(f"Unknown contents location type: {location}")
|
|
291
290
|
|
|
@@ -336,24 +335,19 @@ class MemoryContents(Contents):
|
|
|
336
335
|
|
|
337
336
|
def __init__(
|
|
338
337
|
self,
|
|
339
|
-
mode: str = "r+b",
|
|
340
338
|
entity_type: Optional[str] = None,
|
|
341
339
|
filetype: Optional[str] = None,
|
|
342
340
|
*,
|
|
343
341
|
initial_data: Optional[bytes] = None,
|
|
344
342
|
**kwargs
|
|
345
343
|
):
|
|
346
|
-
super().__init__(
|
|
344
|
+
super().__init__(entity_type, filetype, **kwargs)
|
|
347
345
|
self._buffer = BytesIO(initial_data or b"")
|
|
348
346
|
|
|
349
347
|
def read(self, size: int = -1) -> bytes:
|
|
350
|
-
if not self.readable():
|
|
351
|
-
raise IOError("Contents not readable")
|
|
352
348
|
return self._buffer.read(size)
|
|
353
349
|
|
|
354
350
|
def write(self, b: bytes) -> int:
|
|
355
|
-
if not self.writable():
|
|
356
|
-
raise IOError("Contents not writable")
|
|
357
351
|
return self._buffer.write(b)
|
|
358
352
|
|
|
359
353
|
def seek(self, offset: int, whence: int = SEEK_SET) -> int:
|
|
@@ -370,6 +364,10 @@ class MemoryContents(Contents):
|
|
|
370
364
|
self._buffer.close()
|
|
371
365
|
super().close()
|
|
372
366
|
|
|
367
|
+
def delete(self):
|
|
368
|
+
"""Clear the in-memory buffer."""
|
|
369
|
+
self._buffer = BytesIO(b"")
|
|
370
|
+
|
|
373
371
|
def truncate(self, size: Optional[int] = None) -> int:
|
|
374
372
|
return self._buffer.truncate(size)
|
|
375
373
|
|
|
@@ -435,7 +433,6 @@ class WorkspaceAttachmentContents(Contents):
|
|
|
435
433
|
|
|
436
434
|
def __init__(
|
|
437
435
|
self,
|
|
438
|
-
mode: str = "rb",
|
|
439
436
|
entity_type: Optional[str] = None,
|
|
440
437
|
filetype: Optional[str] = None,
|
|
441
438
|
*,
|
|
@@ -446,7 +443,7 @@ class WorkspaceAttachmentContents(Contents):
|
|
|
446
443
|
chunk_size: int = DEFAULT_CHUNK_SIZE,
|
|
447
444
|
**kwargs
|
|
448
445
|
):
|
|
449
|
-
super().__init__(
|
|
446
|
+
super().__init__(entity_type, filetype, **kwargs)
|
|
450
447
|
self._workspace_id = workspace_id
|
|
451
448
|
self._entity_id = entity_id
|
|
452
449
|
self._client = client
|
|
@@ -575,11 +572,7 @@ class WorkspaceAttachmentContents(Contents):
|
|
|
575
572
|
self._position = 0
|
|
576
573
|
|
|
577
574
|
def read(self, size: int = -1) -> bytes:
|
|
578
|
-
if
|
|
579
|
-
raise IOError("Contents not readable")
|
|
580
|
-
|
|
581
|
-
# If writable or already fully loaded, use buffer
|
|
582
|
-
if self.writable() or self._fully_loaded:
|
|
575
|
+
if self._fully_loaded:
|
|
583
576
|
if not self._buffer:
|
|
584
577
|
self._load_full()
|
|
585
578
|
return self._buffer.read(size)
|
|
@@ -613,9 +606,6 @@ class WorkspaceAttachmentContents(Contents):
|
|
|
613
606
|
return data
|
|
614
607
|
|
|
615
608
|
def write(self, b: bytes) -> int:
|
|
616
|
-
if not self.writable():
|
|
617
|
-
raise IOError("Contents not writable")
|
|
618
|
-
|
|
619
609
|
if not self._buffer:
|
|
620
610
|
self._load_full()
|
|
621
611
|
|
|
@@ -684,10 +674,8 @@ class WorkspaceAttachmentContents(Contents):
|
|
|
684
674
|
|
|
685
675
|
def close(self):
|
|
686
676
|
if not self._closed:
|
|
687
|
-
# Flush any pending writes before closing
|
|
688
677
|
if self._modified:
|
|
689
678
|
self.flush()
|
|
690
|
-
|
|
691
679
|
if self._buffer:
|
|
692
680
|
self._buffer.close()
|
|
693
681
|
if self._http_client:
|
|
@@ -695,6 +683,15 @@ class WorkspaceAttachmentContents(Contents):
|
|
|
695
683
|
self._http_client = None
|
|
696
684
|
super().close()
|
|
697
685
|
|
|
686
|
+
def delete(self):
|
|
687
|
+
"""Delete the entity from the workspace using delete_entity()."""
|
|
688
|
+
from octostar.utils.workspace import delete_entity
|
|
689
|
+
|
|
690
|
+
delete_entity.sync(
|
|
691
|
+
os_entity_uid=self._entity_id,
|
|
692
|
+
client=self._client
|
|
693
|
+
)
|
|
694
|
+
|
|
698
695
|
def truncate(self, size: Optional[int] = None) -> int:
|
|
699
696
|
if not self._buffer:
|
|
700
697
|
self._load_full()
|
|
@@ -758,3 +755,160 @@ class WorkspaceAttachmentContents(Contents):
|
|
|
758
755
|
entity_id=entity_id,
|
|
759
756
|
client=client
|
|
760
757
|
)
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
class TemporaryAttachmentContents(Contents):
|
|
761
|
+
"""
|
|
762
|
+
Contents implementation for Octostar temporary blob storage.
|
|
763
|
+
|
|
764
|
+
Uses octostar-api utilities (read_temporary_blob, write_temporary_blob,
|
|
765
|
+
delete_temporary_blob) to store files in the user's temporary S3 bucket.
|
|
766
|
+
|
|
767
|
+
Temporary blobs are keyed by filename (not workspace/entity), and are not
|
|
768
|
+
associated with any workspace entity. Use WorkspaceAttachmentContents for that.
|
|
769
|
+
"""
|
|
770
|
+
|
|
771
|
+
def __init__(
|
|
772
|
+
self,
|
|
773
|
+
entity_type: Optional[str] = None,
|
|
774
|
+
filetype: Optional[str] = None,
|
|
775
|
+
*,
|
|
776
|
+
filename: str,
|
|
777
|
+
client,
|
|
778
|
+
initial_data: Optional[bytes] = None,
|
|
779
|
+
**kwargs
|
|
780
|
+
):
|
|
781
|
+
super().__init__(entity_type, filetype, **kwargs)
|
|
782
|
+
self._filename = filename
|
|
783
|
+
self._client = client
|
|
784
|
+
|
|
785
|
+
self._buffer: Optional[BytesIO] = None
|
|
786
|
+
self._fully_loaded = False
|
|
787
|
+
self._modified = False
|
|
788
|
+
|
|
789
|
+
if initial_data is not None:
|
|
790
|
+
self._buffer = BytesIO(initial_data)
|
|
791
|
+
self._fully_loaded = True
|
|
792
|
+
|
|
793
|
+
def _load_full(self):
|
|
794
|
+
"""Load the entire blob into memory using read_temporary_blob()."""
|
|
795
|
+
if self._fully_loaded:
|
|
796
|
+
return
|
|
797
|
+
|
|
798
|
+
from octostar.utils.workspace import read_temporary_blob
|
|
799
|
+
|
|
800
|
+
data = read_temporary_blob.sync(
|
|
801
|
+
filename=self._filename,
|
|
802
|
+
decode=False,
|
|
803
|
+
client=self._client
|
|
804
|
+
)
|
|
805
|
+
self._buffer = BytesIO(data or b"")
|
|
806
|
+
self._fully_loaded = True
|
|
807
|
+
|
|
808
|
+
def read(self, size: int = -1) -> bytes:
|
|
809
|
+
if not self._buffer:
|
|
810
|
+
self._load_full()
|
|
811
|
+
return self._buffer.read(size)
|
|
812
|
+
|
|
813
|
+
def write(self, b: bytes) -> int:
|
|
814
|
+
if not self._buffer:
|
|
815
|
+
self._load_full()
|
|
816
|
+
n = self._buffer.write(b)
|
|
817
|
+
self._modified = True
|
|
818
|
+
return n
|
|
819
|
+
|
|
820
|
+
def seek(self, offset: int, whence: int = SEEK_SET) -> int:
|
|
821
|
+
if not self._buffer:
|
|
822
|
+
self._load_full()
|
|
823
|
+
return self._buffer.seek(offset, whence)
|
|
824
|
+
|
|
825
|
+
def tell(self) -> int:
|
|
826
|
+
if not self._buffer:
|
|
827
|
+
self._load_full()
|
|
828
|
+
return self._buffer.tell()
|
|
829
|
+
|
|
830
|
+
def flush(self):
|
|
831
|
+
"""Flush the internal buffer and write to temp bucket if modified."""
|
|
832
|
+
if self._buffer:
|
|
833
|
+
self._buffer.flush()
|
|
834
|
+
|
|
835
|
+
if not self._modified or not self._buffer:
|
|
836
|
+
return
|
|
837
|
+
|
|
838
|
+
from octostar.utils.workspace import write_temporary_blob
|
|
839
|
+
|
|
840
|
+
current_pos = self._buffer.tell()
|
|
841
|
+
self._buffer.seek(0, SEEK_SET)
|
|
842
|
+
data = self._buffer.read()
|
|
843
|
+
self._buffer.seek(current_pos, SEEK_SET)
|
|
844
|
+
|
|
845
|
+
write_temporary_blob.sync(
|
|
846
|
+
filename=self._filename,
|
|
847
|
+
file=data,
|
|
848
|
+
client=self._client
|
|
849
|
+
)
|
|
850
|
+
self._modified = False
|
|
851
|
+
|
|
852
|
+
def close(self):
|
|
853
|
+
if not self._closed:
|
|
854
|
+
if self._modified:
|
|
855
|
+
self.flush()
|
|
856
|
+
if self._buffer:
|
|
857
|
+
self._buffer.close()
|
|
858
|
+
super().close()
|
|
859
|
+
|
|
860
|
+
def delete(self):
|
|
861
|
+
"""Delete the blob from the temporary bucket."""
|
|
862
|
+
from octostar.utils.workspace import delete_temporary_blob
|
|
863
|
+
|
|
864
|
+
delete_temporary_blob.sync(
|
|
865
|
+
filename=self._filename,
|
|
866
|
+
client=self._client
|
|
867
|
+
)
|
|
868
|
+
|
|
869
|
+
def truncate(self, size: Optional[int] = None) -> int:
|
|
870
|
+
if not self._buffer:
|
|
871
|
+
self._load_full()
|
|
872
|
+
self._modified = True
|
|
873
|
+
return self._buffer.truncate(size)
|
|
874
|
+
|
|
875
|
+
def getvalue(self) -> bytes:
|
|
876
|
+
if not self._buffer or not self._fully_loaded:
|
|
877
|
+
self._load_full()
|
|
878
|
+
return self._buffer.getvalue()
|
|
879
|
+
|
|
880
|
+
def to_locator(self) -> Dict[str, Any]:
|
|
881
|
+
"""
|
|
882
|
+
Serialize to locator with filename.
|
|
883
|
+
|
|
884
|
+
Returns:
|
|
885
|
+
{"location": "temporary_attachment", "filename": "..."}
|
|
886
|
+
"""
|
|
887
|
+
locator = {
|
|
888
|
+
"location": ContentsLocation.TEMPORARY_ATTACHMENT.value,
|
|
889
|
+
"filename": self._filename
|
|
890
|
+
}
|
|
891
|
+
if self._entity_type:
|
|
892
|
+
locator["entity_type"] = self._entity_type
|
|
893
|
+
if self._filetype:
|
|
894
|
+
locator["filetype"] = self._filetype
|
|
895
|
+
return locator
|
|
896
|
+
|
|
897
|
+
@staticmethod
|
|
898
|
+
def _from_locator(locator: Dict[str, Any], client=None) -> 'TemporaryAttachmentContents':
|
|
899
|
+
"""
|
|
900
|
+
Create TemporaryAttachmentContents from a locator dictionary.
|
|
901
|
+
|
|
902
|
+
Args:
|
|
903
|
+
locator: Locator dictionary with filename
|
|
904
|
+
client: Octostar client
|
|
905
|
+
|
|
906
|
+
Returns:
|
|
907
|
+
New TemporaryAttachmentContents instance
|
|
908
|
+
"""
|
|
909
|
+
return TemporaryAttachmentContents(
|
|
910
|
+
entity_type=locator.get("entity_type"),
|
|
911
|
+
filetype=locator.get("filetype"),
|
|
912
|
+
filename=locator["filename"],
|
|
913
|
+
client=client
|
|
914
|
+
)
|
|
@@ -26,7 +26,7 @@ from ..core.dict import recursive_update_dict, travel_dict, jsondict_hash
|
|
|
26
26
|
from ..core.timestamp import now, string_to_datetime
|
|
27
27
|
from .fastapi import DefaultErrorRoute, Route
|
|
28
28
|
from ..ontology.inheritance import is_child_concept as is_child_concept_fn, get_label_keys
|
|
29
|
-
from .contents import Contents, MemoryContents, WorkspaceAttachmentContents, ContentsLocation
|
|
29
|
+
from .contents import Contents, MemoryContents, WorkspaceAttachmentContents, TemporaryAttachmentContents, ContentsLocation
|
|
30
30
|
|
|
31
31
|
RELATIONSHIP_ENTITY_NAME = "os_relationship"
|
|
32
32
|
LOCAL_RELATIONSHIP_ENTITY_NAME = "os_workspace_relationship"
|
|
@@ -453,11 +453,14 @@ class NifiContextManager(object):
|
|
|
453
453
|
fetch_concept_relationships = {}
|
|
454
454
|
# FIND FILES TO WRITE
|
|
455
455
|
for entity in entities:
|
|
456
|
-
if entity.is_child_concept("
|
|
456
|
+
if entity.is_child_concept("os_attachable"):
|
|
457
457
|
has_write_flag = entity.sync_params.get(NifiContextManager.SyncFlag.WRITE_CONTENTS)
|
|
458
|
-
|
|
459
|
-
if
|
|
460
|
-
if entity.
|
|
458
|
+
is_temporary = entity.request.get("is_temporary")
|
|
459
|
+
if is_temporary:
|
|
460
|
+
if entity._contents and not isinstance(entity._contents, WorkspaceAttachmentContents):
|
|
461
|
+
files_to_write.append(entity)
|
|
462
|
+
elif has_write_flag:
|
|
463
|
+
if entity.contents:
|
|
461
464
|
files_to_write.append(entity)
|
|
462
465
|
# FIND ENTITIES TO UPSERT
|
|
463
466
|
self._find_entities_to_upsert(entities, entities_to_upsert, reserved_fields)
|
|
@@ -487,8 +490,7 @@ class NifiContextManager(object):
|
|
|
487
490
|
for file in files_to_write:
|
|
488
491
|
if not file.contents:
|
|
489
492
|
continue
|
|
490
|
-
|
|
491
|
-
# Pass Contents instance directly — write_file uses duck typing
|
|
493
|
+
old_contents = file._contents
|
|
492
494
|
new_file_record = write_file.sync(
|
|
493
495
|
file.write_os_workspace,
|
|
494
496
|
"./" + file.record["os_item_name"],
|
|
@@ -517,6 +519,11 @@ class NifiContextManager(object):
|
|
|
517
519
|
"entity_type": file.record["os_concept"],
|
|
518
520
|
"filetype": file.record["os_item_content_type"]
|
|
519
521
|
}
|
|
522
|
+
if isinstance(old_contents, TemporaryAttachmentContents):
|
|
523
|
+
try:
|
|
524
|
+
old_contents.delete()
|
|
525
|
+
except Exception:
|
|
526
|
+
pass
|
|
520
527
|
# UPSERT ENTITIES
|
|
521
528
|
if entities_to_upsert:
|
|
522
529
|
new_entities = upsert_entities.sync(
|
|
@@ -1062,9 +1069,16 @@ class NifiEntity(object):
|
|
|
1062
1069
|
if isinstance(file, Contents):
|
|
1063
1070
|
child_entity._contents = file
|
|
1064
1071
|
else:
|
|
1065
|
-
|
|
1066
|
-
|
|
1072
|
+
temp_filename = f"tmp_{child_entity.record['os_entity_uid']}"
|
|
1073
|
+
temp_contents = TemporaryAttachmentContents(
|
|
1074
|
+
entity_type=FILE_ENTITY_NAME,
|
|
1075
|
+
filetype=filetype,
|
|
1076
|
+
filename=temp_filename,
|
|
1077
|
+
client=self.context.client,
|
|
1078
|
+
initial_data=file,
|
|
1067
1079
|
)
|
|
1080
|
+
temp_contents.flush()
|
|
1081
|
+
child_entity._contents = temp_contents
|
|
1068
1082
|
child_entity.request["contents_pointer"] = child_entity._contents.to_locator()
|
|
1069
1083
|
return child_entity, child_rel
|
|
1070
1084
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
streamlit_octostar_utils/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
2
2
|
streamlit_octostar_utils/api_crafter/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
3
3
|
streamlit_octostar_utils/api_crafter/celery.py,sha256=IFxeJlxn1C6bP-7bhRlHMGhRJY0Ab8TwB2eUj1DLjaM,33501
|
|
4
|
-
streamlit_octostar_utils/api_crafter/contents.py,sha256=
|
|
4
|
+
streamlit_octostar_utils/api_crafter/contents.py,sha256=htnCnDqnLx2o0dIk2xioLJ3SSzhqm3n0viJsxyG78pk,29273
|
|
5
5
|
streamlit_octostar_utils/api_crafter/fastapi.py,sha256=7J_GqXouvX0Y7pIpsgO5q14StJDArtGdXhTAvXeIjGI,14372
|
|
6
|
-
streamlit_octostar_utils/api_crafter/nifi.py,sha256=
|
|
6
|
+
streamlit_octostar_utils/api_crafter/nifi.py,sha256=He5Hjd0QpUQmE8WF0wXu9WY5xsWMtZOd0JxKbixSFtw,48290
|
|
7
7
|
streamlit_octostar_utils/api_crafter/parallelism.py,sha256=YDQ5aQ6w4bwI_UAydQOOLYQr3svuweMAH-Jdf5jpYPI,29388
|
|
8
8
|
streamlit_octostar_utils/api_crafter/parser/__init__.py,sha256=YeYWF6sdQiCFV_RKNW2t9Vs6KJExE2pbXxWTe_DOayY,107
|
|
9
9
|
streamlit_octostar_utils/api_crafter/parser/combine_fields.py,sha256=ddc44xkajw8MU0peAX_263DL7rPXbTKbHUjpOhRgvyU,8790
|
|
@@ -39,7 +39,7 @@ streamlit_octostar_utils/threading/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzp
|
|
|
39
39
|
streamlit_octostar_utils/threading/async_task_manager.py,sha256=q7N6YZwUvIYMzkSHmsJNheNVCv93c03H6Hyg9uH8pvk,4747
|
|
40
40
|
streamlit_octostar_utils/threading/session_callback_manager.py,sha256=LvZVP4g6tvKtYmI13f2j1sX_7hm61Groqp5xJine9_k,3973
|
|
41
41
|
streamlit_octostar_utils/threading/session_state_hot_swapper.py,sha256=6eeCQI6A42hp4DmW2NQw2rbeR-k9N8DhfBKQdN_fbLU,811
|
|
42
|
-
streamlit_octostar_utils-0.4.2.
|
|
43
|
-
streamlit_octostar_utils-0.4.2.
|
|
44
|
-
streamlit_octostar_utils-0.4.2.
|
|
45
|
-
streamlit_octostar_utils-0.4.2.
|
|
42
|
+
streamlit_octostar_utils-0.4.2.dev2.dist-info/METADATA,sha256=5sx_MMyva6Wx2TZY_5IEhlrRnQh0RMweOzokzTv4ua8,2413
|
|
43
|
+
streamlit_octostar_utils-0.4.2.dev2.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
44
|
+
streamlit_octostar_utils-0.4.2.dev2.dist-info/licenses/LICENSE,sha256=dkwVPyV03fPHHtERnF6RnvRXcll__tud9gWca1RcgnQ,1073
|
|
45
|
+
streamlit_octostar_utils-0.4.2.dev2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|