fxn 0.0.42__py3-none-any.whl → 0.0.44__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 -1
- fxn/beta/client.py +59 -2
- fxn/beta/remote.py +40 -47
- fxn/c/configuration.py +62 -30
- fxn/c/value.py +3 -2
- fxn/cli/__init__.py +12 -8
- fxn/cli/compile.py +147 -0
- fxn/cli/predictions.py +16 -13
- fxn/cli/predictors.py +35 -4
- fxn/client.py +66 -5
- fxn/{compile/compile.py → compile.py} +22 -16
- fxn/function.py +8 -3
- fxn/logging.py +219 -0
- fxn/{compile/sandbox.py → sandbox.py} +62 -33
- fxn/services/prediction.py +47 -36
- fxn/types/dtype.py +3 -3
- fxn/types/prediction.py +5 -13
- fxn/types/predictor.py +1 -1
- fxn/version.py +1 -1
- {fxn-0.0.42.dist-info → fxn-0.0.44.dist-info}/METADATA +3 -2
- fxn-0.0.44.dist-info/RECORD +47 -0
- {fxn-0.0.42.dist-info → fxn-0.0.44.dist-info}/WHEEL +1 -1
- fxn/compile/__init__.py +0 -7
- fxn/compile/signature.py +0 -183
- fxn-0.0.42.dist-info/RECORD +0 -47
- {fxn-0.0.42.dist-info → fxn-0.0.44.dist-info}/entry_points.txt +0 -0
- {fxn-0.0.42.dist-info → fxn-0.0.44.dist-info/licenses}/LICENSE +0 -0
- {fxn-0.0.42.dist-info → fxn-0.0.44.dist-info}/top_level.txt +0 -0
fxn/services/prediction.py
CHANGED
@@ -11,16 +11,29 @@ from pathlib import Path
|
|
11
11
|
from PIL import Image
|
12
12
|
from pydantic import BaseModel
|
13
13
|
from requests import get
|
14
|
-
from rich.progress import
|
15
|
-
from tempfile import gettempdir
|
16
|
-
from typing import
|
14
|
+
from rich.progress import BarColumn, DownloadColumn, TransferSpeedColumn, TimeRemainingColumn
|
15
|
+
from tempfile import gettempdir, NamedTemporaryFile
|
16
|
+
from typing import Iterator
|
17
17
|
from urllib.parse import urlparse
|
18
18
|
|
19
19
|
from ..c import Configuration, Predictor, Prediction as CPrediction, Value as CValue, ValueFlags, ValueMap
|
20
20
|
from ..client import FunctionClient
|
21
|
+
from ..logging import CustomProgressTask
|
21
22
|
from ..types import Acceleration, Prediction, PredictionResource
|
22
23
|
|
23
|
-
Value =
|
24
|
+
Value = (
|
25
|
+
None |
|
26
|
+
float |
|
27
|
+
int |
|
28
|
+
bool |
|
29
|
+
ndarray |
|
30
|
+
str |
|
31
|
+
list[object] |
|
32
|
+
dict[str, object] |
|
33
|
+
Image.Image |
|
34
|
+
BytesIO |
|
35
|
+
memoryview
|
36
|
+
)
|
24
37
|
|
25
38
|
class PredictionService:
|
26
39
|
|
@@ -47,11 +60,10 @@ class PredictionService:
|
|
47
60
|
tag: str,
|
48
61
|
*,
|
49
62
|
inputs: dict[str, Value] | None=None,
|
50
|
-
acceleration: Acceleration=
|
63
|
+
acceleration: Acceleration="auto",
|
51
64
|
device=None,
|
52
65
|
client_id: str=None,
|
53
|
-
configuration_id: str=None
|
54
|
-
verbose: bool=False
|
66
|
+
configuration_id: str=None
|
55
67
|
) -> Prediction:
|
56
68
|
"""
|
57
69
|
Create a prediction.
|
@@ -62,7 +74,6 @@ class PredictionService:
|
|
62
74
|
acceleration (Acceleration): Prediction acceleration.
|
63
75
|
client_id (str): Function client identifier. Specify this to override the current client identifier.
|
64
76
|
configuration_id (str): Configuration identifier. Specify this to override the current client configuration identifier.
|
65
|
-
verbose (bool): Enable verbose logging.
|
66
77
|
|
67
78
|
Returns:
|
68
79
|
Prediction: Created prediction.
|
@@ -78,8 +89,7 @@ class PredictionService:
|
|
78
89
|
acceleration=acceleration,
|
79
90
|
device=device,
|
80
91
|
client_id=client_id,
|
81
|
-
configuration_id=configuration_id
|
82
|
-
verbose=verbose
|
92
|
+
configuration_id=configuration_id
|
83
93
|
)
|
84
94
|
with (
|
85
95
|
self.__to_value_map(inputs) as input_map,
|
@@ -87,14 +97,14 @@ class PredictionService:
|
|
87
97
|
):
|
88
98
|
return self.__to_prediction(tag, prediction)
|
89
99
|
|
90
|
-
|
100
|
+
def stream (
|
91
101
|
self,
|
92
102
|
tag: str,
|
93
103
|
*,
|
94
104
|
inputs: dict[str, Value],
|
95
|
-
acceleration: Acceleration=
|
105
|
+
acceleration: Acceleration="auto",
|
96
106
|
device=None
|
97
|
-
) ->
|
107
|
+
) -> Iterator[Prediction]:
|
98
108
|
"""
|
99
109
|
Stream a prediction.
|
100
110
|
|
@@ -142,11 +152,10 @@ class PredictionService:
|
|
142
152
|
def __get_predictor (
|
143
153
|
self,
|
144
154
|
tag: str,
|
145
|
-
acceleration: Acceleration=
|
155
|
+
acceleration: Acceleration="auto",
|
146
156
|
device=None,
|
147
157
|
client_id: str=None,
|
148
|
-
configuration_id: str=None
|
149
|
-
verbose: bool=False
|
158
|
+
configuration_id: str=None
|
150
159
|
) -> Predictor:
|
151
160
|
if tag in self.__cache:
|
152
161
|
return self.__cache[tag]
|
@@ -155,20 +164,13 @@ class PredictionService:
|
|
155
164
|
client_id=client_id,
|
156
165
|
configuration_id=configuration_id
|
157
166
|
)
|
158
|
-
with Configuration() as configuration
|
159
|
-
TextColumn("[bold blue]{task.fields[filename]}"),
|
160
|
-
BarColumn(),
|
161
|
-
DownloadColumn(),
|
162
|
-
TransferSpeedColumn(),
|
163
|
-
TimeRemainingColumn(),
|
164
|
-
disable=not verbose
|
165
|
-
) as progress:
|
167
|
+
with Configuration() as configuration:
|
166
168
|
configuration.tag = prediction.tag
|
167
169
|
configuration.token = prediction.configuration
|
168
170
|
configuration.acceleration = acceleration
|
169
171
|
configuration.device = device
|
170
172
|
for resource in prediction.resources:
|
171
|
-
path = self.__download_resource(resource
|
173
|
+
path = self.__download_resource(resource)
|
172
174
|
configuration.add_resource(resource.type, path)
|
173
175
|
predictor = Predictor(configuration)
|
174
176
|
self.__cache[tag] = predictor
|
@@ -227,12 +229,7 @@ class PredictionService:
|
|
227
229
|
)
|
228
230
|
return prediction
|
229
231
|
|
230
|
-
def __download_resource (
|
231
|
-
self,
|
232
|
-
resource: PredictionResource,
|
233
|
-
*,
|
234
|
-
progress: Progress
|
235
|
-
) -> Path:
|
232
|
+
def __download_resource (self, resource: PredictionResource) -> Path:
|
236
233
|
path = self.__get_resource_path(resource)
|
237
234
|
if path.exists():
|
238
235
|
return path
|
@@ -241,12 +238,26 @@ class PredictionService:
|
|
241
238
|
response.raise_for_status()
|
242
239
|
size = int(response.headers.get("content-length", 0))
|
243
240
|
stem = Path(urlparse(resource.url).path).name
|
244
|
-
|
245
|
-
|
241
|
+
completed = 0
|
242
|
+
color = "dark_orange" if not resource.type == "dso" else "purple"
|
243
|
+
with (
|
244
|
+
CustomProgressTask(
|
245
|
+
loading_text=f"[{color}]{stem}[/{color}]",
|
246
|
+
columns=[
|
247
|
+
BarColumn(),
|
248
|
+
DownloadColumn(),
|
249
|
+
TransferSpeedColumn(),
|
250
|
+
TimeRemainingColumn()
|
251
|
+
]
|
252
|
+
) as task,
|
253
|
+
NamedTemporaryFile(mode="wb", delete=False) as tmp_file
|
254
|
+
):
|
246
255
|
for chunk in response.iter_content(chunk_size=8192):
|
247
256
|
if chunk:
|
248
|
-
|
249
|
-
|
257
|
+
tmp_file.write(chunk)
|
258
|
+
completed += len(chunk)
|
259
|
+
task.update(total=size, completed=completed)
|
260
|
+
Path(tmp_file.name).replace(path)
|
250
261
|
return path
|
251
262
|
|
252
263
|
def __get_resource_path (self, resource: PredictionResource) -> Path:
|
@@ -267,7 +278,7 @@ class PredictionService:
|
|
267
278
|
return Path(gettempdir())
|
268
279
|
|
269
280
|
@classmethod
|
270
|
-
def __try_ensure_serializable (cls, object:
|
281
|
+
def __try_ensure_serializable (cls, object: object) -> object:
|
271
282
|
if object is None:
|
272
283
|
return object
|
273
284
|
if isinstance(object, list):
|
fxn/types/dtype.py
CHANGED
@@ -11,6 +11,9 @@ class Dtype (str, Enum):
|
|
11
11
|
This follows `numpy` dtypes.
|
12
12
|
"""
|
13
13
|
null = "null"
|
14
|
+
float16 = "float16"
|
15
|
+
float32 = "float32"
|
16
|
+
float64 = "float64"
|
14
17
|
int8 = "int8"
|
15
18
|
int16 = "int16"
|
16
19
|
int32 = "int32"
|
@@ -19,9 +22,6 @@ class Dtype (str, Enum):
|
|
19
22
|
uint16 = "uint16"
|
20
23
|
uint32 = "uint32"
|
21
24
|
uint64 = "uint64"
|
22
|
-
float16 = "float16"
|
23
|
-
float32 = "float32"
|
24
|
-
float64 = "float64"
|
25
25
|
bool = "bool"
|
26
26
|
string = "string"
|
27
27
|
list = "list"
|
fxn/types/prediction.py
CHANGED
@@ -3,9 +3,10 @@
|
|
3
3
|
# Copyright © 2025 NatML Inc. All Rights Reserved.
|
4
4
|
#
|
5
5
|
|
6
|
-
from enum import IntFlag
|
7
6
|
from pydantic import BaseModel, Field
|
8
|
-
from typing import
|
7
|
+
from typing import Literal
|
8
|
+
|
9
|
+
Acceleration = Literal["auto", "cpu", "gpu", "npu"]
|
9
10
|
|
10
11
|
class PredictionResource (BaseModel):
|
11
12
|
"""
|
@@ -39,17 +40,8 @@ class Prediction (BaseModel):
|
|
39
40
|
tag: str = Field(description="Predictor tag.")
|
40
41
|
configuration: str | None = Field(default=None, description="Prediction configuration token. This is only populated for `EDGE` predictions.")
|
41
42
|
resources: list[PredictionResource] | None = Field(default=None, description="Prediction resources. This is only populated for `EDGE` predictions.")
|
42
|
-
results: list[
|
43
|
+
results: list[object] | None = Field(default=None, description="Prediction results.")
|
43
44
|
latency: float | None = Field(default=None, description="Prediction latency in milliseconds.")
|
44
45
|
error: str | None = Field(default=None, description="Prediction error. This is `None` if the prediction completed successfully.")
|
45
46
|
logs: str | None = Field(default=None, description="Prediction logs.")
|
46
|
-
created: str = Field(description="Date created.")
|
47
|
-
|
48
|
-
class Acceleration (IntFlag):
|
49
|
-
"""
|
50
|
-
Predictor acceleration.
|
51
|
-
"""
|
52
|
-
Auto = 0,
|
53
|
-
CPU = 1 << 0,
|
54
|
-
GPU = 1 << 1,
|
55
|
-
NPU = 1 << 2
|
47
|
+
created: str = Field(description="Date created.")
|
fxn/types/predictor.py
CHANGED
fxn/version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: fxn
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.44
|
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
|
@@ -222,6 +222,7 @@ Requires-Dist: pydantic>=2.0
|
|
222
222
|
Requires-Dist: requests
|
223
223
|
Requires-Dist: rich
|
224
224
|
Requires-Dist: typer
|
225
|
+
Dynamic: license-file
|
225
226
|
|
226
227
|
# Function for Python and CLI
|
227
228
|
|
@@ -0,0 +1,47 @@
|
|
1
|
+
fxn/__init__.py,sha256=eOYYoHwwQWzYVnyBO1VtcWR0JnUm1GPl4kr8IzhnCqg,257
|
2
|
+
fxn/client.py,sha256=Deje8eiS1VOHX85tQnV34viv2CPVx2ljwHSbyVB5Z1o,3790
|
3
|
+
fxn/compile.py,sha256=XO_0a0hEfM3SI03cb8EFs2xL6E6XpmrVtRPo2icR6J0,3529
|
4
|
+
fxn/function.py,sha256=XeEuALkbVhkvwEBUfP0A2fu3tdimwHemoR17oomhzc8,1407
|
5
|
+
fxn/logging.py,sha256=MsTSf0GZxrHNDwVAXDOh8_zRUg9hkeZ8DfhFUJs7D8A,7250
|
6
|
+
fxn/sandbox.py,sha256=w2dnHMBaKOERxFMpeAP11X6_SPqcvnpd6SmX6b_FOYQ,7000
|
7
|
+
fxn/version.py,sha256=zQOEiQse1Ff3n-mSuBrT9-JLRGel6n8RluZbXIshvHI,95
|
8
|
+
fxn/beta/__init__.py,sha256=gKoDhuXtXCjdhUYUqmF0gDPMhJfg3UwFgbvMtRB5ipo,111
|
9
|
+
fxn/beta/client.py,sha256=0lfwQPcB9ToIJC7AcCXO6DlJKkmId8EChhd9bk29GGE,2611
|
10
|
+
fxn/beta/prediction.py,sha256=9DTBahNF6m0TicLab2o9e8IKpiSV6K7cUSTYaFju0ZU,356
|
11
|
+
fxn/beta/remote.py,sha256=HC8OIslZYyxw3XafVCCrP_wrPa00y5uekkKd_tkzyV0,7551
|
12
|
+
fxn/c/__init__.py,sha256=NMIduqO_MYtI9jVCu6ZxvbBtYQXoQyNEWblNy3m2UPY,313
|
13
|
+
fxn/c/configuration.py,sha256=56_-NNT4yoHDNfvB6jJNYF2eKJYMRLVrv3mIg7g6qaE,5597
|
14
|
+
fxn/c/fxnc.py,sha256=YrvwOlzPmTlSDuz2zmKZfws2WK5BY4YZ62edoplcMJU,1381
|
15
|
+
fxn/c/map.py,sha256=47fBJ0Q6uB_xeW3sn9aCLYJ539edg8ff9DU-EIfWRGA,2352
|
16
|
+
fxn/c/prediction.py,sha256=-d-5yreFAaRS-nDHzhfabRNtgYcmJGiY_N2dt09gk84,2689
|
17
|
+
fxn/c/predictor.py,sha256=48poLj1AthzCgU9n6Wv9gL8o4gFucIlOnBO2wdor6r0,1925
|
18
|
+
fxn/c/stream.py,sha256=Y1Xv1Bt3_qlnWg9rCn7NWESpouF1eKMzDiQjhZWbXTg,1105
|
19
|
+
fxn/c/value.py,sha256=h5n91nm8C3YvEEFORfJBUdncZ29DFIdUKGWQ_KpLsWc,7420
|
20
|
+
fxn/cli/__init__.py,sha256=OcdxY751a5avAWNYUpBG92kjqpKmYXwhZxgB1mGwUpA,1396
|
21
|
+
fxn/cli/auth.py,sha256=6iGbNbjxfCr8OZT3_neLThXdWeKRBZATwru8vU0XmRw,1688
|
22
|
+
fxn/cli/compile.py,sha256=y5SOGSr5_B_WY-TYbg3Q9kCCaYGlbyQcDOYSPeg2lDc,5490
|
23
|
+
fxn/cli/misc.py,sha256=LcJbCj_GAgtGraTRva2zHHOPpNwI6SOFntRksxwlqvM,843
|
24
|
+
fxn/cli/predictions.py,sha256=ma7wbsKD5CFCRTU_TtJ8N0nN1fgFX2BZPGG8qm8HlNI,3182
|
25
|
+
fxn/cli/predictors.py,sha256=bVQAuBue_Jxb79X85RTCzOerWRRT2Ny1oF5DNYAsx4M,1545
|
26
|
+
fxn/lib/__init__.py,sha256=-w1ikmmki5NMpzJjERW-O4SwOfBNkimej_0jL8ujYRk,71
|
27
|
+
fxn/lib/linux/arm64/libFunction.so,sha256=NU9PEuQNObqtWPr5vXrWeQuYhzBfmX_Z4guaregFjrI,207632
|
28
|
+
fxn/lib/linux/x86_64/libFunction.so,sha256=qZNlczayaaHIP_tJ9eeZ1TVpV1Os-ztvSWOoBuY9yWE,236272
|
29
|
+
fxn/lib/macos/arm64/Function.dylib,sha256=ODM3zDbI4Tomx7_QSvnqOE42OBYYblntkSq6gftBP4c,263664
|
30
|
+
fxn/lib/macos/x86_64/Function.dylib,sha256=qIu4dhx0Xk5dQHgTnZTcm2IpoMYJwRPmKRi9J-UnkAY,263680
|
31
|
+
fxn/lib/windows/arm64/Function.dll,sha256=FyL-oipK9wSxXdbD9frc8QFbUKTPMCdtmCkCT8ooIIM,419328
|
32
|
+
fxn/lib/windows/x86_64/Function.dll,sha256=iL6w1FwDgBkHlNhQmhE7XgfoeHsiYQgpVGzeGDdHGUw,454656
|
33
|
+
fxn/services/__init__.py,sha256=Bif8IttwJ089mSRsd3MFdob7z2eF-MKigKu4ZQFZBCQ,190
|
34
|
+
fxn/services/prediction.py,sha256=QCop-f7ojkGR7DI5tLJe3FPnr0BvPJ_vWhCk4kg8Fqg,10373
|
35
|
+
fxn/services/predictor.py,sha256=Wl_7YKiD5mTpC5x2Zaq4BpatRjwRUX8Th9GIrwd38MA,791
|
36
|
+
fxn/services/user.py,sha256=ADl5MFLsk4K0altgKHnI-i64E3g1wU3e56Noq_ciRuk,685
|
37
|
+
fxn/types/__init__.py,sha256=MEg71rzbGgoWfgB4Yi5QvxbnovHTZRIzCUZLtWtWP1E,292
|
38
|
+
fxn/types/dtype.py,sha256=71Tuu4IydmELcBcSBbmWswhCE-7WqBSQ4VkETsFRzjA,617
|
39
|
+
fxn/types/prediction.py,sha256=BdLTxnKiSFbz5warX8g_Z4DedNxXK3gaNjSKR2FP8tA,2051
|
40
|
+
fxn/types/predictor.py,sha256=KRGZEuDt7WPMCyRcZvQq4y2FMocfVrLEUNJCJgfDY9Y,4000
|
41
|
+
fxn/types/user.py,sha256=Z44TwEocyxSrfKyzcNfmAXUrpX_Ry8fJ7MffSxRn4oU,1071
|
42
|
+
fxn-0.0.44.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
43
|
+
fxn-0.0.44.dist-info/METADATA,sha256=5o1xzi17jmhMTf14XKQHixi_msQz57j7oTx3DtjCQOg,16144
|
44
|
+
fxn-0.0.44.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
45
|
+
fxn-0.0.44.dist-info/entry_points.txt,sha256=O_AwD5dYaeB-YT1F9hPAPuDYCkw_W0tdNGYbc5RVR2k,45
|
46
|
+
fxn-0.0.44.dist-info/top_level.txt,sha256=1ULIEGrnMlhId8nYAkjmRn9g3KEFuHKboq193SEKQkA,4
|
47
|
+
fxn-0.0.44.dist-info/RECORD,,
|
fxn/compile/__init__.py
DELETED
fxn/compile/signature.py
DELETED
@@ -1,183 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Function
|
3
|
-
# Copyright © 2025 NatML Inc. All Rights Reserved.
|
4
|
-
#
|
5
|
-
|
6
|
-
from collections.abc import Mapping, Sequence
|
7
|
-
from enum import Enum
|
8
|
-
from inspect import isasyncgenfunction, iscoroutinefunction, isgeneratorfunction, signature
|
9
|
-
from io import BytesIO
|
10
|
-
import numpy as np
|
11
|
-
from PIL import Image
|
12
|
-
from pydantic import BaseModel, TypeAdapter
|
13
|
-
from typing import get_type_hints, get_origin, get_args, Any, Dict, List, Union
|
14
|
-
|
15
|
-
from ..types import Dtype, EnumerationMember, Parameter, Signature
|
16
|
-
|
17
|
-
class FunctionType (str, Enum):
|
18
|
-
Coroutine = "ASYNC_FUNCTION"
|
19
|
-
Function = "FUNCTION"
|
20
|
-
Generator = "GENERATOR"
|
21
|
-
AsyncGenerator = "ASYNC_GENERATOR"
|
22
|
-
|
23
|
-
def get_function_type (func) -> FunctionType:
|
24
|
-
if isasyncgenfunction(func):
|
25
|
-
return FunctionType.AsyncGenerator
|
26
|
-
elif iscoroutinefunction(func):
|
27
|
-
return FunctionType.Coroutine
|
28
|
-
elif isgeneratorfunction(func):
|
29
|
-
return FunctionType.Generator
|
30
|
-
else:
|
31
|
-
return FunctionType.Function
|
32
|
-
|
33
|
-
def infer_function_signature (func) -> Signature:
|
34
|
-
inputs = _get_input_parameters(func)
|
35
|
-
outputs = _get_output_parameters(func)
|
36
|
-
signature = Signature(inputs=inputs, outputs=outputs)
|
37
|
-
return signature
|
38
|
-
|
39
|
-
def _get_input_parameters (func) -> list[Parameter]:
|
40
|
-
sig = signature(func)
|
41
|
-
type_hints = get_type_hints(func)
|
42
|
-
parameters = []
|
43
|
-
for name, param in sig.parameters.items():
|
44
|
-
param_type = type_hints.get(name)
|
45
|
-
if param_type is None:
|
46
|
-
raise TypeError(f"Missing type annotation for parameter '{name}' in function '{func.__name__}'")
|
47
|
-
dtype = _infer_dtype(param_type)
|
48
|
-
enumeration = [EnumerationMember(
|
49
|
-
name=member.name,
|
50
|
-
value=member.value
|
51
|
-
) for member in param_type] if _is_enum_subclass(param_type) else None
|
52
|
-
value_schema = _get_type_schema(param_type) if dtype in { Dtype.list, Dtype.dict } else None
|
53
|
-
input_param = Parameter(
|
54
|
-
name=name,
|
55
|
-
type=dtype,
|
56
|
-
description=None,
|
57
|
-
optional=param.default != param.empty,
|
58
|
-
range=None,
|
59
|
-
enumeration=enumeration,
|
60
|
-
value_schema=value_schema
|
61
|
-
)
|
62
|
-
parameters.append(input_param)
|
63
|
-
return parameters
|
64
|
-
|
65
|
-
def _get_output_parameters (func) -> list[Parameter]:
|
66
|
-
# Check for return annotation
|
67
|
-
sig = signature(func)
|
68
|
-
if sig.return_annotation is sig.empty:
|
69
|
-
raise TypeError(f"Missing return type annotation for function '{func.__name__}'")
|
70
|
-
# Gather return types
|
71
|
-
return_types = []
|
72
|
-
if _is_tuple_type(sig.return_annotation):
|
73
|
-
return_types = get_args(sig.return_annotation)
|
74
|
-
if not return_types or Ellipsis in return_types:
|
75
|
-
raise TypeError(f"Return type of function '{func.__name__}' must be fully typed with generic type arguments.")
|
76
|
-
else:
|
77
|
-
return_types = [sig.return_annotation]
|
78
|
-
# Create parameters
|
79
|
-
parameters = [_get_output_parameter(f"output{idx}", output_type) for idx, output_type in enumerate(return_types)]
|
80
|
-
return parameters
|
81
|
-
|
82
|
-
def _get_output_parameter (name: str, return_type) -> Parameter:
|
83
|
-
dtype = _infer_dtype(return_type)
|
84
|
-
enumeration = [EnumerationMember(
|
85
|
-
name=member.name,
|
86
|
-
value=member.value
|
87
|
-
) for member in return_type] if _is_enum_subclass(return_type) else None
|
88
|
-
value_schema = _get_type_schema(return_type) if dtype in { Dtype.list, Dtype.dict } else None
|
89
|
-
parameter = Parameter(
|
90
|
-
name=name,
|
91
|
-
type=dtype,
|
92
|
-
description=None,
|
93
|
-
optional=False,
|
94
|
-
range=None,
|
95
|
-
enumeration=enumeration,
|
96
|
-
value_schema=value_schema
|
97
|
-
)
|
98
|
-
return parameter
|
99
|
-
|
100
|
-
def _infer_dtype (param_type) -> Dtype:
|
101
|
-
param_type = _strip_optional(param_type)
|
102
|
-
origin = get_origin(param_type)
|
103
|
-
args = get_args(param_type)
|
104
|
-
if origin is None:
|
105
|
-
if param_type is np.ndarray:
|
106
|
-
return Dtype.float32
|
107
|
-
elif param_type is Image.Image:
|
108
|
-
return Dtype.image
|
109
|
-
elif param_type in { bytes, bytearray, memoryview, BytesIO }:
|
110
|
-
return Dtype.binary
|
111
|
-
elif param_type is int:
|
112
|
-
return Dtype.int32
|
113
|
-
elif param_type is float:
|
114
|
-
return Dtype.float32
|
115
|
-
elif param_type is bool:
|
116
|
-
return Dtype.bool
|
117
|
-
elif param_type is str:
|
118
|
-
return Dtype.string
|
119
|
-
elif _is_enum_subclass(param_type):
|
120
|
-
return Dtype.string
|
121
|
-
elif param_type is list:
|
122
|
-
return Dtype.list
|
123
|
-
elif param_type is dict:
|
124
|
-
return Dtype.dict
|
125
|
-
elif _is_pydantic_model(param_type):
|
126
|
-
return Dtype.dict
|
127
|
-
else:
|
128
|
-
raise TypeError(f"Unsupported parameter type: {param_type}")
|
129
|
-
else:
|
130
|
-
if origin in { list, List, Sequence }:
|
131
|
-
return Dtype.list
|
132
|
-
elif origin in { dict, Dict, Mapping }:
|
133
|
-
return Dtype.dict
|
134
|
-
elif origin is np.ndarray:
|
135
|
-
if args:
|
136
|
-
dtype_arg = args[0]
|
137
|
-
dtype = _numpy_to_fxn_dtype(dtype_arg)
|
138
|
-
if dtype is not None:
|
139
|
-
return dtype
|
140
|
-
return Dtype.float32
|
141
|
-
else:
|
142
|
-
raise TypeError(f"Unsupported parameter type: {param_type}")
|
143
|
-
|
144
|
-
def _is_enum_subclass (cls) -> bool:
|
145
|
-
return isinstance(cls, type) and issubclass(cls, Enum)
|
146
|
-
|
147
|
-
def _is_pydantic_model (cls) -> bool:
|
148
|
-
return isinstance(cls, type) and issubclass(cls, BaseModel)
|
149
|
-
|
150
|
-
def _is_tuple_type (param_type) -> bool:
|
151
|
-
origin = get_origin(param_type)
|
152
|
-
return origin is tuple
|
153
|
-
|
154
|
-
def _strip_optional (param_type):
|
155
|
-
if get_origin(param_type) is Union:
|
156
|
-
args = get_args(param_type)
|
157
|
-
non_none_args = [arg for arg in args if arg is not type(None)]
|
158
|
-
if len(non_none_args) == 1:
|
159
|
-
return non_none_args[0]
|
160
|
-
return param_type
|
161
|
-
|
162
|
-
def _numpy_to_fxn_dtype (dtype) -> Dtype | None:
|
163
|
-
dtype_mapping = {
|
164
|
-
np.int8: Dtype.int8,
|
165
|
-
np.int16: Dtype.int16,
|
166
|
-
np.int32: Dtype.int32,
|
167
|
-
np.int64: Dtype.int64,
|
168
|
-
np.uint8: Dtype.uint8,
|
169
|
-
np.uint16: Dtype.uint16,
|
170
|
-
np.uint32: Dtype.uint32,
|
171
|
-
np.uint64: Dtype.uint64,
|
172
|
-
np.float16: Dtype.float16,
|
173
|
-
np.float32: Dtype.float32,
|
174
|
-
np.float64: Dtype.float64,
|
175
|
-
np.bool_: Dtype.bool,
|
176
|
-
}
|
177
|
-
return dtype_mapping.get(dtype, None)
|
178
|
-
|
179
|
-
def _get_type_schema (param_type) -> dict[str, Any] | None:
|
180
|
-
try:
|
181
|
-
return TypeAdapter(param_type).json_schema(mode="serialization")
|
182
|
-
except Exception:
|
183
|
-
return None
|
fxn-0.0.42.dist-info/RECORD
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
fxn/__init__.py,sha256=co_h8b85Oz3gyrT8T30RbwFQZ8Zf0i57ynGC2H44VZs,207
|
2
|
-
fxn/client.py,sha256=i56oIr4f4ODjKhnD2EugBWQULVubIIFHqqBsoix23xw,1666
|
3
|
-
fxn/function.py,sha256=JBZnGaLedgoY-wV5Tg-Rxwpd3tK_ADkD0Qve45NBaA0,1342
|
4
|
-
fxn/version.py,sha256=-M_EgT0O4ScSm10y5QibgzW8y3KbHfvkosDKMCfirOQ,95
|
5
|
-
fxn/beta/__init__.py,sha256=gKoDhuXtXCjdhUYUqmF0gDPMhJfg3UwFgbvMtRB5ipo,111
|
6
|
-
fxn/beta/client.py,sha256=x1AVAz0PlX0Wnemi7KXk5XfC8R6HC7vOQaGUviPJLN8,363
|
7
|
-
fxn/beta/prediction.py,sha256=9DTBahNF6m0TicLab2o9e8IKpiSV6K7cUSTYaFju0ZU,356
|
8
|
-
fxn/beta/remote.py,sha256=MMFM6QYyxNkpf2czql_JZz9dVbuWHIzhC4mq7pcyPdo,7778
|
9
|
-
fxn/c/__init__.py,sha256=NMIduqO_MYtI9jVCu6ZxvbBtYQXoQyNEWblNy3m2UPY,313
|
10
|
-
fxn/c/configuration.py,sha256=Jq4kWLu3xb1MWjkfNA4xPr_TykABppbHctUEOHBFdRM,4887
|
11
|
-
fxn/c/fxnc.py,sha256=YrvwOlzPmTlSDuz2zmKZfws2WK5BY4YZ62edoplcMJU,1381
|
12
|
-
fxn/c/map.py,sha256=47fBJ0Q6uB_xeW3sn9aCLYJ539edg8ff9DU-EIfWRGA,2352
|
13
|
-
fxn/c/prediction.py,sha256=-d-5yreFAaRS-nDHzhfabRNtgYcmJGiY_N2dt09gk84,2689
|
14
|
-
fxn/c/predictor.py,sha256=48poLj1AthzCgU9n6Wv9gL8o4gFucIlOnBO2wdor6r0,1925
|
15
|
-
fxn/c/stream.py,sha256=Y1Xv1Bt3_qlnWg9rCn7NWESpouF1eKMzDiQjhZWbXTg,1105
|
16
|
-
fxn/c/value.py,sha256=zkmuKb153UUEnenPO560gXFzxJ_ATvs8_HM-j3OLrJU,7362
|
17
|
-
fxn/cli/__init__.py,sha256=OBwaKLyHBqUUqwJD6waGzRRosMwbisLxCPgki0Ye_lU,1126
|
18
|
-
fxn/cli/auth.py,sha256=6iGbNbjxfCr8OZT3_neLThXdWeKRBZATwru8vU0XmRw,1688
|
19
|
-
fxn/cli/misc.py,sha256=LcJbCj_GAgtGraTRva2zHHOPpNwI6SOFntRksxwlqvM,843
|
20
|
-
fxn/cli/predictions.py,sha256=HN7-2BLTgwSn_4LYJQ7Ez9TpTKAZfiEGB62eMF_USaA,3084
|
21
|
-
fxn/cli/predictors.py,sha256=t4DYwGTw_3z0dNDSqLmGmWeksPExGVPHyhHsxmVZk48,447
|
22
|
-
fxn/compile/__init__.py,sha256=BXIcV2Ghp8YkfYZyhHuZjjV3BCLSuaoiTgu9YeFb-w0,130
|
23
|
-
fxn/compile/compile.py,sha256=7PzPEjmHu_mQMoLcRrFOe1TJ11iZMgxcGt4rESqk6fg,3040
|
24
|
-
fxn/compile/sandbox.py,sha256=3ewg1C3lST0KETxkx1qmqMuqcj6YJHBMdCVq4ne-2l8,5425
|
25
|
-
fxn/compile/signature.py,sha256=QiB546g5p_MfiGt8hRi5BZ-_cmGaZm8vuYs47m2W-XM,6436
|
26
|
-
fxn/lib/__init__.py,sha256=-w1ikmmki5NMpzJjERW-O4SwOfBNkimej_0jL8ujYRk,71
|
27
|
-
fxn/lib/linux/arm64/libFunction.so,sha256=NU9PEuQNObqtWPr5vXrWeQuYhzBfmX_Z4guaregFjrI,207632
|
28
|
-
fxn/lib/linux/x86_64/libFunction.so,sha256=qZNlczayaaHIP_tJ9eeZ1TVpV1Os-ztvSWOoBuY9yWE,236272
|
29
|
-
fxn/lib/macos/arm64/Function.dylib,sha256=ODM3zDbI4Tomx7_QSvnqOE42OBYYblntkSq6gftBP4c,263664
|
30
|
-
fxn/lib/macos/x86_64/Function.dylib,sha256=qIu4dhx0Xk5dQHgTnZTcm2IpoMYJwRPmKRi9J-UnkAY,263680
|
31
|
-
fxn/lib/windows/arm64/Function.dll,sha256=FyL-oipK9wSxXdbD9frc8QFbUKTPMCdtmCkCT8ooIIM,419328
|
32
|
-
fxn/lib/windows/x86_64/Function.dll,sha256=iL6w1FwDgBkHlNhQmhE7XgfoeHsiYQgpVGzeGDdHGUw,454656
|
33
|
-
fxn/services/__init__.py,sha256=Bif8IttwJ089mSRsd3MFdob7z2eF-MKigKu4ZQFZBCQ,190
|
34
|
-
fxn/services/prediction.py,sha256=IKudi7n3bm-RAW26dg188ItDgGnJcW4rcN48LD37CEg,10185
|
35
|
-
fxn/services/predictor.py,sha256=Wl_7YKiD5mTpC5x2Zaq4BpatRjwRUX8Th9GIrwd38MA,791
|
36
|
-
fxn/services/user.py,sha256=ADl5MFLsk4K0altgKHnI-i64E3g1wU3e56Noq_ciRuk,685
|
37
|
-
fxn/types/__init__.py,sha256=MEg71rzbGgoWfgB4Yi5QvxbnovHTZRIzCUZLtWtWP1E,292
|
38
|
-
fxn/types/dtype.py,sha256=b0V91aknED2Ql0_BOG_vEg__YJVJByxsgB0cR4rtotE,617
|
39
|
-
fxn/types/prediction.py,sha256=YVnRcqm6IPEx0796OuT3dqn_jOPjhWblzuM2lkk-Vzo,2173
|
40
|
-
fxn/types/predictor.py,sha256=51hhb1rCYFt_r86pbOIVeV_tXYE6BVhcNP27_xmQG1Q,4006
|
41
|
-
fxn/types/user.py,sha256=Z44TwEocyxSrfKyzcNfmAXUrpX_Ry8fJ7MffSxRn4oU,1071
|
42
|
-
fxn-0.0.42.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
43
|
-
fxn-0.0.42.dist-info/METADATA,sha256=RM5c7vePEj9cP3OSysoHclvklaV5-byVneeQnhVSKuU,16122
|
44
|
-
fxn-0.0.42.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
45
|
-
fxn-0.0.42.dist-info/entry_points.txt,sha256=O_AwD5dYaeB-YT1F9hPAPuDYCkw_W0tdNGYbc5RVR2k,45
|
46
|
-
fxn-0.0.42.dist-info/top_level.txt,sha256=1ULIEGrnMlhId8nYAkjmRn9g3KEFuHKboq193SEKQkA,4
|
47
|
-
fxn-0.0.42.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|