jaclang 0.5.18__py3-none-any.whl → 0.6.1__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 (57) hide show
  1. jaclang/cli/cli.py +94 -5
  2. jaclang/cli/cmdreg.py +18 -6
  3. jaclang/compiler/__init__.py +12 -5
  4. jaclang/compiler/absyntree.py +4 -5
  5. jaclang/compiler/generated/jac_parser.py +2 -2
  6. jaclang/compiler/jac.lark +2 -2
  7. jaclang/compiler/parser.py +48 -8
  8. jaclang/compiler/passes/main/__init__.py +3 -2
  9. jaclang/compiler/passes/main/access_modifier_pass.py +173 -0
  10. jaclang/compiler/passes/main/def_impl_match_pass.py +4 -1
  11. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +10 -7
  12. jaclang/compiler/passes/main/import_pass.py +70 -40
  13. jaclang/compiler/passes/main/pyast_gen_pass.py +47 -83
  14. jaclang/compiler/passes/main/pyast_load_pass.py +136 -73
  15. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +218 -0
  16. jaclang/compiler/passes/main/pyout_pass.py +14 -13
  17. jaclang/compiler/passes/main/registry_pass.py +8 -3
  18. jaclang/compiler/passes/main/schedules.py +7 -3
  19. jaclang/compiler/passes/main/sym_tab_build_pass.py +32 -29
  20. jaclang/compiler/passes/main/tests/test_import_pass.py +13 -2
  21. jaclang/compiler/passes/tool/jac_formatter_pass.py +83 -21
  22. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +11 -4
  23. jaclang/compiler/passes/transform.py +2 -0
  24. jaclang/compiler/symtable.py +10 -3
  25. jaclang/compiler/tests/test_importer.py +9 -0
  26. jaclang/compiler/workspace.py +17 -5
  27. jaclang/core/aott.py +43 -63
  28. jaclang/core/construct.py +157 -21
  29. jaclang/core/importer.py +77 -65
  30. jaclang/core/llms/__init__.py +20 -0
  31. jaclang/core/llms/anthropic.py +61 -0
  32. jaclang/core/llms/base.py +206 -0
  33. jaclang/core/llms/groq.py +67 -0
  34. jaclang/core/llms/huggingface.py +73 -0
  35. jaclang/core/llms/ollama.py +78 -0
  36. jaclang/core/llms/openai.py +61 -0
  37. jaclang/core/llms/togetherai.py +60 -0
  38. jaclang/core/llms/utils.py +9 -0
  39. jaclang/core/memory.py +48 -0
  40. jaclang/core/shelve_storage.py +55 -0
  41. jaclang/core/utils.py +16 -1
  42. jaclang/plugin/__init__.py +1 -2
  43. jaclang/plugin/builtin.py +1 -1
  44. jaclang/plugin/default.py +134 -18
  45. jaclang/plugin/feature.py +35 -13
  46. jaclang/plugin/spec.py +52 -10
  47. jaclang/plugin/tests/test_jaseci.py +219 -0
  48. jaclang/settings.py +1 -1
  49. jaclang/utils/helpers.py +6 -2
  50. jaclang/utils/treeprinter.py +14 -6
  51. jaclang-0.6.1.dist-info/METADATA +17 -0
  52. {jaclang-0.5.18.dist-info → jaclang-0.6.1.dist-info}/RECORD +55 -42
  53. jaclang/core/llms.py +0 -111
  54. jaclang-0.5.18.dist-info/METADATA +0 -7
  55. {jaclang-0.5.18.dist-info → jaclang-0.6.1.dist-info}/WHEEL +0 -0
  56. {jaclang-0.5.18.dist-info → jaclang-0.6.1.dist-info}/entry_points.txt +0 -0
  57. {jaclang-0.5.18.dist-info → jaclang-0.6.1.dist-info}/top_level.txt +0 -0
jaclang/core/aott.py CHANGED
@@ -8,78 +8,40 @@ import re
8
8
  from enum import Enum
9
9
  from typing import Any
10
10
 
11
+ from jaclang.core.llms.base import BaseLLM
11
12
  from jaclang.core.registry import SemInfo, SemRegistry, SemScope
12
13
 
13
14
 
14
- PROMPT_TEMPLATE = """
15
- [System Prompt]
16
- This is an operation you must perform and return the output values. Neither, the methodology, extra sentences nor the code are not needed.
17
- Input/Type formatting: Explanation of the Input (variable_name) (type) = value
18
-
19
- [Information]
20
- {information}
21
-
22
- [Inputs Information]
23
- {inputs_information}
24
-
25
- [Output Information]
26
- {output_information}
27
-
28
- [Type Explanations]
29
- {type_explanations}
30
-
31
- [Action]
32
- {action}
33
-
34
- {reason_suffix}
35
- """ # noqa E501
36
-
37
- WITH_REASON_SUFFIX = """
38
- Reason and return the output result(s) only, adhering to the provided Type in the following format
39
-
40
- [Reasoning] <Reason>
41
- [Output] <Result>
42
- """
43
-
44
- WITHOUT_REASON_SUFFIX = """Generate and return the output result(s) only, adhering to the provided Type in the following format
45
-
46
- [Output] <result>
47
- """ # noqa E501
48
-
49
-
50
15
  def aott_raise(
16
+ model: BaseLLM,
51
17
  information: str,
52
18
  inputs_information: str,
53
19
  output_information: str,
54
20
  type_explanations: str,
55
21
  action: str,
56
- reason: bool,
22
+ context: str,
23
+ method: str,
24
+ tools: list["Tool"],
25
+ model_params: dict,
57
26
  ) -> str:
58
27
  """AOTT Raise uses the information (Meanings types values) provided to generate a prompt(meaning in)."""
59
- return PROMPT_TEMPLATE.format(
60
- information=information,
61
- inputs_information=inputs_information,
62
- output_information=output_information,
63
- type_explanations=type_explanations,
64
- action=action,
65
- reason_suffix=WITH_REASON_SUFFIX if reason else WITHOUT_REASON_SUFFIX,
66
- )
67
-
68
-
69
- def get_reasoning_output(s: str) -> tuple:
70
- """Get the reasoning and output from the meaning out string."""
71
- reasoning_match = re.search(r"\[Reasoning\](.*)\[Output\]", s)
72
- output_match = re.search(r"\[Output\](.*)", s)
73
-
74
- if reasoning_match and output_match:
75
- reasoning = reasoning_match.group(1)
76
- output = output_match.group(1)
77
- return (reasoning.strip(), output.strip())
78
- elif output_match:
79
- output = output_match.group(1)
80
- return (None, output.strip())
28
+ 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
+ method_prompt = model.MTLLM_METHOD_PROMPTS[method]
39
+ meaning_in = f"{system_prompt}\n{mtllm_prompt}\n{method_prompt}"
40
+ return model(meaning_in, **model_params)
81
41
  else:
82
- return (None, None)
42
+ assert tools, "Tools must be provided for the ReAct method."
43
+ # TODO: Implement ReAct method
44
+ return ""
83
45
 
84
46
 
85
47
  def get_info_types(
@@ -176,22 +138,31 @@ def get_type_explanation(
176
138
  _, type_info = mod_registry.lookup(scope=sem_info_scope)
177
139
  type_info_str = []
178
140
  type_info_types = []
141
+ type_example = [f"{sem_info.name}("]
179
142
  if sem_info.type == "Enum" and isinstance(type_info, list):
180
143
  for enum_item in type_info:
181
144
  type_info_str.append(
182
- f"{enum_item.semstr} (EnumItem) ({enum_item.name})"
145
+ f"{enum_item.semstr} ({enum_item.name}) (EnumItem)"
183
146
  )
147
+ type_example[0] = type_example[0].replace("(", f".{enum_item.name}")
184
148
  elif sem_info.type in ["obj", "class", "node", "edge"] and isinstance(
185
149
  type_info, list
186
150
  ):
187
151
  for arch_item in type_info:
152
+ if arch_item.type in ["obj", "class", "node", "edge"]:
153
+ continue
188
154
  type_info_str.append(
189
- f"{arch_item.semstr} ({arch_item.type}) ({arch_item.name})"
155
+ f"{arch_item.semstr} ({arch_item.name}) ({arch_item.type})"
190
156
  )
157
+ type_example.append(f"{arch_item.name}={arch_item.type}, ")
191
158
  if arch_item.type and extract_non_primary_type(arch_item.type):
192
159
  type_info_types.extend(extract_non_primary_type(arch_item.type))
160
+ if len(type_example) > 1:
161
+ type_example[-1] = type_example[-1].replace(", ", ")")
162
+ else:
163
+ type_example.append(")")
193
164
  return (
194
- f"{sem_info.semstr} ({sem_info.type}) ({sem_info.name}) = {', '.join(type_info_str)}",
165
+ f"{sem_info.semstr} ({sem_info.name}) ({sem_info.type}) eg:- {''.join(type_example)} -> {', '.join(type_info_str)}", # noqa: E501
195
166
  set(type_info_types),
196
167
  )
197
168
  return None, None
@@ -232,3 +203,12 @@ def get_type_annotation(data: Any) -> str: # noqa: ANN401
232
203
  return "dict[str, Any]"
233
204
  else:
234
205
  return str(type(data).__name__)
206
+
207
+
208
+ class Tool:
209
+ """Tool class for the AOTT operations."""
210
+
211
+ def __init__(self) -> None:
212
+ """Initialize the Tool class."""
213
+ # TODO: Implement the Tool class
214
+ pass
jaclang/core/construct.py CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- # import shelve
6
- import types
7
5
  import unittest
8
6
  from dataclasses import dataclass, field
9
- from typing import Any, Callable, Optional, Union
10
-
7
+ from typing import Callable, Optional
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
12
+ from jaclang.plugin.feature import JacFeature as Jac
13
+ from jaclang.plugin.spec import DSFunc
14
14
 
15
15
 
16
16
  @dataclass(eq=False)
@@ -18,6 +18,7 @@ class ElementAnchor:
18
18
  """Element Anchor."""
19
19
 
20
20
  obj: Architype
21
+ id: UUID = field(default_factory=uuid4)
21
22
 
22
23
 
23
24
  @dataclass(eq=False)
@@ -35,6 +36,37 @@ class NodeAnchor(ObjectAnchor):
35
36
 
36
37
  obj: NodeArchitype
37
38
  edges: list[EdgeArchitype] = field(default_factory=lambda: [])
39
+ edge_ids: list[UUID] = field(default_factory=lambda: [])
40
+ persistent: bool = False
41
+
42
+ def __getstate__(self) -> dict:
43
+ """Override getstate for pickle and shelve."""
44
+ state = self.__dict__.copy()
45
+ state.pop("obj")
46
+ if self.edges and "edges" in state:
47
+ edges = state.pop("edges")
48
+ state["edge_ids"] = [e._jac_.id for e in edges]
49
+
50
+ return state
51
+
52
+ def __setstate__(self, state: dict) -> None:
53
+ """Override setstate for pickle and shelve."""
54
+ self.__dict__.update(state)
55
+ if "edge_ids" in state:
56
+ self.edge_ids = state.pop("edge_ids")
57
+
58
+ def populate_edges(self) -> None:
59
+ """Populate edges from edge ids."""
60
+ if len(self.edges) == 0 and len(self.edge_ids) > 0:
61
+ for e_id in self.edge_ids:
62
+ edge = Jac.context().get_obj(e_id)
63
+ if edge is None:
64
+ raise ValueError(f"Edge with id {e_id} not found.")
65
+ elif not isinstance(edge, EdgeArchitype):
66
+ raise ValueError(f"Object with id {e_id} is not an edge.")
67
+ else:
68
+ self.edges.append(edge)
69
+ self.edge_ids.clear()
38
70
 
39
71
  def connect_node(self, nd: NodeArchitype, edg: EdgeArchitype) -> NodeArchitype:
40
72
  """Connect a node with given edge."""
@@ -48,6 +80,8 @@ class NodeAnchor(ObjectAnchor):
48
80
  target_obj: Optional[list[NodeArchitype]],
49
81
  ) -> list[EdgeArchitype]:
50
82
  """Get edges connected to this node."""
83
+ self.populate_edges()
84
+
51
85
  edge_list: list[EdgeArchitype] = [*self.edges]
52
86
  ret_edges: list[EdgeArchitype] = []
53
87
  edge_list = filter_func(edge_list) if filter_func else edge_list
@@ -76,6 +110,9 @@ class NodeAnchor(ObjectAnchor):
76
110
  target_obj: Optional[list[NodeArchitype]],
77
111
  ) -> list[NodeArchitype]:
78
112
  """Get set of nodes connected to this node."""
113
+ self.populate_edges()
114
+ for edge in self.edges:
115
+ edge.populate_nodes()
79
116
  edge_list: list[EdgeArchitype] = [*self.edges]
80
117
  node_list: list[NodeArchitype] = []
81
118
  edge_list = filter_func(edge_list) if filter_func else edge_list
@@ -126,7 +163,29 @@ class EdgeAnchor(ObjectAnchor):
126
163
  obj: EdgeArchitype
127
164
  source: Optional[NodeArchitype] = None
128
165
  target: Optional[NodeArchitype] = None
166
+ source_id: Optional[UUID] = None
167
+ target_id: Optional[UUID] = None
129
168
  is_undirected: bool = False
169
+ persistent: bool = False
170
+
171
+ def __getstate__(self) -> dict:
172
+ """Override getstate for pickle and shelve."""
173
+ state = self.__dict__.copy()
174
+ state.pop("obj")
175
+
176
+ if self.source:
177
+ state["source_id"] = self.source._jac_.id
178
+ state.pop("source")
179
+
180
+ if self.target:
181
+ state["target_id"] = self.target._jac_.id
182
+ state.pop("target")
183
+
184
+ return state
185
+
186
+ def __setstate__(self, state: dict) -> None:
187
+ """Override setstate for pickle and shelve."""
188
+ self.__dict__.update(state)
130
189
 
131
190
  def attach(
132
191
  self, src: NodeArchitype, trg: NodeArchitype, is_undirected: bool = False
@@ -268,26 +327,113 @@ class Architype:
268
327
  """Create default architype."""
269
328
  self._jac_: ObjectAnchor = ObjectAnchor(obj=self)
270
329
 
330
+ def __hash__(self) -> int:
331
+ """Override hash for architype."""
332
+ return hash(self._jac_.id)
333
+
334
+ def __eq__(self, other: object) -> bool:
335
+ """Override equality for architype."""
336
+ if not isinstance(other, Architype):
337
+ return False
338
+ else:
339
+ return self._jac_.id == other._jac_.id
340
+
341
+ def __repr__(self) -> str:
342
+ """Override repr for architype."""
343
+ return f"{self.__class__.__name__}"
344
+
345
+ def __getstate__(self) -> dict:
346
+ """Override getstate for pickle and shelve."""
347
+ raise NotImplementedError
348
+
271
349
 
272
350
  class NodeArchitype(Architype):
273
351
  """Node Architype Protocol."""
274
352
 
353
+ _jac_: NodeAnchor
354
+
275
355
  def __init__(self) -> None:
276
356
  """Create node architype."""
277
357
  self._jac_: NodeAnchor = NodeAnchor(obj=self)
358
+ Jac.context().save_obj(self, persistent=self._jac_.persistent)
359
+
360
+ def save(self) -> None:
361
+ """Save the node to the memory/storage hierarchy."""
362
+ self._jac_.persistent = True
363
+ Jac.context().save_obj(self, persistent=True)
364
+
365
+ def __getstate__(self) -> dict:
366
+ """Override getstate for pickle and shelve."""
367
+ state = self.__dict__.copy()
368
+ state["_jac_"] = self._jac_.__getstate__()
369
+ return state
370
+
371
+ def __setstate__(self, state: dict) -> None:
372
+ """Override setstate for pickle and shelve."""
373
+ self.__dict__.update(state)
374
+ self._jac_ = NodeAnchor(obj=self)
375
+ self._jac_.__setstate__(state["_jac_"])
278
376
 
279
377
 
280
378
  class EdgeArchitype(Architype):
281
379
  """Edge Architype Protocol."""
282
380
 
381
+ _jac_: EdgeAnchor
382
+ persistent: bool = False
383
+
283
384
  def __init__(self) -> None:
284
385
  """Create edge architype."""
285
386
  self._jac_: EdgeAnchor = EdgeAnchor(obj=self)
387
+ Jac.context().save_obj(self, persistent=self.persistent)
388
+
389
+ def save(self) -> None:
390
+ """Save the edge to the memory/storage hierarchy."""
391
+ self.persistent = True
392
+ Jac.context().save_obj(self, persistent=True)
393
+
394
+ def __getstate__(self) -> dict:
395
+ """Override getstate for pickle and shelve."""
396
+ state = self.__dict__.copy()
397
+ state["_jac_"] = self._jac_.__getstate__()
398
+ return state
399
+
400
+ def __setstate__(self, state: dict) -> None:
401
+ """Override setstate for pickle and shelve."""
402
+ self.__dict__.update(state)
403
+ self._jac_ = EdgeAnchor(obj=self)
404
+ self._jac_.__setstate__(state["_jac_"])
405
+
406
+ def populate_nodes(self) -> None:
407
+ """Populate nodes for the edges from node ids."""
408
+ if self._jac_.source_id:
409
+ obj = Jac.context().get_obj(self._jac_.source_id)
410
+ if obj is None:
411
+ raise ValueError(f"Node with id {self._jac_.source_id} not found.")
412
+ elif not isinstance(obj, NodeArchitype):
413
+ raise ValueError(
414
+ f"Object with id {self._jac_.source_id} is not a node."
415
+ )
416
+ else:
417
+ self._jac_.source = obj
418
+ self._jac_.source_id = None
419
+ if self._jac_.target_id:
420
+ obj = Jac.context().get_obj(self._jac_.target_id)
421
+ if obj is None:
422
+ raise ValueError(f"Node with id {self._jac_.target_id} not found.")
423
+ elif not isinstance(obj, NodeArchitype):
424
+ raise ValueError(
425
+ f"Object with id {self._jac_.target_id} is not a node."
426
+ )
427
+ else:
428
+ self._jac_.target = obj
429
+ self._jac_.target_id = None
286
430
 
287
431
 
288
432
  class WalkerArchitype(Architype):
289
433
  """Walker Architype Protocol."""
290
434
 
435
+ _jac_: WalkerAnchor
436
+
291
437
  def __init__(self) -> None:
292
438
  """Create walker architype."""
293
439
  self._jac_: WalkerAnchor = WalkerAnchor(obj=self)
@@ -301,6 +447,12 @@ class Root(NodeArchitype):
301
447
  reachable_nodes: list[NodeArchitype] = []
302
448
  connections: set[tuple[NodeArchitype, NodeArchitype, EdgeArchitype]] = set()
303
449
 
450
+ def __init__(self) -> None:
451
+ """Create root node."""
452
+ super().__init__()
453
+ self._jac_.id = UUID(int=0)
454
+ self._jac_.persistent = True
455
+
304
456
  def reset(self) -> None:
305
457
  """Reset the root."""
306
458
  self.reachable_nodes = []
@@ -315,19 +467,6 @@ class GenericEdge(EdgeArchitype):
315
467
  _jac_exit_funcs_ = []
316
468
 
317
469
 
318
- @dataclass(eq=False)
319
- class DSFunc:
320
- """Data Spatial Function."""
321
-
322
- name: str
323
- trigger: type | types.UnionType | tuple[type | types.UnionType, ...] | None
324
- func: Callable[[Any, Any], Any] | None = None
325
-
326
- def resolve(self, cls: type) -> None:
327
- """Resolve the function."""
328
- self.func = getattr(cls, self.name)
329
-
330
-
331
470
  class JacTestResult(unittest.TextTestResult):
332
471
  """Jac test result class."""
333
472
 
@@ -407,9 +546,6 @@ class JacTestCheck:
407
546
  """Create a new test."""
408
547
  JacTestCheck.test_suite.addTest(unittest.FunctionTestCase(test_fun))
409
548
 
410
- def __getattr__(self, name: str) -> Union[bool, Any]:
549
+ def __getattr__(self, name: str) -> object:
411
550
  """Make convenient check.Equal(...) etc."""
412
551
  return getattr(JacTestCheck.test_case, name)
413
-
414
-
415
- root = Root()
jaclang/core/importer.py CHANGED
@@ -10,6 +10,7 @@ from typing import Optional, Union
10
10
  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
+ from jaclang.core.utils import sys_path_context
13
14
  from jaclang.utils.log import logging
14
15
 
15
16
 
@@ -21,56 +22,41 @@ def jac_importer(
21
22
  mdl_alias: Optional[str] = None,
22
23
  override_name: Optional[str] = None,
23
24
  mod_bundle: Optional[Module] = None,
24
- lng: Optional[str] = None,
25
+ lng: Optional[str] = "jac",
25
26
  items: Optional[dict[str, Union[str, bool]]] = None,
26
27
  ) -> Optional[types.ModuleType]:
27
28
  """Core Import Process."""
28
- dir_path, file_name = (
29
- path.split(path.join(*(target.split("."))) + ".py")
30
- if lng == "py"
31
- else path.split(path.join(*(target.split("."))) + ".jac")
29
+ dir_path, file_name = path.split(
30
+ path.join(*(target.split("."))) + (".jac" if lng == "jac" else ".py")
32
31
  )
33
32
  module_name = path.splitext(file_name)[0]
34
33
  package_path = dir_path.replace(path.sep, ".")
35
34
 
36
- if package_path and f"{package_path}.{module_name}" in sys.modules and lng != "py":
35
+ if (
36
+ not override_name
37
+ and package_path
38
+ and f"{package_path}.{module_name}" in sys.modules
39
+ ):
37
40
  return sys.modules[f"{package_path}.{module_name}"]
38
- elif not package_path and module_name in sys.modules and lng != "py":
41
+ elif not override_name and not package_path and module_name in sys.modules:
39
42
  return sys.modules[module_name]
40
43
 
41
- caller_dir = path.dirname(base_path) if not path.isdir(base_path) else base_path
42
- if not caller_dir:
43
- caller_dir = getcwd()
44
- chomp_target = target
45
- if chomp_target.startswith("."):
46
- chomp_target = chomp_target[1:]
47
- while chomp_target.startswith("."):
48
- caller_dir = path.dirname(caller_dir)
49
- chomp_target = chomp_target[1:]
50
- caller_dir = path.join(caller_dir, dir_path)
51
-
44
+ caller_dir = get_caller_dir(target, base_path, dir_path)
52
45
  full_target = path.normpath(path.join(caller_dir, file_name))
53
- path_added = False
54
- if caller_dir not in sys.path:
55
- sys.path.append(caller_dir)
56
- path_added = True
57
46
 
58
- module_name = override_name if override_name else module_name
59
- module = types.ModuleType(module_name)
60
- module.__file__ = full_target
61
- module.__name__ = module_name
62
- module.__dict__["__jac_mod_bundle__"] = mod_bundle
63
- if lng != "py":
47
+ if lng == "py":
48
+ module = py_import(
49
+ target=target, items=items, absorb=absorb, mdl_alias=mdl_alias
50
+ )
51
+ else:
52
+ module_name = override_name if override_name else module_name
53
+ module = create_jac_py_module(
54
+ mod_bundle, module_name, package_path, full_target
55
+ )
64
56
  if mod_bundle:
65
- codeobj = (
66
- mod_bundle.gen.py_bytecode
67
- if full_target == mod_bundle.loc.mod_path
68
- else mod_bundle.mod_deps[full_target].gen.py_bytecode
69
- )
70
- if isinstance(codeobj, bytes):
71
- codeobj = marshal.loads(codeobj)
57
+ codeobj = mod_bundle.mod_deps[full_target].gen.py_bytecode
58
+ codeobj = marshal.loads(codeobj) if isinstance(codeobj, bytes) else None
72
59
  else:
73
-
74
60
  gen_dir = path.join(caller_dir, Con.JAC_GEN_DIR)
75
61
  pyc_file_path = path.join(gen_dir, module_name + ".jbc")
76
62
  if (
@@ -89,46 +75,60 @@ def jac_importer(
89
75
  return None
90
76
  else:
91
77
  codeobj = marshal.loads(result.ir.gen.py_bytecode)
92
-
93
- if package_path:
94
- parts = package_path.split(".")
95
- for i in range(len(parts)):
96
- package_name = ".".join(parts[: i + 1])
97
- if package_name not in sys.modules:
98
- sys.modules[package_name] = types.ModuleType(package_name)
99
-
100
- setattr(sys.modules[package_path], module_name, module)
101
- sys.modules[f"{package_path}.{module_name}"] = module
102
- sys.modules[module_name] = module
103
-
104
78
  if not codeobj:
105
79
  raise ImportError(f"No bytecode found for {full_target}")
106
- exec(codeobj, module.__dict__)
80
+ with sys_path_context(caller_dir):
81
+ exec(codeobj, module.__dict__)
107
82
 
108
- (
109
- py_import(target=target, items=items, absorb=absorb, mdl_alias=mdl_alias)
110
- if lng == "py" or lng == "jac"
111
- else None
112
- )
83
+ return module
113
84
 
114
- if path_added:
115
- sys.path.remove(caller_dir)
116
85
 
86
+ def create_jac_py_module(
87
+ mod_bundle: Optional[Module], module_name: str, package_path: str, full_target: str
88
+ ) -> types.ModuleType:
89
+ """Create a module."""
90
+ module = types.ModuleType(module_name)
91
+ module.__file__ = full_target
92
+ module.__name__ = module_name
93
+ module.__dict__["__jac_mod_bundle__"] = mod_bundle
94
+ if package_path:
95
+ parts = package_path.split(".")
96
+ for i in range(len(parts)):
97
+ package_name = ".".join(parts[: i + 1])
98
+ if package_name not in sys.modules:
99
+ sys.modules[package_name] = types.ModuleType(package_name)
100
+
101
+ setattr(sys.modules[package_path], module_name, module)
102
+ sys.modules[f"{package_path}.{module_name}"] = module
103
+ sys.modules[module_name] = module
117
104
  return module
118
105
 
119
106
 
107
+ def get_caller_dir(target: str, base_path: str, dir_path: str) -> str:
108
+ """Get the directory of the caller."""
109
+ caller_dir = base_path if path.isdir(base_path) else path.dirname(base_path)
110
+ caller_dir = caller_dir if caller_dir else getcwd()
111
+ chomp_target = target
112
+ if chomp_target.startswith("."):
113
+ chomp_target = chomp_target[1:]
114
+ while chomp_target.startswith("."):
115
+ caller_dir = path.dirname(caller_dir)
116
+ chomp_target = chomp_target[1:]
117
+ caller_dir = path.join(caller_dir, dir_path)
118
+ return caller_dir
119
+
120
+
120
121
  def py_import(
121
122
  target: str,
122
123
  items: Optional[dict[str, Union[str, bool]]] = None,
123
124
  absorb: bool = False,
124
125
  mdl_alias: Optional[str] = None,
125
- ) -> None:
126
+ ) -> types.ModuleType:
126
127
  """Import a Python module."""
127
128
  try:
128
129
  target = target.lstrip(".") if target.startswith("..") else target
129
- imported_module = importlib.import_module(target)
130
+ imported_module = importlib.import_module(name=target)
130
131
  main_module = __import__("__main__")
131
- # importer = importlib.import_module(caller)
132
132
  if absorb:
133
133
  for name in dir(imported_module):
134
134
  if not name.startswith("_"):
@@ -136,11 +136,21 @@ def py_import(
136
136
 
137
137
  elif items:
138
138
  for name, alias in items.items():
139
- setattr(
140
- main_module,
141
- alias if isinstance(alias, str) else name,
142
- getattr(imported_module, name),
143
- )
139
+ try:
140
+ setattr(
141
+ main_module,
142
+ alias if isinstance(alias, str) else name,
143
+ getattr(imported_module, name),
144
+ )
145
+ except AttributeError as e:
146
+ if hasattr(imported_module, "__path__"):
147
+ setattr(
148
+ main_module,
149
+ alias if isinstance(alias, str) else name,
150
+ importlib.import_module(f"{target}.{name}"),
151
+ )
152
+ else:
153
+ raise e
144
154
 
145
155
  else:
146
156
  setattr(
@@ -148,5 +158,7 @@ def py_import(
148
158
  mdl_alias if isinstance(mdl_alias, str) else target,
149
159
  imported_module,
150
160
  )
151
- except ImportError:
161
+ return imported_module
162
+ except ImportError as e:
152
163
  print(f"Failed to import module {target}")
164
+ raise e
@@ -0,0 +1,20 @@
1
+ """LLM implementations for MTLLM."""
2
+
3
+ from .anthropic import Anthropic
4
+ from .base import BaseLLM
5
+ from .groq import Groq
6
+ from .huggingface import Huggingface
7
+ from .ollama import Ollama
8
+ from .openai import OpenAI
9
+ from .togetherai import TogetherAI
10
+
11
+
12
+ __all__ = [
13
+ "Anthropic",
14
+ "Ollama",
15
+ "Huggingface",
16
+ "Groq",
17
+ "BaseLLM",
18
+ "OpenAI",
19
+ "TogetherAI",
20
+ ]