jaclang 0.7.2__py3-none-any.whl → 0.7.8__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.

Potentially problematic release.


This version of jaclang might be problematic. Click here for more details.

Files changed (95) hide show
  1. jaclang/cli/cli.py +2 -2
  2. jaclang/compiler/__init__.py +11 -12
  3. jaclang/compiler/absyntree.py +499 -294
  4. jaclang/compiler/codeloc.py +2 -2
  5. jaclang/compiler/constant.py +100 -2
  6. jaclang/compiler/jac.lark +27 -19
  7. jaclang/compiler/parser.py +119 -92
  8. jaclang/compiler/passes/main/access_modifier_pass.py +20 -12
  9. jaclang/compiler/passes/main/def_impl_match_pass.py +28 -14
  10. jaclang/compiler/passes/main/def_use_pass.py +59 -40
  11. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +65 -43
  12. jaclang/compiler/passes/main/import_pass.py +8 -6
  13. jaclang/compiler/passes/main/pyast_gen_pass.py +97 -42
  14. jaclang/compiler/passes/main/pyast_load_pass.py +47 -12
  15. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +19 -10
  16. jaclang/compiler/passes/main/registry_pass.py +6 -6
  17. jaclang/compiler/passes/main/sub_node_tab_pass.py +0 -5
  18. jaclang/compiler/passes/main/sym_tab_build_pass.py +43 -235
  19. jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +21 -4
  20. jaclang/compiler/passes/main/tests/test_def_use_pass.py +5 -10
  21. jaclang/compiler/passes/main/type_check_pass.py +2 -1
  22. jaclang/compiler/passes/tool/jac_formatter_pass.py +30 -9
  23. jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +16 -0
  24. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +16 -0
  25. jaclang/compiler/passes/tool/tests/fixtures/genai/essay_review.jac +1 -1
  26. jaclang/compiler/passes/tool/tests/fixtures/genai/expert_answer.jac +1 -1
  27. jaclang/compiler/passes/tool/tests/fixtures/genai/joke_gen.jac +1 -1
  28. jaclang/compiler/passes/tool/tests/fixtures/genai/odd_word_out.jac +1 -1
  29. jaclang/compiler/passes/tool/tests/fixtures/genai/personality_finder.jac +1 -1
  30. jaclang/compiler/passes/tool/tests/fixtures/genai/text_to_type.jac +1 -1
  31. jaclang/compiler/passes/tool/tests/fixtures/genai/translator.jac +1 -1
  32. jaclang/compiler/passes/tool/tests/fixtures/genai/wikipedia.jac +1 -1
  33. jaclang/compiler/passes/transform.py +2 -4
  34. jaclang/compiler/passes/utils/mypy_ast_build.py +1 -8
  35. jaclang/{core/registry.py → compiler/semtable.py} +1 -3
  36. jaclang/compiler/symtable.py +142 -101
  37. jaclang/compiler/tests/test_parser.py +2 -2
  38. jaclang/core/{construct.py → architype.py} +25 -240
  39. jaclang/core/constructs.py +44 -0
  40. jaclang/core/context.py +157 -0
  41. jaclang/core/importer.py +18 -9
  42. jaclang/core/memory.py +99 -0
  43. jaclang/core/test.py +90 -0
  44. jaclang/core/utils.py +2 -2
  45. jaclang/langserve/engine.py +127 -50
  46. jaclang/langserve/server.py +34 -61
  47. jaclang/langserve/tests/fixtures/base_module_structure.jac +28 -0
  48. jaclang/langserve/tests/fixtures/circle.jac +16 -12
  49. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  50. jaclang/langserve/tests/fixtures/circle_pure.test.jac +15 -0
  51. jaclang/langserve/tests/fixtures/import_include_statements.jac +6 -0
  52. jaclang/langserve/tests/fixtures/py_import.py +26 -0
  53. jaclang/langserve/tests/test_server.py +93 -18
  54. jaclang/langserve/utils.py +124 -10
  55. jaclang/plugin/builtin.py +1 -1
  56. jaclang/plugin/default.py +25 -77
  57. jaclang/plugin/feature.py +25 -7
  58. jaclang/plugin/spec.py +18 -20
  59. jaclang/settings.py +3 -0
  60. jaclang/tests/fixtures/abc.jac +16 -12
  61. jaclang/tests/fixtures/aott_raise.jac +1 -1
  62. jaclang/tests/fixtures/byllmissue.jac +9 -0
  63. jaclang/tests/fixtures/edgetypeissue.jac +10 -0
  64. jaclang/tests/fixtures/hello.jac +1 -1
  65. jaclang/tests/fixtures/impl_match_confused.impl.jac +1 -0
  66. jaclang/tests/fixtures/impl_match_confused.jac +5 -0
  67. jaclang/tests/fixtures/maxfail_run_test.jac +17 -5
  68. jaclang/tests/fixtures/run_test.jac +17 -5
  69. jaclang/tests/test_bugs.py +19 -0
  70. jaclang/tests/test_cli.py +1 -1
  71. jaclang/tests/test_language.py +65 -100
  72. jaclang/tests/test_reference.py +1 -1
  73. jaclang/utils/lang_tools.py +5 -4
  74. jaclang/utils/test.py +2 -1
  75. jaclang/utils/treeprinter.py +22 -8
  76. {jaclang-0.7.2.dist-info → jaclang-0.7.8.dist-info}/METADATA +1 -1
  77. {jaclang-0.7.2.dist-info → jaclang-0.7.8.dist-info}/RECORD +79 -83
  78. jaclang/core/aott.py +0 -310
  79. jaclang/core/llms/__init__.py +0 -20
  80. jaclang/core/llms/anthropic.py +0 -90
  81. jaclang/core/llms/base.py +0 -206
  82. jaclang/core/llms/groq.py +0 -70
  83. jaclang/core/llms/huggingface.py +0 -76
  84. jaclang/core/llms/ollama.py +0 -81
  85. jaclang/core/llms/openai.py +0 -65
  86. jaclang/core/llms/togetherai.py +0 -63
  87. jaclang/core/llms/utils.py +0 -9
  88. jaclang/tests/fixtures/math_question.jpg +0 -0
  89. jaclang/tests/fixtures/with_llm_function.jac +0 -33
  90. jaclang/tests/fixtures/with_llm_lower.jac +0 -45
  91. jaclang/tests/fixtures/with_llm_method.jac +0 -51
  92. jaclang/tests/fixtures/with_llm_type.jac +0 -52
  93. jaclang/tests/fixtures/with_llm_vision.jac +0 -25
  94. {jaclang-0.7.2.dist-info → jaclang-0.7.8.dist-info}/WHEEL +0 -0
  95. {jaclang-0.7.2.dist-info → jaclang-0.7.8.dist-info}/entry_points.txt +0 -0
@@ -2,16 +2,13 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import shelve
6
- import unittest
7
- from contextvars import ContextVar
5
+ import types
8
6
  from dataclasses import dataclass, field
9
- from typing import Callable, Optional
7
+ from typing import Any, Callable, Optional
10
8
  from uuid import UUID, uuid4
11
9
 
12
10
  from jaclang.compiler.constant import EdgeDir
13
11
  from jaclang.core.utils import collect_node_connections
14
- from jaclang.plugin.spec import DSFunc
15
12
 
16
13
 
17
14
  @dataclass(eq=False)
@@ -232,7 +229,13 @@ class WalkerAnchor(ObjectAnchor):
232
229
 
233
230
  def visit_node(
234
231
  self,
235
- nds: list[NodeArchitype | EdgeArchitype] | NodeArchitype | EdgeArchitype,
232
+ nds: (
233
+ list[NodeArchitype | EdgeArchitype]
234
+ | list[NodeArchitype]
235
+ | list[EdgeArchitype]
236
+ | NodeArchitype
237
+ | EdgeArchitype
238
+ ),
236
239
  ) -> bool:
237
240
  """Walker visits node."""
238
241
  nd_list: list[NodeArchitype | EdgeArchitype]
@@ -254,7 +257,13 @@ class WalkerAnchor(ObjectAnchor):
254
257
 
255
258
  def ignore_node(
256
259
  self,
257
- nds: list[NodeArchitype | EdgeArchitype] | NodeArchitype | EdgeArchitype,
260
+ nds: (
261
+ list[NodeArchitype | EdgeArchitype]
262
+ | list[NodeArchitype]
263
+ | list[EdgeArchitype]
264
+ | NodeArchitype
265
+ | EdgeArchitype
266
+ ),
258
267
  ) -> bool:
259
268
  """Walker ignores node."""
260
269
  nd_list: list[NodeArchitype | EdgeArchitype]
@@ -480,238 +489,14 @@ class Root(NodeArchitype):
480
489
  self._jac_.edges = []
481
490
 
482
491
 
483
- class Memory:
484
- """Memory module interface."""
485
-
486
- mem: dict[UUID, Architype] = {}
487
- save_obj_list: dict[UUID, Architype] = {}
488
-
489
- def __init__(self) -> None:
490
- """init."""
491
- pass
492
-
493
- def get_obj(self, obj_id: UUID) -> Architype | None:
494
- """Get object from memory."""
495
- return self.get_obj_from_store(obj_id)
496
-
497
- def get_obj_from_store(self, obj_id: UUID) -> Architype | None:
498
- """Get object from the underlying store."""
499
- ret = self.mem.get(obj_id)
500
- return ret
501
-
502
- def has_obj(self, obj_id: UUID) -> bool:
503
- """Check if the object exists."""
504
- return self.has_obj_in_store(obj_id)
505
-
506
- def has_obj_in_store(self, obj_id: UUID) -> bool:
507
- """Check if the object exists in the underlying store."""
508
- return obj_id in self.mem
509
-
510
- def save_obj(self, item: Architype, persistent: bool) -> None:
511
- """Save object."""
512
- self.mem[item._jac_.id] = item
513
- if persistent:
514
- # TODO: check if it needs to be saved, i.e. dirty or not
515
- self.save_obj_list[item._jac_.id] = item
516
-
517
- def commit(self) -> None:
518
- """Commit changes to persistent storage, if applicable."""
519
- pass
520
-
521
- def close(self) -> None:
522
- """Close any connection, if applicable."""
523
- self.mem.clear()
524
-
525
-
526
- class ShelveStorage(Memory):
527
- """Shelve storage for jaclang runtime object."""
528
-
529
- storage: shelve.Shelf | None = None
530
-
531
- def __init__(self, session: str = "") -> None:
532
- """Init shelve storage."""
533
- super().__init__()
534
- if session:
535
- self.connect(session)
536
-
537
- def get_obj_from_store(self, obj_id: UUID) -> Architype | None:
538
- """Get object from the underlying store."""
539
- obj = super().get_obj_from_store(obj_id)
540
- if obj is None and self.storage:
541
- obj = self.storage.get(str(obj_id))
542
- if obj is not None:
543
- self.mem[obj_id] = obj
544
-
545
- return obj
546
-
547
- def has_obj_in_store(self, obj_id: UUID | str) -> bool:
548
- """Check if the object exists in the underlying store."""
549
- return obj_id in self.mem or (
550
- str(obj_id) in self.storage if self.storage else False
551
- )
552
-
553
- def commit(self) -> None:
554
- """Commit changes to persistent storage."""
555
- if self.storage is not None:
556
- for obj_id, obj in self.save_obj_list.items():
557
- self.storage[str(obj_id)] = obj
558
- self.save_obj_list.clear()
559
-
560
- def connect(self, session: str) -> None:
561
- """Connect to storage."""
562
- self.session = session
563
- self.storage = shelve.open(session)
564
-
565
- def close(self) -> None:
566
- """Close the storage."""
567
- super().close()
568
- self.commit()
569
- if self.storage:
570
- self.storage.close()
571
- self.storage = None
572
-
573
-
574
- class ExecutionContext:
575
- """Default Execution Context implementation."""
576
-
577
- mem: Optional[Memory]
578
- root: Optional[Root]
579
-
580
- def __init__(self) -> None:
581
- """Create execution context."""
582
- super().__init__()
583
- self.mem = ShelveStorage()
584
- self.root = None
585
-
586
- def init_memory(self, session: str = "") -> None:
587
- """Initialize memory."""
588
- if session:
589
- self.mem = ShelveStorage(session)
590
- else:
591
- self.mem = Memory()
592
-
593
- def get_root(self) -> Root:
594
- """Get the root object."""
595
- if self.mem is None:
596
- raise ValueError("Memory not initialized")
597
-
598
- if not self.root:
599
- root = self.mem.get_obj(UUID(int=0))
600
- if root is None:
601
- self.root = Root()
602
- self.mem.save_obj(self.root, persistent=self.root._jac_.persistent)
603
- elif not isinstance(root, Root):
604
- raise ValueError(f"Invalid root object: {root}")
605
- else:
606
- self.root = root
607
- return self.root
608
-
609
- def get_obj(self, obj_id: UUID) -> Architype | None:
610
- """Get object from memory."""
611
- if self.mem is None:
612
- raise ValueError("Memory not initialized")
613
-
614
- return self.mem.get_obj(obj_id)
615
-
616
- def save_obj(self, item: Architype, persistent: bool) -> None:
617
- """Save object to memory."""
618
- if self.mem is None:
619
- raise ValueError("Memory not initialized")
620
-
621
- self.mem.save_obj(item, persistent)
622
-
623
- def reset(self) -> None:
624
- """Reset the execution context."""
625
- if self.mem:
626
- self.mem.close()
627
- self.mem = None
628
- self.root = None
629
-
630
-
631
- exec_context: ContextVar[ExecutionContext | None] = ContextVar(
632
- "ExecutionContext", default=None
633
- )
634
-
635
-
636
- class JacTestResult(unittest.TextTestResult):
637
- """Jac test result class."""
638
-
639
- def __init__(
640
- self,
641
- stream, # noqa
642
- descriptions, # noqa
643
- verbosity: int,
644
- max_failures: Optional[int] = None,
645
- ) -> None:
646
- """Initialize FailFastTestResult object."""
647
- super().__init__(stream, descriptions, verbosity) # noqa
648
- self.failures_count = JacTestCheck.failcount
649
- self.max_failures = max_failures
650
-
651
- def addFailure(self, test, err) -> None: # noqa
652
- """Count failures and stop."""
653
- super().addFailure(test, err)
654
- self.failures_count += 1
655
- if self.max_failures is not None and self.failures_count >= self.max_failures:
656
- self.stop()
657
-
658
- def stop(self) -> None:
659
- """Stop the test execution."""
660
- self.shouldStop = True
661
-
662
-
663
- class JacTextTestRunner(unittest.TextTestRunner):
664
- """Jac test runner class."""
665
-
666
- def __init__(self, max_failures: Optional[int] = None, **kwargs) -> None: # noqa
667
- """Initialize JacTextTestRunner object."""
668
- self.max_failures = max_failures
669
- super().__init__(**kwargs)
670
-
671
- def _makeResult(self) -> JacTestResult: # noqa
672
- """Override the method to return an instance of JacTestResult."""
673
- return JacTestResult(
674
- self.stream,
675
- self.descriptions,
676
- self.verbosity,
677
- max_failures=self.max_failures,
678
- )
679
-
680
-
681
- class JacTestCheck:
682
- """Jac Testing and Checking."""
683
-
684
- test_case = unittest.TestCase()
685
- test_suite = unittest.TestSuite()
686
- breaker = False
687
- failcount = 0
688
-
689
- @staticmethod
690
- def reset() -> None:
691
- """Clear the test suite."""
692
- JacTestCheck.test_case = unittest.TestCase()
693
- JacTestCheck.test_suite = unittest.TestSuite()
694
-
695
- @staticmethod
696
- def run_test(xit: bool, maxfail: int | None, verbose: bool) -> None:
697
- """Run the test suite."""
698
- verb = 2 if verbose else 1
699
- runner = JacTextTestRunner(max_failures=maxfail, failfast=xit, verbosity=verb)
700
- result = runner.run(JacTestCheck.test_suite)
701
- if result.wasSuccessful():
702
- print("Passed successfully.")
703
- else:
704
- fails = len(result.failures)
705
- JacTestCheck.failcount += fails
706
- JacTestCheck.breaker = (
707
- (JacTestCheck.failcount >= maxfail) if maxfail else True
708
- )
492
+ @dataclass(eq=False)
493
+ class DSFunc:
494
+ """Data Spatial Function."""
709
495
 
710
- @staticmethod
711
- def add_test(test_fun: Callable) -> None:
712
- """Create a new test."""
713
- JacTestCheck.test_suite.addTest(unittest.FunctionTestCase(test_fun))
496
+ name: str
497
+ trigger: type | types.UnionType | tuple[type | types.UnionType, ...] | None
498
+ func: Callable[[Any, Any], Any] | None = None
714
499
 
715
- def __getattr__(self, name: str) -> object:
716
- """Make convenient check.Equal(...) etc."""
717
- return getattr(JacTestCheck.test_case, name)
500
+ def resolve(self, cls: type) -> None:
501
+ """Resolve the function."""
502
+ self.func = getattr(cls, self.name)
@@ -0,0 +1,44 @@
1
+ """Core constructs for Jac Language."""
2
+
3
+ from __future__ import annotations
4
+
5
+
6
+ from .architype import (
7
+ Architype,
8
+ DSFunc,
9
+ EdgeAnchor,
10
+ EdgeArchitype,
11
+ ElementAnchor,
12
+ GenericEdge,
13
+ NodeAnchor,
14
+ NodeArchitype,
15
+ ObjectAnchor,
16
+ Root,
17
+ WalkerAnchor,
18
+ WalkerArchitype,
19
+ )
20
+ from .context import ExecutionContext, exec_context
21
+ from .memory import Memory, ShelveStorage
22
+ from .test import JacTestCheck, JacTestResult, JacTextTestRunner
23
+
24
+ __all__ = [
25
+ "ElementAnchor",
26
+ "ObjectAnchor",
27
+ "NodeAnchor",
28
+ "EdgeAnchor",
29
+ "WalkerAnchor",
30
+ "Architype",
31
+ "NodeArchitype",
32
+ "EdgeArchitype",
33
+ "WalkerArchitype",
34
+ "GenericEdge",
35
+ "Root",
36
+ "DSFunc",
37
+ "Memory",
38
+ "ShelveStorage",
39
+ "ExecutionContext",
40
+ "exec_context",
41
+ "JacTestResult",
42
+ "JacTextTestRunner",
43
+ "JacTestCheck",
44
+ ]
@@ -0,0 +1,157 @@
1
+ """Core constructs for Jac Language."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import unittest
6
+ from contextvars import ContextVar
7
+ from typing import Callable, Optional
8
+ from uuid import UUID
9
+
10
+ from .architype import Architype, Root
11
+ from .memory import Memory, ShelveStorage
12
+
13
+
14
+ class ExecutionContext:
15
+ """Default Execution Context implementation."""
16
+
17
+ mem: Optional[Memory]
18
+ root: Optional[Root]
19
+
20
+ def __init__(self) -> None:
21
+ """Create execution context."""
22
+ super().__init__()
23
+ self.mem = ShelveStorage()
24
+ self.root = None
25
+
26
+ def init_memory(self, session: str = "") -> None:
27
+ """Initialize memory."""
28
+ if session:
29
+ self.mem = ShelveStorage(session)
30
+ else:
31
+ self.mem = Memory()
32
+
33
+ def get_root(self) -> Root:
34
+ """Get the root object."""
35
+ if self.mem is None:
36
+ raise ValueError("Memory not initialized")
37
+
38
+ if not self.root:
39
+ root = self.mem.get_obj(UUID(int=0))
40
+ if root is None:
41
+ self.root = Root()
42
+ self.mem.save_obj(self.root, persistent=self.root._jac_.persistent)
43
+ elif not isinstance(root, Root):
44
+ raise ValueError(f"Invalid root object: {root}")
45
+ else:
46
+ self.root = root
47
+ return self.root
48
+
49
+ def get_obj(self, obj_id: UUID) -> Architype | None:
50
+ """Get object from memory."""
51
+ if self.mem is None:
52
+ raise ValueError("Memory not initialized")
53
+
54
+ return self.mem.get_obj(obj_id)
55
+
56
+ def save_obj(self, item: Architype, persistent: bool) -> None:
57
+ """Save object to memory."""
58
+ if self.mem is None:
59
+ raise ValueError("Memory not initialized")
60
+
61
+ self.mem.save_obj(item, persistent)
62
+
63
+ def reset(self) -> None:
64
+ """Reset the execution context."""
65
+ if self.mem:
66
+ self.mem.close()
67
+ self.mem = None
68
+ self.root = None
69
+
70
+
71
+ exec_context: ContextVar[ExecutionContext | None] = ContextVar(
72
+ "ExecutionContext", default=None
73
+ )
74
+
75
+
76
+ class JacTestResult(unittest.TextTestResult):
77
+ """Jac test result class."""
78
+
79
+ def __init__(
80
+ self,
81
+ stream, # noqa
82
+ descriptions, # noqa
83
+ verbosity: int,
84
+ max_failures: Optional[int] = None,
85
+ ) -> None:
86
+ """Initialize FailFastTestResult object."""
87
+ super().__init__(stream, descriptions, verbosity) # noqa
88
+ self.failures_count = JacTestCheck.failcount
89
+ self.max_failures = max_failures
90
+
91
+ def addFailure(self, test, err) -> None: # noqa
92
+ """Count failures and stop."""
93
+ super().addFailure(test, err)
94
+ self.failures_count += 1
95
+ if self.max_failures is not None and self.failures_count >= self.max_failures:
96
+ self.stop()
97
+
98
+ def stop(self) -> None:
99
+ """Stop the test execution."""
100
+ self.shouldStop = True
101
+
102
+
103
+ class JacTextTestRunner(unittest.TextTestRunner):
104
+ """Jac test runner class."""
105
+
106
+ def __init__(self, max_failures: Optional[int] = None, **kwargs) -> None: # noqa
107
+ """Initialize JacTextTestRunner object."""
108
+ self.max_failures = max_failures
109
+ super().__init__(**kwargs)
110
+
111
+ def _makeResult(self) -> JacTestResult: # noqa
112
+ """Override the method to return an instance of JacTestResult."""
113
+ return JacTestResult(
114
+ self.stream,
115
+ self.descriptions,
116
+ self.verbosity,
117
+ max_failures=self.max_failures,
118
+ )
119
+
120
+
121
+ class JacTestCheck:
122
+ """Jac Testing and Checking."""
123
+
124
+ test_case = unittest.TestCase()
125
+ test_suite = unittest.TestSuite()
126
+ breaker = False
127
+ failcount = 0
128
+
129
+ @staticmethod
130
+ def reset() -> None:
131
+ """Clear the test suite."""
132
+ JacTestCheck.test_case = unittest.TestCase()
133
+ JacTestCheck.test_suite = unittest.TestSuite()
134
+
135
+ @staticmethod
136
+ def run_test(xit: bool, maxfail: int | None, verbose: bool) -> None:
137
+ """Run the test suite."""
138
+ verb = 2 if verbose else 1
139
+ runner = JacTextTestRunner(max_failures=maxfail, failfast=xit, verbosity=verb)
140
+ result = runner.run(JacTestCheck.test_suite)
141
+ if result.wasSuccessful():
142
+ print("Passed successfully.")
143
+ else:
144
+ fails = len(result.failures)
145
+ JacTestCheck.failcount += fails
146
+ JacTestCheck.breaker = (
147
+ (JacTestCheck.failcount >= maxfail) if maxfail else True
148
+ )
149
+
150
+ @staticmethod
151
+ def add_test(test_fun: Callable) -> None:
152
+ """Create a new test."""
153
+ JacTestCheck.test_suite.addTest(unittest.FunctionTestCase(test_fun))
154
+
155
+ def __getattr__(self, name: str) -> object:
156
+ """Make convenient check.Equal(...) etc."""
157
+ return getattr(JacTestCheck.test_case, name)
jaclang/core/importer.py CHANGED
@@ -11,7 +11,6 @@ from jaclang.compiler.absyntree import Module
11
11
  from jaclang.compiler.compile import compile_jac
12
12
  from jaclang.compiler.constant import Constants as Con
13
13
  from jaclang.core.utils import sys_path_context
14
- from jaclang.utils.log import logging
15
14
 
16
15
 
17
16
  def jac_importer(
@@ -21,7 +20,7 @@ def jac_importer(
21
20
  cachable: bool = True,
22
21
  mdl_alias: Optional[str] = None,
23
22
  override_name: Optional[str] = None,
24
- mod_bundle: Optional[Module] = None,
23
+ mod_bundle: Optional[Module | str] = None,
25
24
  lng: Optional[str] = "jac",
26
25
  items: Optional[dict[str, Union[str, bool]]] = None,
27
26
  ) -> Optional[types.ModuleType]:
@@ -41,6 +40,14 @@ def jac_importer(
41
40
  elif not override_name and not package_path and module_name in sys.modules:
42
41
  return sys.modules[module_name]
43
42
 
43
+ valid_mod_bundle = (
44
+ sys.modules[mod_bundle].__jac_mod_bundle__
45
+ if isinstance(mod_bundle, str)
46
+ and mod_bundle in sys.modules
47
+ and "__jac_mod_bundle__" in sys.modules[mod_bundle].__dict__
48
+ else None
49
+ )
50
+
44
51
  caller_dir = get_caller_dir(target, base_path, dir_path)
45
52
  full_target = path.normpath(path.join(caller_dir, file_name))
46
53
 
@@ -51,10 +58,10 @@ def jac_importer(
51
58
  else:
52
59
  module_name = override_name if override_name else module_name
53
60
  module = create_jac_py_module(
54
- mod_bundle, module_name, package_path, full_target
61
+ valid_mod_bundle, module_name, package_path, full_target
55
62
  )
56
- if mod_bundle:
57
- codeobj = mod_bundle.mod_deps[full_target].gen.py_bytecode
63
+ if valid_mod_bundle:
64
+ codeobj = valid_mod_bundle.mod_deps[full_target].gen.py_bytecode
58
65
  codeobj = marshal.loads(codeobj) if isinstance(codeobj, bytes) else None
59
66
  else:
60
67
  gen_dir = path.join(caller_dir, Con.JAC_GEN_DIR)
@@ -69,9 +76,8 @@ def jac_importer(
69
76
  else:
70
77
  result = compile_jac(full_target, cache_result=cachable)
71
78
  if result.errors_had or not result.ir.gen.py_bytecode:
72
- for e in result.errors_had:
73
- print(e)
74
- logging.error(e)
79
+ # for e in result.errors_had:
80
+ # print(e)
75
81
  return None
76
82
  else:
77
83
  codeobj = marshal.loads(result.ir.gen.py_bytecode)
@@ -84,7 +90,10 @@ def jac_importer(
84
90
 
85
91
 
86
92
  def create_jac_py_module(
87
- mod_bundle: Optional[Module], module_name: str, package_path: str, full_target: str
93
+ mod_bundle: Optional[Module | str],
94
+ module_name: str,
95
+ package_path: str,
96
+ full_target: str,
88
97
  ) -> types.ModuleType:
89
98
  """Create a module."""
90
99
  module = types.ModuleType(module_name)
jaclang/core/memory.py ADDED
@@ -0,0 +1,99 @@
1
+ """Core constructs for Jac Language."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import shelve
6
+ from uuid import UUID
7
+
8
+ from .architype import Architype
9
+
10
+
11
+ class Memory:
12
+ """Memory module interface."""
13
+
14
+ mem: dict[UUID, Architype] = {}
15
+ save_obj_list: dict[UUID, Architype] = {}
16
+
17
+ def __init__(self) -> None:
18
+ """init."""
19
+ pass
20
+
21
+ def get_obj(self, obj_id: UUID) -> Architype | None:
22
+ """Get object from memory."""
23
+ return self.get_obj_from_store(obj_id)
24
+
25
+ def get_obj_from_store(self, obj_id: UUID) -> Architype | None:
26
+ """Get object from the underlying store."""
27
+ ret = self.mem.get(obj_id)
28
+ return ret
29
+
30
+ def has_obj(self, obj_id: UUID) -> bool:
31
+ """Check if the object exists."""
32
+ return self.has_obj_in_store(obj_id)
33
+
34
+ def has_obj_in_store(self, obj_id: UUID) -> bool:
35
+ """Check if the object exists in the underlying store."""
36
+ return obj_id in self.mem
37
+
38
+ def save_obj(self, item: Architype, persistent: bool) -> None:
39
+ """Save object."""
40
+ self.mem[item._jac_.id] = item
41
+ if persistent:
42
+ # TODO: check if it needs to be saved, i.e. dirty or not
43
+ self.save_obj_list[item._jac_.id] = item
44
+
45
+ def commit(self) -> None:
46
+ """Commit changes to persistent storage, if applicable."""
47
+ pass
48
+
49
+ def close(self) -> None:
50
+ """Close any connection, if applicable."""
51
+ self.mem.clear()
52
+
53
+
54
+ class ShelveStorage(Memory):
55
+ """Shelve storage for jaclang runtime object."""
56
+
57
+ storage: shelve.Shelf | None = None
58
+
59
+ def __init__(self, session: str = "") -> None:
60
+ """Init shelve storage."""
61
+ super().__init__()
62
+ if session:
63
+ self.connect(session)
64
+
65
+ def get_obj_from_store(self, obj_id: UUID) -> Architype | None:
66
+ """Get object from the underlying store."""
67
+ obj = super().get_obj_from_store(obj_id)
68
+ if obj is None and self.storage:
69
+ obj = self.storage.get(str(obj_id))
70
+ if obj is not None:
71
+ self.mem[obj_id] = obj
72
+
73
+ return obj
74
+
75
+ def has_obj_in_store(self, obj_id: UUID | str) -> bool:
76
+ """Check if the object exists in the underlying store."""
77
+ return obj_id in self.mem or (
78
+ str(obj_id) in self.storage if self.storage else False
79
+ )
80
+
81
+ def commit(self) -> None:
82
+ """Commit changes to persistent storage."""
83
+ if self.storage is not None:
84
+ for obj_id, obj in self.save_obj_list.items():
85
+ self.storage[str(obj_id)] = obj
86
+ self.save_obj_list.clear()
87
+
88
+ def connect(self, session: str) -> None:
89
+ """Connect to storage."""
90
+ self.session = session
91
+ self.storage = shelve.open(session)
92
+
93
+ def close(self) -> None:
94
+ """Close the storage."""
95
+ super().close()
96
+ self.commit()
97
+ if self.storage:
98
+ self.storage.close()
99
+ self.storage = None