fal 1.3.0__py3-none-any.whl → 1.3.1__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.
Potentially problematic release.
This version of fal might be problematic. Click here for more details.
- fal/__main__.py +3 -1
- fal/_fal_version.py +2 -2
- fal/app.py +9 -1
- fal/cli/deploy.py +14 -9
- fal/cli/run.py +2 -1
- fal/exceptions/_base.py +10 -9
- fal/toolkit/file/file.py +21 -4
- fal/toolkit/file/providers/fal.py +176 -0
- fal/toolkit/file/types.py +18 -0
- fal/utils.py +13 -2
- {fal-1.3.0.dist-info → fal-1.3.1.dist-info}/METADATA +1 -1
- {fal-1.3.0.dist-info → fal-1.3.1.dist-info}/RECORD +15 -15
- {fal-1.3.0.dist-info → fal-1.3.1.dist-info}/WHEEL +1 -1
- {fal-1.3.0.dist-info → fal-1.3.1.dist-info}/entry_points.txt +0 -0
- {fal-1.3.0.dist-info → fal-1.3.1.dist-info}/top_level.txt +0 -0
fal/__main__.py
CHANGED
fal/_fal_version.py
CHANGED
fal/app.py
CHANGED
|
@@ -143,7 +143,7 @@ class AppClient:
|
|
|
143
143
|
with httpx.Client() as client:
|
|
144
144
|
retries = 100
|
|
145
145
|
for _ in range(retries):
|
|
146
|
-
resp = client.get(info.url + "/health")
|
|
146
|
+
resp = client.get(info.url + "/health", timeout=60)
|
|
147
147
|
|
|
148
148
|
if resp.is_success:
|
|
149
149
|
break
|
|
@@ -205,6 +205,14 @@ class App(fal.api.BaseServable):
|
|
|
205
205
|
"Running apps through SDK is not implemented yet."
|
|
206
206
|
)
|
|
207
207
|
|
|
208
|
+
@classmethod
|
|
209
|
+
def get_endpoints(cls) -> list[str]:
|
|
210
|
+
return [
|
|
211
|
+
signature.path
|
|
212
|
+
for _, endpoint in inspect.getmembers(cls, inspect.isfunction)
|
|
213
|
+
if (signature := getattr(endpoint, "route_signature", None))
|
|
214
|
+
]
|
|
215
|
+
|
|
208
216
|
def collect_routes(self) -> dict[RouteSignature, Callable[..., Any]]:
|
|
209
217
|
return {
|
|
210
218
|
signature: endpoint
|
fal/cli/deploy.py
CHANGED
|
@@ -81,13 +81,14 @@ def _deploy(args):
|
|
|
81
81
|
|
|
82
82
|
user = _get_user()
|
|
83
83
|
host = FalServerlessHost(args.host)
|
|
84
|
-
|
|
84
|
+
loaded = load_function_from(
|
|
85
85
|
host,
|
|
86
86
|
file_path,
|
|
87
87
|
func_name,
|
|
88
88
|
)
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
isolated_function = loaded.function
|
|
90
|
+
app_name = args.app_name or loaded.app_name
|
|
91
|
+
app_auth = args.auth or loaded.app_auth or "private"
|
|
91
92
|
app_id = host.register(
|
|
92
93
|
func=isolated_function.func,
|
|
93
94
|
options=isolated_function.options,
|
|
@@ -106,12 +107,16 @@ def _deploy(args):
|
|
|
106
107
|
"Registered a new revision for function "
|
|
107
108
|
f"'{app_name}' (revision='{app_id}')."
|
|
108
109
|
)
|
|
109
|
-
args.console.print(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
)
|
|
110
|
+
args.console.print("Playground:")
|
|
111
|
+
for endpoint in loaded.endpoints:
|
|
112
|
+
args.console.print(
|
|
113
|
+
f"\thttps://fal.ai/models/{user.username}/{app_name}{endpoint}"
|
|
114
|
+
)
|
|
115
|
+
args.console.print("Endpoints:")
|
|
116
|
+
for endpoint in loaded.endpoints:
|
|
117
|
+
args.console.print(
|
|
118
|
+
f"\thttps://{gateway_host}/{user.username}/{app_name}{endpoint}"
|
|
119
|
+
)
|
|
115
120
|
|
|
116
121
|
|
|
117
122
|
def add_parser(main_subparsers, parents):
|
fal/cli/run.py
CHANGED
|
@@ -6,7 +6,8 @@ def _run(args):
|
|
|
6
6
|
from fal.utils import load_function_from
|
|
7
7
|
|
|
8
8
|
host = FalServerlessHost(args.host)
|
|
9
|
-
|
|
9
|
+
loaded = load_function_from(host, *args.func_ref)
|
|
10
|
+
isolated_function = loaded.function
|
|
10
11
|
# let our exc handlers handle UserFunctionException
|
|
11
12
|
isolated_function.reraise = False
|
|
12
13
|
isolated_function()
|
fal/exceptions/_base.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Sequence
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
class FalServerlessException(Exception):
|
|
@@ -40,11 +39,13 @@ class FieldException(FalServerlessException):
|
|
|
40
39
|
status_code: int = 422
|
|
41
40
|
type: str = "value_error"
|
|
42
41
|
|
|
43
|
-
def to_pydantic_format(self) ->
|
|
44
|
-
return
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
42
|
+
def to_pydantic_format(self) -> dict[str, list[dict]]:
|
|
43
|
+
return dict(
|
|
44
|
+
detail=[
|
|
45
|
+
{
|
|
46
|
+
"loc": ["body", self.field],
|
|
47
|
+
"msg": self.message,
|
|
48
|
+
"type": self.type,
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
)
|
fal/toolkit/file/file.py
CHANGED
|
@@ -149,14 +149,31 @@ class File(BaseModel):
|
|
|
149
149
|
path: str | Path,
|
|
150
150
|
content_type: Optional[str] = None,
|
|
151
151
|
repository: FileRepository | RepositoryId = DEFAULT_REPOSITORY,
|
|
152
|
+
multipart: bool | None = None,
|
|
152
153
|
) -> File:
|
|
153
154
|
file_path = Path(path)
|
|
154
155
|
if not file_path.exists():
|
|
155
156
|
raise FileNotFoundError(f"File {file_path} does not exist")
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
|
|
158
|
+
repo = (
|
|
159
|
+
repository
|
|
160
|
+
if isinstance(repository, FileRepository)
|
|
161
|
+
else get_builtin_repository(repository)
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
content_type = content_type or "application/octet-stream"
|
|
165
|
+
|
|
166
|
+
url, data = repo.save_file(
|
|
167
|
+
file_path,
|
|
168
|
+
content_type=content_type,
|
|
169
|
+
multipart=multipart,
|
|
170
|
+
)
|
|
171
|
+
return cls(
|
|
172
|
+
url=url,
|
|
173
|
+
file_data=data.data if data else None,
|
|
174
|
+
content_type=content_type,
|
|
175
|
+
file_name=file_path.name,
|
|
176
|
+
file_size=file_path.stat().st_size,
|
|
160
177
|
)
|
|
161
178
|
|
|
162
179
|
def as_bytes(self) -> bytes:
|
|
@@ -2,9 +2,11 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
4
|
import json
|
|
5
|
+
import math
|
|
5
6
|
import os
|
|
6
7
|
from base64 import b64encode
|
|
7
8
|
from dataclasses import dataclass
|
|
9
|
+
from pathlib import Path
|
|
8
10
|
from urllib.error import HTTPError
|
|
9
11
|
from urllib.request import Request, urlopen
|
|
10
12
|
|
|
@@ -87,11 +89,185 @@ class FalFileRepository(FalFileRepositoryBase):
|
|
|
87
89
|
return self._save(file, "gcs")
|
|
88
90
|
|
|
89
91
|
|
|
92
|
+
class MultipartUpload:
|
|
93
|
+
MULTIPART_THRESHOLD = 100 * 1024 * 1024
|
|
94
|
+
MULTIPART_CHUNK_SIZE = 100 * 1024 * 1024
|
|
95
|
+
MULTIPART_MAX_CONCURRENCY = 10
|
|
96
|
+
|
|
97
|
+
def __init__(
|
|
98
|
+
self,
|
|
99
|
+
file_path: str | Path,
|
|
100
|
+
chunk_size: int | None = None,
|
|
101
|
+
content_type: str | None = None,
|
|
102
|
+
max_concurrency: int | None = None,
|
|
103
|
+
) -> None:
|
|
104
|
+
self.file_path = file_path
|
|
105
|
+
self.chunk_size = chunk_size or self.MULTIPART_CHUNK_SIZE
|
|
106
|
+
self.content_type = content_type or "application/octet-stream"
|
|
107
|
+
self.max_concurrency = max_concurrency or self.MULTIPART_MAX_CONCURRENCY
|
|
108
|
+
|
|
109
|
+
self._parts: list[dict] = []
|
|
110
|
+
|
|
111
|
+
key_creds = key_credentials()
|
|
112
|
+
if not key_creds:
|
|
113
|
+
raise FileUploadException("FAL_KEY must be set")
|
|
114
|
+
|
|
115
|
+
key_id, key_secret = key_creds
|
|
116
|
+
|
|
117
|
+
self._auth_headers = {
|
|
118
|
+
"Authorization": f"Key {key_id}:{key_secret}",
|
|
119
|
+
}
|
|
120
|
+
grpc_host = os.environ.get("FAL_HOST", "api.alpha.fal.ai")
|
|
121
|
+
rest_host = grpc_host.replace("api", "rest", 1)
|
|
122
|
+
self._storage_upload_url = f"https://{rest_host}/storage/upload"
|
|
123
|
+
|
|
124
|
+
def create(self):
|
|
125
|
+
try:
|
|
126
|
+
req = Request(
|
|
127
|
+
f"{self._storage_upload_url}/initiate-multipart",
|
|
128
|
+
method="POST",
|
|
129
|
+
headers={
|
|
130
|
+
**self._auth_headers,
|
|
131
|
+
"Accept": "application/json",
|
|
132
|
+
"Content-Type": "application/json",
|
|
133
|
+
},
|
|
134
|
+
data=json.dumps(
|
|
135
|
+
{
|
|
136
|
+
"file_name": os.path.basename(self.file_path),
|
|
137
|
+
"content_type": self.content_type,
|
|
138
|
+
}
|
|
139
|
+
).encode(),
|
|
140
|
+
)
|
|
141
|
+
with urlopen(req) as response:
|
|
142
|
+
result = json.load(response)
|
|
143
|
+
self._upload_id = result["upload_id"]
|
|
144
|
+
self._file_url = result["file_url"]
|
|
145
|
+
except HTTPError as exc:
|
|
146
|
+
raise FileUploadException(
|
|
147
|
+
f"Error initiating upload. Status {exc.status}: {exc.reason}"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
def _upload_part(self, url: str, part_number: int) -> dict:
|
|
151
|
+
with open(self.file_path, "rb") as f:
|
|
152
|
+
start = (part_number - 1) * self.chunk_size
|
|
153
|
+
f.seek(start)
|
|
154
|
+
data = f.read(self.chunk_size)
|
|
155
|
+
req = Request(
|
|
156
|
+
url,
|
|
157
|
+
method="PUT",
|
|
158
|
+
headers={"Content-Type": self.content_type},
|
|
159
|
+
data=data,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
try:
|
|
163
|
+
with urlopen(req) as resp:
|
|
164
|
+
return {
|
|
165
|
+
"part_number": part_number,
|
|
166
|
+
"etag": resp.headers["ETag"],
|
|
167
|
+
}
|
|
168
|
+
except HTTPError as exc:
|
|
169
|
+
raise FileUploadException(
|
|
170
|
+
f"Error uploading part {part_number} to {url}. "
|
|
171
|
+
f"Status {exc.status}: {exc.reason}"
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
def upload(self) -> None:
|
|
175
|
+
import concurrent.futures
|
|
176
|
+
|
|
177
|
+
parts = math.ceil(os.path.getsize(self.file_path) / self.chunk_size)
|
|
178
|
+
with concurrent.futures.ThreadPoolExecutor(
|
|
179
|
+
max_workers=self.max_concurrency
|
|
180
|
+
) as executor:
|
|
181
|
+
futures = []
|
|
182
|
+
for part_number in range(1, parts + 1):
|
|
183
|
+
upload_url = (
|
|
184
|
+
f"{self._file_url}?upload_id={self._upload_id}"
|
|
185
|
+
f"&part_number={part_number}"
|
|
186
|
+
)
|
|
187
|
+
futures.append(
|
|
188
|
+
executor.submit(self._upload_part, upload_url, part_number)
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
for future in concurrent.futures.as_completed(futures):
|
|
192
|
+
entry = future.result()
|
|
193
|
+
self._parts.append(entry)
|
|
194
|
+
|
|
195
|
+
def complete(self):
|
|
196
|
+
url = f"{self._file_url}?upload_id={self._upload_id}"
|
|
197
|
+
try:
|
|
198
|
+
req = Request(
|
|
199
|
+
url,
|
|
200
|
+
method="POST",
|
|
201
|
+
headers={
|
|
202
|
+
"Accept": "application/json",
|
|
203
|
+
"Content-Type": "application/json",
|
|
204
|
+
},
|
|
205
|
+
data=json.dumps({"parts": self._parts}).encode(),
|
|
206
|
+
)
|
|
207
|
+
with urlopen(req):
|
|
208
|
+
pass
|
|
209
|
+
except HTTPError as e:
|
|
210
|
+
raise FileUploadException(
|
|
211
|
+
f"Error completing upload {url}. Status {e.status}: {e.reason}"
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
return self._file_url
|
|
215
|
+
|
|
216
|
+
|
|
90
217
|
@dataclass
|
|
91
218
|
class FalFileRepositoryV2(FalFileRepositoryBase):
|
|
92
219
|
def save(self, file: FileData) -> str:
|
|
93
220
|
return self._save(file, "fal-cdn")
|
|
94
221
|
|
|
222
|
+
def _save_multipart(
|
|
223
|
+
self,
|
|
224
|
+
file_path: str | Path,
|
|
225
|
+
chunk_size: int | None = None,
|
|
226
|
+
content_type: str | None = None,
|
|
227
|
+
max_concurrency: int | None = None,
|
|
228
|
+
) -> str:
|
|
229
|
+
multipart = MultipartUpload(
|
|
230
|
+
file_path,
|
|
231
|
+
chunk_size=chunk_size,
|
|
232
|
+
content_type=content_type,
|
|
233
|
+
max_concurrency=max_concurrency,
|
|
234
|
+
)
|
|
235
|
+
multipart.create()
|
|
236
|
+
multipart.upload()
|
|
237
|
+
return multipart.complete()
|
|
238
|
+
|
|
239
|
+
def save_file(
|
|
240
|
+
self,
|
|
241
|
+
file_path: str | Path,
|
|
242
|
+
content_type: str,
|
|
243
|
+
multipart: bool | None = None,
|
|
244
|
+
multipart_threshold: int | None = None,
|
|
245
|
+
multipart_chunk_size: int | None = None,
|
|
246
|
+
multipart_max_concurrency: int | None = None,
|
|
247
|
+
) -> tuple[str, FileData | None]:
|
|
248
|
+
if multipart is None:
|
|
249
|
+
threshold = multipart_threshold or MultipartUpload.MULTIPART_THRESHOLD
|
|
250
|
+
multipart = os.path.getsize(file_path) > threshold
|
|
251
|
+
|
|
252
|
+
if multipart:
|
|
253
|
+
url = self._save_multipart(
|
|
254
|
+
file_path,
|
|
255
|
+
chunk_size=multipart_chunk_size,
|
|
256
|
+
content_type=content_type,
|
|
257
|
+
max_concurrency=multipart_max_concurrency,
|
|
258
|
+
)
|
|
259
|
+
data = None
|
|
260
|
+
else:
|
|
261
|
+
with open(file_path, "rb") as f:
|
|
262
|
+
data = FileData(
|
|
263
|
+
f.read(),
|
|
264
|
+
content_type=content_type,
|
|
265
|
+
file_name=os.path.basename(file_path),
|
|
266
|
+
)
|
|
267
|
+
url = self.save(data)
|
|
268
|
+
|
|
269
|
+
return url, data
|
|
270
|
+
|
|
95
271
|
|
|
96
272
|
@dataclass
|
|
97
273
|
class InMemoryRepository(FileRepository):
|
fal/toolkit/file/types.py
CHANGED
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from mimetypes import guess_extension, guess_type
|
|
5
|
+
from pathlib import Path
|
|
5
6
|
from typing import Literal
|
|
6
7
|
from uuid import uuid4
|
|
7
8
|
|
|
@@ -35,3 +36,20 @@ RepositoryId = Literal["fal", "fal_v2", "in_memory", "gcp_storage", "r2", "cdn"]
|
|
|
35
36
|
class FileRepository:
|
|
36
37
|
def save(self, data: FileData) -> str:
|
|
37
38
|
raise NotImplementedError()
|
|
39
|
+
|
|
40
|
+
def save_file(
|
|
41
|
+
self,
|
|
42
|
+
file_path: str | Path,
|
|
43
|
+
content_type: str,
|
|
44
|
+
multipart: bool | None = None,
|
|
45
|
+
multipart_threshold: int | None = None,
|
|
46
|
+
multipart_chunk_size: int | None = None,
|
|
47
|
+
multipart_max_concurrency: int | None = None,
|
|
48
|
+
) -> tuple[str, FileData | None]:
|
|
49
|
+
if multipart:
|
|
50
|
+
raise NotImplementedError()
|
|
51
|
+
|
|
52
|
+
with open(file_path, "rb") as fobj:
|
|
53
|
+
data = FileData(fobj.read(), content_type, Path(file_path).name)
|
|
54
|
+
|
|
55
|
+
return self.save(data), data
|
fal/utils.py
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
3
5
|
import fal._serialization
|
|
4
6
|
from fal import App, wrap_app
|
|
5
7
|
|
|
6
8
|
from .api import FalServerlessError, FalServerlessHost, IsolatedFunction
|
|
7
9
|
|
|
8
10
|
|
|
11
|
+
@dataclass
|
|
12
|
+
class LoadedFunction:
|
|
13
|
+
function: IsolatedFunction
|
|
14
|
+
endpoints: list[str]
|
|
15
|
+
app_name: str | None
|
|
16
|
+
app_auth: str | None
|
|
17
|
+
|
|
18
|
+
|
|
9
19
|
def load_function_from(
|
|
10
20
|
host: FalServerlessHost,
|
|
11
21
|
file_path: str,
|
|
12
22
|
function_name: str | None = None,
|
|
13
|
-
) ->
|
|
23
|
+
) -> LoadedFunction:
|
|
14
24
|
import runpy
|
|
15
25
|
|
|
16
26
|
module = runpy.run_path(file_path)
|
|
@@ -45,6 +55,7 @@ def load_function_from(
|
|
|
45
55
|
fal._serialization.include_package_from_path(file_path)
|
|
46
56
|
|
|
47
57
|
target = module[function_name]
|
|
58
|
+
endpoints = target.get_endpoints() or ["/"]
|
|
48
59
|
if isinstance(target, type) and issubclass(target, App):
|
|
49
60
|
app_name = target.app_name
|
|
50
61
|
app_auth = target.app_auth
|
|
@@ -54,4 +65,4 @@ def load_function_from(
|
|
|
54
65
|
raise FalServerlessError(
|
|
55
66
|
f"Function '{function_name}' is not a fal.function or a fal.App"
|
|
56
67
|
)
|
|
57
|
-
return target, app_name, app_auth
|
|
68
|
+
return LoadedFunction(target, endpoints, app_name=app_name, app_auth=app_auth)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
fal/__init__.py,sha256=wXs1G0gSc7ZK60-bHe-B2m0l_sA6TrFk4BxY0tMoLe8,784
|
|
2
|
-
fal/__main__.py,sha256=
|
|
3
|
-
fal/_fal_version.py,sha256=
|
|
2
|
+
fal/__main__.py,sha256=4JMK66Wj4uLZTKbF-sT3LAxOsr6buig77PmOkJCRRxw,83
|
|
3
|
+
fal/_fal_version.py,sha256=cOVPCvD2h2G_2KB6G3ddreYkIQfAnS6WqgAkF_qgGOQ,411
|
|
4
4
|
fal/_serialization.py,sha256=rD2YiSa8iuzCaZohZwN_MPEB-PpSKbWRDeaIDpTEjyY,7653
|
|
5
5
|
fal/_version.py,sha256=EBGqrknaf1WygENX-H4fBefLvHryvJBBGtVJetaB0NY,266
|
|
6
6
|
fal/api.py,sha256=bOCxmOQSbdcR6h6VLPEuvsD4i0j_Mod6E2UNP07cAQo,41893
|
|
7
|
-
fal/app.py,sha256=
|
|
7
|
+
fal/app.py,sha256=Cw0opdt7V6W6XXoo1QVufPiGITysh7QTngeQ0grL6V4,17073
|
|
8
8
|
fal/apps.py,sha256=FrKmaAUo8U9vE_fcva0GQvk4sCrzaTEr62lGtu3Ld5M,6825
|
|
9
9
|
fal/container.py,sha256=V7riyyq8AZGwEX9QaqRQDZyDN_bUKeRKV1OOZArXjL0,622
|
|
10
10
|
fal/flags.py,sha256=oWN_eidSUOcE9wdPK_77si3A1fpgOC0UEERPsvNLIMc,842
|
|
@@ -12,7 +12,7 @@ fal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
12
12
|
fal/rest_client.py,sha256=kGBGmuyHfX1lR910EoKCYPjsyU8MdXawT_cW2q8Sajc,568
|
|
13
13
|
fal/sdk.py,sha256=wA58DYnSK1vdsBi8Or9Z8kvMMEyBNfeZYk_xulSfTWE,20078
|
|
14
14
|
fal/sync.py,sha256=ZuIJA2-hTPNANG9B_NNJZUsO68EIdTH0dc9MzeVE2VU,4340
|
|
15
|
-
fal/utils.py,sha256=
|
|
15
|
+
fal/utils.py,sha256=WfS-Cx7GQFtzpZEdJYTOeglEGT_omMIrDiQ_l0PghGE,2120
|
|
16
16
|
fal/workflows.py,sha256=jx3tGy2R7cN6lLvOzT6lhhlcjmiq64iZls2smVrmQj0,14657
|
|
17
17
|
fal/auth/__init__.py,sha256=r8iA2-5ih7-Fik3gEC4HEWNFbGoxpYnXpZu1icPIoS0,3561
|
|
18
18
|
fal/auth/auth0.py,sha256=rSG1mgH-QGyKfzd7XyAaj1AYsWt-ho8Y_LZ-FUVWzh4,5421
|
|
@@ -22,18 +22,18 @@ fal/cli/apps.py,sha256=-DDp-Gvxz5kHho5YjAhbri8vOny_9cftAI_wP2KR5nU,8175
|
|
|
22
22
|
fal/cli/auth.py,sha256=--MhfHGwxmtHbRkGioyn1prKn_U-pBzbz0G_QeZou-U,1352
|
|
23
23
|
fal/cli/create.py,sha256=a8WDq-nJLFTeoIXqpb5cr7GR7YR9ZZrQCawNm34KXXE,627
|
|
24
24
|
fal/cli/debug.py,sha256=u_urnyFzSlNnrq93zz_GXE9FX4VyVxDoamJJyrZpFI0,1312
|
|
25
|
-
fal/cli/deploy.py,sha256=
|
|
25
|
+
fal/cli/deploy.py,sha256=asSa8UpX7BzepcvmH_Heitwwpv-5xKromZkpjfi-hwI,5033
|
|
26
26
|
fal/cli/doctor.py,sha256=U4ne9LX5gQwNblsYQ27XdO8AYDgbYjTO39EtxhwexRM,983
|
|
27
27
|
fal/cli/keys.py,sha256=trDpA3LJu9S27qE_K8Hr6fKLK4vwVzbxUHq8TFrV4pw,3157
|
|
28
28
|
fal/cli/main.py,sha256=_Wh_DQc02qwh-ZN7v41lZm0lDR1WseViXVOcqUlyWLg,2009
|
|
29
29
|
fal/cli/parser.py,sha256=r1hd5e8Jq6yzDZw8-S0On1EjJbjRtHMuVuHC6MlvUj4,2835
|
|
30
|
-
fal/cli/run.py,sha256=
|
|
30
|
+
fal/cli/run.py,sha256=YOD1PBzqFTpjeL55SpIe5SuBCnYTOzD_wvBBuPIhqSY,896
|
|
31
31
|
fal/cli/secrets.py,sha256=740msFm7d41HruudlcfqUXlFl53N-WmChsQP9B9M9Po,2572
|
|
32
32
|
fal/console/__init__.py,sha256=ernZ4bzvvliQh5SmrEqQ7lA5eVcbw6Ra2jalKtA7dxg,132
|
|
33
33
|
fal/console/icons.py,sha256=De9MfFaSkO2Lqfne13n3PrYfTXJVIzYZVqYn5BWsdrA,108
|
|
34
34
|
fal/console/ux.py,sha256=KMQs3UHQvVHDxDQQqlot-WskVKoMQXOE3jiVkkfmIMY,356
|
|
35
35
|
fal/exceptions/__init__.py,sha256=5b2rFnvLf2Q4fPGedcYN_JVLv-j6iOy5DNG7jB6FNUk,180
|
|
36
|
-
fal/exceptions/_base.py,sha256=
|
|
36
|
+
fal/exceptions/_base.py,sha256=Kuq9UeGrWAa0RHsnkl5STD2GUbCxWz9dsL0TEqvpNdc,1294
|
|
37
37
|
fal/exceptions/_cuda.py,sha256=q5EPFYEb7Iyw03cHrQlRHnH5xOvjwTwQdM6a9N3GB8k,1494
|
|
38
38
|
fal/exceptions/auth.py,sha256=gxRago5coI__vSIcdcsqhhq1lRPkvCnwPAueIaXTAdw,329
|
|
39
39
|
fal/logging/__init__.py,sha256=snqprf7-sKw6oAATS_Yxklf-a3XhLg0vIHICPwLp6TM,1583
|
|
@@ -45,9 +45,9 @@ fal/toolkit/__init__.py,sha256=sV95wiUzKoiDqF9vDgq4q-BLa2sD6IpuKSqp5kdTQNE,658
|
|
|
45
45
|
fal/toolkit/exceptions.py,sha256=elHZ7dHCJG5zlHGSBbz-ilkZe9QUvQMomJFi8Pt91LA,198
|
|
46
46
|
fal/toolkit/optimize.py,sha256=p75sovF0SmRP6zxzpIaaOmqlxvXB_xEz3XPNf59EF7w,1339
|
|
47
47
|
fal/toolkit/file/__init__.py,sha256=FbNl6wD-P0aSSTUwzHt4HujBXrbC3ABmaigPQA4hRfg,70
|
|
48
|
-
fal/toolkit/file/file.py,sha256=
|
|
49
|
-
fal/toolkit/file/types.py,sha256=
|
|
50
|
-
fal/toolkit/file/providers/fal.py,sha256=
|
|
48
|
+
fal/toolkit/file/file.py,sha256=qk_hj7U3cfvuWO-qF_eC_R8lzzVhudfnt1erWEa8eDQ,6578
|
|
49
|
+
fal/toolkit/file/types.py,sha256=GymH0CJesJvsZ6wph7GqTGTuNjzvyMgLxQmBBxoKzS0,1627
|
|
50
|
+
fal/toolkit/file/providers/fal.py,sha256=ClCWM4GI11hOjEIVv2IJZj2SdzBNO8iS1r1WaXFcF6I,10090
|
|
51
51
|
fal/toolkit/file/providers/gcp.py,sha256=pUVH2qNcnO_VrDQQU8MmfYOQZMGaKQIqE4yGnYdQhAc,2003
|
|
52
52
|
fal/toolkit/file/providers/r2.py,sha256=WxmOHF5WxHt6tKMcFjWj7ZWO8a1EXysO9lfYv_tB3MI,2627
|
|
53
53
|
fal/toolkit/image/__init__.py,sha256=aLcU8HzD7HyOxx-C-Bbx9kYCMHdBhy9tR98FSVJ6gSA,1830
|
|
@@ -123,8 +123,8 @@ openapi_fal_rest/models/workflow_node_type.py,sha256=-FzyeY2bxcNmizKbJI8joG7byRi
|
|
|
123
123
|
openapi_fal_rest/models/workflow_schema.py,sha256=4K5gsv9u9pxx2ItkffoyHeNjBBYf6ur5bN4m_zePZNY,2019
|
|
124
124
|
openapi_fal_rest/models/workflow_schema_input.py,sha256=2OkOXWHTNsCXHWS6EGDFzcJKkW5FIap-2gfO233EvZQ,1191
|
|
125
125
|
openapi_fal_rest/models/workflow_schema_output.py,sha256=EblwSPAGfWfYVWw_WSSaBzQVju296is9o28rMBAd0mc,1196
|
|
126
|
-
fal-1.3.
|
|
127
|
-
fal-1.3.
|
|
128
|
-
fal-1.3.
|
|
129
|
-
fal-1.3.
|
|
130
|
-
fal-1.3.
|
|
126
|
+
fal-1.3.1.dist-info/METADATA,sha256=Xy6_mCqUDjtkFtJRGtxQSEsHMNt7srJgvoorONf4LYs,3766
|
|
127
|
+
fal-1.3.1.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
|
|
128
|
+
fal-1.3.1.dist-info/entry_points.txt,sha256=32zwTUC1U1E7nSTIGCoANQOQ3I7-qHG5wI6gsVz5pNU,37
|
|
129
|
+
fal-1.3.1.dist-info/top_level.txt,sha256=r257X1L57oJL8_lM0tRrfGuXFwm66i1huwQygbpLmHw,21
|
|
130
|
+
fal-1.3.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|