fxn 0.0.41__py3-none-any.whl → 0.0.43__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 +4 -1
- fxn/beta/__init__.py +6 -0
- fxn/beta/client.py +16 -0
- fxn/beta/prediction.py +16 -0
- fxn/beta/remote.py +207 -0
- fxn/c/__init__.py +1 -1
- fxn/c/configuration.py +1 -1
- fxn/c/fxnc.py +1 -1
- fxn/c/map.py +1 -1
- fxn/c/prediction.py +2 -2
- fxn/c/predictor.py +2 -3
- fxn/c/stream.py +2 -3
- fxn/c/value.py +1 -1
- fxn/cli/__init__.py +10 -10
- fxn/cli/auth.py +1 -1
- fxn/cli/compile.py +141 -0
- fxn/cli/misc.py +1 -1
- fxn/cli/predictions.py +17 -14
- fxn/cli/predictors.py +31 -48
- fxn/client.py +85 -12
- fxn/compile.py +76 -0
- fxn/function.py +6 -2
- fxn/lib/__init__.py +1 -1
- fxn/lib/linux/arm64/libFunction.so +0 -0
- fxn/lib/linux/x86_64/libFunction.so +0 -0
- fxn/lib/macos/arm64/Function.dylib +0 -0
- fxn/lib/macos/x86_64/Function.dylib +0 -0
- fxn/lib/windows/arm64/Function.dll +0 -0
- fxn/lib/windows/x86_64/Function.dll +0 -0
- fxn/logging.py +137 -0
- fxn/sandbox.py +206 -0
- fxn/services/__init__.py +1 -1
- fxn/services/prediction.py +32 -32
- fxn/services/predictor.py +6 -3
- fxn/services/user.py +6 -3
- fxn/types/__init__.py +3 -3
- fxn/types/dtype.py +1 -1
- fxn/types/prediction.py +12 -2
- fxn/types/predictor.py +3 -14
- fxn/types/user.py +1 -1
- fxn/version.py +2 -2
- {fxn-0.0.41.dist-info → fxn-0.0.43.dist-info}/METADATA +3 -3
- fxn-0.0.43.dist-info/RECORD +47 -0
- {fxn-0.0.41.dist-info → fxn-0.0.43.dist-info}/WHEEL +1 -1
- fxn/cli/env.py +0 -40
- fxn-0.0.41.dist-info/RECORD +0 -40
- {fxn-0.0.41.dist-info → fxn-0.0.43.dist-info}/LICENSE +0 -0
- {fxn-0.0.41.dist-info → fxn-0.0.43.dist-info}/entry_points.txt +0 -0
- {fxn-0.0.41.dist-info → fxn-0.0.43.dist-info}/top_level.txt +0 -0
fxn/sandbox.py
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
#
|
2
|
+
# Function
|
3
|
+
# Copyright © 2025 NatML Inc. All Rights Reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
from __future__ import annotations
|
7
|
+
from abc import ABC, abstractmethod
|
8
|
+
from hashlib import sha256
|
9
|
+
from pathlib import Path
|
10
|
+
from pydantic import BaseModel
|
11
|
+
from requests import put
|
12
|
+
from rich.progress import BarColumn, TextColumn
|
13
|
+
from typing import Literal
|
14
|
+
|
15
|
+
from .function import Function
|
16
|
+
from .logging import CustomProgressTask
|
17
|
+
|
18
|
+
class WorkdirCommand (BaseModel):
|
19
|
+
kind: Literal["workdir"] = "workdir"
|
20
|
+
path: str
|
21
|
+
|
22
|
+
class EnvCommand (BaseModel):
|
23
|
+
kind: Literal["env"] = "env"
|
24
|
+
env: dict[str, str]
|
25
|
+
|
26
|
+
class UploadableCommand (BaseModel, ABC):
|
27
|
+
from_path: str
|
28
|
+
to_path: str
|
29
|
+
manifest: dict[str, str] | None = None
|
30
|
+
|
31
|
+
@abstractmethod
|
32
|
+
def get_files (self) -> list[Path]:
|
33
|
+
pass
|
34
|
+
|
35
|
+
class UploadFileCommand (UploadableCommand):
|
36
|
+
kind: Literal["upload_file"] = "upload_file"
|
37
|
+
|
38
|
+
def get_files (self) -> list[Path]:
|
39
|
+
return [Path(self.from_path).resolve()]
|
40
|
+
|
41
|
+
class UploadDirectoryCommand (UploadableCommand):
|
42
|
+
kind: Literal["upload_dir"] = "upload_dir"
|
43
|
+
|
44
|
+
def get_files (self) -> list[Path]:
|
45
|
+
from_path = Path(self.from_path)
|
46
|
+
assert from_path.is_absolute(), "Cannot upload directory because directory path must be absolute"
|
47
|
+
return [file for file in from_path.rglob("*") if file.is_file()]
|
48
|
+
|
49
|
+
class EntrypointCommand (UploadableCommand):
|
50
|
+
kind: Literal["entrypoint"] = "entrypoint"
|
51
|
+
name: str
|
52
|
+
|
53
|
+
def get_files (self) -> list[Path]:
|
54
|
+
return [Path(self.from_path).resolve()]
|
55
|
+
|
56
|
+
class PipInstallCommand (BaseModel):
|
57
|
+
kind: Literal["pip_install"] = "pip_install"
|
58
|
+
packages: list[str]
|
59
|
+
|
60
|
+
class AptInstallCommand (BaseModel):
|
61
|
+
kind: Literal["apt_install"] = "apt_install"
|
62
|
+
packages: list[str]
|
63
|
+
|
64
|
+
Command = (
|
65
|
+
WorkdirCommand |
|
66
|
+
EnvCommand |
|
67
|
+
UploadFileCommand |
|
68
|
+
UploadDirectoryCommand |
|
69
|
+
PipInstallCommand |
|
70
|
+
AptInstallCommand |
|
71
|
+
EntrypointCommand
|
72
|
+
)
|
73
|
+
|
74
|
+
class Sandbox (BaseModel):
|
75
|
+
"""
|
76
|
+
Sandbox which defines a containerized environment for compiling your Python function.
|
77
|
+
"""
|
78
|
+
commands: list[Command] = []
|
79
|
+
|
80
|
+
def workdir (self, path: str | Path) -> Sandbox:
|
81
|
+
"""
|
82
|
+
Change the current working directory for subsequent commands.
|
83
|
+
|
84
|
+
Parameters:
|
85
|
+
path (str | Path): Path to change to.
|
86
|
+
"""
|
87
|
+
command = WorkdirCommand(path=str(path))
|
88
|
+
return Sandbox(commands=self.commands + [command])
|
89
|
+
|
90
|
+
def env (self, **env: str) -> Sandbox:
|
91
|
+
"""
|
92
|
+
Set environment variables in the sandbox.
|
93
|
+
"""
|
94
|
+
command = EnvCommand(env=env)
|
95
|
+
return Sandbox(commands=self.commands + [command])
|
96
|
+
|
97
|
+
def upload_file (
|
98
|
+
self,
|
99
|
+
from_path: str | Path,
|
100
|
+
to_path: str | Path = "./"
|
101
|
+
) -> Sandbox:
|
102
|
+
"""
|
103
|
+
Upload a file to the sandbox.
|
104
|
+
|
105
|
+
Parameters:
|
106
|
+
from_path (str | Path): File path on the local file system.
|
107
|
+
to_path (str | Path): Remote path to upload file to.
|
108
|
+
"""
|
109
|
+
command = UploadFileCommand(from_path=str(from_path), to_path=str(to_path))
|
110
|
+
return Sandbox(commands=self.commands + [command])
|
111
|
+
|
112
|
+
def upload_directory (
|
113
|
+
self,
|
114
|
+
from_path: str | Path,
|
115
|
+
to_path: str | Path = "."
|
116
|
+
) -> Sandbox:
|
117
|
+
"""
|
118
|
+
Upload a directory to the sandbox.
|
119
|
+
|
120
|
+
Parameters:
|
121
|
+
from_path (str | Path): Directory path on the local file system.
|
122
|
+
to_path (str | Path): Remote path to upload directory to.
|
123
|
+
"""
|
124
|
+
command = UploadDirectoryCommand(from_path=str(from_path), to_path=str(to_path))
|
125
|
+
return Sandbox(commands=self.commands + [command])
|
126
|
+
|
127
|
+
def pip_install (self, *packages: str) -> Sandbox:
|
128
|
+
"""
|
129
|
+
Install Python packages in the sandbox.
|
130
|
+
|
131
|
+
Parameters:
|
132
|
+
packages (list): Packages to install.
|
133
|
+
"""
|
134
|
+
command = PipInstallCommand(packages=packages)
|
135
|
+
return Sandbox(commands=self.commands + [command])
|
136
|
+
|
137
|
+
def apt_install (self, *packages: str) -> Sandbox:
|
138
|
+
"""
|
139
|
+
Install Debian packages in the sandbox.
|
140
|
+
|
141
|
+
Parameters:
|
142
|
+
packages (list): Packages to install.
|
143
|
+
"""
|
144
|
+
command = AptInstallCommand(packages=packages)
|
145
|
+
return Sandbox(commands=self.commands + [command])
|
146
|
+
|
147
|
+
def populate (self, fxn: Function=None) -> Sandbox: # CHECK # In place
|
148
|
+
"""
|
149
|
+
Populate all metadata.
|
150
|
+
"""
|
151
|
+
fxn = fxn if fxn is not None else Function()
|
152
|
+
entrypoint = next(cmd for cmd in self.commands if isinstance(cmd, EntrypointCommand))
|
153
|
+
entry_path = Path(entrypoint.from_path).resolve()
|
154
|
+
for command in self.commands:
|
155
|
+
if isinstance(command, UploadableCommand):
|
156
|
+
cwd = Path.cwd()
|
157
|
+
from_path = Path(command.from_path)
|
158
|
+
to_path = Path(command.to_path)
|
159
|
+
if not from_path.is_absolute():
|
160
|
+
from_path = (entry_path / from_path).resolve()
|
161
|
+
command.from_path = str(from_path)
|
162
|
+
files = command.get_files()
|
163
|
+
name = from_path.relative_to(cwd) if from_path.is_relative_to(cwd) else from_path.resolve()
|
164
|
+
with CustomProgressTask(
|
165
|
+
loading_text=f"Uploading [light_slate_blue]{name}[/light_slate_blue]...",
|
166
|
+
done_text=f"Uploaded [light_slate_blue]{name}[/light_slate_blue]",
|
167
|
+
columns=[
|
168
|
+
BarColumn(),
|
169
|
+
TextColumn("{task.completed}/{task.total}")
|
170
|
+
]
|
171
|
+
) as task:
|
172
|
+
manifest = { }
|
173
|
+
for idx, file in enumerate(files):
|
174
|
+
rel_file_path = file.relative_to(from_path) if from_path.is_dir() else file.name
|
175
|
+
dst_path = to_path / rel_file_path
|
176
|
+
checksum = self.__upload_file(file, fxn=fxn)
|
177
|
+
manifest[str(dst_path)] = checksum
|
178
|
+
task.update(total=len(files), completed=idx+1)
|
179
|
+
command.manifest = manifest
|
180
|
+
return self
|
181
|
+
|
182
|
+
def __upload_file (self, path: Path, fxn: Function) -> str:
|
183
|
+
assert path.is_file(), "Cannot upload file at path {path} because it is not a file"
|
184
|
+
hash = self.__compute_hash(path)
|
185
|
+
try:
|
186
|
+
fxn.client.request(method="HEAD", path=f"/resources/{hash}")
|
187
|
+
except:
|
188
|
+
resource = fxn.client.request(
|
189
|
+
method="POST",
|
190
|
+
path="/resources",
|
191
|
+
body={ "name": hash },
|
192
|
+
response_type=_Resource
|
193
|
+
)
|
194
|
+
with path.open("rb") as f:
|
195
|
+
put(resource.url, data=f).raise_for_status()
|
196
|
+
return hash
|
197
|
+
|
198
|
+
def __compute_hash (self, path: Path) -> str:
|
199
|
+
hash = sha256()
|
200
|
+
with path.open("rb") as f:
|
201
|
+
for chunk in iter(lambda: f.read(4096), b""):
|
202
|
+
hash.update(chunk)
|
203
|
+
return hash.hexdigest()
|
204
|
+
|
205
|
+
class _Resource (BaseModel):
|
206
|
+
url: str
|
fxn/services/__init__.py
CHANGED
fxn/services/prediction.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Function
|
3
|
-
# Copyright ©
|
3
|
+
# Copyright © 2025 NatML Inc. All Rights Reserved.
|
4
4
|
#
|
5
5
|
|
6
6
|
from dataclasses import asdict, is_dataclass
|
@@ -11,13 +11,14 @@ 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
|
14
|
+
from rich.progress import BarColumn, DownloadColumn, TransferSpeedColumn, TimeRemainingColumn
|
15
|
+
from tempfile import gettempdir, NamedTemporaryFile
|
16
16
|
from typing import Any, AsyncIterator
|
17
17
|
from urllib.parse import urlparse
|
18
18
|
|
19
|
-
from ..client import FunctionClient
|
20
19
|
from ..c import Configuration, Predictor, Prediction as CPrediction, Value as CValue, ValueFlags, ValueMap
|
20
|
+
from ..client import FunctionClient
|
21
|
+
from ..logging import CustomProgressTask
|
21
22
|
from ..types import Acceleration, Prediction, PredictionResource
|
22
23
|
|
23
24
|
Value = ndarray | str | float | int | bool | list[Any] | dict[str, Any] | Image.Image | BytesIO | memoryview
|
@@ -50,8 +51,7 @@ class PredictionService:
|
|
50
51
|
acceleration: Acceleration=Acceleration.Auto,
|
51
52
|
device=None,
|
52
53
|
client_id: str=None,
|
53
|
-
configuration_id: str=None
|
54
|
-
verbose: bool=False
|
54
|
+
configuration_id: str=None
|
55
55
|
) -> Prediction:
|
56
56
|
"""
|
57
57
|
Create a prediction.
|
@@ -62,7 +62,6 @@ class PredictionService:
|
|
62
62
|
acceleration (Acceleration): Prediction acceleration.
|
63
63
|
client_id (str): Function client identifier. Specify this to override the current client identifier.
|
64
64
|
configuration_id (str): Configuration identifier. Specify this to override the current client configuration identifier.
|
65
|
-
verbose (bool): Enable verbose logging.
|
66
65
|
|
67
66
|
Returns:
|
68
67
|
Prediction: Created prediction.
|
@@ -78,8 +77,7 @@ class PredictionService:
|
|
78
77
|
acceleration=acceleration,
|
79
78
|
device=device,
|
80
79
|
client_id=client_id,
|
81
|
-
configuration_id=configuration_id
|
82
|
-
verbose=verbose
|
80
|
+
configuration_id=configuration_id
|
83
81
|
)
|
84
82
|
with (
|
85
83
|
self.__to_value_map(inputs) as input_map,
|
@@ -134,9 +132,10 @@ class PredictionService:
|
|
134
132
|
"tag": tag,
|
135
133
|
"clientId": client_id,
|
136
134
|
"configurationId": configuration_id,
|
137
|
-
}
|
135
|
+
},
|
136
|
+
response_type=Prediction
|
138
137
|
)
|
139
|
-
return
|
138
|
+
return prediction
|
140
139
|
|
141
140
|
def __get_predictor (
|
142
141
|
self,
|
@@ -144,8 +143,7 @@ class PredictionService:
|
|
144
143
|
acceleration: Acceleration=Acceleration.Auto,
|
145
144
|
device=None,
|
146
145
|
client_id: str=None,
|
147
|
-
configuration_id: str=None
|
148
|
-
verbose: bool=False
|
146
|
+
configuration_id: str=None
|
149
147
|
) -> Predictor:
|
150
148
|
if tag in self.__cache:
|
151
149
|
return self.__cache[tag]
|
@@ -154,20 +152,13 @@ class PredictionService:
|
|
154
152
|
client_id=client_id,
|
155
153
|
configuration_id=configuration_id
|
156
154
|
)
|
157
|
-
with Configuration() as configuration
|
158
|
-
TextColumn("[bold blue]{task.fields[filename]}"),
|
159
|
-
BarColumn(),
|
160
|
-
DownloadColumn(),
|
161
|
-
TransferSpeedColumn(),
|
162
|
-
TimeRemainingColumn(),
|
163
|
-
disable=not verbose
|
164
|
-
) as progress:
|
155
|
+
with Configuration() as configuration:
|
165
156
|
configuration.tag = prediction.tag
|
166
157
|
configuration.token = prediction.configuration
|
167
158
|
configuration.acceleration = acceleration
|
168
159
|
configuration.device = device
|
169
160
|
for resource in prediction.resources:
|
170
|
-
path = self.__download_resource(resource
|
161
|
+
path = self.__download_resource(resource)
|
171
162
|
configuration.add_resource(resource.type, path)
|
172
163
|
predictor = Predictor(configuration)
|
173
164
|
self.__cache[tag] = predictor
|
@@ -226,12 +217,7 @@ class PredictionService:
|
|
226
217
|
)
|
227
218
|
return prediction
|
228
219
|
|
229
|
-
def __download_resource (
|
230
|
-
self,
|
231
|
-
resource: PredictionResource,
|
232
|
-
*,
|
233
|
-
progress: Progress
|
234
|
-
) -> Path:
|
220
|
+
def __download_resource (self, resource: PredictionResource) -> Path:
|
235
221
|
path = self.__get_resource_path(resource)
|
236
222
|
if path.exists():
|
237
223
|
return path
|
@@ -240,12 +226,26 @@ class PredictionService:
|
|
240
226
|
response.raise_for_status()
|
241
227
|
size = int(response.headers.get("content-length", 0))
|
242
228
|
stem = Path(urlparse(resource.url).path).name
|
243
|
-
|
244
|
-
|
229
|
+
completed = 0
|
230
|
+
color = "dark_orange" if not resource.type == "dso" else "purple"
|
231
|
+
with (
|
232
|
+
CustomProgressTask(
|
233
|
+
loading_text=f"[{color}]{stem}[/{color}]",
|
234
|
+
columns=[
|
235
|
+
BarColumn(),
|
236
|
+
DownloadColumn(),
|
237
|
+
TransferSpeedColumn(),
|
238
|
+
TimeRemainingColumn()
|
239
|
+
]
|
240
|
+
) as task,
|
241
|
+
NamedTemporaryFile(mode="wb", delete=False) as tmp_file
|
242
|
+
):
|
245
243
|
for chunk in response.iter_content(chunk_size=8192):
|
246
244
|
if chunk:
|
247
|
-
|
248
|
-
|
245
|
+
tmp_file.write(chunk)
|
246
|
+
completed += len(chunk)
|
247
|
+
task.update(total=size, completed=completed)
|
248
|
+
Path(tmp_file.name).replace(path)
|
249
249
|
return path
|
250
250
|
|
251
251
|
def __get_resource_path (self, resource: PredictionResource) -> Path:
|
fxn/services/predictor.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Function
|
3
|
-
# Copyright ©
|
3
|
+
# Copyright © 2025 NatML Inc. All Rights Reserved.
|
4
4
|
#
|
5
5
|
|
6
6
|
from ..client import FunctionClient, FunctionAPIError
|
@@ -22,8 +22,11 @@ class PredictorService:
|
|
22
22
|
Predictor: Predictor.
|
23
23
|
"""
|
24
24
|
try:
|
25
|
-
|
26
|
-
|
25
|
+
return self.client.request(
|
26
|
+
method="GET",
|
27
|
+
path=f"/predictors/{tag}",
|
28
|
+
response_type=Predictor
|
29
|
+
)
|
27
30
|
except FunctionAPIError as error:
|
28
31
|
if error.status_code == 404:
|
29
32
|
return None
|
fxn/services/user.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Function
|
3
|
-
# Copyright ©
|
3
|
+
# Copyright © 2025 NatML Inc. All Rights Reserved.
|
4
4
|
#
|
5
5
|
|
6
6
|
from ..client import FunctionClient, FunctionAPIError
|
@@ -19,8 +19,11 @@ class UserService:
|
|
19
19
|
User: User.
|
20
20
|
"""
|
21
21
|
try:
|
22
|
-
|
23
|
-
|
22
|
+
return self.client.request(
|
23
|
+
method="GET",
|
24
|
+
path="/users",
|
25
|
+
response_type=User
|
26
|
+
)
|
24
27
|
except FunctionAPIError as error:
|
25
28
|
if error.status_code == 401:
|
26
29
|
return None
|
fxn/types/__init__.py
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
#
|
2
2
|
# Function
|
3
|
-
# Copyright ©
|
3
|
+
# Copyright © 2025 NatML Inc. All Rights Reserved.
|
4
4
|
#
|
5
5
|
|
6
6
|
from .dtype import Dtype
|
7
|
-
from .prediction import Prediction, PredictionResource
|
8
|
-
from .predictor import
|
7
|
+
from .prediction import Acceleration, Prediction, PredictionResource
|
8
|
+
from .predictor import AccessMode, EnumerationMember, Parameter, Predictor, PredictorStatus, Signature
|
9
9
|
from .user import User
|
fxn/types/dtype.py
CHANGED
fxn/types/prediction.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
#
|
2
2
|
# Function
|
3
|
-
# Copyright ©
|
3
|
+
# Copyright © 2025 NatML Inc. All Rights Reserved.
|
4
4
|
#
|
5
5
|
|
6
|
+
from enum import IntFlag
|
6
7
|
from pydantic import BaseModel, Field
|
7
8
|
from typing import Any
|
8
9
|
|
@@ -42,4 +43,13 @@ class Prediction (BaseModel):
|
|
42
43
|
latency: float | None = Field(default=None, description="Prediction latency in milliseconds.")
|
43
44
|
error: str | None = Field(default=None, description="Prediction error. This is `None` if the prediction completed successfully.")
|
44
45
|
logs: str | None = Field(default=None, description="Prediction logs.")
|
45
|
-
created: str = Field(description="Date created.")
|
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
|
fxn/types/predictor.py
CHANGED
@@ -1,24 +1,15 @@
|
|
1
1
|
#
|
2
2
|
# Function
|
3
|
-
# Copyright ©
|
3
|
+
# Copyright © 2025 NatML Inc. All Rights Reserved.
|
4
4
|
#
|
5
5
|
|
6
|
-
from enum import Enum
|
6
|
+
from enum import Enum
|
7
7
|
from pydantic import AliasChoices, BaseModel, ConfigDict, Field
|
8
8
|
from typing import Any
|
9
9
|
|
10
10
|
from .dtype import Dtype
|
11
11
|
from .user import User
|
12
12
|
|
13
|
-
class Acceleration (IntFlag):
|
14
|
-
"""
|
15
|
-
Predictor acceleration.
|
16
|
-
"""
|
17
|
-
Auto = 0,
|
18
|
-
CPU = 1 << 0,
|
19
|
-
GPU = 1 << 1,
|
20
|
-
NPU = 1 << 2
|
21
|
-
|
22
13
|
class AccessMode (str, Enum):
|
23
14
|
"""
|
24
15
|
Predictor access mode.
|
@@ -30,7 +21,7 @@ class PredictorStatus (str, Enum):
|
|
30
21
|
"""
|
31
22
|
Predictor status.
|
32
23
|
"""
|
33
|
-
|
24
|
+
Compiling = "COMPILING"
|
34
25
|
Active = "ACTIVE"
|
35
26
|
Invalid = "INVALID"
|
36
27
|
Archived = "ARCHIVED"
|
@@ -57,7 +48,6 @@ class Parameter (BaseModel):
|
|
57
48
|
optional (bool): Whether the parameter is optional.
|
58
49
|
range (tuple): Parameter value range for numeric parameters.
|
59
50
|
enumeration (list): Parameter value choices for enumeration parameters.
|
60
|
-
default_value (str | float | int | bool | ndarray | list | dict | PIL.Image | BytesIO): Parameter default value.
|
61
51
|
value_schema (dict): Parameter JSON schema. This is only populated for `list` and `dict` parameters.
|
62
52
|
"""
|
63
53
|
name: str = Field(description="Parameter name.")
|
@@ -66,7 +56,6 @@ class Parameter (BaseModel):
|
|
66
56
|
optional: bool | None = Field(default=None, description="Whether the parameter is optional.")
|
67
57
|
range: tuple[float, float] | None = Field(default=None, description="Parameter value range for numeric parameters.")
|
68
58
|
enumeration: list[EnumerationMember] | None = Field(default=None, description="Parameter value choices for enumeration parameters.")
|
69
|
-
default_value: str | float | int | bool | list[Any] | dict[str, Any] | None = Field(default=None, description="Parameter default value.", serialization_alias="defaultValue", validation_alias=AliasChoices("default_value", "defaultValue"))
|
70
59
|
value_schema: dict[str, Any] | None = Field(default=None, description="Parameter JSON schema. This is only populated for `list` and `dict` parameters.", serialization_alias="schema", validation_alias=AliasChoices("schema", "value_schema"))
|
71
60
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
72
61
|
|
fxn/types/user.py
CHANGED
fxn/version.py
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: fxn
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.43
|
4
4
|
Summary: Run prediction functions locally in Python. Register at https://fxn.ai.
|
5
5
|
Author-email: "NatML Inc." <hi@fxn.ai>
|
6
|
-
License:
|
6
|
+
License: Apache License
|
7
7
|
Version 2.0, January 2004
|
8
8
|
http://www.apache.org/licenses/
|
9
9
|
|
@@ -0,0 +1,47 @@
|
|
1
|
+
fxn/__init__.py,sha256=62Jg67pac85KHx1pd0ipJqTZmdd8bOrzCHw7qrSThVw,242
|
2
|
+
fxn/client.py,sha256=Deje8eiS1VOHX85tQnV34viv2CPVx2ljwHSbyVB5Z1o,3790
|
3
|
+
fxn/compile.py,sha256=v5ZiXZoBmurdbPPIIPyh6uLA3dgDRQK2epKmP31VNjk,2800
|
4
|
+
fxn/function.py,sha256=JBZnGaLedgoY-wV5Tg-Rxwpd3tK_ADkD0Qve45NBaA0,1342
|
5
|
+
fxn/logging.py,sha256=sDEoRiCoVOWwHaoTep5820dS5IAVt0YRL9UI58lyAx0,4728
|
6
|
+
fxn/sandbox.py,sha256=w2dnHMBaKOERxFMpeAP11X6_SPqcvnpd6SmX6b_FOYQ,7000
|
7
|
+
fxn/version.py,sha256=2DgGAdo8M0eRSYqVhukqPY23jLiNk1bQDMfLzUqoxmg,95
|
8
|
+
fxn/beta/__init__.py,sha256=gKoDhuXtXCjdhUYUqmF0gDPMhJfg3UwFgbvMtRB5ipo,111
|
9
|
+
fxn/beta/client.py,sha256=x1AVAz0PlX0Wnemi7KXk5XfC8R6HC7vOQaGUviPJLN8,363
|
10
|
+
fxn/beta/prediction.py,sha256=9DTBahNF6m0TicLab2o9e8IKpiSV6K7cUSTYaFju0ZU,356
|
11
|
+
fxn/beta/remote.py,sha256=MMFM6QYyxNkpf2czql_JZz9dVbuWHIzhC4mq7pcyPdo,7778
|
12
|
+
fxn/c/__init__.py,sha256=NMIduqO_MYtI9jVCu6ZxvbBtYQXoQyNEWblNy3m2UPY,313
|
13
|
+
fxn/c/configuration.py,sha256=Jq4kWLu3xb1MWjkfNA4xPr_TykABppbHctUEOHBFdRM,4887
|
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=zkmuKb153UUEnenPO560gXFzxJ_ATvs8_HM-j3OLrJU,7362
|
20
|
+
fxn/cli/__init__.py,sha256=6HY2vwoR6W6bT3tXYyeVlp1Ap4F_8BdS0APomiwTG98,1303
|
21
|
+
fxn/cli/auth.py,sha256=6iGbNbjxfCr8OZT3_neLThXdWeKRBZATwru8vU0XmRw,1688
|
22
|
+
fxn/cli/compile.py,sha256=g8u2J58fKL9pyDkMUQe7sX4FMg27npISe0k5tG6GeEY,5307
|
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=zWk1Y35m1a0849xVammTaxrkOfSucB2qEhG-r9cUgTQ,10243
|
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=KRGZEuDt7WPMCyRcZvQq4y2FMocfVrLEUNJCJgfDY9Y,4000
|
41
|
+
fxn/types/user.py,sha256=Z44TwEocyxSrfKyzcNfmAXUrpX_Ry8fJ7MffSxRn4oU,1071
|
42
|
+
fxn-0.0.43.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
43
|
+
fxn-0.0.43.dist-info/METADATA,sha256=u2o6KhRYg6lkAeKgHVBnT1-x9pp-0uUK5xtma4CI8rg,16122
|
44
|
+
fxn-0.0.43.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
45
|
+
fxn-0.0.43.dist-info/entry_points.txt,sha256=O_AwD5dYaeB-YT1F9hPAPuDYCkw_W0tdNGYbc5RVR2k,45
|
46
|
+
fxn-0.0.43.dist-info/top_level.txt,sha256=1ULIEGrnMlhId8nYAkjmRn9g3KEFuHKboq193SEKQkA,4
|
47
|
+
fxn-0.0.43.dist-info/RECORD,,
|
fxn/cli/env.py
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Function
|
3
|
-
# Copyright © 2024 NatML Inc. All Rights Reserved.
|
4
|
-
#
|
5
|
-
|
6
|
-
from rich import print_json
|
7
|
-
from typer import Argument, Option, Typer
|
8
|
-
|
9
|
-
from ..function import Function
|
10
|
-
from .auth import get_access_key
|
11
|
-
|
12
|
-
app = Typer(no_args_is_help=True)
|
13
|
-
|
14
|
-
@app.command(name="list", help="List environment variables.")
|
15
|
-
def list_envs (
|
16
|
-
organization: str=Option(None, help="Organization username. Use this for organization environment variables."),
|
17
|
-
):
|
18
|
-
fxn = Function(get_access_key())
|
19
|
-
environments = fxn.environment_variables.list(organization=organization)
|
20
|
-
environments = [env.model_dump() for env in environments]
|
21
|
-
print_json(data=environments)
|
22
|
-
|
23
|
-
@app.command(name="create", help="Create an environment variable.")
|
24
|
-
def create_env (
|
25
|
-
name: str=Argument(..., help="Variable name."),
|
26
|
-
value: str=Argument(..., help="Variable value."),
|
27
|
-
organization: str=Option(None, help="Organization username. Use this for organization environment variables."),
|
28
|
-
):
|
29
|
-
fxn = Function(get_access_key())
|
30
|
-
environment = fxn.environment_variables.create(name=name, value=value, organization=organization)
|
31
|
-
print_json(data=environment.model_dump())
|
32
|
-
|
33
|
-
@app.command(name="delete", help="Delete an environment variable.")
|
34
|
-
def delete_env (
|
35
|
-
name: str=Argument(..., help="Variable name."),
|
36
|
-
organization: str=Option(None, help="Organization username. Use this for organization environment variables."),
|
37
|
-
):
|
38
|
-
fxn = Function(get_access_key())
|
39
|
-
result = fxn.environment_variables.delete(name=name, organization=organization)
|
40
|
-
print_json(data=result)
|