jaclang 0.8.7__py3-none-any.whl → 0.8.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of jaclang might be problematic. Click here for more details.
- jaclang/cli/cli.py +13 -27
- jaclang/cli/cmdreg.py +44 -0
- jaclang/compiler/constant.py +0 -1
- jaclang/compiler/jac.lark +3 -6
- jaclang/compiler/larkparse/jac_parser.py +2 -2
- jaclang/compiler/parser.py +213 -34
- jaclang/compiler/passes/main/__init__.py +2 -4
- jaclang/compiler/passes/main/def_use_pass.py +0 -4
- jaclang/compiler/passes/main/predynamo_pass.py +221 -0
- jaclang/compiler/passes/main/pyast_gen_pass.py +70 -52
- jaclang/compiler/passes/main/pyast_load_pass.py +52 -20
- jaclang/compiler/passes/main/sym_tab_build_pass.py +1 -1
- jaclang/compiler/passes/main/tests/fixtures/checker/import_sym.jac +2 -0
- jaclang/compiler/passes/main/tests/fixtures/checker/import_sym_test.jac +6 -0
- jaclang/compiler/passes/main/tests/fixtures/checker/imported_sym.jac +5 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_arg_param_match.jac +37 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +18 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_cat_is_animal.jac +18 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_float.jac +7 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_param_types.jac +11 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_self_type.jac +9 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_sym_inherit.jac +42 -0
- jaclang/compiler/passes/main/tests/fixtures/predynamo_fix3.jac +43 -0
- jaclang/compiler/passes/main/tests/fixtures/predynamo_where_assign.jac +13 -0
- jaclang/compiler/passes/main/tests/fixtures/predynamo_where_return.jac +11 -0
- jaclang/compiler/passes/main/tests/test_checker_pass.py +191 -0
- jaclang/compiler/passes/main/tests/test_predynamo_pass.py +57 -0
- jaclang/compiler/passes/main/type_checker_pass.py +29 -73
- jaclang/compiler/passes/tool/doc_ir_gen_pass.py +204 -44
- jaclang/compiler/passes/tool/jac_formatter_pass.py +119 -69
- jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +3 -3
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +4 -5
- jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +171 -11
- jaclang/compiler/passes/transform.py +12 -8
- jaclang/compiler/program.py +14 -6
- jaclang/compiler/tests/fixtures/jac_import_py_files.py +4 -0
- jaclang/compiler/tests/fixtures/jac_module.jac +3 -0
- jaclang/compiler/tests/fixtures/multiple_syntax_errors.jac +10 -0
- jaclang/compiler/tests/fixtures/python_module.py +1 -0
- jaclang/compiler/tests/test_importer.py +39 -0
- jaclang/compiler/tests/test_parser.py +49 -0
- jaclang/compiler/type_system/type_evaluator.py +351 -67
- jaclang/compiler/type_system/type_utils.py +246 -0
- jaclang/compiler/type_system/types.py +58 -2
- jaclang/compiler/unitree.py +79 -94
- jaclang/langserve/engine.jac +138 -159
- jaclang/langserve/server.jac +25 -1
- jaclang/langserve/tests/fixtures/circle.jac +3 -3
- jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
- jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
- jaclang/langserve/tests/fixtures/completion_test_err.jac +10 -0
- jaclang/langserve/tests/server_test/circle_template.jac +80 -0
- jaclang/langserve/tests/server_test/glob_template.jac +4 -0
- jaclang/langserve/tests/server_test/test_lang_serve.py +154 -309
- jaclang/langserve/tests/server_test/utils.py +153 -116
- jaclang/langserve/tests/test_server.py +21 -84
- jaclang/langserve/utils.jac +12 -15
- jaclang/runtimelib/machine.py +7 -0
- jaclang/runtimelib/meta_importer.py +27 -1
- jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
- jaclang/runtimelib/tests/fixtures/savable_object.jac +2 -2
- jaclang/settings.py +18 -14
- jaclang/tests/fixtures/abc_check.jac +3 -3
- jaclang/tests/fixtures/arch_rel_import_creation.jac +12 -12
- jaclang/tests/fixtures/chandra_bugs2.jac +3 -3
- jaclang/tests/fixtures/create_dynamic_archetype.jac +13 -13
- jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
- jaclang/tests/fixtures/params/param_syntax_err.jac +9 -0
- jaclang/tests/fixtures/params/test_complex_params.jac +42 -0
- jaclang/tests/fixtures/params/test_failing_kwonly.jac +207 -0
- jaclang/tests/fixtures/params/test_failing_posonly.jac +116 -0
- jaclang/tests/fixtures/params/test_failing_varargs.jac +300 -0
- jaclang/tests/fixtures/params/test_kwonly_params.jac +29 -0
- jaclang/tests/fixtures/py2jac_params.py +8 -0
- jaclang/tests/fixtures/run_test.jac +4 -4
- jaclang/tests/test_cli.py +37 -1
- jaclang/tests/test_language.py +74 -16
- jaclang/utils/helpers.py +47 -2
- jaclang/utils/module_resolver.py +10 -0
- jaclang/utils/test.py +8 -0
- jaclang/utils/treeprinter.py +0 -18
- {jaclang-0.8.7.dist-info → jaclang-0.8.8.dist-info}/METADATA +1 -2
- {jaclang-0.8.7.dist-info → jaclang-0.8.8.dist-info}/RECORD +85 -60
- {jaclang-0.8.7.dist-info → jaclang-0.8.8.dist-info}/WHEEL +1 -1
- jaclang/compiler/passes/main/inheritance_pass.py +0 -131
- jaclang/langserve/dev_engine.jac +0 -645
- jaclang/langserve/dev_server.jac +0 -201
- jaclang/langserve/tests/server_test/code_test.py +0 -0
- {jaclang-0.8.7.dist-info → jaclang-0.8.8.dist-info}/entry_points.txt +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import re;
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
glob a
|
|
4
|
+
glob a: int = 5;
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
with entry {
|
|
8
8
|
arguments = { x : None for x in re.findall(r'\{([A-Za-z0-9_]+)\}', "Apple {apple} pineapple {pineapple}") };
|
|
9
|
-
a
|
|
9
|
+
a: int = 5;
|
|
10
10
|
if False {
|
|
11
|
-
with open(f"Apple{apple}.txt") as f
|
|
11
|
+
with open(f"Apple{apple}.txt") as f {
|
|
12
12
|
# Fix syntax highlighting
|
|
13
13
|
print(
|
|
14
14
|
f.read()
|
|
@@ -2,23 +2,23 @@ import from jaclang.runtimelib.machine { JacMachine }
|
|
|
2
2
|
# Dynamically create a node archetype
|
|
3
3
|
glob source_code =
|
|
4
4
|
"""
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
node dynamic_node {
|
|
6
|
+
has value:int;
|
|
7
|
+
can print_value with entry {
|
|
8
|
+
print("Dynamic Node Value:", f'{self.value}');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
""";
|
|
12
12
|
|
|
13
13
|
# Create a new walker archetype dynamically
|
|
14
14
|
glob walker_code =
|
|
15
15
|
"""
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
walker dynamic_walker {
|
|
17
|
+
can visit_nodes with entry {
|
|
18
|
+
visit [-->];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
""";
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
with entry {
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
glob x = 5, y = 2;
|
|
2
2
|
|
|
3
3
|
test a {
|
|
4
|
-
|
|
4
|
+
assert almostEqual(5, x);
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
test b {
|
|
8
|
-
|
|
8
|
+
assert "l" in "llm";
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
test c {
|
|
12
|
-
|
|
12
|
+
assert x - y == 3;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
test d {
|
|
16
|
-
|
|
16
|
+
assert 1 == 2;
|
|
17
17
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Test complex parameter combinations
|
|
2
|
+
|
|
3
|
+
def ultimate_signature(
|
|
4
|
+
pos_only: int,
|
|
5
|
+
pos_def: str = "def",
|
|
6
|
+
/,
|
|
7
|
+
reg_def: bool = True,
|
|
8
|
+
*args: int,
|
|
9
|
+
kw_req: str,
|
|
10
|
+
kw_opt: int = 100,
|
|
11
|
+
**kwargs: any
|
|
12
|
+
) -> str {
|
|
13
|
+
return f"{pos_only}|{pos_def}|{reg_def}|{len(args)}|{kw_req}|{kw_opt}|{len(kwargs)}";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
def separators_only(/, *, x: int) -> int {
|
|
17
|
+
return x;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
def edge_case_mix(a: int, /, b: str, *args: float, c: bool, **kwargs: str) -> str {
|
|
21
|
+
return f"{a}-{b}-{len(args)}-{c}-{len(kwargs)}";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
def recursive_test(data: int, /, depth: int = 0, *, max_depth: int = 2) -> int {
|
|
25
|
+
if depth >= max_depth {
|
|
26
|
+
return data;
|
|
27
|
+
}
|
|
28
|
+
return recursive_test(data + 1, depth + 1, max_depth=max_depth);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
def validation_test(x: int, y: str = "test", /, z: float, *args: int, w: bool, **kwargs: str) -> str {
|
|
32
|
+
return f"x:{x},y:{y},z:{z},args:{len(args)},w:{w},kwargs:{len(kwargs)}";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
with entry {
|
|
36
|
+
print("ULTIMATE_MIN:", ultimate_signature(1, reg_def=2.5, kw_req="test"));
|
|
37
|
+
print("ULTIMATE_FULL:", ultimate_signature(1, "custom", 3.14, False, 10, 20, kw_req="req", kw_opt=200, extra="data"));
|
|
38
|
+
print("SEPARATORS:", separators_only(x=42));
|
|
39
|
+
print("EDGE_MIX:", edge_case_mix(1, "test", 1.1, 2.2, c=True, name="edge"));
|
|
40
|
+
print("RECURSIVE:", recursive_test(5), recursive_test(10, max_depth=1));
|
|
41
|
+
print("VALIDATION:", validation_test(1, 2.5, 10, 20, w=True, debug="on"));
|
|
42
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Test failing keyword-only parameter cases
|
|
2
|
+
|
|
3
|
+
def strict_kwonly(*, x: int, y: str) -> str {
|
|
4
|
+
return f"{x}: {y}";
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
def kwonly_with_defaults(*, req: int, opt: str = "default") -> str {
|
|
8
|
+
return f"{req}-{opt}";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
def mixed_kwonly(a: int, *, kw1: str, kw2: bool = False) -> dict {
|
|
12
|
+
return {"a": a, "kw1": kw1, "kw2": kw2};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def complex_kwonly(pos: int, /, reg: str, *args: float, kw_req: bool, kw_opt: int = 10, **kwargs: any) -> dict {
|
|
16
|
+
return {"pos": pos, "reg": reg, "args": list(args), "kw_req": kw_req, "kw_opt": kw_opt, "kwargs": kwargs};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
def only_star_separator(*, x: int) -> int {
|
|
20
|
+
return x * 2;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
def nested_kwonly_issues(*, outer: dict, inner: list = []) -> int {
|
|
24
|
+
return len(outer) + len(inner);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
with entry {
|
|
28
|
+
print("=== TESTING KEYWORD-ONLY FAILURES ===");
|
|
29
|
+
|
|
30
|
+
# Test 1: Calling kw-only with positional arguments
|
|
31
|
+
try {
|
|
32
|
+
result = strict_kwonly(42, "test");
|
|
33
|
+
print("❌ FAIL: Should reject positional for kw-only");
|
|
34
|
+
} except Exception as e {
|
|
35
|
+
print("✅ PASS: Caught kw-only positional error:", type(e).__name__);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# Test 2: Missing required keyword-only argument
|
|
39
|
+
try {
|
|
40
|
+
result = strict_kwonly(x=42);
|
|
41
|
+
print("❌ FAIL: Should reject missing required kw-only");
|
|
42
|
+
} except Exception as e {
|
|
43
|
+
print("✅ PASS: Caught missing kw-only error:", type(e).__name__);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# Test 3: Missing required in defaults mix
|
|
47
|
+
try {
|
|
48
|
+
result = kwonly_with_defaults(opt="custom");
|
|
49
|
+
print("❌ FAIL: Should reject missing required kw-only");
|
|
50
|
+
} except Exception as e {
|
|
51
|
+
print("✅ PASS: Caught missing required in defaults:", type(e).__name__);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# Test 4: Extra unknown keyword arguments (without **kwargs)
|
|
55
|
+
try {
|
|
56
|
+
result = strict_kwonly(x=42, y="test", extra="unknown");
|
|
57
|
+
print("❌ FAIL: Should reject unknown keyword");
|
|
58
|
+
} except Exception as e {
|
|
59
|
+
print("✅ PASS: Caught unknown keyword error:", type(e).__name__);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Test 5: Mixed signature - wrong positional count
|
|
63
|
+
try {
|
|
64
|
+
result = mixed_kwonly(1, 2, kw1="test");
|
|
65
|
+
print("❌ FAIL: Should reject too many positional");
|
|
66
|
+
} except Exception as e {
|
|
67
|
+
print("✅ PASS: Caught too many positional error:", type(e).__name__);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# Test 6: Mixed signature - missing kw-only required
|
|
71
|
+
try {
|
|
72
|
+
result = mixed_kwonly(42);
|
|
73
|
+
print("❌ FAIL: Should reject missing kw-only in mixed");
|
|
74
|
+
} except Exception as e {
|
|
75
|
+
print("✅ PASS: Caught missing kw-only in mixed:", type(e).__name__);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# Test 7: Complex signature - kw-only as positional
|
|
79
|
+
try {
|
|
80
|
+
result = complex_kwonly(1, "reg", 1.5, True);
|
|
81
|
+
print("❌ FAIL: Should reject kw-only as positional");
|
|
82
|
+
} except Exception as e {
|
|
83
|
+
print("✅ PASS: Caught kw-only as positional error:", type(e).__name__);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# Test 8: Complex signature - missing required kw-only
|
|
87
|
+
try {
|
|
88
|
+
result = complex_kwonly(1, "reg", 1.5, 2.5);
|
|
89
|
+
print("❌ FAIL: Should reject missing kw-only in complex");
|
|
90
|
+
} except Exception as e {
|
|
91
|
+
print("✅ PASS: Caught missing kw-only in complex:", type(e).__name__);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# Test 9: Only star separator - positional call
|
|
95
|
+
try {
|
|
96
|
+
result = only_star_separator(42);
|
|
97
|
+
print("❌ FAIL: Should reject positional for star-only");
|
|
98
|
+
} except Exception as e {
|
|
99
|
+
print("✅ PASS: Caught star-only positional error:", type(e).__name__);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# Test 11: Mutable default issues
|
|
104
|
+
try {
|
|
105
|
+
result1 = nested_kwonly_issues(outer={"a": 1});
|
|
106
|
+
result2 = nested_kwonly_issues(outer={"b": 2});
|
|
107
|
+
print("✅ INFO: Mutable defaults - result1:", result1, "result2:", result2);
|
|
108
|
+
} except Exception as e {
|
|
109
|
+
print("❌ FAIL: Mutable defaults caused error:", type(e).__name__);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
# Test 12: Valid calls that should work
|
|
113
|
+
try {
|
|
114
|
+
result = strict_kwonly(x=42, y="valid");
|
|
115
|
+
print("✅ PASS: Valid kw-only call:", result);
|
|
116
|
+
} except Exception as e {
|
|
117
|
+
print("❌ FAIL: Valid kw-only call rejected:", type(e).__name__);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
result = kwonly_with_defaults(req=100);
|
|
122
|
+
print("✅ PASS: Valid kw-only with defaults:", result);
|
|
123
|
+
} except Exception as e {
|
|
124
|
+
print("❌ FAIL: Valid defaults call rejected:", type(e).__name__);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
result = mixed_kwonly(5, kw1="test");
|
|
129
|
+
print("✅ PASS: Valid mixed kw-only:", result);
|
|
130
|
+
} except Exception as e {
|
|
131
|
+
print("❌ FAIL: Valid mixed call rejected:", type(e).__name__);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
def additional_kwonly_edge_cases() -> None {
|
|
136
|
+
print("\n=== ADDITIONAL KEYWORD-ONLY EDGE CASES ===");
|
|
137
|
+
|
|
138
|
+
# Test 14: Keyword argument name conflicts with Python keywords
|
|
139
|
+
def python_keyword_conflicts(*, class_name: str, import_path: str = "default") -> str {
|
|
140
|
+
return f"{class_name}: {import_path}";
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
result = python_keyword_conflicts(class_name="TestClass");
|
|
145
|
+
print("✅ PASS: Python keyword as param name:", result);
|
|
146
|
+
} except Exception as e {
|
|
147
|
+
print("❌ FAIL: Python keyword param failed:", type(e).__name__);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# Test 15: Very long keyword-only parameter lists
|
|
151
|
+
def many_kwonly_params(
|
|
152
|
+
*,
|
|
153
|
+
p1: int, p2: int, p3: int, p4: int, p5: int,
|
|
154
|
+
p6: str = "d6", p7: str = "d7", p8: str = "d8"
|
|
155
|
+
) -> dict {
|
|
156
|
+
return {"sum": p1+p2+p3+p4+p5, "strings": [p6, p7, p8]};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
result = many_kwonly_params(p1=1, p2=2, p3=3, p4=4, p5=5);
|
|
161
|
+
print("✅ PASS: Many kw-only params:", result);
|
|
162
|
+
} except Exception as e {
|
|
163
|
+
print("❌ FAIL: Many kw-only params failed:", type(e).__name__);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
# Test 16: Nested function calls as keyword arguments
|
|
167
|
+
def helper_func() -> str {
|
|
168
|
+
return "helper_result";
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
def kwonly_with_function_calls(*, data: str, processed: bool = True) -> str {
|
|
172
|
+
return f"data={data}, processed={processed}";
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
result = kwonly_with_function_calls(data=helper_func(), processed=False);
|
|
177
|
+
print("✅ PASS: Function calls as kw args:", result);
|
|
178
|
+
} except Exception as e {
|
|
179
|
+
print("❌ FAIL: Function calls as kw args failed:", type(e).__name__);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
# Test 17: Empty string and special values
|
|
183
|
+
try {
|
|
184
|
+
result = strict_kwonly(x=0, y="");
|
|
185
|
+
print("✅ PASS: Edge values (0, empty string):", result);
|
|
186
|
+
} except Exception as e {
|
|
187
|
+
print("❌ FAIL: Edge values failed:", type(e).__name__);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
# Test 18: Really test duplicate keyword detection properly
|
|
191
|
+
# Note: This might not be detectable at runtime in some languages
|
|
192
|
+
def test_duplicate_detection() -> None {
|
|
193
|
+
try {
|
|
194
|
+
# This should be a syntax error, but let's see what happens
|
|
195
|
+
call_string = "strict_kwonly(x=42, y='test', x=99)";
|
|
196
|
+
print("INFO: Would test duplicate keywords, but this is syntax-level");
|
|
197
|
+
} except Exception as e {
|
|
198
|
+
print("✅ PASS: Duplicate detection works:", type(e).__name__);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
test_duplicate_detection();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
with entry {
|
|
206
|
+
additional_kwonly_edge_cases();
|
|
207
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Test failing positional-only parameter cases
|
|
2
|
+
|
|
3
|
+
def strict_posonly(a: int, b: str, /) -> str {
|
|
4
|
+
return f"{a}: {b}";
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
def mixed_posonly(x: int, /, y: str, z: float = 1.0) -> str {
|
|
8
|
+
return f"{x}-{y}-{z}";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
def complex_posonly(a: int, b: str = "def", /, c: float, *args: int, kw: bool, **kwargs: any) -> dict {
|
|
12
|
+
return {"a": a, "b": b, "c": c, "args": list(args), "kw": kw, "kwargs": kwargs};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def edge_case_posonly(/, x: int) -> int {
|
|
16
|
+
return x;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
def no_regular_params(a: int, /, *, b: str) -> str {
|
|
20
|
+
return f"{a}: {b}";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
with entry {
|
|
24
|
+
print("=== TESTING POSITIONAL-ONLY FAILURES ===");
|
|
25
|
+
|
|
26
|
+
# Test 1: Calling pos-only with keyword arguments
|
|
27
|
+
try {
|
|
28
|
+
result = strict_posonly(a=10, b="test");
|
|
29
|
+
print("❌ FAIL: Should reject pos-only as keywords");
|
|
30
|
+
} except Exception as e {
|
|
31
|
+
print("✅ PASS: Caught pos-only keyword error");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Test 2: Partial keyword arguments on pos-only
|
|
35
|
+
try {
|
|
36
|
+
result = strict_posonly(10, b="test");
|
|
37
|
+
print("❌ FAIL: Should reject mixed pos-only calling");
|
|
38
|
+
} except Exception as e {
|
|
39
|
+
print("✅ PASS: Caught mixed pos-only error");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# Test 3: Too many positional arguments
|
|
43
|
+
try {
|
|
44
|
+
result = strict_posonly(1, "test", "extra");
|
|
45
|
+
print("❌ FAIL: Should reject too many args");
|
|
46
|
+
} except Exception as e {
|
|
47
|
+
print("✅ PASS: Caught too many args error");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Test 4: Missing required positional-only
|
|
51
|
+
try {
|
|
52
|
+
result = strict_posonly(42);
|
|
53
|
+
print("❌ FAIL: Should reject missing required pos-only");
|
|
54
|
+
} except Exception as e {
|
|
55
|
+
print("✅ PASS: Caught missing pos-only error");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# Test 5: Mixed signature - wrong keyword usage
|
|
59
|
+
try {
|
|
60
|
+
result = mixed_posonly(x=10, y="test");
|
|
61
|
+
print("❌ FAIL: Should reject pos-only x as keyword");
|
|
62
|
+
} except Exception as e {
|
|
63
|
+
print("✅ PASS: Caught mixed signature error");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# Test 6: Complex signature - pos-only as keyword
|
|
67
|
+
try {
|
|
68
|
+
result = complex_posonly(a=1, c=2.5, kw=True);
|
|
69
|
+
print("❌ FAIL: Should reject pos-only a as keyword");
|
|
70
|
+
} except Exception as e {
|
|
71
|
+
print("✅ PASS: Caught complex pos-only error");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Test 7: Edge case - only separator with keyword
|
|
75
|
+
try {
|
|
76
|
+
result = edge_case_posonly(x=42);
|
|
77
|
+
print("✅ PASS: Edge case works:", result);
|
|
78
|
+
} except Exception as e {
|
|
79
|
+
print("✅ PASS: Edge case properly rejected");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# Test 8: No regular params - wrong calling pattern
|
|
83
|
+
try {
|
|
84
|
+
result = no_regular_params(1, "test");
|
|
85
|
+
print("❌ FAIL: Should reject positional for keyword-only");
|
|
86
|
+
} except Exception as e {
|
|
87
|
+
print("✅ PASS: Caught no-regular-params error");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
result = strict_posonly("not_int", "test");
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# Test 10: Empty call to required pos-only
|
|
95
|
+
try {
|
|
96
|
+
result = strict_posonly();
|
|
97
|
+
print("❌ FAIL: Should reject empty call");
|
|
98
|
+
} except Exception as e {
|
|
99
|
+
print("✅ PASS: Caught empty call error");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# Test 11: Valid calls that should work
|
|
103
|
+
try {
|
|
104
|
+
result = strict_posonly(42, "valid");
|
|
105
|
+
print("✅ PASS: Valid pos-only call:", result);
|
|
106
|
+
} except Exception as e {
|
|
107
|
+
print("❌ FAIL: Valid call rejected");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
result = mixed_posonly(1, "test", 3.14);
|
|
112
|
+
print("✅ PASS: Valid mixed call:", result);
|
|
113
|
+
} except Exception as e {
|
|
114
|
+
print("❌ FAIL: Valid mixed call rejected");
|
|
115
|
+
}
|
|
116
|
+
}
|