jaclang 0.7.1__py3-none-any.whl → 0.7.7__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 (106) hide show
  1. jaclang/cli/cli.py +2 -2
  2. jaclang/compiler/absyntree.py +539 -297
  3. jaclang/compiler/codeloc.py +2 -2
  4. jaclang/compiler/constant.py +100 -2
  5. jaclang/compiler/jac.lark +27 -19
  6. jaclang/compiler/parser.py +119 -92
  7. jaclang/compiler/passes/main/access_modifier_pass.py +20 -12
  8. jaclang/compiler/passes/main/def_impl_match_pass.py +32 -12
  9. jaclang/compiler/passes/main/def_use_pass.py +59 -40
  10. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +71 -30
  11. jaclang/compiler/passes/main/import_pass.py +12 -7
  12. jaclang/compiler/passes/main/pyast_gen_pass.py +110 -47
  13. jaclang/compiler/passes/main/pyast_load_pass.py +49 -13
  14. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +25 -11
  15. jaclang/compiler/passes/main/pyout_pass.py +3 -1
  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/tests/test_import_pass.py +8 -0
  22. jaclang/compiler/passes/main/tests/test_type_check_pass.py +1 -1
  23. jaclang/compiler/passes/main/type_check_pass.py +2 -1
  24. jaclang/compiler/passes/tool/jac_formatter_pass.py +44 -11
  25. jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +16 -0
  26. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +16 -0
  27. jaclang/compiler/passes/tool/tests/fixtures/doc_string.jac +15 -0
  28. jaclang/compiler/passes/tool/tests/fixtures/genai/essay_review.jac +1 -1
  29. jaclang/compiler/passes/tool/tests/fixtures/genai/expert_answer.jac +1 -1
  30. jaclang/compiler/passes/tool/tests/fixtures/genai/joke_gen.jac +1 -1
  31. jaclang/compiler/passes/tool/tests/fixtures/genai/odd_word_out.jac +1 -1
  32. jaclang/compiler/passes/tool/tests/fixtures/genai/personality_finder.jac +1 -1
  33. jaclang/compiler/passes/tool/tests/fixtures/genai/text_to_type.jac +1 -1
  34. jaclang/compiler/passes/tool/tests/fixtures/genai/translator.jac +1 -1
  35. jaclang/compiler/passes/tool/tests/fixtures/genai/wikipedia.jac +1 -1
  36. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +7 -5
  37. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +1 -2
  38. jaclang/compiler/passes/transform.py +2 -4
  39. jaclang/{core/registry.py → compiler/semtable.py} +1 -3
  40. jaclang/compiler/symtable.py +150 -89
  41. jaclang/compiler/tests/test_parser.py +2 -2
  42. jaclang/core/aott.py +118 -18
  43. jaclang/core/{construct.py → architype.py} +44 -93
  44. jaclang/core/constructs.py +44 -0
  45. jaclang/core/context.py +157 -0
  46. jaclang/core/importer.py +18 -9
  47. jaclang/core/memory.py +53 -2
  48. jaclang/core/test.py +90 -0
  49. jaclang/core/utils.py +2 -2
  50. jaclang/langserve/engine.py +199 -138
  51. jaclang/langserve/server.py +48 -53
  52. jaclang/langserve/tests/fixtures/base_module_structure.jac +28 -0
  53. jaclang/langserve/tests/fixtures/circle.jac +16 -12
  54. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  55. jaclang/langserve/tests/fixtures/circle_pure.impl.jac +8 -4
  56. jaclang/langserve/tests/fixtures/circle_pure.jac +2 -2
  57. jaclang/langserve/tests/fixtures/circle_pure.test.jac +15 -0
  58. jaclang/langserve/tests/fixtures/import_include_statements.jac +6 -0
  59. jaclang/langserve/tests/fixtures/py_import.py +26 -0
  60. jaclang/langserve/tests/test_server.py +200 -2
  61. jaclang/langserve/utils.py +214 -10
  62. jaclang/plugin/builtin.py +1 -1
  63. jaclang/plugin/default.py +48 -92
  64. jaclang/plugin/feature.py +33 -17
  65. jaclang/plugin/spec.py +18 -20
  66. jaclang/plugin/tests/test_features.py +0 -33
  67. jaclang/settings.py +4 -0
  68. jaclang/tests/fixtures/abc.jac +16 -12
  69. jaclang/tests/fixtures/aott_raise.jac +1 -1
  70. jaclang/tests/fixtures/byllmissue.jac +12 -0
  71. jaclang/tests/fixtures/edgetypeissue.jac +10 -0
  72. jaclang/tests/fixtures/hash_init_check.jac +17 -0
  73. jaclang/tests/fixtures/hello.jac +1 -1
  74. jaclang/tests/fixtures/impl_match_confused.impl.jac +1 -0
  75. jaclang/tests/fixtures/impl_match_confused.jac +5 -0
  76. jaclang/tests/fixtures/math_question.jpg +0 -0
  77. jaclang/tests/fixtures/maxfail_run_test.jac +17 -5
  78. jaclang/tests/fixtures/nosigself.jac +19 -0
  79. jaclang/tests/fixtures/run_test.jac +17 -5
  80. jaclang/tests/fixtures/walker_override.jac +21 -0
  81. jaclang/tests/fixtures/with_llm_function.jac +1 -1
  82. jaclang/tests/fixtures/with_llm_lower.jac +1 -1
  83. jaclang/tests/fixtures/with_llm_method.jac +1 -1
  84. jaclang/tests/fixtures/with_llm_type.jac +1 -1
  85. jaclang/tests/fixtures/with_llm_vision.jac +25 -0
  86. jaclang/tests/test_bugs.py +19 -0
  87. jaclang/tests/test_cli.py +1 -1
  88. jaclang/tests/test_language.py +197 -82
  89. jaclang/tests/test_reference.py +1 -1
  90. jaclang/utils/lang_tools.py +5 -4
  91. jaclang/utils/test.py +2 -1
  92. jaclang/utils/treeprinter.py +35 -4
  93. {jaclang-0.7.1.dist-info → jaclang-0.7.7.dist-info}/METADATA +3 -2
  94. {jaclang-0.7.1.dist-info → jaclang-0.7.7.dist-info}/RECORD +96 -88
  95. jaclang/core/llms/__init__.py +0 -20
  96. jaclang/core/llms/anthropic.py +0 -61
  97. jaclang/core/llms/base.py +0 -206
  98. jaclang/core/llms/groq.py +0 -67
  99. jaclang/core/llms/huggingface.py +0 -73
  100. jaclang/core/llms/ollama.py +0 -78
  101. jaclang/core/llms/openai.py +0 -61
  102. jaclang/core/llms/togetherai.py +0 -60
  103. jaclang/core/llms/utils.py +0 -9
  104. jaclang/core/shelve_storage.py +0 -55
  105. {jaclang-0.7.1.dist-info → jaclang-0.7.7.dist-info}/WHEEL +0 -0
  106. {jaclang-0.7.1.dist-info → jaclang-0.7.7.dist-info}/entry_points.txt +0 -0
jaclang/core/aott.py CHANGED
@@ -4,18 +4,34 @@ AOTT: Automated Operational Type Transformation.
4
4
  This has all the necessary functions to perform the AOTT operations.
5
5
  """
6
6
 
7
+ import base64
8
+ import logging
7
9
  import re
8
10
  from enum import Enum
11
+ from io import BytesIO
9
12
  from typing import Any
10
13
 
11
- from jaclang.core.llms.base import BaseLLM
12
- from jaclang.core.registry import SemInfo, SemRegistry, SemScope
14
+
15
+ try:
16
+ from PIL import Image
17
+ except ImportError:
18
+ Image = None
19
+
20
+ from jaclang.compiler.semtable import SemInfo, SemRegistry, SemScope
21
+
22
+ try:
23
+ from mtllm.llms import BaseLLM
24
+ except ImportError:
25
+ BaseLLM = None
26
+
27
+
28
+ IMG_FORMATS = ["PngImageFile", "JpegImageFile"]
13
29
 
14
30
 
15
31
  def aott_raise(
16
- model: BaseLLM,
32
+ model: BaseLLM, # type: ignore
17
33
  information: str,
18
- inputs_information: str,
34
+ inputs_information: str | list[dict],
19
35
  output_information: str,
20
36
  type_explanations: str,
21
37
  action: str,
@@ -25,18 +41,43 @@ def aott_raise(
25
41
  model_params: dict,
26
42
  ) -> str:
27
43
  """AOTT Raise uses the information (Meanings types values) provided to generate a prompt(meaning in)."""
44
+ system_prompt = model.MTLLM_SYSTEM_PROMPT
45
+ meaning_in: str | list[dict]
28
46
  if method != "ReAct":
29
- system_prompt = model.MTLLM_SYSTEM_PROMPT
30
- mtllm_prompt = model.MTLLM_PROMPT.format(
31
- information=information,
32
- inputs_information=inputs_information,
33
- output_information=output_information,
34
- type_explanations=type_explanations,
35
- action=action,
36
- context=context,
37
- )
38
47
  method_prompt = model.MTLLM_METHOD_PROMPTS[method]
39
- meaning_in = f"{system_prompt}\n{mtllm_prompt}\n{method_prompt}"
48
+ if isinstance(inputs_information, str):
49
+ mtllm_prompt = model.MTLLM_PROMPT.format(
50
+ information=information,
51
+ inputs_information=inputs_information,
52
+ output_information=output_information,
53
+ type_explanations=type_explanations,
54
+ action=action,
55
+ context=context,
56
+ ).strip()
57
+ meaning_in = f"{system_prompt}\n{mtllm_prompt}\n{method_prompt}".strip()
58
+ else:
59
+ upper_half = model.MTLLM_PROMPT.split("{inputs_information}")[0]
60
+ lower_half = model.MTLLM_PROMPT.split("{inputs_information}")[1]
61
+ upper_half = upper_half.format(
62
+ information=information,
63
+ context=context,
64
+ )
65
+ lower_half = lower_half.format(
66
+ output_information=output_information,
67
+ type_explanations=type_explanations,
68
+ action=action,
69
+ )
70
+ meaning_in = (
71
+ [
72
+ {"type": "text", "text": system_prompt},
73
+ {"type": "text", "text": upper_half},
74
+ ]
75
+ + inputs_information
76
+ + [
77
+ {"type": "text", "text": lower_half},
78
+ {"type": "text", "text": method_prompt},
79
+ ]
80
+ )
40
81
  return model(meaning_in, **model_params)
41
82
  else:
42
83
  assert tools, "Tools must be provided for the ReAct method."
@@ -71,7 +112,7 @@ def get_info_types(
71
112
  else None
72
113
  )
73
114
  info_str.append(
74
- f"{sem_info.semstr} ({sem_info.name}) ({sem_info.type}) = {get_object_string(incl[1])}"
115
+ f"{sem_info.semstr} ({sem_info.name}) ({sem_info.type}) = {get_object_string(incl[1])}".strip()
75
116
  )
76
117
  return ("\n".join(info_str), collected_types)
77
118
 
@@ -142,7 +183,7 @@ def get_type_explanation(
142
183
  if sem_info.type == "Enum" and isinstance(type_info, list):
143
184
  for enum_item in type_info:
144
185
  type_info_str.append(
145
- f"{enum_item.semstr} ({enum_item.name}) (EnumItem)"
186
+ f"{enum_item.semstr} ({enum_item.name}) (EnumItem)".strip()
146
187
  )
147
188
  type_example[0] = type_example[0].replace("(", f".{enum_item.name}")
148
189
  elif sem_info.type in ["obj", "class", "node", "edge"] and isinstance(
@@ -152,7 +193,7 @@ def get_type_explanation(
152
193
  if arch_item.type in ["obj", "class", "node", "edge"]:
153
194
  continue
154
195
  type_info_str.append(
155
- f"{arch_item.semstr} ({arch_item.name}) ({arch_item.type})"
196
+ f"{arch_item.semstr} ({arch_item.name}) ({arch_item.type})".strip()
156
197
  )
157
198
  type_example.append(f"{arch_item.name}={arch_item.type}, ")
158
199
  if arch_item.type and extract_non_primary_type(arch_item.type):
@@ -162,7 +203,7 @@ def get_type_explanation(
162
203
  else:
163
204
  type_example.append(")")
164
205
  return (
165
- f"{sem_info.semstr} ({sem_info.name}) ({sem_info.type}) eg:- {''.join(type_example)} -> {', '.join(type_info_str)}", # noqa: E501
206
+ f"{sem_info.semstr} ({sem_info.name}) ({sem_info.type}) eg:- {''.join(type_example)} -> {', '.join(type_info_str)}".strip(), # noqa: E501
166
207
  set(type_info_types),
167
208
  )
168
209
  return None, None
@@ -212,3 +253,62 @@ class Tool:
212
253
  """Initialize the Tool class."""
213
254
  # TODO: Implement the Tool class
214
255
  pass
256
+
257
+
258
+ def get_input_information(
259
+ inputs: list[tuple[str, str, str, Any]], type_collector: list
260
+ ) -> str | list[dict]:
261
+ """
262
+ Get the input information for the AOTT operation.
263
+
264
+ Returns:
265
+ str | list[dict]: If the input does not contain images, returns a string with the input information.
266
+ If the input contains images, returns a list of dictionaries representing the input information,
267
+ where each dictionary contains either text or image_url.
268
+
269
+ """
270
+ contains_imgs = any(get_type_annotation(i[3]) in IMG_FORMATS for i in inputs)
271
+ if not contains_imgs:
272
+ inputs_information_list = []
273
+ for i in inputs:
274
+ typ_anno = get_type_annotation(i[3])
275
+ type_collector.extend(extract_non_primary_type(typ_anno))
276
+ inputs_information_list.append(
277
+ f"{i[0] if i[0] else ''} ({i[2]}) ({typ_anno}) = {get_object_string(i[3])}".strip()
278
+ )
279
+ return "\n".join(inputs_information_list)
280
+ else:
281
+ inputs_information_dict_list: list[dict] = []
282
+ for i in inputs:
283
+ if get_type_annotation(i[3]) in IMG_FORMATS:
284
+ img_base64 = image_to_base64(i[3])
285
+ image_repr: list[dict] = [
286
+ {
287
+ "type": "text",
288
+ "text": f"{i[0] if i[0] else ''} ({i[2]}) (Image) = ".strip(),
289
+ },
290
+ {"type": "image_url", "image_url": {"url": img_base64}},
291
+ ]
292
+ inputs_information_dict_list.extend(image_repr)
293
+ continue
294
+ typ_anno = get_type_annotation(i[3])
295
+ type_collector.extend(extract_non_primary_type(typ_anno))
296
+ inputs_information_dict_list.append(
297
+ {
298
+ "type": "text",
299
+ "text": f"{i[0] if i[0] else ''} ({i[2]}) ({typ_anno}) = {get_object_string(i[3])}".strip(),
300
+ }
301
+ )
302
+ return inputs_information_dict_list
303
+
304
+
305
+ def image_to_base64(image: Image) -> str: # type: ignore
306
+ """Convert an image to base64 expected by OpenAI."""
307
+ if not Image:
308
+ log = logging.getLogger(__name__)
309
+ log.error("Pillow is not installed. Please install Pillow to use images.")
310
+ return ""
311
+ img_format = image.format
312
+ with BytesIO() as buffer:
313
+ image.save(buffer, format=img_format, quality=100)
314
+ return f"data:image/{img_format.lower()};base64,{base64.b64encode(buffer.getvalue()).decode()}"
@@ -2,15 +2,13 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import unittest
5
+ import types
6
6
  from dataclasses import dataclass, field
7
- from typing import Callable, Optional
7
+ from typing import Any, Callable, Optional
8
8
  from uuid import UUID, uuid4
9
9
 
10
10
  from jaclang.compiler.constant import EdgeDir
11
11
  from jaclang.core.utils import collect_node_connections
12
- from jaclang.plugin.feature import JacFeature as Jac
13
- from jaclang.plugin.spec import DSFunc
14
12
 
15
13
 
16
14
  @dataclass(eq=False)
@@ -57,6 +55,8 @@ class NodeAnchor(ObjectAnchor):
57
55
 
58
56
  def populate_edges(self) -> None:
59
57
  """Populate edges from edge ids."""
58
+ from jaclang.plugin.feature import JacFeature as Jac
59
+
60
60
  if len(self.edges) == 0 and len(self.edge_ids) > 0:
61
61
  for e_id in self.edge_ids:
62
62
  edge = Jac.context().get_obj(e_id)
@@ -229,7 +229,13 @@ class WalkerAnchor(ObjectAnchor):
229
229
 
230
230
  def visit_node(
231
231
  self,
232
- nds: list[NodeArchitype | EdgeArchitype] | NodeArchitype | EdgeArchitype,
232
+ nds: (
233
+ list[NodeArchitype | EdgeArchitype]
234
+ | list[NodeArchitype]
235
+ | list[EdgeArchitype]
236
+ | NodeArchitype
237
+ | EdgeArchitype
238
+ ),
233
239
  ) -> bool:
234
240
  """Walker visits node."""
235
241
  nd_list: list[NodeArchitype | EdgeArchitype]
@@ -251,7 +257,13 @@ class WalkerAnchor(ObjectAnchor):
251
257
 
252
258
  def ignore_node(
253
259
  self,
254
- nds: list[NodeArchitype | EdgeArchitype] | NodeArchitype | EdgeArchitype,
260
+ nds: (
261
+ list[NodeArchitype | EdgeArchitype]
262
+ | list[NodeArchitype]
263
+ | list[EdgeArchitype]
264
+ | NodeArchitype
265
+ | EdgeArchitype
266
+ ),
255
267
  ) -> bool:
256
268
  """Walker ignores node."""
257
269
  nd_list: list[NodeArchitype | EdgeArchitype]
@@ -354,11 +366,15 @@ class NodeArchitype(Architype):
354
366
 
355
367
  def __init__(self) -> None:
356
368
  """Create node architype."""
369
+ from jaclang.plugin.feature import JacFeature as Jac
370
+
357
371
  self._jac_: NodeAnchor = NodeAnchor(obj=self)
358
372
  Jac.context().save_obj(self, persistent=self._jac_.persistent)
359
373
 
360
374
  def save(self) -> None:
361
375
  """Save the node to the memory/storage hierarchy."""
376
+ from jaclang.plugin.feature import JacFeature as Jac
377
+
362
378
  self._jac_.persistent = True
363
379
  Jac.context().save_obj(self, persistent=True)
364
380
 
@@ -383,11 +399,15 @@ class EdgeArchitype(Architype):
383
399
 
384
400
  def __init__(self) -> None:
385
401
  """Create edge architype."""
402
+ from jaclang.plugin.feature import JacFeature as Jac
403
+
386
404
  self._jac_: EdgeAnchor = EdgeAnchor(obj=self)
387
405
  Jac.context().save_obj(self, persistent=self.persistent)
388
406
 
389
407
  def save(self) -> None:
390
408
  """Save the edge to the memory/storage hierarchy."""
409
+ from jaclang.plugin.feature import JacFeature as Jac
410
+
391
411
  self.persistent = True
392
412
  Jac.context().save_obj(self, persistent=True)
393
413
 
@@ -405,6 +425,8 @@ class EdgeArchitype(Architype):
405
425
 
406
426
  def populate_nodes(self) -> None:
407
427
  """Populate nodes for the edges from node ids."""
428
+ from jaclang.plugin.feature import JacFeature as Jac
429
+
408
430
  if self._jac_.source_id:
409
431
  obj = Jac.context().get_obj(self._jac_.source_id)
410
432
  if obj is None:
@@ -439,6 +461,13 @@ class WalkerArchitype(Architype):
439
461
  self._jac_: WalkerAnchor = WalkerAnchor(obj=self)
440
462
 
441
463
 
464
+ class GenericEdge(EdgeArchitype):
465
+ """Generic Root Node."""
466
+
467
+ _jac_entry_funcs_ = []
468
+ _jac_exit_funcs_ = []
469
+
470
+
442
471
  class Root(NodeArchitype):
443
472
  """Generic Root Node."""
444
473
 
@@ -460,92 +489,14 @@ class Root(NodeArchitype):
460
489
  self._jac_.edges = []
461
490
 
462
491
 
463
- class GenericEdge(EdgeArchitype):
464
- """Generic Root Node."""
465
-
466
- _jac_entry_funcs_ = []
467
- _jac_exit_funcs_ = []
468
-
469
-
470
- class JacTestResult(unittest.TextTestResult):
471
- """Jac test result class."""
472
-
473
- def __init__(
474
- self,
475
- stream, # noqa
476
- descriptions, # noqa
477
- verbosity: int,
478
- max_failures: Optional[int] = None,
479
- ) -> None:
480
- """Initialize FailFastTestResult object."""
481
- super().__init__(stream, descriptions, verbosity) # noqa
482
- self.failures_count = JacTestCheck.failcount
483
- self.max_failures = max_failures
484
-
485
- def addFailure(self, test, err) -> None: # noqa
486
- """Count failures and stop."""
487
- super().addFailure(test, err)
488
- self.failures_count += 1
489
- if self.max_failures is not None and self.failures_count >= self.max_failures:
490
- self.stop()
491
-
492
- def stop(self) -> None:
493
- """Stop the test execution."""
494
- self.shouldStop = True
495
-
496
-
497
- class JacTextTestRunner(unittest.TextTestRunner):
498
- """Jac test runner class."""
499
-
500
- def __init__(self, max_failures: Optional[int] = None, **kwargs) -> None: # noqa
501
- """Initialize JacTextTestRunner object."""
502
- self.max_failures = max_failures
503
- super().__init__(**kwargs)
504
-
505
- def _makeResult(self) -> JacTestResult: # noqa
506
- """Override the method to return an instance of JacTestResult."""
507
- return JacTestResult(
508
- self.stream,
509
- self.descriptions,
510
- self.verbosity,
511
- max_failures=self.max_failures,
512
- )
513
-
514
-
515
- class JacTestCheck:
516
- """Jac Testing and Checking."""
517
-
518
- test_case = unittest.TestCase()
519
- test_suite = unittest.TestSuite()
520
- breaker = False
521
- failcount = 0
522
-
523
- @staticmethod
524
- def reset() -> None:
525
- """Clear the test suite."""
526
- JacTestCheck.test_case = unittest.TestCase()
527
- JacTestCheck.test_suite = unittest.TestSuite()
528
-
529
- @staticmethod
530
- def run_test(xit: bool, maxfail: int | None, verbose: bool) -> None:
531
- """Run the test suite."""
532
- verb = 2 if verbose else 1
533
- runner = JacTextTestRunner(max_failures=maxfail, failfast=xit, verbosity=verb)
534
- result = runner.run(JacTestCheck.test_suite)
535
- if result.wasSuccessful():
536
- print("Passed successfully.")
537
- else:
538
- fails = len(result.failures)
539
- JacTestCheck.failcount += fails
540
- JacTestCheck.breaker = (
541
- (JacTestCheck.failcount >= maxfail) if maxfail else True
542
- )
492
+ @dataclass(eq=False)
493
+ class DSFunc:
494
+ """Data Spatial Function."""
543
495
 
544
- @staticmethod
545
- def add_test(test_fun: Callable) -> None:
546
- """Create a new test."""
547
- 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
548
499
 
549
- def __getattr__(self, name: str) -> object:
550
- """Make convenient check.Equal(...) etc."""
551
- 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)