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.
- jaclang/cli/cli.py +2 -2
- jaclang/compiler/absyntree.py +539 -297
- jaclang/compiler/codeloc.py +2 -2
- jaclang/compiler/constant.py +100 -2
- jaclang/compiler/jac.lark +27 -19
- jaclang/compiler/parser.py +119 -92
- jaclang/compiler/passes/main/access_modifier_pass.py +20 -12
- jaclang/compiler/passes/main/def_impl_match_pass.py +32 -12
- jaclang/compiler/passes/main/def_use_pass.py +59 -40
- jaclang/compiler/passes/main/fuse_typeinfo_pass.py +71 -30
- jaclang/compiler/passes/main/import_pass.py +12 -7
- jaclang/compiler/passes/main/pyast_gen_pass.py +110 -47
- jaclang/compiler/passes/main/pyast_load_pass.py +49 -13
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +25 -11
- jaclang/compiler/passes/main/pyout_pass.py +3 -1
- jaclang/compiler/passes/main/registry_pass.py +6 -6
- jaclang/compiler/passes/main/sub_node_tab_pass.py +0 -5
- jaclang/compiler/passes/main/sym_tab_build_pass.py +43 -235
- jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +21 -4
- jaclang/compiler/passes/main/tests/test_def_use_pass.py +5 -10
- jaclang/compiler/passes/main/tests/test_import_pass.py +8 -0
- jaclang/compiler/passes/main/tests/test_type_check_pass.py +1 -1
- jaclang/compiler/passes/main/type_check_pass.py +2 -1
- jaclang/compiler/passes/tool/jac_formatter_pass.py +44 -11
- jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +16 -0
- jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +16 -0
- jaclang/compiler/passes/tool/tests/fixtures/doc_string.jac +15 -0
- jaclang/compiler/passes/tool/tests/fixtures/genai/essay_review.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/expert_answer.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/joke_gen.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/odd_word_out.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/personality_finder.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/text_to_type.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/translator.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/wikipedia.jac +1 -1
- jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +7 -5
- jaclang/compiler/passes/tool/tests/test_unparse_validate.py +1 -2
- jaclang/compiler/passes/transform.py +2 -4
- jaclang/{core/registry.py → compiler/semtable.py} +1 -3
- jaclang/compiler/symtable.py +150 -89
- jaclang/compiler/tests/test_parser.py +2 -2
- jaclang/core/aott.py +118 -18
- jaclang/core/{construct.py → architype.py} +44 -93
- jaclang/core/constructs.py +44 -0
- jaclang/core/context.py +157 -0
- jaclang/core/importer.py +18 -9
- jaclang/core/memory.py +53 -2
- jaclang/core/test.py +90 -0
- jaclang/core/utils.py +2 -2
- jaclang/langserve/engine.py +199 -138
- jaclang/langserve/server.py +48 -53
- jaclang/langserve/tests/fixtures/base_module_structure.jac +28 -0
- jaclang/langserve/tests/fixtures/circle.jac +16 -12
- jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
- jaclang/langserve/tests/fixtures/circle_pure.impl.jac +8 -4
- jaclang/langserve/tests/fixtures/circle_pure.jac +2 -2
- jaclang/langserve/tests/fixtures/circle_pure.test.jac +15 -0
- jaclang/langserve/tests/fixtures/import_include_statements.jac +6 -0
- jaclang/langserve/tests/fixtures/py_import.py +26 -0
- jaclang/langserve/tests/test_server.py +200 -2
- jaclang/langserve/utils.py +214 -10
- jaclang/plugin/builtin.py +1 -1
- jaclang/plugin/default.py +48 -92
- jaclang/plugin/feature.py +33 -17
- jaclang/plugin/spec.py +18 -20
- jaclang/plugin/tests/test_features.py +0 -33
- jaclang/settings.py +4 -0
- jaclang/tests/fixtures/abc.jac +16 -12
- jaclang/tests/fixtures/aott_raise.jac +1 -1
- jaclang/tests/fixtures/byllmissue.jac +12 -0
- jaclang/tests/fixtures/edgetypeissue.jac +10 -0
- jaclang/tests/fixtures/hash_init_check.jac +17 -0
- jaclang/tests/fixtures/hello.jac +1 -1
- jaclang/tests/fixtures/impl_match_confused.impl.jac +1 -0
- jaclang/tests/fixtures/impl_match_confused.jac +5 -0
- jaclang/tests/fixtures/math_question.jpg +0 -0
- jaclang/tests/fixtures/maxfail_run_test.jac +17 -5
- jaclang/tests/fixtures/nosigself.jac +19 -0
- jaclang/tests/fixtures/run_test.jac +17 -5
- jaclang/tests/fixtures/walker_override.jac +21 -0
- jaclang/tests/fixtures/with_llm_function.jac +1 -1
- jaclang/tests/fixtures/with_llm_lower.jac +1 -1
- jaclang/tests/fixtures/with_llm_method.jac +1 -1
- jaclang/tests/fixtures/with_llm_type.jac +1 -1
- jaclang/tests/fixtures/with_llm_vision.jac +25 -0
- jaclang/tests/test_bugs.py +19 -0
- jaclang/tests/test_cli.py +1 -1
- jaclang/tests/test_language.py +197 -82
- jaclang/tests/test_reference.py +1 -1
- jaclang/utils/lang_tools.py +5 -4
- jaclang/utils/test.py +2 -1
- jaclang/utils/treeprinter.py +35 -4
- {jaclang-0.7.1.dist-info → jaclang-0.7.7.dist-info}/METADATA +3 -2
- {jaclang-0.7.1.dist-info → jaclang-0.7.7.dist-info}/RECORD +96 -88
- jaclang/core/llms/__init__.py +0 -20
- jaclang/core/llms/anthropic.py +0 -61
- jaclang/core/llms/base.py +0 -206
- jaclang/core/llms/groq.py +0 -67
- jaclang/core/llms/huggingface.py +0 -73
- jaclang/core/llms/ollama.py +0 -78
- jaclang/core/llms/openai.py +0 -61
- jaclang/core/llms/togetherai.py +0 -60
- jaclang/core/llms/utils.py +0 -9
- jaclang/core/shelve_storage.py +0 -55
- {jaclang-0.7.1.dist-info → jaclang-0.7.7.dist-info}/WHEEL +0 -0
- {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
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
|
|
464
|
-
|
|
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
|
-
|
|
545
|
-
|
|
546
|
-
|
|
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
|
|
550
|
-
"""
|
|
551
|
-
|
|
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
|
+
]
|
jaclang/core/context.py
ADDED
|
@@ -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
|
-
|
|
61
|
+
valid_mod_bundle, module_name, package_path, full_target
|
|
55
62
|
)
|
|
56
|
-
if
|
|
57
|
-
codeobj =
|
|
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
|
-
|
|
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
|
|
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)
|