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.
Files changed (197) hide show
  1. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/PKG-INFO +22 -10
  2. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/README.md +20 -9
  3. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/pyproject.toml +7 -3
  4. pyscriptc-0.2.0/src/pyscriptc/_pyright_stubs/functools/__init__.pyi +274 -0
  5. pyscriptc-0.2.0/src/pyscriptc/_pyright_stubs/struct/__init__.pyi +29 -0
  6. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/builtins.py +12 -1
  7. pyscriptc-0.2.0/src/pyscriptc/check.py +320 -0
  8. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/cli.py +171 -32
  9. pyscriptc-0.2.0/src/pyscriptc/doctor.py +103 -0
  10. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/ir.py +85 -6
  11. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/llvm.py +777 -65
  12. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/lower/__init__.py +451 -87
  13. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/lower/_calls.py +783 -54
  14. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/lower/_classes.py +717 -53
  15. pyscriptc-0.2.0/src/pyscriptc/lower/_closures.py +309 -0
  16. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/lower/_core.py +119 -27
  17. pyscriptc-0.2.0/src/pyscriptc/lower/_expr.py +1788 -0
  18. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/lower/_stdlib.py +262 -33
  19. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/lower/_stdlib_shared.py +2 -0
  20. pyscriptc-0.2.0/src/pyscriptc/lower/_stmt.py +2125 -0
  21. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/package.py +3 -2
  22. pyscriptc-0.2.0/src/pyscriptc/restlower.py +2545 -0
  23. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_coll.c +58 -0
  24. pyscriptc-0.2.0/src/pyscriptc/runtime/ps_copy.c +105 -0
  25. pyscriptc-0.2.0/src/pyscriptc/runtime/ps_csv.c +160 -0
  26. pyscriptc-0.2.0/src/pyscriptc/runtime/ps_fmt.c +1030 -0
  27. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_help.c +112 -0
  28. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_io.c +152 -18
  29. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_json.c +201 -17
  30. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_more.c +3 -0
  31. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_osmore.c +98 -3
  32. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_path.c +243 -0
  33. pyscriptc-0.2.0/src/pyscriptc/runtime/ps_rand.c +219 -0
  34. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_re.c +278 -24
  35. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_rt.c +142 -5
  36. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_rt.h +32 -3
  37. pyscriptc-0.2.0/src/pyscriptc/runtime/ps_wrap.c +522 -0
  38. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/stdlib_queue.py +31 -4
  39. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/stdmore.py +58 -1
  40. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/telemetry.py +70 -2
  41. pyscriptc-0.2.0/src/pyscriptc/typefacts.py +2955 -0
  42. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc.egg-info/PKG-INFO +22 -10
  43. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc.egg-info/SOURCES.txt +39 -0
  44. pyscriptc-0.2.0/src/pyscriptc.egg-info/requires.txt +2 -0
  45. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_adoption.py +1 -1
  46. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_band.py +0 -10
  47. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_break.py +0 -18
  48. pyscriptc-0.2.0/tests/test_census_self.py +33 -0
  49. pyscriptc-0.2.0/tests/test_checker_adapters.py +439 -0
  50. pyscriptc-0.2.0/tests/test_checker_align.py +113 -0
  51. pyscriptc-0.2.0/tests/test_checker_resolve.py +137 -0
  52. pyscriptc-0.2.0/tests/test_cli_dx.py +138 -0
  53. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_compare_chain.py +0 -12
  54. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_continue.py +0 -26
  55. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_coverage.py +7 -7
  56. pyscriptc-0.2.0/tests/test_dunder.py +262 -0
  57. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_append.py +1 -1
  58. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_print.py +8 -2
  59. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_sortedkey.py +19 -10
  60. pyscriptc-0.2.0/tests/test_e2_exc_forms.py +372 -0
  61. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_entrypoints.py +14 -4
  62. pyscriptc-0.2.0/tests/test_format_specs.py +87 -0
  63. pyscriptc-0.2.0/tests/test_fstring_specs.py +86 -0
  64. pyscriptc-0.2.0/tests/test_gates.py +607 -0
  65. pyscriptc-0.2.0/tests/test_identity_eq.py +188 -0
  66. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_is_none.py +2 -37
  67. pyscriptc-0.2.0/tests/test_list_comp_if.py +181 -0
  68. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_lwave.py +5 -20
  69. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_match.py +150 -19
  70. pyscriptc-0.2.0/tests/test_module_cond.py +72 -0
  71. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_module_fstring.py +3 -1
  72. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_module_set.py +1 -1
  73. pyscriptc-0.2.0/tests/test_numeric_tower.py +264 -0
  74. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_pow.py +21 -18
  75. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_pyjwt_compat.py +4 -3
  76. pyscriptc-0.2.0/tests/test_pyrefly_tsp_facts.py +160 -0
  77. pyscriptc-0.2.0/tests/test_pyright_checker.py +103 -0
  78. pyscriptc-0.2.0/tests/test_pyright_facts.py +484 -0
  79. pyscriptc-0.2.0/tests/test_r10_catchable.py +141 -0
  80. pyscriptc-0.2.0/tests/test_r20_builtins.py +235 -0
  81. pyscriptc-0.2.0/tests/test_r23_callables2.py +277 -0
  82. pyscriptc-0.2.0/tests/test_r24_iterators.py +304 -0
  83. pyscriptc-0.2.0/tests/test_r26_optional.py +160 -0
  84. pyscriptc-0.2.0/tests/test_r27_re_search.py +278 -0
  85. pyscriptc-0.2.0/tests/test_r28_json.py +183 -0
  86. pyscriptc-0.2.0/tests/test_r29_collections.py +232 -0
  87. pyscriptc-0.2.0/tests/test_r30_itertools.py +433 -0
  88. pyscriptc-0.2.0/tests/test_r33_pathlib.py +255 -0
  89. pyscriptc-0.2.0/tests/test_r36.py +237 -0
  90. pyscriptc-0.2.0/tests/test_r40_with.py +292 -0
  91. pyscriptc-0.2.0/tests/test_r7_r14.py +313 -0
  92. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_re_a.py +2 -9
  93. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_re_compile_module.py +25 -6
  94. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_re_debug.py +3 -5
  95. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_re_dotall.py +2 -2
  96. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_scripting.py +6 -7
  97. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_spike.py +2 -2
  98. pyscriptc-0.2.0/tests/test_stdlib_wave.py +455 -0
  99. pyscriptc-0.2.0/tests/test_t2_typevar.py +417 -0
  100. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_telemetry.py +130 -0
  101. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_tuple_membership.py +0 -5
  102. pyscriptc-0.2.0/tests/test_typefacts.py +150 -0
  103. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_version_surface.py +3 -3
  104. pyscriptc-0.1.0/src/pyscriptc/check.py +0 -49
  105. pyscriptc-0.1.0/src/pyscriptc/lower/_expr.py +0 -886
  106. pyscriptc-0.1.0/src/pyscriptc/lower/_stmt.py +0 -1173
  107. pyscriptc-0.1.0/src/pyscriptc/restlower.py +0 -1008
  108. pyscriptc-0.1.0/src/pyscriptc.egg-info/requires.txt +0 -1
  109. pyscriptc-0.1.0/tests/test_census_self.py +0 -24
  110. pyscriptc-0.1.0/tests/test_gates.py +0 -336
  111. pyscriptc-0.1.0/tests/test_list_comp_if.py +0 -122
  112. pyscriptc-0.1.0/tests/test_stdlib_wave.py +0 -115
  113. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/LICENSE +0 -0
  114. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/setup.cfg +0 -0
  115. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/__init__.py +0 -0
  116. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/__main__.py +0 -0
  117. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/_posthog_token.py +0 -0
  118. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/canonical.py +0 -0
  119. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/coverage.py +0 -0
  120. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/debug.py +0 -0
  121. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/diagnostics.py +0 -0
  122. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/errors.py +0 -0
  123. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/log.py +0 -0
  124. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_argv.c +0 -0
  125. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_b64.c +0 -0
  126. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_dt.c +0 -0
  127. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_hash.c +0 -0
  128. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_hmac.c +0 -0
  129. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_island.c +0 -0
  130. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_mix.c +0 -0
  131. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_struct.c +0 -0
  132. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_time.c +0 -0
  133. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_unicode.c +0 -0
  134. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc/runtime/ps_url.c +0 -0
  135. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc.egg-info/dependency_links.txt +0 -0
  136. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc.egg-info/entry_points.txt +0 -0
  137. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/src/pyscriptc.egg-info/top_level.txt +0 -0
  138. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_agen_closed.py +0 -0
  139. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_all_completed.py +0 -0
  140. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_assert.py +0 -0
  141. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_baseline.py +0 -0
  142. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_basic_format.py +0 -0
  143. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_benchmarks.py +0 -0
  144. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_bool_surface.py +0 -0
  145. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_canonical.py +0 -0
  146. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_census.py +0 -0
  147. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_compat.py +0 -0
  148. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_compat2_calibration.py +0 -0
  149. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_compat2_corpus.py +0 -0
  150. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_compat2_probes.py +0 -0
  151. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_compat2_triage.py +0 -0
  152. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_constructors.py +0 -0
  153. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_cross.py +0 -0
  154. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_debug.py +0 -0
  155. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_decorator.py +0 -0
  156. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_defaultaction.py +0 -0
  157. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_del.py +0 -0
  158. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_devnull.py +0 -0
  159. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_assert.py +0 -0
  160. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_boolop_value.py +0 -0
  161. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_del.py +0 -0
  162. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_entry.py +0 -0
  163. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_fortuple.py +0 -0
  164. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_intbytes.py +0 -0
  165. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_loops.py +0 -0
  166. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_negstep.py +0 -0
  167. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e1_sysargv.py +0 -0
  168. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_e2_exc.py +0 -0
  169. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_errno_platform.py +0 -0
  170. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_examples.py +0 -0
  171. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_fd_hygiene.py +0 -0
  172. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_fence_messages.py +0 -0
  173. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_flipcheck.py +0 -0
  174. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_float_inf.py +0 -0
  175. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_frozenset.py +0 -0
  176. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_frozenset_str.py +0 -0
  177. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_holdout_guard.py +0 -0
  178. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_ifexp.py +0 -0
  179. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_int_surface.py +0 -0
  180. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_io_annotation.py +0 -0
  181. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_irscore.py +0 -0
  182. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_log.py +0 -0
  183. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_nan_in.py +0 -0
  184. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_nativeprobe.py +0 -0
  185. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_or_mixed.py +0 -0
  186. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_ordereddict.py +0 -0
  187. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_package.py +0 -0
  188. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_r_batch.py +0 -0
  189. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_re_ascii.py +0 -0
  190. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_reduce.py +0 -0
  191. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_rest.py +0 -0
  192. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_slice_step.py +0 -0
  193. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_stdlib_bench.py +0 -0
  194. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_str_surface.py +0 -0
  195. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_timeout_max.py +0 -0
  196. {pyscriptc-0.1.0 → pyscriptc-0.2.0}/tests/test_tuple_ellipsis.py +0 -0
  197. {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.1.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. [mypy](https://mypy-lang.org/) is a preflight: its tree is not an input. Anything the subset does not prove is a fence, not a guess.
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
- Requirements: CPython 3.10 or later (the IR is stamped with the interpreter that lowered it) and a clang that can assemble textual LLVM IR. `pipx install pyscriptc` and `pip install pyscriptc` work the same way.
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 mypy) to typed IR, then LLVM IR, then a native binary via clang or `zig cc`.
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 | mypy preflight + the `PS1xxx`/`PS2xxx` fence tables |
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
- - `and` / `or` across two types, f-string format specs, a slice step other than 1, `break`, `continue`, `finally`, `except as`, user decorators, `super()`, multiple inheritance, `**kwargs`, keyword-only and positional-only parameters, and starred calls
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 mypy. 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.
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
- - CPython 3.10 or later (the IR is stamped with the interpreter that lowered it)
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 mypy before lowering. `examples/big_literal.py` lowers to IR, then LLVM emission refuses the integer because it does not fit in `i64`.
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. [mypy](https://mypy-lang.org/) is a preflight: its tree is not an input. Anything the subset does not prove is a fence, not a guess.
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
- Requirements: CPython 3.10 or later (the IR is stamped with the interpreter that lowered it) and a clang that can assemble textual LLVM IR. `pipx install pyscriptc` and `pip install pyscriptc` work the same way.
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 mypy) to typed IR, then LLVM IR, then a native binary via clang or `zig cc`.
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 | mypy preflight + the `PS1xxx`/`PS2xxx` fence tables |
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
- - `and` / `or` across two types, f-string format specs, a slice step other than 1, `break`, `continue`, `finally`, `except as`, user decorators, `super()`, multiple inheritance, `**kwargs`, keyword-only and positional-only parameters, and starred calls
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 mypy. 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.
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
- - CPython 3.10 or later (the IR is stamped with the interpreter that lowered it)
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 mypy before lowering. `examples/big_literal.py` lowers to IR, then LLVM emission refuses the integer because it does not fit in `i64`.
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.1.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 = ["mypy>=2.4"]
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 = 8
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