pyscriptc 0.1.0__tar.gz → 0.2.0__tar.gz
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.
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/PKG-INFO +22 -10
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/README.md +20 -9
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/pyproject.toml +7 -3
- pyscriptc-0.2.0/src/pyscriptc/_pyright_stubs/functools/__init__.pyi +274 -0
- pyscriptc-0.2.0/src/pyscriptc/_pyright_stubs/struct/__init__.pyi +29 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/builtins.py +12 -1
- pyscriptc-0.2.0/src/pyscriptc/check.py +320 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/cli.py +171 -32
- pyscriptc-0.2.0/src/pyscriptc/doctor.py +103 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/ir.py +85 -6
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/llvm.py +777 -65
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/lower/__init__.py +451 -87
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/lower/_calls.py +783 -54
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/lower/_classes.py +717 -53
- pyscriptc-0.2.0/src/pyscriptc/lower/_closures.py +309 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/lower/_core.py +119 -27
- pyscriptc-0.2.0/src/pyscriptc/lower/_expr.py +1788 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/lower/_stdlib.py +262 -33
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/lower/_stdlib_shared.py +2 -0
- pyscriptc-0.2.0/src/pyscriptc/lower/_stmt.py +2125 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/package.py +3 -2
- pyscriptc-0.2.0/src/pyscriptc/restlower.py +2545 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_coll.c +58 -0
- pyscriptc-0.2.0/src/pyscriptc/runtime/ps_copy.c +105 -0
- pyscriptc-0.2.0/src/pyscriptc/runtime/ps_csv.c +160 -0
- pyscriptc-0.2.0/src/pyscriptc/runtime/ps_fmt.c +1030 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_help.c +112 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_io.c +152 -18
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_json.c +201 -17
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_more.c +3 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_osmore.c +98 -3
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_path.c +243 -0
- pyscriptc-0.2.0/src/pyscriptc/runtime/ps_rand.c +219 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_re.c +278 -24
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_rt.c +142 -5
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_rt.h +32 -3
- pyscriptc-0.2.0/src/pyscriptc/runtime/ps_wrap.c +522 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/stdlib_queue.py +31 -4
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/stdmore.py +58 -1
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/telemetry.py +70 -2
- pyscriptc-0.2.0/src/pyscriptc/typefacts.py +2955 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc.egg-info/PKG-INFO +22 -10
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc.egg-info/SOURCES.txt +39 -0
- pyscriptc-0.2.0/src/pyscriptc.egg-info/requires.txt +2 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_adoption.py +1 -1
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_band.py +0 -10
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_break.py +0 -18
- pyscriptc-0.2.0/tests/test_census_self.py +33 -0
- pyscriptc-0.2.0/tests/test_checker_adapters.py +439 -0
- pyscriptc-0.2.0/tests/test_checker_align.py +113 -0
- pyscriptc-0.2.0/tests/test_checker_resolve.py +137 -0
- pyscriptc-0.2.0/tests/test_cli_dx.py +138 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_compare_chain.py +0 -12
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_continue.py +0 -26
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_coverage.py +7 -7
- pyscriptc-0.2.0/tests/test_dunder.py +262 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_append.py +1 -1
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_print.py +8 -2
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_sortedkey.py +19 -10
- pyscriptc-0.2.0/tests/test_e2_exc_forms.py +372 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_entrypoints.py +14 -4
- pyscriptc-0.2.0/tests/test_format_specs.py +87 -0
- pyscriptc-0.2.0/tests/test_fstring_specs.py +86 -0
- pyscriptc-0.2.0/tests/test_gates.py +607 -0
- pyscriptc-0.2.0/tests/test_identity_eq.py +188 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_is_none.py +2 -37
- pyscriptc-0.2.0/tests/test_list_comp_if.py +181 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_lwave.py +5 -20
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_match.py +150 -19
- pyscriptc-0.2.0/tests/test_module_cond.py +72 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_module_fstring.py +3 -1
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_module_set.py +1 -1
- pyscriptc-0.2.0/tests/test_numeric_tower.py +264 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_pow.py +21 -18
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_pyjwt_compat.py +4 -3
- pyscriptc-0.2.0/tests/test_pyrefly_tsp_facts.py +160 -0
- pyscriptc-0.2.0/tests/test_pyright_checker.py +103 -0
- pyscriptc-0.2.0/tests/test_pyright_facts.py +484 -0
- pyscriptc-0.2.0/tests/test_r10_catchable.py +141 -0
- pyscriptc-0.2.0/tests/test_r20_builtins.py +235 -0
- pyscriptc-0.2.0/tests/test_r23_callables2.py +277 -0
- pyscriptc-0.2.0/tests/test_r24_iterators.py +304 -0
- pyscriptc-0.2.0/tests/test_r26_optional.py +160 -0
- pyscriptc-0.2.0/tests/test_r27_re_search.py +278 -0
- pyscriptc-0.2.0/tests/test_r28_json.py +183 -0
- pyscriptc-0.2.0/tests/test_r29_collections.py +232 -0
- pyscriptc-0.2.0/tests/test_r30_itertools.py +433 -0
- pyscriptc-0.2.0/tests/test_r33_pathlib.py +255 -0
- pyscriptc-0.2.0/tests/test_r36.py +237 -0
- pyscriptc-0.2.0/tests/test_r40_with.py +292 -0
- pyscriptc-0.2.0/tests/test_r7_r14.py +313 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_re_a.py +2 -9
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_re_compile_module.py +25 -6
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_re_debug.py +3 -5
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_re_dotall.py +2 -2
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_scripting.py +6 -7
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_spike.py +2 -2
- pyscriptc-0.2.0/tests/test_stdlib_wave.py +455 -0
- pyscriptc-0.2.0/tests/test_t2_typevar.py +417 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_telemetry.py +130 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_tuple_membership.py +0 -5
- pyscriptc-0.2.0/tests/test_typefacts.py +150 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_version_surface.py +3 -3
- pyscriptc-0.1.0/src/pyscriptc/check.py +0 -49
- pyscriptc-0.1.0/src/pyscriptc/lower/_expr.py +0 -886
- pyscriptc-0.1.0/src/pyscriptc/lower/_stmt.py +0 -1173
- pyscriptc-0.1.0/src/pyscriptc/restlower.py +0 -1008
- pyscriptc-0.1.0/src/pyscriptc.egg-info/requires.txt +0 -1
- pyscriptc-0.1.0/tests/test_census_self.py +0 -24
- pyscriptc-0.1.0/tests/test_gates.py +0 -336
- pyscriptc-0.1.0/tests/test_list_comp_if.py +0 -122
- pyscriptc-0.1.0/tests/test_stdlib_wave.py +0 -115
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/LICENSE +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/setup.cfg +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/__init__.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/__main__.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/_posthog_token.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/canonical.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/coverage.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/debug.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/diagnostics.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/errors.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/log.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_argv.c +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_b64.c +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_dt.c +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_hash.c +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_hmac.c +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_island.c +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_mix.c +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_struct.c +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_time.c +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_unicode.c +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_url.c +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc.egg-info/dependency_links.txt +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc.egg-info/entry_points.txt +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc.egg-info/top_level.txt +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_agen_closed.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_all_completed.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_assert.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_baseline.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_basic_format.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_benchmarks.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_bool_surface.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_canonical.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_census.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_compat.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_compat2_calibration.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_compat2_corpus.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_compat2_probes.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_compat2_triage.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_constructors.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_cross.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_debug.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_decorator.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_defaultaction.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_del.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_devnull.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_assert.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_boolop_value.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_del.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_entry.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_fortuple.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_intbytes.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_loops.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_negstep.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_sysargv.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e2_exc.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_errno_platform.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_examples.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_fd_hygiene.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_fence_messages.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_flipcheck.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_float_inf.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_frozenset.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_frozenset_str.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_holdout_guard.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_ifexp.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_int_surface.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_io_annotation.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_irscore.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_log.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_nan_in.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_nativeprobe.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_or_mixed.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_ordereddict.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_package.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_r_batch.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_re_ascii.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_reduce.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_rest.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_slice_step.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_stdlib_bench.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_str_surface.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_timeout_max.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_tuple_ellipsis.py +0 -0
- {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_type_checking.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyscriptc
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Lower a typed subset of Python to LLVM, with CPython as the island.
|
|
5
5
|
Author: Joaquin Terrasa
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -22,6 +22,7 @@ Requires-Python: >=3.10
|
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
23
23
|
License-File: LICENSE
|
|
24
24
|
Requires-Dist: mypy>=2.4
|
|
25
|
+
Requires-Dist: pyrefly<1.5,>=1.4.0
|
|
25
26
|
Dynamic: license-file
|
|
26
27
|
|
|
27
28
|
<h1 align="center">pyscriptc</h1>
|
|
@@ -34,7 +35,7 @@ Dynamic: license-file
|
|
|
34
35
|
<a href="LICENSE"><img alt="License" src="https://img.shields.io/badge/license-Apache--2.0-blue"></a>
|
|
35
36
|
</p>
|
|
36
37
|
|
|
37
|
-
A compiler that lowers a small, annotated subset of Python to a typed IR and then to LLVM. Parsing is CPython’s own `ast` module. [
|
|
38
|
+
A compiler that lowers a small, annotated subset of Python to a typed IR and then to LLVM. Parsing is CPython’s own `ast` module. [pyrefly](https://pyrefly.org/) is a preflight: its tree is not an input. Anything the subset does not prove is a fence, not a guess.
|
|
38
39
|
|
|
39
40
|
## Try it now
|
|
40
41
|
|
|
@@ -51,11 +52,22 @@ pyscriptc compile examples/sum_squares.py --run --call sum_squares --args '[10]'
|
|
|
51
52
|
uv tool install pyscriptc
|
|
52
53
|
```
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
`pipx install pyscriptc` and `pip install pyscriptc` work the same way. The installed command finds the pyrefly checker that ships with it, so no extra PATH setup is needed. Prebuilt standalone binaries (macOS arm64, Linux x86_64 and aarch64) are attached to each [GitHub Release](https://github.com/sigilco/pyscriptc/releases); the binary does not bundle a checker yet, so use the PyPI install if you want type checking out of the box. PyPI installs require CPython 3.10 or later (the IR is stamped with the interpreter that lowered it).
|
|
56
|
+
|
|
57
|
+
Either way, compiling a program needs a clang that can assemble textual LLVM IR (`zig cc` also works, and enables `--driver zig` cross-compilation):
|
|
58
|
+
|
|
59
|
+
| Platform | Command |
|
|
60
|
+
| --- | --- |
|
|
61
|
+
| macOS | `xcode-select --install` (or `brew install llvm` / `brew install zig`) |
|
|
62
|
+
| Debian / Ubuntu | `sudo apt install clang` (or `zig` on newer releases) |
|
|
63
|
+
| Fedora | `sudo dnf install clang` (or `zig`) |
|
|
64
|
+
| Arch | `sudo pacman -S clang` (or `zig`) |
|
|
65
|
+
| Any Linux or macOS | `mise use -g zig` or `brew install zig` |
|
|
66
|
+
| Windows | `winget install zig.zig` (or `scoop install zig`) |
|
|
55
67
|
|
|
56
68
|
## What it does
|
|
57
69
|
|
|
58
|
-
- Lowers an annotated Python subset (strict `x: T` typing, checked by
|
|
70
|
+
- Lowers an annotated Python subset (strict `x: T` typing, checked by pyrefly) to typed IR, then LLVM IR, then a native binary via clang or `zig cc`.
|
|
59
71
|
- Anything the subset does not prove stops at a named `PSxxxx` fence with a hint — it never guesses at semantics.
|
|
60
72
|
- `int` is a Python int: `i64` only when the value fits, traps on overflow, refuses literals that would truncate. `//` is floor division.
|
|
61
73
|
- Island calls (`subprocess.check_output`, `socket.gethostname`, `threading`, `logging`) embed CPython on first use — and only binaries that call them link libpython.
|
|
@@ -66,7 +78,7 @@ Requirements: CPython 3.10 or later (the IR is stamped with the interpreter that
|
|
|
66
78
|
| Layer | What it is |
|
|
67
79
|
| --- | --- |
|
|
68
80
|
| Parser | CPython's own `ast` module |
|
|
69
|
-
| Checker |
|
|
81
|
+
| Checker | pyrefly preflight + the `PS1xxx`/`PS2xxx` fence tables |
|
|
70
82
|
| IR | typed JSON, stamped per-interpreter (`gates-v1`) |
|
|
71
83
|
| Backend | hand-emitted LLVM IR text → `clang` / `zig cc` |
|
|
72
84
|
| Island | optional embedded-CPython calls, CPython-linked only when used |
|
|
@@ -98,7 +110,7 @@ The IR stamp is `gates-v1`. Lowered:
|
|
|
98
110
|
|
|
99
111
|
Fenced (no LLVM for that file):
|
|
100
112
|
|
|
101
|
-
- `
|
|
113
|
+
- `finally`, `except ... as`, f-string format specs, user decorators, `super()`, multiple inheritance, `**kwargs`, keyword-only and positional-only parameters, and starred calls
|
|
102
114
|
- String literals outside Latin-1
|
|
103
115
|
- `bool` arithmetic, `list[bool]`, and `dict` values of `bool`. `bool` is not promoted to `float`
|
|
104
116
|
- Calls such as `str.encode("ascii")`, `math.gcd`, `functools.partial`, `itertools.count`, `operator.itemgetter`, `importlib.import_module`, and `asyncio.run` that are outside the lowered surface
|
|
@@ -115,17 +127,17 @@ A `for` target that is new in the function is stored as `0`, `0.0`, or `""` befo
|
|
|
115
127
|
|
|
116
128
|
`in` on a list uses `==`. `math.nan in [math.nan]` is false here. CPython's list finds that same object by identity before it compares.
|
|
117
129
|
|
|
118
|
-
`typing` stays in
|
|
130
|
+
`typing` stays in the checker. It is not a runtime lowering. Island constants (`sys.platform`, `sys.version`, `sys.executable`, `sys.maxsize`, `socket.AF_INET`, `ssl.OPENSSL_VERSION`, `ssl.HAS_SNI`, `stat.S_IFREG`, `ctypes.sizeof`) are baked from the interpreter that lowers the file. `sys.exit` is libc `exit`. `subprocess.check_output` takes a `list[str]` and returns `bytes`. `os.getenv` raises `KeyError` when the variable is unset. `date` plus `timedelta` uses the normalized day count; `datetime` plus `timedelta` uses the whole delta.
|
|
119
131
|
|
|
120
132
|
## Requirements
|
|
121
133
|
|
|
122
|
-
-
|
|
123
|
-
- [uv](https://docs.astral.sh/uv/)
|
|
134
|
+
- [mise](https://mise.jdx.dev/), then `mise trust && mise install` (provides python, uv, node, pnpm; already-installed tools that satisfy the pins are reused)
|
|
124
135
|
- Clang that can assemble textual LLVM IR
|
|
125
136
|
|
|
126
137
|
## Run
|
|
127
138
|
|
|
128
139
|
```bash
|
|
140
|
+
mise trust && mise install
|
|
129
141
|
uv sync
|
|
130
142
|
uv run pyscriptc compile examples/sum_squares.py --run --call sum_squares --args '[10]' -o /tmp/sum_squares
|
|
131
143
|
```
|
|
@@ -142,7 +154,7 @@ uv run pyscriptc compile examples/gates_probe.py --run --call probe -o /tmp/prob
|
|
|
142
154
|
uv run pyscriptc compile examples/fence_method.py --emit llvm -o /tmp/fence.ll
|
|
143
155
|
```
|
|
144
156
|
|
|
145
|
-
`floors()` prints `3`. `probe()` prints `0`. The fence exits nonzero, names `encode`, and does not write LLVM. `examples/wave_probe.py` prints `0` when the codec wave matches CPython. `examples/rest_probe.py` prints `0` when the rest of the queue matches CPython. `examples/fence_pickle.py` exits nonzero with `PS2002` because `pickle` is outside the import table. `examples/invoice.py`, `examples/access_log.py`, `examples/request_id.py`, `examples/release_note.py`, `examples/blob_digest.py`, `examples/url_gate.py`, and `examples/hostname.py` are the scripts in [docs/examples.md](docs/examples.md). `examples/bad_annotation.py` fails in
|
|
157
|
+
`floors()` prints `3`. `probe()` prints `0`. The fence exits nonzero, names `encode`, and does not write LLVM. `examples/wave_probe.py` prints `0` when the codec wave matches CPython. `examples/rest_probe.py` prints `0` when the rest of the queue matches CPython. `examples/fence_pickle.py` exits nonzero with `PS2002` because `pickle` is outside the import table. `examples/invoice.py`, `examples/access_log.py`, `examples/request_id.py`, `examples/release_note.py`, `examples/blob_digest.py`, `examples/url_gate.py`, and `examples/hostname.py` are the scripts in [docs/examples.md](docs/examples.md). `examples/bad_annotation.py` fails in the checker before lowering. `examples/big_literal.py` lowers to IR, then LLVM emission refuses the integer because it does not fit in `i64`.
|
|
146
158
|
|
|
147
159
|
`re.compile` returns a `Pattern` with a `pattern` field. `findall`, `sub`, and `split` on that object use the field. `hashlib` returns an opaque `Hash`; `hexdigest` and `digest` are the methods that lower. `urlsplit` returns a `SplitResult` of five strings (`scheme`, `netloc`, `path`, `query`, `fragment`). `struct.unpack` is a list, so `[0]` is the first value. `json.loads` takes its type from the annotation it is assigned to, or from the return annotation. `parse_qs` splits on `&` only, which is what CPython 3.14 does. A pattern that can match empty forever, such as `()*`, stops with `RuntimeError` once the matcher spends its fuel. `re.error`, `struct.error`, and `binascii.Error` surface here as `ValueError`.
|
|
148
160
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<a href="LICENSE"><img alt="License" src="https://img.shields.io/badge/license-Apache--2.0-blue"></a>
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
|
-
A compiler that lowers a small, annotated subset of Python to a typed IR and then to LLVM. Parsing is CPython’s own `ast` module. [
|
|
11
|
+
A compiler that lowers a small, annotated subset of Python to a typed IR and then to LLVM. Parsing is CPython’s own `ast` module. [pyrefly](https://pyrefly.org/) is a preflight: its tree is not an input. Anything the subset does not prove is a fence, not a guess.
|
|
12
12
|
|
|
13
13
|
## Try it now
|
|
14
14
|
|
|
@@ -25,11 +25,22 @@ pyscriptc compile examples/sum_squares.py --run --call sum_squares --args '[10]'
|
|
|
25
25
|
uv tool install pyscriptc
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
`pipx install pyscriptc` and `pip install pyscriptc` work the same way. The installed command finds the pyrefly checker that ships with it, so no extra PATH setup is needed. Prebuilt standalone binaries (macOS arm64, Linux x86_64 and aarch64) are attached to each [GitHub Release](https://github.com/sigilco/pyscriptc/releases); the binary does not bundle a checker yet, so use the PyPI install if you want type checking out of the box. PyPI installs require CPython 3.10 or later (the IR is stamped with the interpreter that lowered it).
|
|
29
|
+
|
|
30
|
+
Either way, compiling a program needs a clang that can assemble textual LLVM IR (`zig cc` also works, and enables `--driver zig` cross-compilation):
|
|
31
|
+
|
|
32
|
+
| Platform | Command |
|
|
33
|
+
| --- | --- |
|
|
34
|
+
| macOS | `xcode-select --install` (or `brew install llvm` / `brew install zig`) |
|
|
35
|
+
| Debian / Ubuntu | `sudo apt install clang` (or `zig` on newer releases) |
|
|
36
|
+
| Fedora | `sudo dnf install clang` (or `zig`) |
|
|
37
|
+
| Arch | `sudo pacman -S clang` (or `zig`) |
|
|
38
|
+
| Any Linux or macOS | `mise use -g zig` or `brew install zig` |
|
|
39
|
+
| Windows | `winget install zig.zig` (or `scoop install zig`) |
|
|
29
40
|
|
|
30
41
|
## What it does
|
|
31
42
|
|
|
32
|
-
- Lowers an annotated Python subset (strict `x: T` typing, checked by
|
|
43
|
+
- Lowers an annotated Python subset (strict `x: T` typing, checked by pyrefly) to typed IR, then LLVM IR, then a native binary via clang or `zig cc`.
|
|
33
44
|
- Anything the subset does not prove stops at a named `PSxxxx` fence with a hint — it never guesses at semantics.
|
|
34
45
|
- `int` is a Python int: `i64` only when the value fits, traps on overflow, refuses literals that would truncate. `//` is floor division.
|
|
35
46
|
- Island calls (`subprocess.check_output`, `socket.gethostname`, `threading`, `logging`) embed CPython on first use — and only binaries that call them link libpython.
|
|
@@ -40,7 +51,7 @@ Requirements: CPython 3.10 or later (the IR is stamped with the interpreter that
|
|
|
40
51
|
| Layer | What it is |
|
|
41
52
|
| --- | --- |
|
|
42
53
|
| Parser | CPython's own `ast` module |
|
|
43
|
-
| Checker |
|
|
54
|
+
| Checker | pyrefly preflight + the `PS1xxx`/`PS2xxx` fence tables |
|
|
44
55
|
| IR | typed JSON, stamped per-interpreter (`gates-v1`) |
|
|
45
56
|
| Backend | hand-emitted LLVM IR text → `clang` / `zig cc` |
|
|
46
57
|
| Island | optional embedded-CPython calls, CPython-linked only when used |
|
|
@@ -72,7 +83,7 @@ The IR stamp is `gates-v1`. Lowered:
|
|
|
72
83
|
|
|
73
84
|
Fenced (no LLVM for that file):
|
|
74
85
|
|
|
75
|
-
- `
|
|
86
|
+
- `finally`, `except ... as`, f-string format specs, user decorators, `super()`, multiple inheritance, `**kwargs`, keyword-only and positional-only parameters, and starred calls
|
|
76
87
|
- String literals outside Latin-1
|
|
77
88
|
- `bool` arithmetic, `list[bool]`, and `dict` values of `bool`. `bool` is not promoted to `float`
|
|
78
89
|
- Calls such as `str.encode("ascii")`, `math.gcd`, `functools.partial`, `itertools.count`, `operator.itemgetter`, `importlib.import_module`, and `asyncio.run` that are outside the lowered surface
|
|
@@ -89,17 +100,17 @@ A `for` target that is new in the function is stored as `0`, `0.0`, or `""` befo
|
|
|
89
100
|
|
|
90
101
|
`in` on a list uses `==`. `math.nan in [math.nan]` is false here. CPython's list finds that same object by identity before it compares.
|
|
91
102
|
|
|
92
|
-
`typing` stays in
|
|
103
|
+
`typing` stays in the checker. It is not a runtime lowering. Island constants (`sys.platform`, `sys.version`, `sys.executable`, `sys.maxsize`, `socket.AF_INET`, `ssl.OPENSSL_VERSION`, `ssl.HAS_SNI`, `stat.S_IFREG`, `ctypes.sizeof`) are baked from the interpreter that lowers the file. `sys.exit` is libc `exit`. `subprocess.check_output` takes a `list[str]` and returns `bytes`. `os.getenv` raises `KeyError` when the variable is unset. `date` plus `timedelta` uses the normalized day count; `datetime` plus `timedelta` uses the whole delta.
|
|
93
104
|
|
|
94
105
|
## Requirements
|
|
95
106
|
|
|
96
|
-
-
|
|
97
|
-
- [uv](https://docs.astral.sh/uv/)
|
|
107
|
+
- [mise](https://mise.jdx.dev/), then `mise trust && mise install` (provides python, uv, node, pnpm; already-installed tools that satisfy the pins are reused)
|
|
98
108
|
- Clang that can assemble textual LLVM IR
|
|
99
109
|
|
|
100
110
|
## Run
|
|
101
111
|
|
|
102
112
|
```bash
|
|
113
|
+
mise trust && mise install
|
|
103
114
|
uv sync
|
|
104
115
|
uv run pyscriptc compile examples/sum_squares.py --run --call sum_squares --args '[10]' -o /tmp/sum_squares
|
|
105
116
|
```
|
|
@@ -116,7 +127,7 @@ uv run pyscriptc compile examples/gates_probe.py --run --call probe -o /tmp/prob
|
|
|
116
127
|
uv run pyscriptc compile examples/fence_method.py --emit llvm -o /tmp/fence.ll
|
|
117
128
|
```
|
|
118
129
|
|
|
119
|
-
`floors()` prints `3`. `probe()` prints `0`. The fence exits nonzero, names `encode`, and does not write LLVM. `examples/wave_probe.py` prints `0` when the codec wave matches CPython. `examples/rest_probe.py` prints `0` when the rest of the queue matches CPython. `examples/fence_pickle.py` exits nonzero with `PS2002` because `pickle` is outside the import table. `examples/invoice.py`, `examples/access_log.py`, `examples/request_id.py`, `examples/release_note.py`, `examples/blob_digest.py`, `examples/url_gate.py`, and `examples/hostname.py` are the scripts in [docs/examples.md](docs/examples.md). `examples/bad_annotation.py` fails in
|
|
130
|
+
`floors()` prints `3`. `probe()` prints `0`. The fence exits nonzero, names `encode`, and does not write LLVM. `examples/wave_probe.py` prints `0` when the codec wave matches CPython. `examples/rest_probe.py` prints `0` when the rest of the queue matches CPython. `examples/fence_pickle.py` exits nonzero with `PS2002` because `pickle` is outside the import table. `examples/invoice.py`, `examples/access_log.py`, `examples/request_id.py`, `examples/release_note.py`, `examples/blob_digest.py`, `examples/url_gate.py`, and `examples/hostname.py` are the scripts in [docs/examples.md](docs/examples.md). `examples/bad_annotation.py` fails in the checker before lowering. `examples/big_literal.py` lowers to IR, then LLVM emission refuses the integer because it does not fit in `i64`.
|
|
120
131
|
|
|
121
132
|
`re.compile` returns a `Pattern` with a `pattern` field. `findall`, `sub`, and `split` on that object use the field. `hashlib` returns an opaque `Hash`; `hexdigest` and `digest` are the methods that lower. `urlsplit` returns a `SplitResult` of five strings (`scheme`, `netloc`, `path`, `query`, `fragment`). `struct.unpack` is a list, so `[0]` is the first value. `json.loads` takes its type from the annotation it is assigned to, or from the return annotation. `parse_qs` splits on `&` only, which is what CPython 3.14 does. A pattern that can match empty forever, such as `()*`, stops with `RuntimeError` once the matcher spends its fuel. `re.error`, `struct.error`, and `binascii.Error` surface here as `ValueError`.
|
|
122
133
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pyscriptc"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
description = "Lower a typed subset of Python to LLVM, with CPython as the island."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -19,7 +19,10 @@ classifiers = [
|
|
|
19
19
|
"Programming Language :: Python :: 3.14",
|
|
20
20
|
"Topic :: Software Development :: Compilers",
|
|
21
21
|
]
|
|
22
|
-
dependencies = [
|
|
22
|
+
dependencies = [
|
|
23
|
+
"mypy>=2.4",
|
|
24
|
+
"pyrefly>=1.4.0,<1.5",
|
|
25
|
+
]
|
|
23
26
|
|
|
24
27
|
[project.urls]
|
|
25
28
|
Homepage = "https://github.com/sigilco/pyscriptc"
|
|
@@ -43,7 +46,7 @@ build-backend = "setuptools.build_meta"
|
|
|
43
46
|
where = ["src"]
|
|
44
47
|
|
|
45
48
|
[tool.setuptools.package-data]
|
|
46
|
-
pyscriptc = ["runtime/*.c", "runtime/*.h"]
|
|
49
|
+
pyscriptc = ["runtime/*.c", "runtime/*.h", "_pyright_stubs/*/__init__.pyi"]
|
|
47
50
|
|
|
48
51
|
[tool.pytest.ini_options]
|
|
49
52
|
testpaths = ["tests"]
|
|
@@ -65,6 +68,7 @@ extend-exclude = [
|
|
|
65
68
|
"benchmarks/compat2/corpus/holdout/tests",
|
|
66
69
|
"benchmarks/compat2/corpus/scripts",
|
|
67
70
|
"benchmarks/compat2/corpus/holdout/scripts",
|
|
71
|
+
"src/pyscriptc/_pyright_stubs",
|
|
68
72
|
]
|
|
69
73
|
|
|
70
74
|
[tool.ruff.lint]
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# Vendored from typeshed (Apache-2.0), patched for the lowered contract:
|
|
2
|
+
# functools.partial yields `Any` like the mypy plugin (the subset does not
|
|
3
|
+
# model the shifted parameter list).
|
|
4
|
+
import sys
|
|
5
|
+
import types
|
|
6
|
+
from _typeshed import SupportsAllComparisons, SupportsItems
|
|
7
|
+
from collections.abc import Callable, Hashable, Iterable, Sized
|
|
8
|
+
from types import GenericAlias
|
|
9
|
+
from typing import (
|
|
10
|
+
Any,
|
|
11
|
+
Final,
|
|
12
|
+
Generic,
|
|
13
|
+
Literal,
|
|
14
|
+
NamedTuple,
|
|
15
|
+
ParamSpec,
|
|
16
|
+
TypeAlias,
|
|
17
|
+
TypedDict,
|
|
18
|
+
TypeVar,
|
|
19
|
+
final,
|
|
20
|
+
overload,
|
|
21
|
+
type_check_only,
|
|
22
|
+
)
|
|
23
|
+
from typing_extensions import Self, disjoint_base
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"update_wrapper",
|
|
27
|
+
"wraps",
|
|
28
|
+
"WRAPPER_ASSIGNMENTS",
|
|
29
|
+
"WRAPPER_UPDATES",
|
|
30
|
+
"total_ordering",
|
|
31
|
+
"cmp_to_key",
|
|
32
|
+
"lru_cache",
|
|
33
|
+
"reduce",
|
|
34
|
+
"partial",
|
|
35
|
+
"partialmethod",
|
|
36
|
+
"singledispatch",
|
|
37
|
+
"cached_property",
|
|
38
|
+
"singledispatchmethod",
|
|
39
|
+
"cache",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
_T = TypeVar("_T")
|
|
43
|
+
_T_co = TypeVar("_T_co", covariant=True)
|
|
44
|
+
_S = TypeVar("_S")
|
|
45
|
+
_PWrapped = ParamSpec("_PWrapped")
|
|
46
|
+
_RWrapped = TypeVar("_RWrapped")
|
|
47
|
+
_PWrapper = ParamSpec("_PWrapper")
|
|
48
|
+
_RWrapper = TypeVar("_RWrapper")
|
|
49
|
+
|
|
50
|
+
if sys.version_info >= (3, 14):
|
|
51
|
+
@overload
|
|
52
|
+
def reduce(function: Callable[[_T, _S], _T], iterable: Iterable[_S], /, initial: _T) -> _T: ...
|
|
53
|
+
else:
|
|
54
|
+
@overload
|
|
55
|
+
def reduce(function: Callable[[_T, _S], _T], iterable: Iterable[_S], initial: _T, /) -> _T: ...
|
|
56
|
+
|
|
57
|
+
@overload
|
|
58
|
+
def reduce(function: Callable[[_T, _T], _T], iterable: Iterable[_T], /) -> _T: ...
|
|
59
|
+
|
|
60
|
+
class _CacheInfo(NamedTuple):
|
|
61
|
+
hits: int
|
|
62
|
+
misses: int
|
|
63
|
+
maxsize: int | None
|
|
64
|
+
currsize: int
|
|
65
|
+
|
|
66
|
+
@type_check_only
|
|
67
|
+
class _CacheParameters(TypedDict):
|
|
68
|
+
maxsize: int
|
|
69
|
+
typed: bool
|
|
70
|
+
|
|
71
|
+
@final
|
|
72
|
+
class _lru_cache_wrapper(Generic[_T_co]):
|
|
73
|
+
__wrapped__: Callable[..., _T_co]
|
|
74
|
+
def __call__(self, *args: Hashable, **kwargs: Hashable) -> _T_co: ...
|
|
75
|
+
def cache_info(self) -> _CacheInfo: ...
|
|
76
|
+
def cache_clear(self) -> None: ...
|
|
77
|
+
def cache_parameters(self) -> _CacheParameters: ...
|
|
78
|
+
def __copy__(self) -> _lru_cache_wrapper[_T_co]: ...
|
|
79
|
+
def __deepcopy__(self, memo: Any, /) -> _lru_cache_wrapper[_T_co]: ...
|
|
80
|
+
|
|
81
|
+
# as with ``Callable``, we'll assume that these attributes exist
|
|
82
|
+
__name__: str
|
|
83
|
+
__qualname__: str
|
|
84
|
+
|
|
85
|
+
@overload
|
|
86
|
+
def lru_cache(maxsize: int | None = 128, typed: bool = False) -> Callable[[Callable[..., _T]], _lru_cache_wrapper[_T]]: ...
|
|
87
|
+
@overload
|
|
88
|
+
def lru_cache(maxsize: Callable[..., _T], typed: bool = False) -> _lru_cache_wrapper[_T]: ...
|
|
89
|
+
|
|
90
|
+
if sys.version_info >= (3, 14):
|
|
91
|
+
WRAPPER_ASSIGNMENTS: Final[
|
|
92
|
+
tuple[
|
|
93
|
+
Literal["__module__"],
|
|
94
|
+
Literal["__name__"],
|
|
95
|
+
Literal["__qualname__"],
|
|
96
|
+
Literal["__doc__"],
|
|
97
|
+
Literal["__annotate__"],
|
|
98
|
+
Literal["__type_params__"],
|
|
99
|
+
]
|
|
100
|
+
]
|
|
101
|
+
elif sys.version_info >= (3, 12):
|
|
102
|
+
WRAPPER_ASSIGNMENTS: Final[
|
|
103
|
+
tuple[
|
|
104
|
+
Literal["__module__"],
|
|
105
|
+
Literal["__name__"],
|
|
106
|
+
Literal["__qualname__"],
|
|
107
|
+
Literal["__doc__"],
|
|
108
|
+
Literal["__annotations__"],
|
|
109
|
+
Literal["__type_params__"],
|
|
110
|
+
]
|
|
111
|
+
]
|
|
112
|
+
else:
|
|
113
|
+
WRAPPER_ASSIGNMENTS: Final[
|
|
114
|
+
tuple[Literal["__module__"], Literal["__name__"], Literal["__qualname__"], Literal["__doc__"], Literal["__annotations__"]]
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
WRAPPER_UPDATES: Final[tuple[Literal["__dict__"]]]
|
|
118
|
+
|
|
119
|
+
@type_check_only
|
|
120
|
+
class _Wrapped(Generic[_PWrapped, _RWrapped, _PWrapper, _RWrapper]):
|
|
121
|
+
__wrapped__: Callable[_PWrapped, _RWrapped]
|
|
122
|
+
def __call__(self, *args: _PWrapper.args, **kwargs: _PWrapper.kwargs) -> _RWrapper: ...
|
|
123
|
+
# as with ``Callable``, we'll assume that these attributes exist
|
|
124
|
+
__name__: str
|
|
125
|
+
__qualname__: str
|
|
126
|
+
|
|
127
|
+
@type_check_only
|
|
128
|
+
class _Wrapper(Generic[_PWrapped, _RWrapped]):
|
|
129
|
+
def __call__(self, f: Callable[_PWrapper, _RWrapper]) -> _Wrapped[_PWrapped, _RWrapped, _PWrapper, _RWrapper]: ...
|
|
130
|
+
|
|
131
|
+
if sys.version_info >= (3, 14):
|
|
132
|
+
def update_wrapper(
|
|
133
|
+
wrapper: Callable[_PWrapper, _RWrapper],
|
|
134
|
+
wrapped: Callable[_PWrapped, _RWrapped],
|
|
135
|
+
assigned: Iterable[str] = ("__module__", "__name__", "__qualname__", "__doc__", "__annotate__", "__type_params__"),
|
|
136
|
+
updated: Iterable[str] = ("__dict__",),
|
|
137
|
+
) -> _Wrapped[_PWrapped, _RWrapped, _PWrapper, _RWrapper]: ...
|
|
138
|
+
def wraps(
|
|
139
|
+
wrapped: Callable[_PWrapped, _RWrapped],
|
|
140
|
+
assigned: Iterable[str] = ("__module__", "__name__", "__qualname__", "__doc__", "__annotate__", "__type_params__"),
|
|
141
|
+
updated: Iterable[str] = ("__dict__",),
|
|
142
|
+
) -> _Wrapper[_PWrapped, _RWrapped]: ...
|
|
143
|
+
|
|
144
|
+
elif sys.version_info >= (3, 12):
|
|
145
|
+
def update_wrapper(
|
|
146
|
+
wrapper: Callable[_PWrapper, _RWrapper],
|
|
147
|
+
wrapped: Callable[_PWrapped, _RWrapped],
|
|
148
|
+
assigned: Iterable[str] = ("__module__", "__name__", "__qualname__", "__doc__", "__annotations__", "__type_params__"),
|
|
149
|
+
updated: Iterable[str] = ("__dict__",),
|
|
150
|
+
) -> _Wrapped[_PWrapped, _RWrapped, _PWrapper, _RWrapper]: ...
|
|
151
|
+
def wraps(
|
|
152
|
+
wrapped: Callable[_PWrapped, _RWrapped],
|
|
153
|
+
assigned: Iterable[str] = ("__module__", "__name__", "__qualname__", "__doc__", "__annotations__", "__type_params__"),
|
|
154
|
+
updated: Iterable[str] = ("__dict__",),
|
|
155
|
+
) -> _Wrapper[_PWrapped, _RWrapped]: ...
|
|
156
|
+
|
|
157
|
+
else:
|
|
158
|
+
def update_wrapper(
|
|
159
|
+
wrapper: Callable[_PWrapper, _RWrapper],
|
|
160
|
+
wrapped: Callable[_PWrapped, _RWrapped],
|
|
161
|
+
assigned: Iterable[str] = ("__module__", "__name__", "__qualname__", "__doc__", "__annotations__"),
|
|
162
|
+
updated: Iterable[str] = ("__dict__",),
|
|
163
|
+
) -> _Wrapped[_PWrapped, _RWrapped, _PWrapper, _RWrapper]: ...
|
|
164
|
+
def wraps(
|
|
165
|
+
wrapped: Callable[_PWrapped, _RWrapped],
|
|
166
|
+
assigned: Iterable[str] = ("__module__", "__name__", "__qualname__", "__doc__", "__annotations__"),
|
|
167
|
+
updated: Iterable[str] = ("__dict__",),
|
|
168
|
+
) -> _Wrapper[_PWrapped, _RWrapped]: ...
|
|
169
|
+
|
|
170
|
+
def total_ordering(cls: type[_T]) -> type[_T]: ...
|
|
171
|
+
def cmp_to_key(mycmp: Callable[[_T, _T], int]) -> Callable[[_T], SupportsAllComparisons]: ...
|
|
172
|
+
|
|
173
|
+
def partial(func: Callable[..., Any], /, *args: Any, **kwargs: Any) -> Any: ...
|
|
174
|
+
|
|
175
|
+
# With protocols, this could change into a generic protocol that defines __get__ and returns _T
|
|
176
|
+
_Descriptor: TypeAlias = Any
|
|
177
|
+
|
|
178
|
+
class partialmethod(Generic[_T]):
|
|
179
|
+
func: Callable[..., _T] | _Descriptor
|
|
180
|
+
args: tuple[Any, ...]
|
|
181
|
+
keywords: dict[str, Any]
|
|
182
|
+
if sys.version_info >= (3, 14):
|
|
183
|
+
@overload
|
|
184
|
+
def __new__(self, func: Callable[..., _T], /, *args: Any, **keywords: Any) -> Self: ...
|
|
185
|
+
@overload
|
|
186
|
+
def __new__(self, func: _Descriptor, /, *args: Any, **keywords: Any) -> Self: ...
|
|
187
|
+
else:
|
|
188
|
+
@overload
|
|
189
|
+
def __init__(self, func: Callable[..., _T], /, *args: Any, **keywords: Any) -> None: ...
|
|
190
|
+
@overload
|
|
191
|
+
def __init__(self, func: _Descriptor, /, *args: Any, **keywords: Any) -> None: ...
|
|
192
|
+
|
|
193
|
+
def __get__(self, obj: Any, cls: type[Any] | None = None) -> Callable[..., _T]: ...
|
|
194
|
+
@property
|
|
195
|
+
def __isabstractmethod__(self) -> bool: ...
|
|
196
|
+
def __class_getitem__(cls, item: Any, /) -> GenericAlias: ...
|
|
197
|
+
|
|
198
|
+
if sys.version_info >= (3, 11):
|
|
199
|
+
_RegType: TypeAlias = type[Any] | types.UnionType
|
|
200
|
+
else:
|
|
201
|
+
_RegType: TypeAlias = type[Any]
|
|
202
|
+
|
|
203
|
+
@type_check_only
|
|
204
|
+
class _SingleDispatchCallable(Generic[_T]):
|
|
205
|
+
registry: types.MappingProxyType[Any, Callable[..., _T]]
|
|
206
|
+
def dispatch(self, cls: Any) -> Callable[..., _T]: ...
|
|
207
|
+
|
|
208
|
+
# @fun.register(complex)
|
|
209
|
+
# def _(arg, verbose=False): ...
|
|
210
|
+
@overload
|
|
211
|
+
def register(self, cls: _RegType, func: None = None) -> Callable[[Callable[..., _T]], Callable[..., _T]]: ...
|
|
212
|
+
# @fun.register
|
|
213
|
+
# def _(arg: int, verbose=False):
|
|
214
|
+
@overload
|
|
215
|
+
def register(self, cls: Callable[..., _T], func: None = None) -> Callable[..., _T]: ...
|
|
216
|
+
# fun.register(int, lambda x: x)
|
|
217
|
+
@overload
|
|
218
|
+
def register(self, cls: _RegType, func: Callable[..., _T]) -> Callable[..., _T]: ...
|
|
219
|
+
|
|
220
|
+
def _clear_cache(self) -> None: ...
|
|
221
|
+
def __call__(self, /, *args: Any, **kwargs: Any) -> _T: ...
|
|
222
|
+
|
|
223
|
+
def singledispatch(func: Callable[..., _T]) -> _SingleDispatchCallable[_T]: ...
|
|
224
|
+
|
|
225
|
+
class singledispatchmethod(Generic[_T]):
|
|
226
|
+
dispatcher: _SingleDispatchCallable[_T]
|
|
227
|
+
func: Callable[..., _T]
|
|
228
|
+
def __init__(self, func: Callable[..., _T]) -> None: ...
|
|
229
|
+
@property
|
|
230
|
+
def __isabstractmethod__(self) -> bool: ...
|
|
231
|
+
|
|
232
|
+
@overload
|
|
233
|
+
def register(self, cls: _RegType, method: None = None) -> Callable[[Callable[..., _T]], Callable[..., _T]]: ...
|
|
234
|
+
@overload
|
|
235
|
+
def register(self, cls: Callable[..., _T], method: None = None) -> Callable[..., _T]: ...
|
|
236
|
+
@overload
|
|
237
|
+
def register(self, cls: _RegType, method: Callable[..., _T]) -> Callable[..., _T]: ...
|
|
238
|
+
|
|
239
|
+
def __get__(self, obj: _S, cls: type[_S] | None = None) -> Callable[..., _T]: ...
|
|
240
|
+
|
|
241
|
+
class cached_property(Generic[_T_co]):
|
|
242
|
+
func: Callable[[Any], _T_co]
|
|
243
|
+
attrname: str | None
|
|
244
|
+
def __init__(self, func: Callable[[Any], _T_co]) -> None: ...
|
|
245
|
+
|
|
246
|
+
@overload
|
|
247
|
+
def __get__(self, instance: None, owner: type[Any] | None = None) -> Self: ...
|
|
248
|
+
@overload
|
|
249
|
+
def __get__(self, instance: object, owner: type[Any] | None = None) -> _T_co: ...
|
|
250
|
+
|
|
251
|
+
def __set_name__(self, owner: type[Any], name: str) -> None: ...
|
|
252
|
+
# __set__ is not defined at runtime, but @cached_property is designed to be settable
|
|
253
|
+
def __set__(self, instance: object, value: _T_co) -> None: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
|
|
254
|
+
def __class_getitem__(cls, item: Any, /) -> GenericAlias: ...
|
|
255
|
+
|
|
256
|
+
def cache(user_function: Callable[..., _T], /) -> _lru_cache_wrapper[_T]: ...
|
|
257
|
+
def _make_key(
|
|
258
|
+
args: tuple[Hashable, ...],
|
|
259
|
+
kwds: SupportsItems[Any, Any],
|
|
260
|
+
typed: bool,
|
|
261
|
+
kwd_mark: tuple[object, ...] = ...,
|
|
262
|
+
fasttypes: set[type] = ...,
|
|
263
|
+
tuple: type = ...,
|
|
264
|
+
type: Any = ...,
|
|
265
|
+
len: Callable[[Sized], int] = ...,
|
|
266
|
+
) -> Hashable: ...
|
|
267
|
+
|
|
268
|
+
if sys.version_info >= (3, 14):
|
|
269
|
+
@final
|
|
270
|
+
class _PlaceholderType: ...
|
|
271
|
+
|
|
272
|
+
Placeholder: Final[_PlaceholderType]
|
|
273
|
+
|
|
274
|
+
__all__ += ["Placeholder"]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Vendored from typeshed (Apache-2.0), patched for the lowered contract:
|
|
2
|
+
# struct.unpack* yields `Any` like the mypy plugin (homogeneous list at runtime).
|
|
3
|
+
from _typeshed import ReadableBuffer, WriteableBuffer
|
|
4
|
+
from typing import Any
|
|
5
|
+
from typing_extensions import disjoint_base
|
|
6
|
+
|
|
7
|
+
__all__ = ["calcsize", "pack", "pack_into", "unpack", "unpack_from", "iter_unpack", "Struct", "error"]
|
|
8
|
+
|
|
9
|
+
class error(Exception): ...
|
|
10
|
+
|
|
11
|
+
def pack(fmt: str | bytes, /, *v: Any) -> bytes: ...
|
|
12
|
+
def pack_into(fmt: str | bytes, buffer: WriteableBuffer, offset: int, /, *v: Any) -> None: ...
|
|
13
|
+
def unpack(format: str | bytes, buffer: ReadableBuffer, /) -> Any: ...
|
|
14
|
+
def unpack_from(format: str | bytes, /, buffer: ReadableBuffer, offset: int = 0) -> Any: ...
|
|
15
|
+
def iter_unpack(format: str | bytes, buffer: ReadableBuffer, /) -> Any: ...
|
|
16
|
+
def calcsize(format: str | bytes, /) -> int: ...
|
|
17
|
+
|
|
18
|
+
@disjoint_base
|
|
19
|
+
class Struct:
|
|
20
|
+
@property
|
|
21
|
+
def format(self) -> str: ...
|
|
22
|
+
@property
|
|
23
|
+
def size(self) -> int: ...
|
|
24
|
+
def __init__(self, format: str | bytes) -> None: ...
|
|
25
|
+
def pack(self, *v: Any) -> bytes: ...
|
|
26
|
+
def pack_into(self, buffer: WriteableBuffer, offset: int, *v: Any) -> None: ...
|
|
27
|
+
def unpack(self, buffer: ReadableBuffer, /) -> Any: ...
|
|
28
|
+
def unpack_from(self, buffer: ReadableBuffer, offset: int = 0) -> Any: ...
|
|
29
|
+
def iter_unpack(self, buffer: ReadableBuffer, /) -> Any: ...
|
|
@@ -17,12 +17,16 @@ EXCEPTIONS: dict[str, int] = {
|
|
|
17
17
|
"ZeroDivisionError": 5,
|
|
18
18
|
"RuntimeError": 6,
|
|
19
19
|
"Exception": 7,
|
|
20
|
+
"StopIteration": 8,
|
|
21
|
+
"FileNotFoundError": 9,
|
|
22
|
+
"TypeError": 10,
|
|
23
|
+
"AttributeError": 11,
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
# User exception classes take codes from here up; matches PS_USER_BASE in
|
|
23
27
|
# ps_rt.h. Exception handlers treat every code at or above it as an
|
|
24
28
|
# Exception descendant, since all user exceptions inherit a lowered builtin.
|
|
25
|
-
USER_EXC_BASE =
|
|
29
|
+
USER_EXC_BASE = 12
|
|
26
30
|
|
|
27
31
|
# params are type kinds. return is a type kind, or "self" for the receiver's type.
|
|
28
32
|
STR_METHODS: dict[str, dict[str, Any]] = {
|
|
@@ -84,11 +88,18 @@ def builtin_spec(name: str, arg_types: list[dict[str, Any]]) -> dict[str, Any] |
|
|
|
84
88
|
"bool",
|
|
85
89
|
"bytes",
|
|
86
90
|
"none",
|
|
91
|
+
"exc",
|
|
87
92
|
}
|
|
88
93
|
):
|
|
89
94
|
return {"kind": "str"}
|
|
90
95
|
if name == "str" and len(arg_types) == 1 and arg_types[0]["kind"] == "class" and arg_types[0].get("name") == "Path":
|
|
91
96
|
return {"kind": "str"}
|
|
97
|
+
if (
|
|
98
|
+
name == "id"
|
|
99
|
+
and len(arg_types) == 1
|
|
100
|
+
and arg_types[0]["kind"] in {"list", "dict", "class", "exc", "str", "bytes"}
|
|
101
|
+
):
|
|
102
|
+
return {"kind": "int"}
|
|
92
103
|
return None
|
|
93
104
|
|
|
94
105
|
|