pyfixer-ai 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. pyfixer/__init__.py +4 -0
  2. pyfixer/__main__.py +4 -0
  3. pyfixer/_pair_probe.py +114 -0
  4. pyfixer/ast_detector.py +1278 -0
  5. pyfixer/ast_fixer.py +2446 -0
  6. pyfixer/ast_safety.py +316 -0
  7. pyfixer/ast_style_fixes.py +837 -0
  8. pyfixer/byok.py +565 -0
  9. pyfixer/canon.py +645 -0
  10. pyfixer/cli.py +2060 -0
  11. pyfixer/config.py +216 -0
  12. pyfixer/contracts.py +656 -0
  13. pyfixer/deterministic.py +237 -0
  14. pyfixer/embedder.py +79 -0
  15. pyfixer/feedback_loop.py +221 -0
  16. pyfixer/fewshot.py +166 -0
  17. pyfixer/fixer.py +4334 -0
  18. pyfixer/guardrails.py +138 -0
  19. pyfixer/kbest.py +241 -0
  20. pyfixer/knowledge_base.py +1249 -0
  21. pyfixer/learning.py +495 -0
  22. pyfixer/llm_targeted.py +540 -0
  23. pyfixer/logic_fixes.py +977 -0
  24. pyfixer/main.py +866 -0
  25. pyfixer/oracle_validate.py +174 -0
  26. pyfixer/orchestrator.py +240 -0
  27. pyfixer/postprocess.py +4298 -0
  28. pyfixer/primitives.py +252 -0
  29. pyfixer/py.typed +0 -0
  30. pyfixer/rag_retriever.py +1761 -0
  31. pyfixer/regex_patterns.py +3066 -0
  32. pyfixer/report.py +163 -0
  33. pyfixer/router.py +143 -0
  34. pyfixer/rule_registry.py +231 -0
  35. pyfixer/safety.py +474 -0
  36. pyfixer/sandbox.py +102 -0
  37. pyfixer/sandboxexec.py +210 -0
  38. pyfixer/scanner.py +1303 -0
  39. pyfixer/store.py +502 -0
  40. pyfixer/style_fixes.py +389 -0
  41. pyfixer/tests_gen.py +268 -0
  42. pyfixer/trace.py +39 -0
  43. pyfixer/type_doc_generator.py +611 -0
  44. pyfixer/validators.py +316 -0
  45. pyfixer/verify.py +842 -0
  46. pyfixer/workers.py +420 -0
  47. pyfixer_ai-0.4.0.dist-info/METADATA +420 -0
  48. pyfixer_ai-0.4.0.dist-info/RECORD +52 -0
  49. pyfixer_ai-0.4.0.dist-info/WHEEL +5 -0
  50. pyfixer_ai-0.4.0.dist-info/entry_points.txt +2 -0
  51. pyfixer_ai-0.4.0.dist-info/licenses/LICENSE +21 -0
  52. pyfixer_ai-0.4.0.dist-info/top_level.txt +1 -0
pyfixer/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ """PyFixer — upload a Python file, get bugs found, fixed, and explained.
2
+
3
+ Your API key, your control: fixes are only applied after you approve them.
4
+ """
pyfixer/__main__.py ADDED
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ raise SystemExit(main())
pyfixer/_pair_probe.py ADDED
@@ -0,0 +1,114 @@
1
+ import json
2
+ import signal
3
+ import sys
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+
8
+ def _emit(kind, **kw):
9
+ row = {"kind": kind, **kw}
10
+ print(json.dumps(row))
11
+ sys.stdout.flush()
12
+
13
+
14
+ src_mode = sys.argv[1] # 'exec' | 'import'
15
+ pre_path = sys.argv[2]
16
+ post_path = sys.argv[3]
17
+ calls_path = sys.argv[4]
18
+
19
+ with Path(calls_path).open(encoding="utf-8") as calls_f:
20
+ calls = json.load(calls_f)
21
+
22
+
23
+ def _load(src_path: str):
24
+ import builtins as _b
25
+
26
+ ns: dict[str, Any] = {}
27
+ if src_mode == "import":
28
+ dotted = sys.argv[5]
29
+ if sys.path[0] != src_path:
30
+ sys.path.insert(0, src_path)
31
+ import importlib
32
+
33
+ try:
34
+ dot_m = importlib.import_module(dotted)
35
+ return dot_m, None
36
+ except Exception as exc:
37
+ return None, (type(exc).__name__, str(exc)[:80])
38
+ try:
39
+ with Path(src_path).open(encoding="utf-8") as f:
40
+ code = compile(f.read(), src_path, "exec")
41
+ exec(code, {"__builtins__": _b.__dict__}, ns)
42
+ return ns, None
43
+ except Exception as exc:
44
+ return None, (type(exc).__name__, str(exc)[:80])
45
+
46
+
47
+ def _finger(ns, call, which):
48
+ fn = ns.get(call["func"]) if hasattr(ns, "get") else getattr(ns, call["func"], None)
49
+ if fn is None:
50
+ _emit("no-func", which=which, func=call["func"])
51
+ return None
52
+ kwargs = {}
53
+ for k, expr in call["kwargs"].items():
54
+ try:
55
+ kwargs[k] = eval(expr, {"__builtins__": __builtins__}, {})
56
+ except Exception as exc:
57
+ _emit("eval-fail", which=which, func=call["func"], k=k, exc=type(exc).__name__)
58
+ return None
59
+ try:
60
+ signal.setitimer(signal.ITIMER_REAL, 2.0)
61
+ out = fn(**kwargs)
62
+ signal.setitimer(signal.ITIMER_REAL, 0)
63
+ except TimeoutError:
64
+ _emit("hang", which=which, func=call["func"], param=call["param"])
65
+ return None
66
+ except BaseException as exc:
67
+ _emit(
68
+ "crash",
69
+ which=which,
70
+ func=call["func"],
71
+ param=call["param"],
72
+ value=call.get("label"),
73
+ exc=type(exc).__name__,
74
+ msg=str(exc)[:100],
75
+ )
76
+ return None
77
+ # materialize lazy returns so we fingerprint produced output, not the wrapper
78
+ if hasattr(out, "__next__"):
79
+ try:
80
+ out = list(out)
81
+ except BaseException as exc:
82
+ _emit(
83
+ "gen-crash",
84
+ which=which,
85
+ func=call["func"],
86
+ param=call["param"],
87
+ value=call.get("label"),
88
+ exc=type(exc).__name__,
89
+ )
90
+ return None
91
+ try:
92
+ fp = repr(out)
93
+ except BaseException as exc:
94
+ fp = f"<repr:{type(exc).__name__}>"
95
+ return fp
96
+
97
+
98
+ pre_ns, pre_err = _load(pre_path)
99
+ if pre_err:
100
+ _emit("unloadable", which="pre", exc=pre_err[0], msg=pre_err[1])
101
+ sys.exit(0)
102
+ post_ns, post_err = _load(post_path)
103
+ if post_err:
104
+ _emit("unloadable", which="post", exc=post_err[0], msg=post_err[1])
105
+ sys.exit(0)
106
+
107
+ for call in calls:
108
+ pf = _finger(pre_ns, call, "pre")
109
+ qf = _finger(post_ns, call, "post")
110
+ if pf == qf:
111
+ continue
112
+ _emit(
113
+ "outdiff", func=call["func"], param=call["param"], value=call.get("label"), pre=pf, post=qf
114
+ )