jaclang 0.7.2__py3-none-any.whl → 0.7.5__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 (62) hide show
  1. jaclang/cli/cli.py +2 -2
  2. jaclang/compiler/absyntree.py +337 -273
  3. jaclang/compiler/codeloc.py +2 -2
  4. jaclang/compiler/constant.py +2 -0
  5. jaclang/compiler/jac.lark +25 -19
  6. jaclang/compiler/parser.py +115 -92
  7. jaclang/compiler/passes/main/access_modifier_pass.py +15 -9
  8. jaclang/compiler/passes/main/def_impl_match_pass.py +25 -13
  9. jaclang/compiler/passes/main/def_use_pass.py +48 -17
  10. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +34 -34
  11. jaclang/compiler/passes/main/import_pass.py +8 -6
  12. jaclang/compiler/passes/main/pyast_gen_pass.py +97 -42
  13. jaclang/compiler/passes/main/pyast_load_pass.py +47 -12
  14. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +19 -10
  15. jaclang/compiler/passes/main/registry_pass.py +6 -6
  16. jaclang/compiler/passes/main/sym_tab_build_pass.py +30 -72
  17. jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +21 -4
  18. jaclang/compiler/passes/main/tests/test_def_use_pass.py +5 -10
  19. jaclang/compiler/passes/main/type_check_pass.py +2 -1
  20. jaclang/compiler/passes/tool/jac_formatter_pass.py +30 -9
  21. jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +16 -0
  22. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +16 -0
  23. jaclang/compiler/passes/transform.py +2 -4
  24. jaclang/{core/registry.py → compiler/semtable.py} +1 -3
  25. jaclang/compiler/symtable.py +25 -37
  26. jaclang/compiler/tests/test_parser.py +2 -2
  27. jaclang/core/aott.py +8 -8
  28. jaclang/core/{construct.py → architype.py} +25 -240
  29. jaclang/core/constructs.py +44 -0
  30. jaclang/core/context.py +157 -0
  31. jaclang/core/importer.py +18 -9
  32. jaclang/core/memory.py +99 -0
  33. jaclang/core/test.py +90 -0
  34. jaclang/core/utils.py +2 -2
  35. jaclang/langserve/engine.py +32 -19
  36. jaclang/langserve/tests/fixtures/circle.jac +16 -12
  37. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  38. jaclang/langserve/tests/test_server.py +3 -12
  39. jaclang/langserve/utils.py +10 -6
  40. jaclang/plugin/builtin.py +1 -1
  41. jaclang/plugin/default.py +21 -7
  42. jaclang/plugin/feature.py +24 -6
  43. jaclang/plugin/spec.py +17 -19
  44. jaclang/settings.py +3 -0
  45. jaclang/tests/fixtures/abc.jac +16 -12
  46. jaclang/tests/fixtures/byllmissue.jac +9 -0
  47. jaclang/tests/fixtures/edgetypetest.jac +16 -0
  48. jaclang/tests/fixtures/impl_match_confused.impl.jac +1 -0
  49. jaclang/tests/fixtures/impl_match_confused.jac +5 -0
  50. jaclang/tests/fixtures/maxfail_run_test.jac +17 -5
  51. jaclang/tests/fixtures/run_test.jac +17 -5
  52. jaclang/tests/test_bugs.py +19 -0
  53. jaclang/tests/test_cli.py +1 -1
  54. jaclang/tests/test_language.py +56 -1
  55. jaclang/tests/test_reference.py +1 -1
  56. jaclang/utils/lang_tools.py +5 -4
  57. jaclang/utils/test.py +2 -1
  58. jaclang/utils/treeprinter.py +22 -8
  59. {jaclang-0.7.2.dist-info → jaclang-0.7.5.dist-info}/METADATA +1 -1
  60. {jaclang-0.7.2.dist-info → jaclang-0.7.5.dist-info}/RECORD +62 -54
  61. {jaclang-0.7.2.dist-info → jaclang-0.7.5.dist-info}/WHEEL +0 -0
  62. {jaclang-0.7.2.dist-info → jaclang-0.7.5.dist-info}/entry_points.txt +0 -0
@@ -1,5 +1,6 @@
1
1
  """Test pass module."""
2
2
 
3
+ import jaclang.compiler.absyntree as ast
3
4
  from jaclang.compiler.compile import jac_file_to_pass
4
5
  from jaclang.compiler.passes.main import DeclImplMatchPass
5
6
  from jaclang.utils.test import TestCase
@@ -17,15 +18,31 @@ class DeclImplMatchPassTests(TestCase):
17
18
  state = jac_file_to_pass(self.fixture_abs_path("base.jac"), DeclImplMatchPass)
18
19
  self.assertFalse(state.errors_had)
19
20
  self.assertIn("(o)Test.(c)say_hi", state.ir.sym_tab.tab)
20
- self.assertIsNotNone(state.ir.sym_tab.tab["(o)Test.(c)say_hi"].decl.body)
21
+ self.assertIsNotNone(
22
+ state.ir.sym_tab.tab["(o)Test.(c)say_hi"].decl.name_of.body
23
+ )
21
24
  self.assertIn("(o)Test.(c)__init__", state.ir.sym_tab.tab)
22
- self.assertIsNotNone(state.ir.sym_tab.tab["(o)Test.(c)__init__"].decl.body)
25
+ self.assertIsNotNone(
26
+ state.ir.sym_tab.tab["(o)Test.(c)__init__"].decl.name_of.body
27
+ )
23
28
 
24
29
  def test_ability_connected_to_decl_post(self) -> None:
25
30
  """Basic test for pass."""
26
31
  state = jac_file_to_pass(self.fixture_abs_path("base2.jac"), DeclImplMatchPass)
27
32
  self.assertFalse(state.errors_had)
28
33
  self.assertIn("(o)Test.(c)say_hi", state.ir.sym_tab.tab)
29
- self.assertIsNotNone(state.ir.sym_tab.tab["(o)Test.(c)say_hi"].decl.body)
34
+ self.assertIsNotNone(
35
+ state.ir.sym_tab.tab["(o)Test.(c)say_hi"].decl.name_of.body
36
+ )
30
37
  self.assertIn("(o)Test.(c)__init__", state.ir.sym_tab.tab)
31
- self.assertIsNotNone(state.ir.sym_tab.tab["(o)Test.(c)__init__"].decl.body)
38
+ self.assertIsNotNone(
39
+ state.ir.sym_tab.tab["(o)Test.(c)__init__"].decl.name_of.body
40
+ )
41
+
42
+ def test_arch_ref_has_sym(self) -> None:
43
+ """Basic test for pass."""
44
+ state = jac_file_to_pass(
45
+ self.fixture_abs_path("defs_and_uses.jac"), DeclImplMatchPass
46
+ )
47
+ for i in state.ir.get_all_sub_nodes(ast.ArchRef):
48
+ self.assertIsNotNone(i.sym)
@@ -18,13 +18,8 @@ class DefUsePassTests(TestCase):
18
18
  file_path=self.fixture_abs_path("defs_and_uses.jac"),
19
19
  target=DefUsePass,
20
20
  )
21
- # for i in state.unlinked:
22
- # print(f"Unlinked {i.__class__.__name__} {i.sym_name} {i.loc}")
23
- # for i in state.linked:
24
- # print(
25
- # f"Linked {i.__class__.__name__} {i.sym_name} {i.loc} "
26
- # f", {i.sym_link.decl.loc if i.sym_link else None}"
27
- # )
28
- self.assertGreater(len(state.linked), 5)
29
- self.assertLess(len(state.warnings_had), 50)
30
- self.assertEqual(len(state.errors_had), 0)
21
+ uses = [i.uses for i in state.ir.sym_tab.kid[0].tab.values()]
22
+ self.assertEqual(len(uses[1]), 1)
23
+ self.assertEqual(len(uses[2]), 1)
24
+ self.assertIn("output", [uses[1][0].sym_name, uses[2][0].sym_name])
25
+ self.assertIn("message", [uses[1][0].sym_name, uses[2][0].sym_name])
@@ -8,9 +8,9 @@ import os
8
8
  import pathlib
9
9
  import sys
10
10
 
11
-
12
11
  import jaclang.compiler.absyntree as ast
13
12
  import jaclang.compiler.passes.utils.mypy_ast_build as myab
13
+ from jaclang.compiler.constant import Constants as Con
14
14
  from jaclang.compiler.passes import Pass
15
15
 
16
16
 
@@ -48,6 +48,7 @@ class JacTypeCheckPass(Pass):
48
48
  """Call mypy APIs to implement type checking in Jac."""
49
49
  # Creating mypy api objects
50
50
  options = myab.myb.Options()
51
+ options.cache_dir = Con.JAC_MYPY_CACHE
51
52
  errors = myab.Errors(self, options)
52
53
  fs_cache = myab.FileSystemCache()
53
54
  search_paths = myab.compute_search_paths([], options, str(self.__path))
@@ -484,7 +484,7 @@ class JacFormatPass(Pass):
484
484
 
485
485
  var: Token,
486
486
  """
487
- self.emit(node, node.var.value)
487
+ self.emit(node, node.orig.value)
488
488
 
489
489
  def exit_ability_def(self, node: ast.AbilityDef) -> None:
490
490
  """Sub objects.
@@ -1871,6 +1871,32 @@ class JacFormatPass(Pass):
1871
1871
  if isinstance(node.kid[-1], (ast.Semi, ast.CommentToken)):
1872
1872
  self.emit_ln(node, "")
1873
1873
 
1874
+ def exit_check_stmt(self, node: ast.CheckStmt) -> None:
1875
+ """Sub objects.
1876
+
1877
+ target: ExprType,
1878
+ """
1879
+ start = True
1880
+ for i in node.kid:
1881
+ if isinstance(i, ast.CommentToken):
1882
+ if i.is_inline:
1883
+ self.emit(node, f" {i.gen.jac}")
1884
+ else:
1885
+ if not node.gen.jac.endswith("\n"):
1886
+ self.emit_ln(node, "")
1887
+ self.emit_ln(node, "")
1888
+ self.emit(node, i.gen.jac)
1889
+ elif isinstance(i, ast.Semi):
1890
+ self.emit(node, i.gen.jac)
1891
+ else:
1892
+ if start:
1893
+ self.emit(node, i.gen.jac)
1894
+ start = False
1895
+ else:
1896
+ self.emit(node, f" {i.gen.jac}")
1897
+ if isinstance(node.kid[-1], (ast.Semi, ast.CommentToken)):
1898
+ self.emit_ln(node, "")
1899
+
1874
1900
  def exit_ctrl_stmt(self, node: ast.CtrlStmt) -> None:
1875
1901
  """Sub objects.
1876
1902
 
@@ -2002,7 +2028,6 @@ class JacFormatPass(Pass):
2002
2028
  doc: Optional[Token],
2003
2029
  body: CodeBlock,
2004
2030
  """
2005
- start = True
2006
2031
  for i in node.kid:
2007
2032
  if isinstance(i, ast.CommentToken):
2008
2033
  if i.is_inline:
@@ -2013,14 +2038,10 @@ class JacFormatPass(Pass):
2013
2038
  elif isinstance(i, ast.Semi):
2014
2039
  self.emit(node, i.gen.jac)
2015
2040
  elif isinstance(i, ast.Name):
2016
- if not i.value.startswith("test_t"):
2017
- self.emit(node, f" {i.value} ")
2041
+ if not i.value.startswith("_jac_gen_"):
2042
+ self.emit(node, f" {i.value}")
2018
2043
  else:
2019
- if start:
2020
- self.emit(node, i.gen.jac)
2021
- start = False
2022
- else:
2023
- self.emit(node, f" {i.gen.jac}")
2044
+ self.emit(node, i.gen.jac)
2024
2045
  if isinstance(node.kid[-1], (ast.Semi, ast.CommentToken)):
2025
2046
  self.emit_ln(node, "")
2026
2047
 
@@ -478,3 +478,19 @@ obj JacPlugin {
478
478
  (walker_obj: Any, expr: Any) -> bool {
479
479
  return walker_obj._jac_.visit_node(expr);
480
480
  }
481
+
482
+ glob expected_area = 78.53981633974483;
483
+
484
+ test a1 {
485
+ check assertAlmostEqual(calculate_area(RAD), expected_area);
486
+ }
487
+
488
+ test a2 {
489
+ c = Circle(RAD);
490
+ check assertAlmostEqual(c.area(), expected_area);
491
+ }
492
+
493
+ test a3 {
494
+ c = Circle(RAD);
495
+ check assertEqual(c.shape_type, ShapeType.CIRCLE);
496
+ }
@@ -478,3 +478,19 @@ obj JacPlugin {
478
478
  (walker_obj: Any, expr: Any) -> bool {
479
479
  return walker_obj._jac_.visit_node(expr);
480
480
  }
481
+
482
+ glob expected_area = 78.53981633974483;
483
+
484
+ test a1 {
485
+ check assertAlmostEqual(calculate_area(RAD), expected_area);
486
+ }
487
+
488
+ test a2 {
489
+ c = Circle(RAD);
490
+ check assertAlmostEqual(c.area(), expected_area);
491
+ }
492
+
493
+ test a3 {
494
+ c = Circle(RAD);
495
+ check assertEqual(c.shape_type, ShapeType.CIRCLE);
496
+ }
@@ -22,7 +22,7 @@ class Alert:
22
22
  def __str__(self) -> str:
23
23
  """Return string representation of alert."""
24
24
  return (
25
- f"{self.loc.mod_path}, line {self.loc.first_line},"
25
+ f" {self.loc.mod_path}, line {self.loc.first_line},"
26
26
  f" col {self.loc.col_start}: {self.msg}"
27
27
  )
28
28
 
@@ -40,7 +40,7 @@ class Transform(ABC, Generic[T]):
40
40
  prior: Optional[Transform] = None,
41
41
  ) -> None:
42
42
  """Initialize pass."""
43
- self.logger = logging.getLogger(self.__class__.__module__)
43
+ self.logger = logging.getLogger(self.__class__.__name__)
44
44
  self.errors_had: list[Alert] = [] if not prior else prior.errors_had
45
45
  self.warnings_had: list[Alert] = [] if not prior else prior.warnings_had
46
46
  self.cur_node: AstNode = input_ir # tracks current node during traversal
@@ -59,7 +59,6 @@ class Transform(ABC, Generic[T]):
59
59
  self.__class__,
60
60
  )
61
61
  self.errors_had.append(alrt)
62
- # print("Error:", str(alrt))
63
62
  self.logger.error(str(alrt))
64
63
 
65
64
  def log_warning(self, msg: str, node_override: Optional[AstNode] = None) -> None:
@@ -70,5 +69,4 @@ class Transform(ABC, Generic[T]):
70
69
  self.__class__,
71
70
  )
72
71
  self.warnings_had.append(alrt)
73
- # print("Warning:", str(alrt))
74
72
  self.logger.warning(str(alrt))
@@ -12,9 +12,7 @@ from typing import Optional
12
12
  class SemInfo:
13
13
  """Semantic information class."""
14
14
 
15
- def __init__(
16
- self, name: str, type: Optional[str] = None, semstr: Optional[str] = None
17
- ) -> None:
15
+ def __init__(self, name: str, type: Optional[str] = None, semstr: str = "") -> None:
18
16
  """Initialize the class."""
19
17
  self.name = name
20
18
  self.type = type
@@ -37,30 +37,13 @@ class SymbolType(Enum):
37
37
  BOOL = "bool" # LSP: Boolean
38
38
  SEQUENCE = "sequence" # LSP: Array
39
39
  NULL = "null" # LSP: Null
40
+ UNKNOWN = "unknown" # LSP: Unknown
40
41
 
41
42
  def __str__(self) -> str:
42
43
  """Stringify."""
43
44
  return self.value
44
45
 
45
46
 
46
- class SymbolInfo:
47
- """Symbol Info."""
48
-
49
- def __init__(
50
- self, typ: str = "NoType", acc_tag: Optional[SymbolAccess] = None
51
- ) -> None: # noqa: ANN401
52
- """Initialize."""
53
- self.typ = typ
54
- self.acc_tag: Optional[SymbolAccess] = acc_tag
55
- self.typ_sym_table: Optional[SymbolTable] = None
56
-
57
- @property
58
- def clean_type(self) -> str:
59
- """Get clean type."""
60
- ret_type = self.typ.replace("builtins.", "").replace("NoType", "")
61
- return ret_type
62
-
63
-
64
47
  class SymbolAccess(Enum):
65
48
  """Symbol types."""
66
49
 
@@ -80,20 +63,19 @@ class Symbol:
80
63
 
81
64
  def __init__(
82
65
  self,
83
- defn: ast.AstSymbolNode,
66
+ defn: ast.NameAtom,
84
67
  access: SymbolAccess,
85
68
  parent_tab: SymbolTable,
86
- typ: Optional[type] = None,
87
69
  ) -> None:
88
70
  """Initialize."""
89
- self.typ = typ
90
- self.defn: list[ast.AstSymbolNode] = [defn]
91
- defn.sym_link = self
92
- self.access = access
71
+ self.defn: list[ast.NameAtom] = [defn]
72
+ self.uses: list[ast.NameAtom] = []
73
+ defn.sym = self
74
+ self.access: SymbolAccess = access
93
75
  self.parent_tab = parent_tab
94
76
 
95
77
  @property
96
- def decl(self) -> ast.AstSymbolNode:
78
+ def decl(self) -> ast.NameAtom:
97
79
  """Get decl."""
98
80
  return self.defn[0]
99
81
 
@@ -105,10 +87,10 @@ class Symbol:
105
87
  @property
106
88
  def sym_type(self) -> SymbolType:
107
89
  """Get sym_type."""
108
- return self.decl.sym_type
90
+ return self.decl.sym_category
109
91
 
110
92
  @property
111
- def sym_path_str(self) -> str:
93
+ def sym_dotted_name(self) -> str:
112
94
  """Return a full path of the symbol."""
113
95
  out = [self.defn[0].sym_name]
114
96
  current_tab = self.parent_tab
@@ -121,17 +103,19 @@ class Symbol:
121
103
  out.reverse()
122
104
  return ".".join(out)
123
105
 
124
- def add_defn(self, node: ast.AstSymbolNode) -> None:
106
+ def add_defn(self, node: ast.NameAtom) -> None:
125
107
  """Add defn."""
126
108
  self.defn.append(node)
127
- node.sym_link = self
109
+ node.sym = self
110
+
111
+ def add_use(self, node: ast.NameAtom) -> None:
112
+ """Add use."""
113
+ self.uses.append(node)
114
+ node.sym = self
128
115
 
129
116
  def __repr__(self) -> str:
130
117
  """Repr."""
131
- return (
132
- f"Symbol({self.sym_name}, {self.sym_type}, {self.access}, "
133
- f"{self.typ}, {self.defn})"
134
- )
118
+ return f"Symbol({self.sym_name}, {self.sym_type}, {self.access}, {self.defn})"
135
119
 
136
120
 
137
121
  class SymbolTable:
@@ -146,7 +130,7 @@ class SymbolTable:
146
130
  self.parent = parent if parent else self
147
131
  self.kid: list[SymbolTable] = []
148
132
  self.tab: dict[str, Symbol] = {}
149
- self.uses: list[ast.AstSymbolNode] = []
133
+ self.inherit: list[SymbolTable] = []
150
134
 
151
135
  def has_parent(self) -> bool:
152
136
  """Check if has parent."""
@@ -162,6 +146,10 @@ class SymbolTable:
162
146
  """Lookup a variable in the symbol table."""
163
147
  if name in self.tab:
164
148
  return self.tab[name]
149
+ for i in self.inherit:
150
+ found = i.lookup(name, deep=False)
151
+ if found:
152
+ return found
165
153
  if deep and self.has_parent():
166
154
  return self.get_parent().lookup(name, deep)
167
155
  return None
@@ -184,7 +172,7 @@ class SymbolTable:
184
172
  )
185
173
  if node.sym_name not in self.tab:
186
174
  self.tab[node.sym_name] = Symbol(
187
- defn=node,
175
+ defn=node.name_spec,
188
176
  access=(
189
177
  access_spec
190
178
  if isinstance(access_spec, SymbolAccess)
@@ -193,8 +181,8 @@ class SymbolTable:
193
181
  parent_tab=self,
194
182
  )
195
183
  else:
196
- self.tab[node.sym_name].add_defn(node)
197
- node.sym_link = self.tab[node.sym_name]
184
+ self.tab[node.sym_name].add_defn(node.name_spec)
185
+ node.name_spec.sym = self.tab[node.sym_name]
198
186
  return collision
199
187
 
200
188
  def find_scope(self, name: str) -> Optional[SymbolTable]:
@@ -102,9 +102,9 @@ class TestLarkParser(TestCaseMicroSuite):
102
102
  "JacSource",
103
103
  "EmptyToken",
104
104
  "AstSymbolNode",
105
+ "AstSymbolStubNode",
105
106
  "AstImplNeedingNode",
106
107
  "AstAccessNode",
107
- "TokenSymbol",
108
108
  "Literal",
109
109
  "AstDocNode",
110
110
  "AstSemStrNode",
@@ -119,7 +119,7 @@ class TestLarkParser(TestCaseMicroSuite):
119
119
  "ArchBlockStmt",
120
120
  "EnumBlockStmt",
121
121
  "CodeBlockStmt",
122
- "NameSpec",
122
+ "NameAtom",
123
123
  "ArchSpec",
124
124
  "MatchPattern",
125
125
  ]
jaclang/core/aott.py CHANGED
@@ -17,8 +17,8 @@ try:
17
17
  except ImportError:
18
18
  Image = None
19
19
 
20
+ from jaclang.compiler.semtable import SemInfo, SemRegistry, SemScope
20
21
  from jaclang.core.llms.base import BaseLLM
21
- from jaclang.core.registry import SemInfo, SemRegistry, SemScope
22
22
 
23
23
 
24
24
  IMG_FORMATS = ["PngImageFile", "JpegImageFile"]
@@ -108,7 +108,7 @@ def get_info_types(
108
108
  else None
109
109
  )
110
110
  info_str.append(
111
- f"{sem_info.semstr} ({sem_info.name}) ({sem_info.type}) = {get_object_string(incl[1])}"
111
+ f"{sem_info.semstr} ({sem_info.name}) ({sem_info.type}) = {get_object_string(incl[1])}".strip()
112
112
  )
113
113
  return ("\n".join(info_str), collected_types)
114
114
 
@@ -179,7 +179,7 @@ def get_type_explanation(
179
179
  if sem_info.type == "Enum" and isinstance(type_info, list):
180
180
  for enum_item in type_info:
181
181
  type_info_str.append(
182
- f"{enum_item.semstr} ({enum_item.name}) (EnumItem)"
182
+ f"{enum_item.semstr} ({enum_item.name}) (EnumItem)".strip()
183
183
  )
184
184
  type_example[0] = type_example[0].replace("(", f".{enum_item.name}")
185
185
  elif sem_info.type in ["obj", "class", "node", "edge"] and isinstance(
@@ -189,7 +189,7 @@ def get_type_explanation(
189
189
  if arch_item.type in ["obj", "class", "node", "edge"]:
190
190
  continue
191
191
  type_info_str.append(
192
- f"{arch_item.semstr} ({arch_item.name}) ({arch_item.type})"
192
+ f"{arch_item.semstr} ({arch_item.name}) ({arch_item.type})".strip()
193
193
  )
194
194
  type_example.append(f"{arch_item.name}={arch_item.type}, ")
195
195
  if arch_item.type and extract_non_primary_type(arch_item.type):
@@ -199,7 +199,7 @@ def get_type_explanation(
199
199
  else:
200
200
  type_example.append(")")
201
201
  return (
202
- f"{sem_info.semstr} ({sem_info.name}) ({sem_info.type}) eg:- {''.join(type_example)} -> {', '.join(type_info_str)}", # noqa: E501
202
+ f"{sem_info.semstr} ({sem_info.name}) ({sem_info.type}) eg:- {''.join(type_example)} -> {', '.join(type_info_str)}".strip(), # noqa: E501
203
203
  set(type_info_types),
204
204
  )
205
205
  return None, None
@@ -270,7 +270,7 @@ def get_input_information(
270
270
  typ_anno = get_type_annotation(i[3])
271
271
  type_collector.extend(extract_non_primary_type(typ_anno))
272
272
  inputs_information_list.append(
273
- f"{i[0]} ({i[2]}) ({typ_anno}) = {get_object_string(i[3])}"
273
+ f"{i[0] if i[0] else ''} ({i[2]}) ({typ_anno}) = {get_object_string(i[3])}".strip()
274
274
  )
275
275
  return "\n".join(inputs_information_list)
276
276
  else:
@@ -281,7 +281,7 @@ def get_input_information(
281
281
  image_repr: list[dict] = [
282
282
  {
283
283
  "type": "text",
284
- "text": f"{i[0]} ({i[2]}) (Image) = ",
284
+ "text": f"{i[0] if i[0] else ''} ({i[2]}) (Image) = ".strip(),
285
285
  },
286
286
  {"type": "image_url", "image_url": {"url": img_base64}},
287
287
  ]
@@ -292,7 +292,7 @@ def get_input_information(
292
292
  inputs_information_dict_list.append(
293
293
  {
294
294
  "type": "text",
295
- "text": f"{i[0]} ({i[2]}) ({typ_anno}) = {get_object_string(i[3])}",
295
+ "text": f"{i[0] if i[0] else ''} ({i[2]}) ({typ_anno}) = {get_object_string(i[3])}".strip(),
296
296
  }
297
297
  )
298
298
  return inputs_information_dict_list