fastpython-native 0.2.0__py3-none-any.whl → 0.2.3__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.
fastpython/__init__.py CHANGED
@@ -22,4 +22,4 @@ __all__ = [
22
22
  "simd",
23
23
  "memory",
24
24
  ]
25
- __version__ = "0.2.0"
25
+ __version__ = "0.2.3"
fastpython/api.py CHANGED
@@ -4,10 +4,12 @@ Provides decorators and pre-start compilation helpers to turn Python functions
4
4
  into hardware-optimized machine code.
5
5
  """
6
6
 
7
+ from __future__ import annotations
8
+
7
9
  import functools
8
10
  import inspect
9
11
  import time
10
- from typing import Callable, Dict, Any, Optional
12
+ from typing import Callable, Dict, Any, Optional, Tuple
11
13
 
12
14
  from .hardware.cpu import get_cpu_info
13
15
  from .compiler.toolchain import CompilerToolchain
fastpython/cli.py CHANGED
@@ -76,8 +76,27 @@ def main():
76
76
  sys.argv = [str(target_script)] + args.script_args
77
77
  sys.path.insert(0, str(target_script.parent))
78
78
 
79
- # Execute script
80
- runpy.run_path(str(target_script), run_name="__main__")
79
+ from .importer import auto_accelerate, transform_source
80
+ auto_accelerate(project_dir=str(target_script.parent), verbose=True)
81
+
82
+ with open(target_script, "r", encoding="utf-8") as f:
83
+ src = f.read()
84
+
85
+ try:
86
+ tree, candidates = transform_source(src, str(target_script), verbose=True)
87
+ if candidates:
88
+ cpu = get_cpu_info()
89
+ print(f"[FastPython.Run] Pre-accelerated {len(candidates)} functions in '{target_script.name}': {', '.join(candidates)}")
90
+ code = compile(tree, str(target_script), "exec")
91
+ globs = {
92
+ "__name__": "__main__",
93
+ "__file__": str(target_script),
94
+ "__builtins__": __builtins__,
95
+ "_FASTPYTHON_MAIN_ACCELERATED": True
96
+ }
97
+ exec(code, globs)
98
+ except Exception:
99
+ runpy.run_path(str(target_script), run_name="__main__")
81
100
 
82
101
 
83
102
  if __name__ == "__main__":
@@ -89,6 +89,12 @@ class PythonToCTranspiler(ast.NodeVisitor):
89
89
  # Check return annotation
90
90
  if node.returns:
91
91
  self.return_type = self._resolve_type_annotation(node.returns)
92
+ elif "return" not in self.type_hints:
93
+ # Infer return type from return statements if possible
94
+ for stmt in ast.walk(node):
95
+ if isinstance(stmt, ast.Return) and stmt.value is not None:
96
+ self.return_type = self._infer_expr_type(stmt.value)
97
+ break
92
98
 
93
99
  # Process function body
94
100
  for stmt in node.body:
@@ -260,6 +266,13 @@ class PythonToCTranspiler(ast.NodeVisitor):
260
266
  left = self.visit(node.left)
261
267
  right = self.visit(node.right)
262
268
  if isinstance(node.op, ast.Pow):
269
+ if isinstance(node.right, ast.Constant):
270
+ if node.right.value == 2:
271
+ return f"(({left}) * ({left}))"
272
+ elif node.right.value == 3:
273
+ return f"(({left}) * ({left}) * ({left}))"
274
+ elif node.right.value == 0.5:
275
+ return f"sqrt((double)({left}))"
263
276
  return f"pow((double)({left}), (double)({right}))"
264
277
  elif isinstance(node.op, ast.FloorDiv):
265
278
  return f"((int64_t)({left}) / (int64_t)({right}))"
fastpython/importer.py CHANGED
@@ -1,7 +1,8 @@
1
1
  """
2
2
  Automatic Project Importer & AST Hook for FastPython.
3
- Intercepts imports of project modules, detects computational functions,
3
+ Intercepts imports of project modules, detects computational functions (at root or nested),
4
4
  and compiles them Ahead-of-Time (AOT) to hardware-native machine code.
5
+ Also auto-accelerates the main script (__main__) when imported at the top of the entry point.
5
6
  """
6
7
 
7
8
  import sys
@@ -10,7 +11,7 @@ import ast
10
11
  from pathlib import Path
11
12
  from importlib.abc import MetaPathFinder, Loader
12
13
  from importlib.machinery import ModuleSpec
13
- from typing import Optional, List, Set
14
+ from typing import Optional, List, Set, Tuple
14
15
 
15
16
  from .hardware.cpu import get_cpu_info
16
17
 
@@ -35,6 +36,57 @@ def is_acceleration_candidate(node: ast.FunctionDef) -> bool:
35
36
  return has_loop or (has_arithmetic and len(node.body) > 1)
36
37
 
37
38
 
39
+ class AutoAccelerateTransformer(ast.NodeTransformer):
40
+ """
41
+ AST transformer that walks the entire syntax tree (including nested blocks,
42
+ if __name__ == '__main__': blocks, and classes) and decorates eligible
43
+ computational functions with FastPython native compilation.
44
+ """
45
+ def __init__(self, verbose: bool = True):
46
+ self.candidates: List[str] = []
47
+ self.verbose = verbose
48
+
49
+ def visit_FunctionDef(self, node: ast.FunctionDef):
50
+ self.generic_visit(node)
51
+
52
+ already_decorated = False
53
+ for dec in node.decorator_list:
54
+ if isinstance(dec, ast.Name) and "compile" in dec.id.lower():
55
+ already_decorated = True
56
+ elif isinstance(dec, ast.Call) and isinstance(dec.func, ast.Name) and "compile" in dec.func.id.lower():
57
+ already_decorated = True
58
+
59
+ if not already_decorated and is_acceleration_candidate(node):
60
+ self.candidates.append(node.name)
61
+ call_node = ast.Call(
62
+ func=ast.Name(id="_fastpython_compile", ctx=ast.Load()),
63
+ args=[],
64
+ keywords=[
65
+ ast.keyword(arg="fastmath", value=ast.Constant(value=True)),
66
+ ast.keyword(arg="verbose", value=ast.Constant(value=self.verbose)),
67
+ ]
68
+ )
69
+ node.decorator_list.insert(0, call_node)
70
+
71
+ return node
72
+
73
+
74
+ def transform_source(source: str, filename: str, verbose: bool = True) -> Tuple[ast.AST, List[str]]:
75
+ """Parses Python source, applies AutoAccelerateTransformer across all scopes, and injects imports."""
76
+ tree = ast.parse(source, filename=filename)
77
+ transformer = AutoAccelerateTransformer(verbose=verbose)
78
+ transformer.visit(tree)
79
+ if transformer.candidates:
80
+ import_stmt = ast.ImportFrom(
81
+ module="fastpython",
82
+ names=[ast.alias(name="compile_native", asname="_fastpython_compile")],
83
+ level=0
84
+ )
85
+ tree.body.insert(0, import_stmt)
86
+ ast.fix_missing_locations(tree)
87
+ return tree, transformer.candidates
88
+
89
+
38
90
  class FastPythonLoader(Loader):
39
91
  def __init__(self, fullname: str, filepath: str, verbose: bool = True):
40
92
  self.fullname = fullname
@@ -51,40 +103,14 @@ class FastPythonLoader(Loader):
51
103
  source = f.read()
52
104
 
53
105
  try:
54
- tree = ast.parse(source, filename=self.filepath)
106
+ tree, candidates = transform_source(source, self.filepath, verbose=self.verbose)
55
107
  except Exception:
56
- # Fall back to standard execution if parsing fails
57
108
  exec(compile(source, self.filepath, "exec"), module.__dict__)
58
109
  return
59
110
 
60
- candidates: List[str] = []
61
- for node in tree.body:
62
- if isinstance(node, ast.FunctionDef) and is_acceleration_candidate(node):
63
- candidates.append(node.name)
64
- # Inject decorator: @_fastpython_compile(fastmath=True)
65
- call_node = ast.Call(
66
- func=ast.Name(id="_fastpython_compile", ctx=ast.Load()),
67
- args=[],
68
- keywords=[
69
- ast.keyword(arg="fastmath", value=ast.Constant(value=True)),
70
- ast.keyword(arg="verbose", value=ast.Constant(value=self.verbose)),
71
- ]
72
- )
73
- node.decorator_list.insert(0, call_node)
74
-
75
- if candidates:
76
- if self.verbose:
77
- cpu = get_cpu_info()
78
- print(f"[FastPython.Auto] Accelerating module '{self.fullname}' ({len(candidates)} functions: {', '.join(candidates)}) for {cpu.brand.strip()}...")
79
-
80
- # Inject import of compile_native at top of module
81
- import_stmt = ast.ImportFrom(
82
- module="fastpython",
83
- names=[ast.alias(name="compile_native", asname="_fastpython_compile")],
84
- level=0
85
- )
86
- tree.body.insert(0, import_stmt)
87
- ast.fix_missing_locations(tree)
111
+ if candidates and self.verbose:
112
+ cpu = get_cpu_info()
113
+ print(f"[FastPython.Auto] Accelerating module '{self.fullname}' ({len(candidates)} functions: {', '.join(candidates)}) for {cpu.brand.strip()}...")
88
114
 
89
115
  code_obj = compile(tree, filename=self.filepath, mode="exec")
90
116
  exec(code_obj, module.__dict__)
@@ -176,17 +202,42 @@ _HOOK_INSTALLED = False
176
202
  def auto_accelerate(project_dir: Optional[str] = None, verbose: bool = True):
177
203
  """
178
204
  Installs the FastPython automatic compilation hook.
179
- Every module imported in the project will be analyzed and compiled AOT into
180
- hardware-native machine code before execution.
205
+ Every module imported in the project, as well as the main script entry point,
206
+ will be analyzed and compiled AOT into hardware-native machine code before execution.
181
207
  """
182
208
  global _HOOK_INSTALLED
183
- if _HOOK_INSTALLED:
184
- return
185
209
 
186
210
  root = project_dir or os.getcwd()
187
- finder = FastPythonFinder(project_root=root, verbose=verbose)
188
- sys.meta_path.insert(0, finder)
189
- _HOOK_INSTALLED = True
190
- if verbose:
191
- cpu = get_cpu_info()
192
- print(f"[FastPython.Auto] Hook active for project '{root}'. Hardware: {cpu.summary()}")
211
+
212
+ if not _HOOK_INSTALLED:
213
+ finder = FastPythonFinder(project_root=root, verbose=verbose)
214
+ sys.meta_path.insert(0, finder)
215
+ _HOOK_INSTALLED = True
216
+ if verbose:
217
+ cpu = get_cpu_info()
218
+ print(f"[FastPython.Auto] Hook active for project '{root}'. Hardware: {cpu.summary()}")
219
+
220
+ # Check if imported directly from __main__ entry point script
221
+ try:
222
+ f = sys._getframe(1)
223
+ while f:
224
+ globs = f.f_globals
225
+ if globs.get("__name__") == "__main__":
226
+ main_file = globs.get("__file__")
227
+ if main_file and os.path.isfile(main_file) and not globs.get("_FASTPYTHON_MAIN_ACCELERATED"):
228
+ globs["_FASTPYTHON_MAIN_ACCELERATED"] = True
229
+ with open(main_file, "r", encoding="utf-8") as fp:
230
+ main_source = fp.read()
231
+ tree, candidates = transform_source(main_source, main_file, verbose=verbose)
232
+ if candidates:
233
+ if verbose:
234
+ cpu = get_cpu_info()
235
+ print(f"[FastPython.Auto] Accelerating main script '{Path(main_file).name}' ({len(candidates)} functions: {', '.join(candidates)}) for {cpu.brand.strip()}...")
236
+ code_obj = compile(tree, filename=main_file, mode="exec")
237
+ exec(code_obj, globs)
238
+ sys.exit(0)
239
+ break
240
+ f = f.f_back
241
+ except Exception as e:
242
+ import traceback
243
+ traceback.print_exc()
@@ -1,4 +1,14 @@
1
- from .aligned_mem import allocate, AlignedBuffer
1
+ try:
2
+ from .aligned_mem import allocate, AlignedBuffer
3
+ except (ImportError, Exception):
4
+ def allocate(size, alignment=64):
5
+ return bytearray(size)
6
+ class AlignedBuffer:
7
+ def __init__(self, size, alignment=64):
8
+ self.buf = bytearray(size)
9
+ def __len__(self):
10
+ return len(self.buf)
11
+
2
12
  from .arena import BumpArena
3
13
 
4
14
  __all__ = ["allocate", "AlignedBuffer", "BumpArena"]
@@ -4,7 +4,17 @@ Replaces heap malloc/free cycles with instantaneous O(1) pointer bumps.
4
4
  """
5
5
 
6
6
  from typing import Optional
7
- from .aligned_mem import allocate, AlignedBuffer
7
+
8
+ try:
9
+ from .aligned_mem import allocate, AlignedBuffer
10
+ except (ImportError, Exception):
11
+ def allocate(size, alignment=64):
12
+ return bytearray(size)
13
+ class AlignedBuffer:
14
+ def __init__(self, size, alignment=64):
15
+ self.buf = bytearray(size)
16
+ def __len__(self):
17
+ return len(self.buf)
8
18
 
9
19
 
10
20
  class BumpArena:
@@ -1,6 +1,10 @@
1
1
  import time
2
2
  from typing import Optional, Dict, Any
3
- from . import native_server
3
+
4
+ try:
5
+ from . import native_server
6
+ except (ImportError, Exception):
7
+ native_server = None
4
8
 
5
9
 
6
10
  class FastWebServer:
@@ -16,16 +20,21 @@ class FastWebServer:
16
20
 
17
21
  def start(self):
18
22
  if not self.is_running:
19
- native_server.start(self.port, self.threads)
20
- self.is_running = True
23
+ if native_server is not None:
24
+ native_server.start(self.port, self.threads)
25
+ self.is_running = True
26
+ else:
27
+ raise RuntimeError("FastWebServer native server module is not built for this Python environment.")
21
28
 
22
29
  def stop(self):
23
- if self.is_running:
30
+ if self.is_running and native_server is not None:
24
31
  native_server.stop()
25
32
  self.is_running = False
26
33
 
27
34
  def stats(self) -> Dict[str, Any]:
28
- return native_server.get_stats()
35
+ if native_server is not None:
36
+ return native_server.get_stats()
37
+ return {}
29
38
 
30
39
  def __enter__(self):
31
40
  self.start()
@@ -1,4 +1,16 @@
1
- from .fast_simd import find_char, find_crlf, parse_http_request, dumps
1
+ try:
2
+ from .fast_simd import find_char, find_crlf, parse_http_request, dumps
3
+ except (ImportError, Exception):
4
+ import json
5
+ def dumps(obj):
6
+ return json.dumps(obj)
7
+ def find_char(buf, char):
8
+ return buf.find(char)
9
+ def find_crlf(buf):
10
+ return buf.find(b"\r\n")
11
+ def parse_http_request(req):
12
+ return {}
13
+
2
14
  from .fast_json import fast_scan_keys
3
15
 
4
16
  __all__ = ["find_char", "find_crlf", "parse_http_request", "dumps", "fast_scan_keys"]
@@ -4,7 +4,17 @@ Leverages AVX2 vector registers to parse JSON documents at multi-gigabyte/sec th
4
4
  """
5
5
 
6
6
  from typing import Any, Dict, List, Union
7
- from .fast_simd import dumps as fast_dumps, find_char, find_crlf
7
+
8
+ try:
9
+ from .fast_simd import dumps as fast_dumps, find_char, find_crlf
10
+ except (ImportError, Exception):
11
+ import json
12
+ def fast_dumps(obj):
13
+ return json.dumps(obj)
14
+ def find_char(buf, char):
15
+ return buf.find(char)
16
+ def find_crlf(buf):
17
+ return buf.find(b"\r\n")
8
18
 
9
19
 
10
20
  def fast_scan_keys(json_bytes: bytes) -> Dict[str, Union[int, float, str, bool, None]]:
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastpython-native
3
- Version: 0.2.0
3
+ Version: 0.2.3
4
4
  Summary: AOT Hardware-Adaptive Native Machine Code Compiler for Python
5
- Author: FastPython Team
5
+ Author: alex9347
6
6
  Keywords: compiler,performance,aot,simd,avx2,jit,optimization
7
7
  Classifier: Programming Language :: Python :: 3
8
8
  Classifier: Operating System :: Microsoft :: Windows
@@ -1,29 +1,29 @@
1
- fastpython/__init__.py,sha256=hn1Vl9J1xUfjzP3fFZXW16ILnfHRqmcebtTif-Ie-NA,583
1
+ fastpython/__init__.py,sha256=ZLYZPgE1RLUPl7djtVM2llzhMITq5CmLMkxqvL377QM,583
2
2
  fastpython/__main__.py,sha256=MSmt_5Xg84uHqzTN38JwgseJK8rsJn_11A8WD99VtEo,61
3
- fastpython/api.py,sha256=ZXSTpYrUqnrCEnc1nx8LqbF9g6X-ePUNZ2RPCzrQCu8,6887
3
+ fastpython/api.py,sha256=Urm-aEzv_ohMmEHBbgpKpvsb3NPFf2k1-lvN8dWfz-U,6930
4
4
  fastpython/auto.py,sha256=aHFcXX8gijt01sYlbZymyS4wSzXFZHLLeGvtB1u30OM,283
5
- fastpython/cli.py,sha256=5ezV99gntwqJNOnNzaVSYLmVXhOCd0Aa7iRm-GCbmnQ,3184
6
- fastpython/importer.py,sha256=pq0ghgpK2qFdIIFVv97klm6oeXZcuKgZFZl9JRSpgVg,7275
5
+ fastpython/cli.py,sha256=BRLhrNabnlSY9Xsod6Ji3gboWhFGDXtFRO1zHmOkZlY,4037
6
+ fastpython/importer.py,sha256=8dHjkPMgSs0lCHo06ReHArx-N6xzeSj1lo4hf-PSTPc,9650
7
7
  fastpython/jit.py,sha256=3LyZ-HZvs5uS_rssvSrvKz5aArplz8ZiaRQ1sKcFRDU,922
8
8
  fastpython/accelerators/fast_raytracer.c,sha256=r5Uf3aOIL72c8MzDRRAfTG08q8uGRLvEX_7taHRY1N4,10854
9
9
  fastpython/accelerators/raytracer.py,sha256=IAPf2luONvkSj3rWET1vSBC6t6mizMoYoDCdNiSuQMI,5648
10
10
  fastpython/codegen/__init__.py,sha256=fqqGp_3A9TwzdnC8vWKyfe3zwN6YLPSt_ZnG_DmtzPA,173
11
- fastpython/codegen/transpiler.py,sha256=r-P50B1ZTZw0WqWqA2ycVXPtUMxzpcA04hYBYXWmB9A,20330
11
+ fastpython/codegen/transpiler.py,sha256=KXRVJgOyFelrNuEm7XaI-DWby5JYdfXwoA51UGl4Gf0,21011
12
12
  fastpython/compiler/__init__.py,sha256=oQfnYP3KTfl6Nyr8rBWmTwUGCPqvjIVgo-qzbsiI_r0,158
13
13
  fastpython/compiler/cache.py,sha256=l-7CMjWzqaxfKEKdYhgzVBmWjoRVkf0cnr_iP-zNmS0,2269
14
14
  fastpython/compiler/toolchain.py,sha256=LDVH4LyoRW3r5ooTaYntGUJRz2pPbbK3treOk3CAxFM,5037
15
15
  fastpython/hardware/__init__.py,sha256=moeI5cy5Rb_owglRaUktFwHLF-8fiLQOE7sISpDsA6I,86
16
16
  fastpython/hardware/cpu.py,sha256=g68IdKvmZeZhl59q23rE2YcG5AsXxmrMt8fsSWTTDco,7383
17
- fastpython/memory/__init__.py,sha256=aGD04hLevPOtCVWt3BOEg5ZycekyiXuiXI1dcSJ6bR4,132
17
+ fastpython/memory/__init__.py,sha256=tVzju63avhsALJU6gpZYBJJOIIttVEd1zBRAlkPnUic,416
18
18
  fastpython/memory/aligned_mem.c,sha256=sYEfnOmuwpBeXca-mNX3EwlVgvAL5S6JzZWLh712Mq8,3318
19
- fastpython/memory/arena.py,sha256=34ZwW-d6FjA7940ZIOxZz99iJupJBxn_KjCFsFYintk,1635
20
- fastpython/server/__init__.py,sha256=uLFW9kKwxc0mlBalIDzDJc-zCTCgVVvIueofR8knrD0,979
19
+ fastpython/memory/arena.py,sha256=1qRA5AuTKshM-q9XRwkk6MPFKV_0klc_3ChKPlLSrgg,1919
20
+ fastpython/server/__init__.py,sha256=TYX33EDgngQB-E5BBVFRE_u0vn9tGJOcqcuwDBJIzk8,1320
21
21
  fastpython/server/native_server.c,sha256=LupO6CkSy1f01297ILWzf_eN7lOWwtiY1ACn1KtUEHw,7195
22
- fastpython/simd/__init__.py,sha256=txxoUEhe5Fq67Vh1pdXFYBWXk4Q3l1MmLa76pRltKBc,196
23
- fastpython/simd/fast_json.py,sha256=BV63OYI0sY7q_MUYhuol-s4RHpCvZMFz8lZsyBD6uCU,2191
22
+ fastpython/simd/__init__.py,sha256=ID-MWvL0UYooW-DnZLdPNv6IzXxNlfNCxWHVbCD-ln4,474
23
+ fastpython/simd/fast_json.py,sha256=lr7Y9XMJDF7_4R5nBuiJ641_yfBRXwxHt-KDchhrjPI,2423
24
24
  fastpython/simd/fast_simd.c,sha256=zltkJBr-Jx1kWFWfmLBuzhkizYOhYGRxpVtACnV5csc,9446
25
- fastpython_native-0.2.0.dist-info/METADATA,sha256=uHTsQWjJJisl2HgihnvPsukSa15TfMTXVZzpZPeZAYE,10736
26
- fastpython_native-0.2.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
27
- fastpython_native-0.2.0.dist-info/entry_points.txt,sha256=IGbP7VbTQmM-57joccriVqB2ieX5uU4u0K5k49HvhE0,51
28
- fastpython_native-0.2.0.dist-info/top_level.txt,sha256=XjyQFL6KqwXjTwH8faHiYGaSiNuJMpZ2ChIn64covz4,11
29
- fastpython_native-0.2.0.dist-info/RECORD,,
25
+ fastpython_native-0.2.3.dist-info/METADATA,sha256=0Dy7C2TGqEoaM3svPiKAUrLXB3tue8RDOhFBYWF4e6Y,10729
26
+ fastpython_native-0.2.3.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
27
+ fastpython_native-0.2.3.dist-info/entry_points.txt,sha256=IGbP7VbTQmM-57joccriVqB2ieX5uU4u0K5k49HvhE0,51
28
+ fastpython_native-0.2.3.dist-info/top_level.txt,sha256=XjyQFL6KqwXjTwH8faHiYGaSiNuJMpZ2ChIn64covz4,11
29
+ fastpython_native-0.2.3.dist-info/RECORD,,