fxn 0.0.44__py3-none-any.whl → 0.0.46__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.
- fxn/__init__.py +2 -2
- fxn/beta/__init__.py +4 -0
- fxn/beta/metadata.py +61 -0
- fxn/cli/__init__.py +5 -2
- fxn/cli/compile.py +18 -4
- fxn/cli/sources.py +46 -0
- fxn/compile.py +15 -2
- fxn/version.py +1 -1
- {fxn-0.0.44.dist-info → fxn-0.0.46.dist-info}/METADATA +2 -2
- {fxn-0.0.44.dist-info → fxn-0.0.46.dist-info}/RECORD +14 -12
- {fxn-0.0.44.dist-info → fxn-0.0.46.dist-info}/WHEEL +0 -0
- {fxn-0.0.44.dist-info → fxn-0.0.46.dist-info}/entry_points.txt +0 -0
- {fxn-0.0.44.dist-info → fxn-0.0.46.dist-info}/licenses/LICENSE +0 -0
- {fxn-0.0.44.dist-info → fxn-0.0.46.dist-info}/top_level.txt +0 -0
fxn/__init__.py
CHANGED
@@ -4,8 +4,8 @@
|
|
4
4
|
#
|
5
5
|
|
6
6
|
from .client import FunctionAPIError
|
7
|
-
from .compile import compile, CompileTarget
|
7
|
+
from .compile import compile, CompileMetadata, CompileTarget
|
8
8
|
from .function import Function
|
9
9
|
from .sandbox import Sandbox
|
10
10
|
from .types import *
|
11
|
-
from .version import
|
11
|
+
from .version import __version__
|
fxn/beta/__init__.py
CHANGED
fxn/beta/metadata.py
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
#
|
2
|
+
# Function
|
3
|
+
# Copyright © 2025 NatML Inc. All Rights Reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
from pathlib import Path
|
7
|
+
from pydantic import BaseModel, BeforeValidator, ConfigDict, Field
|
8
|
+
from typing import Annotated, Literal
|
9
|
+
|
10
|
+
def _validate_torch_module (module: "torch.nn.Module") -> "torch.nn.Module": # type: ignore
|
11
|
+
try:
|
12
|
+
from torch.nn import Module # type: ignore
|
13
|
+
if not isinstance(module, Module):
|
14
|
+
raise ValueError(f"Expected torch.nn.Module, got {type(module)}")
|
15
|
+
return module
|
16
|
+
except ImportError:
|
17
|
+
raise ImportError("PyTorch is required to create this metadata but is not installed.")
|
18
|
+
|
19
|
+
def _validate_ort_inference_session (session: "onnxruntime.InferenceSession") -> "onnxruntime.InferenceSession": # type: ignore
|
20
|
+
try:
|
21
|
+
from onnxruntime import InferenceSession # type: ignore
|
22
|
+
if not isinstance(session, InferenceSession):
|
23
|
+
raise ValueError(f"Expected onnxruntime.InferenceSession, got {type(session)}")
|
24
|
+
return session
|
25
|
+
except ImportError:
|
26
|
+
raise ImportError("ONNXRuntime is required to create this metadata but is not installed.")
|
27
|
+
|
28
|
+
class CoreMLInferenceMetadata (BaseModel):
|
29
|
+
"""
|
30
|
+
Metadata required to lower PyTorch models for inference on iOS, macOS, and visionOS with CoreML.
|
31
|
+
"""
|
32
|
+
kind: Literal["meta.inference.coreml"] = "meta.inference.coreml"
|
33
|
+
model: Annotated[object, BeforeValidator(_validate_torch_module)] = Field(description="PyTorch module to apply metadata to.")
|
34
|
+
model_args: list[object] = Field(description="Positional inputs to the model.")
|
35
|
+
model_config = ConfigDict(arbitrary_types_allowed=True, frozen=True)
|
36
|
+
|
37
|
+
class ONNXInferenceMetadata (BaseModel):
|
38
|
+
"""
|
39
|
+
Metadata required to lower PyTorch models for inference.
|
40
|
+
"""
|
41
|
+
kind: Literal["meta.inference.onnx"] = "meta.inference.onnx"
|
42
|
+
model: Annotated[object, BeforeValidator(_validate_torch_module)] = Field(description="PyTorch module to apply metadata to.")
|
43
|
+
model_args: list[object] = Field(description="Positional inputs to the model.")
|
44
|
+
model_config = ConfigDict(arbitrary_types_allowed=True, frozen=True)
|
45
|
+
|
46
|
+
class ONNXRuntimeInferenceSessionMetadata (BaseModel):
|
47
|
+
"""
|
48
|
+
Metadata required to lower ONNXRuntime inference sessions for inference.
|
49
|
+
"""
|
50
|
+
kind: Literal["meta.inference.onnxruntime"] = "meta.inference.onnxruntime"
|
51
|
+
session: Annotated[object, BeforeValidator(_validate_ort_inference_session)] = Field(description="ONNXRuntime inference session to apply metadata to.")
|
52
|
+
model_path: Path = Field(description="ONNX model path. The model must exist at this path in the compiler sandbox.")
|
53
|
+
model_config = ConfigDict(arbitrary_types_allowed=True, frozen=True)
|
54
|
+
|
55
|
+
class GGUFInferenceMetadata (BaseModel): # INCOMPLETE
|
56
|
+
"""
|
57
|
+
Metadata required to lower GGUF models for LLM inference.
|
58
|
+
"""
|
59
|
+
kind: Literal["meta.inference.gguf"] = "meta.inference.gguf"
|
60
|
+
model_path: Path = Field(description="GGUF model path. The model must exist at this path in the compiler sandbox.")
|
61
|
+
model_config = ConfigDict(arbitrary_types_allowed=True, frozen=True)
|
fxn/cli/__init__.py
CHANGED
@@ -5,13 +5,15 @@
|
|
5
5
|
|
6
6
|
import typer
|
7
7
|
|
8
|
+
from ..logging import TracebackMarkupConsole
|
9
|
+
from ..version import __version__
|
10
|
+
|
8
11
|
from .auth import app as auth_app
|
9
12
|
from .compile import compile_predictor
|
10
13
|
from .misc import cli_options
|
11
14
|
from .predictions import create_prediction
|
12
15
|
from .predictors import archive_predictor, delete_predictor, retrieve_predictor
|
13
|
-
from
|
14
|
-
from ..version import __version__
|
16
|
+
from .sources import retrieve_source
|
15
17
|
|
16
18
|
# Define CLI
|
17
19
|
typer.main.console_stderr = TracebackMarkupConsole()
|
@@ -42,6 +44,7 @@ app.command(
|
|
42
44
|
app.command(name="retrieve", help="Retrieve a predictor.")(retrieve_predictor)
|
43
45
|
app.command(name="archive", help="Archive a predictor.")(archive_predictor)
|
44
46
|
app.command(name="delete", help="Delete a predictor.")(delete_predictor)
|
47
|
+
app.command(name="source", help="Retrieve the native source code for a given prediction.")(retrieve_source)
|
45
48
|
|
46
49
|
# Run
|
47
50
|
if __name__ == "__main__":
|
fxn/cli/compile.py
CHANGED
@@ -9,12 +9,12 @@ from inspect import getmembers, getmodulename, isfunction
|
|
9
9
|
from pathlib import Path
|
10
10
|
from pydantic import BaseModel
|
11
11
|
from rich import print as print_rich
|
12
|
-
from rich.progress import SpinnerColumn, TextColumn
|
13
12
|
import sys
|
14
13
|
from typer import Argument, Option
|
15
14
|
from typing import Callable, Literal
|
16
15
|
from urllib.parse import urlparse, urlunparse
|
17
16
|
|
17
|
+
from ..client import FunctionAPIError
|
18
18
|
from ..compile import PredictorSpec
|
19
19
|
from ..function import Function
|
20
20
|
from ..sandbox import EntrypointCommand
|
@@ -25,11 +25,16 @@ class CompileError (Exception):
|
|
25
25
|
pass
|
26
26
|
|
27
27
|
def compile_predictor (
|
28
|
-
path: str=Argument(..., help="Predictor path.")
|
28
|
+
path: str=Argument(..., help="Predictor path."),
|
29
|
+
overwrite: bool=Option(False, "--overwrite", help="Whether to delete any existing predictor with the same tag before compiling."),
|
29
30
|
):
|
30
|
-
run_async(_compile_predictor_async(path))
|
31
|
+
run_async(_compile_predictor_async(path, overwrite=overwrite))
|
31
32
|
|
32
|
-
async def _compile_predictor_async (
|
33
|
+
async def _compile_predictor_async (
|
34
|
+
path: str,
|
35
|
+
*,
|
36
|
+
overwrite: bool
|
37
|
+
):
|
33
38
|
fxn = Function(get_access_key())
|
34
39
|
path: Path = Path(path).resolve()
|
35
40
|
with CustomProgress():
|
@@ -47,6 +52,15 @@ async def _compile_predictor_async (path: str):
|
|
47
52
|
# Compile
|
48
53
|
with CustomProgressTask(loading_text="Running codegen...", done_text="Completed codegen"):
|
49
54
|
with CustomProgressTask(loading_text="Creating predictor..."):
|
55
|
+
if overwrite:
|
56
|
+
try:
|
57
|
+
fxn.client.request(
|
58
|
+
method="DELETE",
|
59
|
+
path=f"/predictors/{spec.tag}"
|
60
|
+
)
|
61
|
+
except FunctionAPIError as error:
|
62
|
+
if error.status_code != 404:
|
63
|
+
raise
|
50
64
|
predictor = fxn.client.request(
|
51
65
|
method="POST",
|
52
66
|
path="/predictors",
|
fxn/cli/sources.py
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#
|
2
|
+
# Function
|
3
|
+
# Copyright © 2025 NatML Inc. All Rights Reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
from datetime import datetime
|
7
|
+
from pathlib import Path
|
8
|
+
from pydantic import BaseModel
|
9
|
+
from rich import print_json
|
10
|
+
from typer import Argument, Option
|
11
|
+
from typing_extensions import Annotated
|
12
|
+
|
13
|
+
from ..function import Function
|
14
|
+
from ..logging import CustomProgress, CustomProgressTask
|
15
|
+
from .auth import get_access_key
|
16
|
+
|
17
|
+
def retrieve_source (
|
18
|
+
predictor: Annotated[str, Option(help="Predictor tag.")] = None,
|
19
|
+
prediction: Annotated[str, Option(help="Prediction identifier. If specified, this MUST be from a prediction returned by the Function API.")] = None,
|
20
|
+
output: Annotated[Path, Option(help="Path to output source file.")] = Path("predictor.cpp")
|
21
|
+
):
|
22
|
+
if not ((predictor is not None) ^ (prediction is not None)):
|
23
|
+
raise ValueError(f"Predictor tag or prediction identifier must be provided, but not both.")
|
24
|
+
fxn = Function(get_access_key())
|
25
|
+
with CustomProgress(transient=True):
|
26
|
+
if prediction is None:
|
27
|
+
with CustomProgressTask(loading_text="Creating prediction..."):
|
28
|
+
empty_prediction = fxn.predictions.create(tag=predictor)
|
29
|
+
prediction = empty_prediction.id
|
30
|
+
with CustomProgressTask(loading_text="Retrieving source..."):
|
31
|
+
source = fxn.client.request(
|
32
|
+
method="GET",
|
33
|
+
path=f"/predictions/{prediction}/source",
|
34
|
+
response_type=_PredictionSource
|
35
|
+
)
|
36
|
+
output.write_text(source.code)
|
37
|
+
source.code = str(output.resolve())
|
38
|
+
print_json(data=source.model_dump(mode="json", by_alias=True))
|
39
|
+
|
40
|
+
class _PredictionSource (BaseModel):
|
41
|
+
tag: str
|
42
|
+
target: str
|
43
|
+
code: str
|
44
|
+
created: datetime
|
45
|
+
compiled: datetime
|
46
|
+
latency: float # millis
|
fxn/compile.py
CHANGED
@@ -11,11 +11,22 @@ from pydantic import BaseModel, ConfigDict, Field
|
|
11
11
|
from types import ModuleType
|
12
12
|
from typing import Literal
|
13
13
|
|
14
|
+
from .beta import (
|
15
|
+
CoreMLInferenceMetadata, GGUFInferenceMetadata,
|
16
|
+
ONNXInferenceMetadata, ONNXRuntimeInferenceSessionMetadata
|
17
|
+
)
|
14
18
|
from .sandbox import Sandbox
|
15
19
|
from .types import AccessMode
|
16
20
|
|
17
21
|
CompileTarget = Literal["android", "ios", "linux", "macos", "visionos", "wasm", "windows"]
|
18
22
|
|
23
|
+
CompileMetadata = (
|
24
|
+
CoreMLInferenceMetadata |
|
25
|
+
GGUFInferenceMetadata |
|
26
|
+
ONNXInferenceMetadata |
|
27
|
+
ONNXRuntimeInferenceSessionMetadata
|
28
|
+
)
|
29
|
+
|
19
30
|
class PredictorSpec (BaseModel):
|
20
31
|
"""
|
21
32
|
Descriptor of a predictor to be compiled.
|
@@ -23,7 +34,6 @@ class PredictorSpec (BaseModel):
|
|
23
34
|
tag: str = Field(description="Predictor tag.")
|
24
35
|
description: str = Field(description="Predictor description. MUST be less than 100 characters long.", min_length=4, max_length=100)
|
25
36
|
sandbox: Sandbox = Field(description="Sandbox to compile the function.")
|
26
|
-
trace_modules: list[ModuleType] = Field(description="Modules to trace and compile.", exclude=True)
|
27
37
|
targets: list[str] | None = Field(description="Targets to compile this predictor for. Pass `None` to compile for our default targets.")
|
28
38
|
access: AccessMode = Field(description="Predictor access.")
|
29
39
|
card: str | None = Field(default=None, description="Predictor card (markdown).")
|
@@ -39,6 +49,7 @@ def compile (
|
|
39
49
|
trace_modules: list[ModuleType]=[],
|
40
50
|
targets: list[CompileTarget]=None,
|
41
51
|
access: AccessMode=AccessMode.Private,
|
52
|
+
metadata: list[CompileMetadata]=[],
|
42
53
|
card: str | Path=None,
|
43
54
|
media: Path=None,
|
44
55
|
license: str=None,
|
@@ -54,6 +65,7 @@ def compile (
|
|
54
65
|
trace_modules (list): Modules to trace and compile.
|
55
66
|
targets (list): Targets to compile this predictor for. Pass `None` to compile for our default targets.
|
56
67
|
access (AccessMode): Predictor access.
|
68
|
+
metadata (list): Metadata to use while compiling the function.
|
57
69
|
card (str | Path): Predictor card markdown string or path to card.
|
58
70
|
media (Path): Predictor thumbnail image (jpeg or png) path.
|
59
71
|
license (str): Predictor license URL. This is required for public predictors.
|
@@ -69,12 +81,13 @@ def compile (
|
|
69
81
|
tag=tag,
|
70
82
|
description=description,
|
71
83
|
sandbox=sandbox if sandbox is not None else Sandbox(),
|
72
|
-
trace_modules=trace_modules,
|
73
84
|
targets=targets,
|
74
85
|
access=access,
|
75
86
|
card=card.read_text() if isinstance(card, Path) else card,
|
76
87
|
media=None, # INCOMPLETE
|
77
88
|
license=license,
|
89
|
+
trace_modules=trace_modules,
|
90
|
+
metadata=metadata,
|
78
91
|
**kwargs
|
79
92
|
)
|
80
93
|
# Wrap
|
fxn/version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: fxn
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.46
|
4
4
|
Summary: Run prediction functions locally in Python. Register at https://fxn.ai.
|
5
5
|
Author-email: "NatML Inc." <hi@fxn.ai>
|
6
6
|
License: Apache License
|
@@ -224,7 +224,7 @@ Requires-Dist: rich
|
|
224
224
|
Requires-Dist: typer
|
225
225
|
Dynamic: license-file
|
226
226
|
|
227
|
-
# Function for Python
|
227
|
+
# Function for Python
|
228
228
|
|
229
229
|

|
230
230
|
|
@@ -1,12 +1,13 @@
|
|
1
|
-
fxn/__init__.py,sha256=
|
1
|
+
fxn/__init__.py,sha256=gnJK7iOmMVWFhluW9bOvTNxJbpT-GwzDJTMmjA_XxOE,284
|
2
2
|
fxn/client.py,sha256=Deje8eiS1VOHX85tQnV34viv2CPVx2ljwHSbyVB5Z1o,3790
|
3
|
-
fxn/compile.py,sha256=
|
3
|
+
fxn/compile.py,sha256=A9dxw6yv1eCd-zEYnqiyjDUZou8TkbEIA_yB9Tn4pXo,3894
|
4
4
|
fxn/function.py,sha256=XeEuALkbVhkvwEBUfP0A2fu3tdimwHemoR17oomhzc8,1407
|
5
5
|
fxn/logging.py,sha256=MsTSf0GZxrHNDwVAXDOh8_zRUg9hkeZ8DfhFUJs7D8A,7250
|
6
6
|
fxn/sandbox.py,sha256=w2dnHMBaKOERxFMpeAP11X6_SPqcvnpd6SmX6b_FOYQ,7000
|
7
|
-
fxn/version.py,sha256=
|
8
|
-
fxn/beta/__init__.py,sha256=
|
7
|
+
fxn/version.py,sha256=NugzjvuR0aE7hGoUmoQvcI8t1IrmT-Xm9J9SaWp3wVk,95
|
8
|
+
fxn/beta/__init__.py,sha256=aQAV-apg11Z7Pn86eIegJ2id7wkRUaYeEaeZthaCmYk,252
|
9
9
|
fxn/beta/client.py,sha256=0lfwQPcB9ToIJC7AcCXO6DlJKkmId8EChhd9bk29GGE,2611
|
10
|
+
fxn/beta/metadata.py,sha256=7mnbIVoGQm6_5Qy-gSV6xpGuSP6LcnFjKbmSBNze34w,3067
|
10
11
|
fxn/beta/prediction.py,sha256=9DTBahNF6m0TicLab2o9e8IKpiSV6K7cUSTYaFju0ZU,356
|
11
12
|
fxn/beta/remote.py,sha256=HC8OIslZYyxw3XafVCCrP_wrPa00y5uekkKd_tkzyV0,7551
|
12
13
|
fxn/c/__init__.py,sha256=NMIduqO_MYtI9jVCu6ZxvbBtYQXoQyNEWblNy3m2UPY,313
|
@@ -17,12 +18,13 @@ fxn/c/prediction.py,sha256=-d-5yreFAaRS-nDHzhfabRNtgYcmJGiY_N2dt09gk84,2689
|
|
17
18
|
fxn/c/predictor.py,sha256=48poLj1AthzCgU9n6Wv9gL8o4gFucIlOnBO2wdor6r0,1925
|
18
19
|
fxn/c/stream.py,sha256=Y1Xv1Bt3_qlnWg9rCn7NWESpouF1eKMzDiQjhZWbXTg,1105
|
19
20
|
fxn/c/value.py,sha256=h5n91nm8C3YvEEFORfJBUdncZ29DFIdUKGWQ_KpLsWc,7420
|
20
|
-
fxn/cli/__init__.py,sha256=
|
21
|
+
fxn/cli/__init__.py,sha256=vLCNLiXneZzMCFViDOngg3kQZ1rZwnZXzUSEOB38Il0,1542
|
21
22
|
fxn/cli/auth.py,sha256=6iGbNbjxfCr8OZT3_neLThXdWeKRBZATwru8vU0XmRw,1688
|
22
|
-
fxn/cli/compile.py,sha256=
|
23
|
+
fxn/cli/compile.py,sha256=dd3IV1bhBCbMEo0Py6KGxn3vfv_TSDCLL2f-4qLzfiw,6037
|
23
24
|
fxn/cli/misc.py,sha256=LcJbCj_GAgtGraTRva2zHHOPpNwI6SOFntRksxwlqvM,843
|
24
25
|
fxn/cli/predictions.py,sha256=ma7wbsKD5CFCRTU_TtJ8N0nN1fgFX2BZPGG8qm8HlNI,3182
|
25
26
|
fxn/cli/predictors.py,sha256=bVQAuBue_Jxb79X85RTCzOerWRRT2Ny1oF5DNYAsx4M,1545
|
27
|
+
fxn/cli/sources.py,sha256=HQ_PBLXY2CZ5tGuuqQeJQTpM9S9rKtBzyNVTK-ywG84,1781
|
26
28
|
fxn/lib/__init__.py,sha256=-w1ikmmki5NMpzJjERW-O4SwOfBNkimej_0jL8ujYRk,71
|
27
29
|
fxn/lib/linux/arm64/libFunction.so,sha256=NU9PEuQNObqtWPr5vXrWeQuYhzBfmX_Z4guaregFjrI,207632
|
28
30
|
fxn/lib/linux/x86_64/libFunction.so,sha256=qZNlczayaaHIP_tJ9eeZ1TVpV1Os-ztvSWOoBuY9yWE,236272
|
@@ -39,9 +41,9 @@ fxn/types/dtype.py,sha256=71Tuu4IydmELcBcSBbmWswhCE-7WqBSQ4VkETsFRzjA,617
|
|
39
41
|
fxn/types/prediction.py,sha256=BdLTxnKiSFbz5warX8g_Z4DedNxXK3gaNjSKR2FP8tA,2051
|
40
42
|
fxn/types/predictor.py,sha256=KRGZEuDt7WPMCyRcZvQq4y2FMocfVrLEUNJCJgfDY9Y,4000
|
41
43
|
fxn/types/user.py,sha256=Z44TwEocyxSrfKyzcNfmAXUrpX_Ry8fJ7MffSxRn4oU,1071
|
42
|
-
fxn-0.0.
|
43
|
-
fxn-0.0.
|
44
|
-
fxn-0.0.
|
45
|
-
fxn-0.0.
|
46
|
-
fxn-0.0.
|
47
|
-
fxn-0.0.
|
44
|
+
fxn-0.0.46.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
45
|
+
fxn-0.0.46.dist-info/METADATA,sha256=l-W_xp1vn_B4ORukQfRqqe_a2G1mN37IORvIfR-TjG8,16136
|
46
|
+
fxn-0.0.46.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
47
|
+
fxn-0.0.46.dist-info/entry_points.txt,sha256=O_AwD5dYaeB-YT1F9hPAPuDYCkw_W0tdNGYbc5RVR2k,45
|
48
|
+
fxn-0.0.46.dist-info/top_level.txt,sha256=1ULIEGrnMlhId8nYAkjmRn9g3KEFuHKboq193SEKQkA,4
|
49
|
+
fxn-0.0.46.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|