IncludeCPP 3.5.0__py3-none-any.whl → 3.6.0__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.
- includecpp/__init__.py +1 -1
- includecpp/core/cssl/CSSL_DOCUMENTATION.md +351 -20
- includecpp/core/cssl/cssl_builtins.py +228 -2
- includecpp/core/cssl/cssl_parser.py +214 -25
- includecpp/core/cssl/cssl_runtime.py +365 -38
- includecpp/core/cssl/cssl_types.py +339 -2
- includecpp/core/cssl_bridge.py +100 -4
- includecpp/core/cssl_bridge.pyi +177 -0
- {includecpp-3.5.0.dist-info → includecpp-3.6.0.dist-info}/METADATA +1 -1
- {includecpp-3.5.0.dist-info → includecpp-3.6.0.dist-info}/RECORD +14 -14
- {includecpp-3.5.0.dist-info → includecpp-3.6.0.dist-info}/WHEEL +0 -0
- {includecpp-3.5.0.dist-info → includecpp-3.6.0.dist-info}/entry_points.txt +0 -0
- {includecpp-3.5.0.dist-info → includecpp-3.6.0.dist-info}/licenses/LICENSE +0 -0
- {includecpp-3.5.0.dist-info → includecpp-3.6.0.dist-info}/top_level.txt +0 -0
|
@@ -546,16 +546,300 @@ class Array(list):
|
|
|
546
546
|
return len(self)
|
|
547
547
|
|
|
548
548
|
|
|
549
|
+
class List(list):
|
|
550
|
+
"""Python-like list with all standard operations.
|
|
551
|
+
|
|
552
|
+
Works exactly like Python lists with additional CSSL methods.
|
|
553
|
+
|
|
554
|
+
Usage:
|
|
555
|
+
list myList;
|
|
556
|
+
myList.append("item");
|
|
557
|
+
myList.insert(0, "first");
|
|
558
|
+
myList.pop();
|
|
559
|
+
myList.find("item"); # Returns index or -1
|
|
560
|
+
"""
|
|
561
|
+
|
|
562
|
+
def __init__(self, element_type: str = 'dynamic'):
|
|
563
|
+
super().__init__()
|
|
564
|
+
self._element_type = element_type
|
|
565
|
+
|
|
566
|
+
def length(self) -> int:
|
|
567
|
+
"""Return list length"""
|
|
568
|
+
return len(self)
|
|
569
|
+
|
|
570
|
+
def size(self) -> int:
|
|
571
|
+
"""Return list size (alias for length)"""
|
|
572
|
+
return len(self)
|
|
573
|
+
|
|
574
|
+
def isEmpty(self) -> bool:
|
|
575
|
+
"""Check if list is empty"""
|
|
576
|
+
return len(self) == 0
|
|
577
|
+
|
|
578
|
+
def first(self) -> Any:
|
|
579
|
+
"""Get first element"""
|
|
580
|
+
return self[0] if self else None
|
|
581
|
+
|
|
582
|
+
def last(self) -> Any:
|
|
583
|
+
"""Get last element"""
|
|
584
|
+
return self[-1] if self else None
|
|
585
|
+
|
|
586
|
+
def at(self, index: int) -> Any:
|
|
587
|
+
"""Get item at index (safe access)"""
|
|
588
|
+
if 0 <= index < len(self):
|
|
589
|
+
return self[index]
|
|
590
|
+
return None
|
|
591
|
+
|
|
592
|
+
def set(self, index: int, value: Any) -> 'List':
|
|
593
|
+
"""Set item at index"""
|
|
594
|
+
if 0 <= index < len(self):
|
|
595
|
+
self[index] = value
|
|
596
|
+
return self
|
|
597
|
+
|
|
598
|
+
def add(self, item: Any) -> 'List':
|
|
599
|
+
"""Add item to end (alias for append)"""
|
|
600
|
+
self.append(item)
|
|
601
|
+
return self
|
|
602
|
+
|
|
603
|
+
def push(self, item: Any) -> 'List':
|
|
604
|
+
"""Push item to end (alias for append)"""
|
|
605
|
+
self.append(item)
|
|
606
|
+
return self
|
|
607
|
+
|
|
608
|
+
def find(self, item: Any) -> int:
|
|
609
|
+
"""Find index of item (-1 if not found)"""
|
|
610
|
+
try:
|
|
611
|
+
return self.index(item)
|
|
612
|
+
except ValueError:
|
|
613
|
+
return -1
|
|
614
|
+
|
|
615
|
+
def contains(self, item: Any) -> bool:
|
|
616
|
+
"""Check if list contains item"""
|
|
617
|
+
return item in self
|
|
618
|
+
|
|
619
|
+
def indexOf(self, item: Any) -> int:
|
|
620
|
+
"""Find index of item (-1 if not found)"""
|
|
621
|
+
return self.find(item)
|
|
622
|
+
|
|
623
|
+
def lastIndexOf(self, item: Any) -> int:
|
|
624
|
+
"""Find last index of item (-1 if not found)"""
|
|
625
|
+
for i in range(len(self) - 1, -1, -1):
|
|
626
|
+
if self[i] == item:
|
|
627
|
+
return i
|
|
628
|
+
return -1
|
|
629
|
+
|
|
630
|
+
def removeAt(self, index: int) -> Any:
|
|
631
|
+
"""Remove and return item at index"""
|
|
632
|
+
if 0 <= index < len(self):
|
|
633
|
+
return self.pop(index)
|
|
634
|
+
return None
|
|
635
|
+
|
|
636
|
+
def removeValue(self, value: Any) -> bool:
|
|
637
|
+
"""Remove first occurrence of value"""
|
|
638
|
+
try:
|
|
639
|
+
self.remove(value)
|
|
640
|
+
return True
|
|
641
|
+
except ValueError:
|
|
642
|
+
return False
|
|
643
|
+
|
|
644
|
+
def removeAll(self, value: Any) -> int:
|
|
645
|
+
"""Remove all occurrences of value, return count"""
|
|
646
|
+
count = 0
|
|
647
|
+
while value in self:
|
|
648
|
+
self.remove(value)
|
|
649
|
+
count += 1
|
|
650
|
+
return count
|
|
651
|
+
|
|
652
|
+
def slice(self, start: int, end: int = None) -> 'List':
|
|
653
|
+
"""Return slice of list"""
|
|
654
|
+
result = List(self._element_type)
|
|
655
|
+
if end is None:
|
|
656
|
+
result.extend(self[start:])
|
|
657
|
+
else:
|
|
658
|
+
result.extend(self[start:end])
|
|
659
|
+
return result
|
|
660
|
+
|
|
661
|
+
def join(self, separator: str = ',') -> str:
|
|
662
|
+
"""Join elements into string"""
|
|
663
|
+
return separator.join(str(item) for item in self)
|
|
664
|
+
|
|
665
|
+
def unique(self) -> 'List':
|
|
666
|
+
"""Return list with unique elements"""
|
|
667
|
+
result = List(self._element_type)
|
|
668
|
+
seen = set()
|
|
669
|
+
for item in self:
|
|
670
|
+
key = item if isinstance(item, (int, str, float, bool)) else id(item)
|
|
671
|
+
if key not in seen:
|
|
672
|
+
seen.add(key)
|
|
673
|
+
result.append(item)
|
|
674
|
+
return result
|
|
675
|
+
|
|
676
|
+
def sorted(self, reverse: bool = False) -> 'List':
|
|
677
|
+
"""Return sorted copy"""
|
|
678
|
+
result = List(self._element_type)
|
|
679
|
+
result.extend(sorted(self, reverse=reverse))
|
|
680
|
+
return result
|
|
681
|
+
|
|
682
|
+
def reversed(self) -> 'List':
|
|
683
|
+
"""Return reversed copy"""
|
|
684
|
+
result = List(self._element_type)
|
|
685
|
+
result.extend(reversed(self))
|
|
686
|
+
return result
|
|
687
|
+
|
|
688
|
+
def shuffle(self) -> 'List':
|
|
689
|
+
"""Shuffle list in place"""
|
|
690
|
+
import random
|
|
691
|
+
random.shuffle(self)
|
|
692
|
+
return self
|
|
693
|
+
|
|
694
|
+
def fill(self, value: Any, count: int = None) -> 'List':
|
|
695
|
+
"""Fill list with value"""
|
|
696
|
+
if count is None:
|
|
697
|
+
for i in range(len(self)):
|
|
698
|
+
self[i] = value
|
|
699
|
+
else:
|
|
700
|
+
self.clear()
|
|
701
|
+
self.extend([value] * count)
|
|
702
|
+
return self
|
|
703
|
+
|
|
704
|
+
def begin(self) -> int:
|
|
705
|
+
"""Return iterator to beginning"""
|
|
706
|
+
return 0
|
|
707
|
+
|
|
708
|
+
def end(self) -> int:
|
|
709
|
+
"""Return iterator to end"""
|
|
710
|
+
return len(self)
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
class Dictionary(dict):
|
|
714
|
+
"""Python-like dictionary with all standard operations.
|
|
715
|
+
|
|
716
|
+
Works exactly like Python dicts with additional CSSL methods.
|
|
717
|
+
|
|
718
|
+
Usage:
|
|
719
|
+
dictionary myDict;
|
|
720
|
+
myDict.set("key", "value");
|
|
721
|
+
myDict.get("key");
|
|
722
|
+
myDict.keys();
|
|
723
|
+
myDict.values();
|
|
724
|
+
"""
|
|
725
|
+
|
|
726
|
+
def __init__(self, key_type: str = 'dynamic', value_type: str = 'dynamic'):
|
|
727
|
+
super().__init__()
|
|
728
|
+
self._key_type = key_type
|
|
729
|
+
self._value_type = value_type
|
|
730
|
+
|
|
731
|
+
def length(self) -> int:
|
|
732
|
+
"""Return dictionary size"""
|
|
733
|
+
return len(self)
|
|
734
|
+
|
|
735
|
+
def size(self) -> int:
|
|
736
|
+
"""Return dictionary size (alias for length)"""
|
|
737
|
+
return len(self)
|
|
738
|
+
|
|
739
|
+
def isEmpty(self) -> bool:
|
|
740
|
+
"""Check if dictionary is empty"""
|
|
741
|
+
return len(self) == 0
|
|
742
|
+
|
|
743
|
+
def set(self, key: Any, value: Any) -> 'Dictionary':
|
|
744
|
+
"""Set key-value pair"""
|
|
745
|
+
self[key] = value
|
|
746
|
+
return self
|
|
747
|
+
|
|
748
|
+
def hasKey(self, key: Any) -> bool:
|
|
749
|
+
"""Check if key exists"""
|
|
750
|
+
return key in self
|
|
751
|
+
|
|
752
|
+
def hasValue(self, value: Any) -> bool:
|
|
753
|
+
"""Check if value exists"""
|
|
754
|
+
return value in self.values()
|
|
755
|
+
|
|
756
|
+
def remove(self, key: Any) -> Any:
|
|
757
|
+
"""Remove and return value for key"""
|
|
758
|
+
return self.pop(key, None)
|
|
759
|
+
|
|
760
|
+
def getOrDefault(self, key: Any, default: Any = None) -> Any:
|
|
761
|
+
"""Get value or default if not found"""
|
|
762
|
+
return self.get(key, default)
|
|
763
|
+
|
|
764
|
+
def setDefault(self, key: Any, default: Any) -> Any:
|
|
765
|
+
"""Set default if key doesn't exist, return value"""
|
|
766
|
+
if key not in self:
|
|
767
|
+
self[key] = default
|
|
768
|
+
return self[key]
|
|
769
|
+
|
|
770
|
+
def merge(self, other: dict) -> 'Dictionary':
|
|
771
|
+
"""Merge another dictionary into this one"""
|
|
772
|
+
self.update(other)
|
|
773
|
+
return self
|
|
774
|
+
|
|
775
|
+
def keysList(self) -> list:
|
|
776
|
+
"""Return keys as list"""
|
|
777
|
+
return list(self.keys())
|
|
778
|
+
|
|
779
|
+
def valuesList(self) -> list:
|
|
780
|
+
"""Return values as list"""
|
|
781
|
+
return list(self.values())
|
|
782
|
+
|
|
783
|
+
def itemsList(self) -> list:
|
|
784
|
+
"""Return items as list of tuples"""
|
|
785
|
+
return list(self.items())
|
|
786
|
+
|
|
787
|
+
def filter(self, predicate: Callable[[Any, Any], bool]) -> 'Dictionary':
|
|
788
|
+
"""Filter dictionary by predicate(key, value)"""
|
|
789
|
+
result = Dictionary(self._key_type, self._value_type)
|
|
790
|
+
for k, v in self.items():
|
|
791
|
+
if predicate(k, v):
|
|
792
|
+
result[k] = v
|
|
793
|
+
return result
|
|
794
|
+
|
|
795
|
+
def map(self, func: Callable[[Any, Any], Any]) -> 'Dictionary':
|
|
796
|
+
"""Apply function to all values"""
|
|
797
|
+
result = Dictionary(self._key_type, self._value_type)
|
|
798
|
+
for k, v in self.items():
|
|
799
|
+
result[k] = func(k, v)
|
|
800
|
+
return result
|
|
801
|
+
|
|
802
|
+
def forEach(self, func: Callable[[Any, Any], None]) -> 'Dictionary':
|
|
803
|
+
"""Execute function for each key-value pair"""
|
|
804
|
+
for k, v in self.items():
|
|
805
|
+
func(k, v)
|
|
806
|
+
return self
|
|
807
|
+
|
|
808
|
+
def invert(self) -> 'Dictionary':
|
|
809
|
+
"""Swap keys and values"""
|
|
810
|
+
result = Dictionary(self._value_type, self._key_type)
|
|
811
|
+
for k, v in self.items():
|
|
812
|
+
result[v] = k
|
|
813
|
+
return result
|
|
814
|
+
|
|
815
|
+
def find(self, value: Any) -> Optional[Any]:
|
|
816
|
+
"""Find first key with given value"""
|
|
817
|
+
for k, v in self.items():
|
|
818
|
+
if v == value:
|
|
819
|
+
return k
|
|
820
|
+
return None
|
|
821
|
+
|
|
822
|
+
def findAll(self, value: Any) -> list:
|
|
823
|
+
"""Find all keys with given value"""
|
|
824
|
+
return [k for k, v in self.items() if v == value]
|
|
825
|
+
|
|
826
|
+
|
|
549
827
|
class Shuffled(list):
|
|
550
828
|
"""Unorganized fast storage for multiple returns.
|
|
551
829
|
|
|
552
830
|
Stores data unorganized for fast and efficient access.
|
|
553
831
|
Supports receiving multiple return values from functions.
|
|
832
|
+
Can be used as a function modifier to allow multiple returns.
|
|
554
833
|
|
|
555
834
|
Usage:
|
|
556
835
|
shuffled<string> results;
|
|
557
836
|
results +<== someFunc(); # Catches all returns
|
|
558
837
|
results.read() # Returns all content as list
|
|
838
|
+
|
|
839
|
+
# As return modifier:
|
|
840
|
+
shuffled string getData() {
|
|
841
|
+
return "name", "address"; # Returns multiple values
|
|
842
|
+
}
|
|
559
843
|
"""
|
|
560
844
|
|
|
561
845
|
def __init__(self, element_type: str = 'dynamic'):
|
|
@@ -575,6 +859,49 @@ class Shuffled(list):
|
|
|
575
859
|
self.append(result)
|
|
576
860
|
return self
|
|
577
861
|
|
|
862
|
+
def add(self, *items) -> 'Shuffled':
|
|
863
|
+
"""Add one or more items"""
|
|
864
|
+
for item in items:
|
|
865
|
+
if isinstance(item, (list, tuple)):
|
|
866
|
+
self.extend(item)
|
|
867
|
+
else:
|
|
868
|
+
self.append(item)
|
|
869
|
+
return self
|
|
870
|
+
|
|
871
|
+
def first(self) -> Any:
|
|
872
|
+
"""Get first element"""
|
|
873
|
+
return self[0] if self else None
|
|
874
|
+
|
|
875
|
+
def last(self) -> Any:
|
|
876
|
+
"""Get last element"""
|
|
877
|
+
return self[-1] if self else None
|
|
878
|
+
|
|
879
|
+
def length(self) -> int:
|
|
880
|
+
"""Return shuffled length"""
|
|
881
|
+
return len(self)
|
|
882
|
+
|
|
883
|
+
def isEmpty(self) -> bool:
|
|
884
|
+
"""Check if empty"""
|
|
885
|
+
return len(self) == 0
|
|
886
|
+
|
|
887
|
+
def contains(self, item: Any) -> bool:
|
|
888
|
+
"""Check if contains item"""
|
|
889
|
+
return item in self
|
|
890
|
+
|
|
891
|
+
def at(self, index: int) -> Any:
|
|
892
|
+
"""Get item at index"""
|
|
893
|
+
if 0 <= index < len(self):
|
|
894
|
+
return self[index]
|
|
895
|
+
return None
|
|
896
|
+
|
|
897
|
+
def toList(self) -> list:
|
|
898
|
+
"""Convert to plain list"""
|
|
899
|
+
return list(self)
|
|
900
|
+
|
|
901
|
+
def toTuple(self) -> tuple:
|
|
902
|
+
"""Convert to tuple"""
|
|
903
|
+
return tuple(self)
|
|
904
|
+
|
|
578
905
|
|
|
579
906
|
class Iterator:
|
|
580
907
|
"""Advanced iterator with programmable tasks.
|
|
@@ -944,10 +1271,20 @@ def create_array(element_type: str = 'dynamic') -> Array:
|
|
|
944
1271
|
return Array(element_type)
|
|
945
1272
|
|
|
946
1273
|
|
|
1274
|
+
def create_list(element_type: str = 'dynamic') -> List:
|
|
1275
|
+
"""Create a List object"""
|
|
1276
|
+
return List(element_type)
|
|
1277
|
+
|
|
1278
|
+
|
|
1279
|
+
def create_dictionary(key_type: str = 'dynamic', value_type: str = 'dynamic') -> Dictionary:
|
|
1280
|
+
"""Create a Dictionary object"""
|
|
1281
|
+
return Dictionary(key_type, value_type)
|
|
1282
|
+
|
|
1283
|
+
|
|
947
1284
|
__all__ = [
|
|
948
1285
|
'DataStruct', 'Shuffled', 'Iterator', 'Combo', 'DataSpace', 'OpenQuote',
|
|
949
|
-
'OpenFind', 'Parameter', 'Stack', 'Vector', 'Array',
|
|
1286
|
+
'OpenFind', 'Parameter', 'Stack', 'Vector', 'Array', 'List', 'Dictionary',
|
|
950
1287
|
'create_datastruct', 'create_shuffled', 'create_iterator',
|
|
951
1288
|
'create_combo', 'create_dataspace', 'create_openquote', 'create_parameter',
|
|
952
|
-
'create_stack', 'create_vector', 'create_array'
|
|
1289
|
+
'create_stack', 'create_vector', 'create_array', 'create_list', 'create_dictionary'
|
|
953
1290
|
]
|
includecpp/core/cssl_bridge.py
CHANGED
|
@@ -429,7 +429,7 @@ class CsslLang:
|
|
|
429
429
|
runtime._inline_payloads = {}
|
|
430
430
|
runtime._inline_payloads[name] = code
|
|
431
431
|
|
|
432
|
-
def share(self, instance: Any, name: str) -> str:
|
|
432
|
+
def share(self, instance: Any, name: str = None) -> str:
|
|
433
433
|
"""
|
|
434
434
|
Share a Python object instance with CSSL scripts (LIVE sharing).
|
|
435
435
|
|
|
@@ -437,6 +437,14 @@ class CsslLang:
|
|
|
437
437
|
will be reflected in the original Python object immediately.
|
|
438
438
|
Call share() again with the same name to update the shared object.
|
|
439
439
|
|
|
440
|
+
Args:
|
|
441
|
+
instance: The Python object to share (or name if using old API)
|
|
442
|
+
name: The name to reference the object in CSSL ($name)
|
|
443
|
+
|
|
444
|
+
Note: Arguments can be passed in either order:
|
|
445
|
+
cssl.share(my_object, "name") # Preferred
|
|
446
|
+
cssl.share("name", my_object) # Also works
|
|
447
|
+
|
|
440
448
|
Usage in Python:
|
|
441
449
|
from includecpp import CSSL
|
|
442
450
|
cssl = CSSL.CsslLang()
|
|
@@ -474,6 +482,21 @@ class CsslLang:
|
|
|
474
482
|
global _live_objects
|
|
475
483
|
runtime = self._get_runtime()
|
|
476
484
|
|
|
485
|
+
# Handle argument order flexibility: share(instance, name) or share(name, instance)
|
|
486
|
+
if name is None:
|
|
487
|
+
# Only one argument - use object type as name
|
|
488
|
+
name = type(instance).__name__
|
|
489
|
+
elif isinstance(instance, str) and not isinstance(name, str):
|
|
490
|
+
# Arguments are swapped: share("name", instance) -> swap them
|
|
491
|
+
instance, name = name, instance
|
|
492
|
+
elif not isinstance(name, str):
|
|
493
|
+
# name is not a string - use its type as name
|
|
494
|
+
name = type(name).__name__
|
|
495
|
+
|
|
496
|
+
# Sanitize filename: remove invalid characters for Windows
|
|
497
|
+
import re
|
|
498
|
+
safe_name = re.sub(r'[<>:"/\\|?*\x00-\x1f]', '_', str(name))
|
|
499
|
+
|
|
477
500
|
# Initialize shared objects registry
|
|
478
501
|
if not hasattr(runtime, '_shared_objects'):
|
|
479
502
|
runtime._shared_objects = {}
|
|
@@ -481,7 +504,7 @@ class CsslLang:
|
|
|
481
504
|
# Generate unique filename: <name>.shareobj<7digits>
|
|
482
505
|
random_suffix = ''.join([str(random.randint(0, 9)) for _ in range(7)])
|
|
483
506
|
share_dir = _get_share_directory()
|
|
484
|
-
filepath = share_dir / f"{
|
|
507
|
+
filepath = share_dir / f"{safe_name}.shareobj{random_suffix}"
|
|
485
508
|
|
|
486
509
|
# Remove old file if updating
|
|
487
510
|
if name in runtime._shared_objects:
|
|
@@ -577,22 +600,65 @@ class CsslLang:
|
|
|
577
600
|
|
|
578
601
|
return None
|
|
579
602
|
|
|
603
|
+
def shared(self, name: str) -> Optional[Any]:
|
|
604
|
+
"""
|
|
605
|
+
Get a shared object by name (alias for get_shared).
|
|
606
|
+
|
|
607
|
+
Returns the actual live object reference, not a copy.
|
|
608
|
+
Works with both Python cssl.share() and CSSL ==> $name shared objects.
|
|
609
|
+
|
|
610
|
+
Usage:
|
|
611
|
+
from includecpp import CSSL
|
|
612
|
+
cssl = CSSL.CsslLang()
|
|
613
|
+
|
|
614
|
+
# Share an object
|
|
615
|
+
my_obj = {"value": 42}
|
|
616
|
+
cssl.share(my_obj, "data")
|
|
617
|
+
|
|
618
|
+
# Retrieve it later
|
|
619
|
+
obj = cssl.shared("data")
|
|
620
|
+
print(obj["value"]) # 42
|
|
621
|
+
|
|
622
|
+
Args:
|
|
623
|
+
name: Name of the shared object (without $ prefix)
|
|
624
|
+
|
|
625
|
+
Returns:
|
|
626
|
+
The live shared object or None if not found
|
|
627
|
+
"""
|
|
628
|
+
return self.get_shared(name)
|
|
629
|
+
|
|
580
630
|
|
|
581
631
|
# Global shared objects registry (for cross-instance sharing)
|
|
582
632
|
_global_shared_objects: Dict[str, str] = {}
|
|
583
633
|
|
|
584
634
|
|
|
585
|
-
def share(instance: Any, name: str) -> str:
|
|
635
|
+
def share(instance: Any, name: str = None) -> str:
|
|
586
636
|
"""
|
|
587
637
|
Share a Python object globally for all CSSL instances (LIVE sharing).
|
|
588
638
|
|
|
589
639
|
Changes made through CSSL will reflect back to the original object.
|
|
640
|
+
|
|
641
|
+
Args can be passed in either order:
|
|
642
|
+
share(my_object, "name") # Preferred
|
|
643
|
+
share("name", my_object) # Also works
|
|
590
644
|
"""
|
|
591
645
|
global _live_objects
|
|
646
|
+
import re
|
|
647
|
+
|
|
648
|
+
# Handle argument order flexibility
|
|
649
|
+
if name is None:
|
|
650
|
+
name = type(instance).__name__
|
|
651
|
+
elif isinstance(instance, str) and not isinstance(name, str):
|
|
652
|
+
instance, name = name, instance
|
|
653
|
+
elif not isinstance(name, str):
|
|
654
|
+
name = type(name).__name__
|
|
655
|
+
|
|
656
|
+
# Sanitize filename
|
|
657
|
+
safe_name = re.sub(r'[<>:"/\\|?*\x00-\x1f]', '_', str(name))
|
|
592
658
|
|
|
593
659
|
random_suffix = ''.join([str(random.randint(0, 9)) for _ in range(7)])
|
|
594
660
|
share_dir = _get_share_directory()
|
|
595
|
-
filepath = share_dir / f"{
|
|
661
|
+
filepath = share_dir / f"{safe_name}.shareobj{random_suffix}"
|
|
596
662
|
|
|
597
663
|
# Remove old file if updating
|
|
598
664
|
if name in _global_shared_objects:
|
|
@@ -645,6 +711,32 @@ def get_shared(name: str) -> Optional[Any]:
|
|
|
645
711
|
return _live_objects.get(name)
|
|
646
712
|
|
|
647
713
|
|
|
714
|
+
def shared(name: str) -> Optional[Any]:
|
|
715
|
+
"""
|
|
716
|
+
Get a shared object by name (alias for get_shared).
|
|
717
|
+
|
|
718
|
+
Works with both Python share() and CSSL ==> $name shared objects.
|
|
719
|
+
|
|
720
|
+
Usage:
|
|
721
|
+
from includecpp import CSSL
|
|
722
|
+
|
|
723
|
+
# Share an object
|
|
724
|
+
my_obj = {"value": 42}
|
|
725
|
+
CSSL.share(my_obj, "data")
|
|
726
|
+
|
|
727
|
+
# Retrieve it later
|
|
728
|
+
obj = CSSL.shared("data")
|
|
729
|
+
print(obj["value"]) # 42
|
|
730
|
+
|
|
731
|
+
Args:
|
|
732
|
+
name: Name of the shared object (without $ prefix)
|
|
733
|
+
|
|
734
|
+
Returns:
|
|
735
|
+
The live shared object or None if not found
|
|
736
|
+
"""
|
|
737
|
+
return get_shared(name)
|
|
738
|
+
|
|
739
|
+
|
|
648
740
|
# Singleton for convenience
|
|
649
741
|
_default_instance: Optional[CsslLang] = None
|
|
650
742
|
|
|
@@ -783,4 +875,8 @@ __all__ = [
|
|
|
783
875
|
'clear_output',
|
|
784
876
|
'module',
|
|
785
877
|
'makemodule',
|
|
878
|
+
'share',
|
|
879
|
+
'unshare',
|
|
880
|
+
'shared',
|
|
881
|
+
'get_shared',
|
|
786
882
|
]
|