fal 0.12.4__py3-none-any.whl → 0.12.6__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 +4 -0
- fal/apps.py +6 -2
- fal/auth/auth0.py +12 -14
- fal/cli.py +68 -34
- fal/console/ux.py +7 -10
- fal/workflows.py +10 -9
- {fal-0.12.4.dist-info → fal-0.12.6.dist-info}/METADATA +6 -2
- {fal-0.12.4.dist-info → fal-0.12.6.dist-info}/RECORD +10 -9
- {fal-0.12.4.dist-info → fal-0.12.6.dist-info}/WHEEL +0 -0
- {fal-0.12.4.dist-info → fal-0.12.6.dist-info}/entry_points.txt +0 -0
fal/__main__.py
ADDED
fal/apps.py
CHANGED
|
@@ -65,8 +65,12 @@ class RequestHandle:
|
|
|
65
65
|
def __post_init__(self):
|
|
66
66
|
app_id = _backwards_compatible_app_id(self.app_id)
|
|
67
67
|
# drop any extra path components
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
parts = app_id.split("/")[:3]
|
|
69
|
+
if parts[0] != "workflows":
|
|
70
|
+
# if the app_id is not a workflow, only keep the first two parts
|
|
71
|
+
parts = parts[:2]
|
|
72
|
+
|
|
73
|
+
self.app_id = "/".join(parts)
|
|
70
74
|
|
|
71
75
|
def status(self, *, logs: bool = False) -> _Status:
|
|
72
76
|
"""Check the status of an async inference request."""
|
fal/auth/auth0.py
CHANGED
|
@@ -9,7 +9,7 @@ import httpx
|
|
|
9
9
|
|
|
10
10
|
from fal.console import console
|
|
11
11
|
from fal.console.icons import CHECK_ICON
|
|
12
|
-
from fal.console.ux import
|
|
12
|
+
from fal.console.ux import maybe_open_browser_tab
|
|
13
13
|
|
|
14
14
|
WEBSITE_URL = "https://fal.ai"
|
|
15
15
|
|
|
@@ -27,19 +27,17 @@ def logout_url(return_url: str):
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
def _open_browser(url: str, code: str | None) -> None:
|
|
30
|
-
|
|
31
|
-
console.print()
|
|
30
|
+
maybe_open_browser_tab(url)
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
)
|
|
32
|
+
console.print(
|
|
33
|
+
"If browser didn't open automatically, on your computer or mobile device navigate to"
|
|
34
|
+
)
|
|
35
|
+
console.print(url)
|
|
36
|
+
|
|
37
|
+
if code:
|
|
38
|
+
console.print(
|
|
39
|
+
f"\nConfirm it shows the following code: [markdown.code]{code}[/]\n"
|
|
40
|
+
)
|
|
43
41
|
|
|
44
42
|
|
|
45
43
|
def login() -> dict:
|
|
@@ -183,7 +181,7 @@ def validate_id_token(token: str):
|
|
|
183
181
|
def verify_access_token_expiration(token: str):
|
|
184
182
|
from jwt import decode
|
|
185
183
|
|
|
186
|
-
leeway =
|
|
184
|
+
leeway = 30 * 60 # 30 minutes
|
|
187
185
|
decode(
|
|
188
186
|
token,
|
|
189
187
|
leeway=-leeway, # negative to consider expired before actual expiration
|
fal/cli.py
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
from dataclasses import dataclass, field
|
|
4
5
|
from http import HTTPStatus
|
|
5
6
|
from sys import argv
|
|
6
|
-
from typing import Literal
|
|
7
|
+
from typing import Any, Callable, Literal
|
|
7
8
|
from uuid import uuid4
|
|
8
9
|
|
|
9
10
|
import click
|
|
10
11
|
import openapi_fal_rest.api.billing.get_user_details as get_user_details
|
|
11
12
|
from rich.table import Table
|
|
13
|
+
from rich_click import RichCommand, RichGroup
|
|
12
14
|
|
|
13
15
|
import fal
|
|
14
16
|
import fal.auth as auth
|
|
@@ -32,16 +34,29 @@ DEBUG_ENABLED = False
|
|
|
32
34
|
logger = get_logger(__name__)
|
|
33
35
|
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
@dataclass
|
|
38
|
+
class State:
|
|
39
|
+
debug: bool = False
|
|
40
|
+
invocation_id: str = field(default_factory=lambda: str(uuid4()))
|
|
38
41
|
|
|
39
|
-
def __init__(self, debug=False):
|
|
40
|
-
self.debug = debug
|
|
41
|
-
self.invocation_id = str(uuid4())
|
|
42
42
|
|
|
43
|
+
def debug_option(*param_decls: str, **kwargs: Any) -> Callable[[click.FC], click.FC]:
|
|
44
|
+
def callback(ctx: click.Context, param: click.Parameter, value: bool) -> None:
|
|
45
|
+
state = ctx.ensure_object(State)
|
|
46
|
+
state.debug = value
|
|
47
|
+
set_debug_logging(value)
|
|
43
48
|
|
|
44
|
-
|
|
49
|
+
if not param_decls:
|
|
50
|
+
param_decls = ("--debug",)
|
|
51
|
+
|
|
52
|
+
kwargs.setdefault("is_flag", True)
|
|
53
|
+
kwargs.setdefault("expose_value", False)
|
|
54
|
+
kwargs.setdefault("callback", callback)
|
|
55
|
+
kwargs.setdefault("help", "Enable detailed errors and verbose logging.")
|
|
56
|
+
return click.option(*param_decls, **kwargs)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class MainGroup(RichGroup):
|
|
45
60
|
"""A custom implementation of the top-level group
|
|
46
61
|
(i.e. called on all commands and subcommands).
|
|
47
62
|
|
|
@@ -54,13 +69,13 @@ class MainGroup(click.Group):
|
|
|
54
69
|
_tracer = get_tracer(__name__)
|
|
55
70
|
|
|
56
71
|
def invoke(self, ctx):
|
|
57
|
-
|
|
72
|
+
from click.exceptions import Abort, ClickException, Exit
|
|
73
|
+
|
|
74
|
+
state = ctx.ensure_object(State)
|
|
58
75
|
qualified_name = " ".join([ctx.info_name] + argv[1:])
|
|
59
|
-
invocation_id = execution_info.invocation_id
|
|
60
|
-
set_debug_logging(execution_info.debug)
|
|
61
76
|
|
|
62
77
|
with self._tracer.start_as_current_span(
|
|
63
|
-
qualified_name, attributes={"invocation_id": invocation_id}
|
|
78
|
+
qualified_name, attributes={"invocation_id": state.invocation_id}
|
|
64
79
|
):
|
|
65
80
|
try:
|
|
66
81
|
logger.debug(
|
|
@@ -68,22 +83,25 @@ class MainGroup(click.Group):
|
|
|
68
83
|
command=qualified_name,
|
|
69
84
|
)
|
|
70
85
|
return super().invoke(ctx)
|
|
86
|
+
except (EOFError, KeyboardInterrupt, ClickException, Exit, Abort):
|
|
87
|
+
# let click's main handle these
|
|
88
|
+
raise
|
|
71
89
|
except Exception as exception:
|
|
72
90
|
logger.error(exception)
|
|
73
|
-
if
|
|
91
|
+
if state.debug:
|
|
74
92
|
# Here we supress detailed errors on click lines because
|
|
75
93
|
# they're mostly decorator calls, irrelevant to the dev's error tracing
|
|
76
94
|
console.print_exception(suppress=[click])
|
|
77
95
|
console.print()
|
|
78
96
|
console.print(
|
|
79
|
-
f"The [markdown.code]invocation_id[/] for this operation is: [white]{invocation_id}[/]"
|
|
97
|
+
f"The [markdown.code]invocation_id[/] for this operation is: [white]{state.invocation_id}[/]"
|
|
80
98
|
)
|
|
81
99
|
else:
|
|
82
100
|
self._exception_handler.handle(exception)
|
|
83
101
|
|
|
84
102
|
def add_command(
|
|
85
103
|
self,
|
|
86
|
-
cmd:
|
|
104
|
+
cmd: RichCommand,
|
|
87
105
|
name: str | None = None,
|
|
88
106
|
aliases: list[str] | None = None,
|
|
89
107
|
) -> None:
|
|
@@ -108,7 +126,7 @@ class MainGroup(click.Group):
|
|
|
108
126
|
self.add_command(alias_cmd, alias)
|
|
109
127
|
|
|
110
128
|
|
|
111
|
-
class AliasCommand(
|
|
129
|
+
class AliasCommand(RichCommand):
|
|
112
130
|
def __init__(self, wrapped):
|
|
113
131
|
self._wrapped = wrapped
|
|
114
132
|
|
|
@@ -123,35 +141,34 @@ class AliasCommand(click.Command):
|
|
|
123
141
|
return self._wrapped.__getattribute__(__name)
|
|
124
142
|
|
|
125
143
|
|
|
126
|
-
@click.group(
|
|
127
|
-
cls=MainGroup,
|
|
128
|
-
context_settings={"allow_interspersed_args": True},
|
|
129
|
-
)
|
|
130
|
-
@click.option(
|
|
131
|
-
"--debug", is_flag=True, help="Enable detailed errors and verbose logging."
|
|
132
|
-
)
|
|
144
|
+
@click.group(cls=MainGroup)
|
|
133
145
|
@click.version_option()
|
|
134
|
-
|
|
146
|
+
@debug_option()
|
|
147
|
+
def cli():
|
|
135
148
|
pass
|
|
136
149
|
|
|
137
150
|
|
|
138
151
|
###### Auth group ######
|
|
139
|
-
@click.group
|
|
152
|
+
@click.group(cls=RichGroup)
|
|
153
|
+
@debug_option()
|
|
140
154
|
def auth_cli():
|
|
141
155
|
pass
|
|
142
156
|
|
|
143
157
|
|
|
144
158
|
@auth_cli.command(name="login")
|
|
159
|
+
@debug_option()
|
|
145
160
|
def auth_login():
|
|
146
161
|
auth.login()
|
|
147
162
|
|
|
148
163
|
|
|
149
164
|
@auth_cli.command(name="logout")
|
|
165
|
+
@debug_option()
|
|
150
166
|
def auth_logout():
|
|
151
167
|
auth.logout()
|
|
152
168
|
|
|
153
169
|
|
|
154
170
|
@auth_cli.command(name="hello", hidden=True)
|
|
171
|
+
@debug_option()
|
|
155
172
|
def auth_test():
|
|
156
173
|
"""
|
|
157
174
|
To test auth.
|
|
@@ -160,9 +177,10 @@ def auth_test():
|
|
|
160
177
|
|
|
161
178
|
|
|
162
179
|
###### Key group ######
|
|
163
|
-
@click.group
|
|
180
|
+
@click.group(cls=RichGroup)
|
|
164
181
|
@click.option("--host", default=DEFAULT_HOST, envvar=HOST_ENVVAR)
|
|
165
182
|
@click.option("--port", default=DEFAULT_PORT, envvar=PORT_ENVVAR, hidden=True)
|
|
183
|
+
@debug_option()
|
|
166
184
|
@click.pass_context
|
|
167
185
|
def key_cli(ctx, host: str, port: str):
|
|
168
186
|
ctx.obj = sdk.FalServerlessClient(f"{host}:{port}")
|
|
@@ -181,6 +199,7 @@ def key_cli(ctx, host: str, port: str):
|
|
|
181
199
|
default=None,
|
|
182
200
|
help="An alias for the key.",
|
|
183
201
|
)
|
|
202
|
+
@debug_option()
|
|
184
203
|
@click.pass_obj
|
|
185
204
|
def key_generate(client: sdk.FalServerlessClient, scope: str, alias: str | None):
|
|
186
205
|
with client.connect() as connection:
|
|
@@ -195,6 +214,7 @@ def key_generate(client: sdk.FalServerlessClient, scope: str, alias: str | None)
|
|
|
195
214
|
|
|
196
215
|
|
|
197
216
|
@key_cli.command(name="list")
|
|
217
|
+
@debug_option()
|
|
198
218
|
@click.pass_obj
|
|
199
219
|
def key_list(client: sdk.FalServerlessClient):
|
|
200
220
|
table = Table(title="Keys")
|
|
@@ -215,6 +235,7 @@ def key_list(client: sdk.FalServerlessClient):
|
|
|
215
235
|
|
|
216
236
|
@key_cli.command(name="revoke")
|
|
217
237
|
@click.argument("key_id", required=True)
|
|
238
|
+
@debug_option()
|
|
218
239
|
@click.pass_obj
|
|
219
240
|
def key_revoke(client: sdk.FalServerlessClient, key_id: str):
|
|
220
241
|
with client.connect() as connection:
|
|
@@ -226,9 +247,10 @@ ALIAS_AUTH_OPTIONS = ["public", "private", "shared"]
|
|
|
226
247
|
ALIAS_AUTH_TYPE = Literal["public", "private", "shared"]
|
|
227
248
|
|
|
228
249
|
|
|
229
|
-
@click.group
|
|
250
|
+
@click.group(cls=RichGroup)
|
|
230
251
|
@click.option("--host", default=DEFAULT_HOST, envvar=HOST_ENVVAR)
|
|
231
252
|
@click.option("--port", default=DEFAULT_PORT, envvar=PORT_ENVVAR, hidden=True)
|
|
253
|
+
@debug_option()
|
|
232
254
|
@click.pass_context
|
|
233
255
|
def function_cli(ctx, host: str, port: str):
|
|
234
256
|
ctx.obj = api.FalServerlessHost(f"{host}:{port}")
|
|
@@ -270,6 +292,7 @@ def load_function_from(
|
|
|
270
292
|
)
|
|
271
293
|
@click.argument("file_path", required=True)
|
|
272
294
|
@click.argument("function_name", required=True)
|
|
295
|
+
@debug_option()
|
|
273
296
|
@click.pass_obj
|
|
274
297
|
def register_application(
|
|
275
298
|
host: api.FalServerlessHost,
|
|
@@ -321,6 +344,7 @@ def register_application(
|
|
|
321
344
|
@function_cli.command("run")
|
|
322
345
|
@click.argument("file_path", required=True)
|
|
323
346
|
@click.argument("function_name", required=True)
|
|
347
|
+
@debug_option()
|
|
324
348
|
@click.pass_obj
|
|
325
349
|
def run(host: api.FalServerlessHost, file_path: str, function_name: str):
|
|
326
350
|
isolated_function = load_function_from(host, file_path, function_name)
|
|
@@ -330,6 +354,7 @@ def run(host: api.FalServerlessHost, file_path: str, function_name: str):
|
|
|
330
354
|
@function_cli.command("logs")
|
|
331
355
|
@click.option("--lines", default=100)
|
|
332
356
|
@click.option("--url", default=None)
|
|
357
|
+
@debug_option()
|
|
333
358
|
@click.pass_obj
|
|
334
359
|
def get_logs(
|
|
335
360
|
host: api.FalServerlessHost, lines: int | None = 100, url: str | None = None
|
|
@@ -340,9 +365,10 @@ def get_logs(
|
|
|
340
365
|
|
|
341
366
|
|
|
342
367
|
##### Alias group #####
|
|
343
|
-
@click.group
|
|
368
|
+
@click.group(cls=RichGroup)
|
|
344
369
|
@click.option("--host", default=DEFAULT_HOST, envvar=HOST_ENVVAR)
|
|
345
370
|
@click.option("--port", default=DEFAULT_PORT, envvar=PORT_ENVVAR, hidden=True)
|
|
371
|
+
@debug_option()
|
|
346
372
|
@click.pass_context
|
|
347
373
|
def alias_cli(ctx, host: str, port: str):
|
|
348
374
|
ctx.obj = api.FalServerlessClient(f"{host}:{port}")
|
|
@@ -383,6 +409,7 @@ def _alias_table(aliases: list[AliasInfo]):
|
|
|
383
409
|
type=click.Choice(ALIAS_AUTH_OPTIONS),
|
|
384
410
|
default="private",
|
|
385
411
|
)
|
|
412
|
+
@debug_option()
|
|
386
413
|
@click.pass_obj
|
|
387
414
|
def alias_set(
|
|
388
415
|
client: api.FalServerlessClient,
|
|
@@ -396,6 +423,7 @@ def alias_set(
|
|
|
396
423
|
|
|
397
424
|
@alias_cli.command("delete")
|
|
398
425
|
@click.argument("alias", required=True)
|
|
426
|
+
@debug_option()
|
|
399
427
|
@click.pass_obj
|
|
400
428
|
def alias_delete(client: api.FalServerlessClient, alias: str):
|
|
401
429
|
with client.connect() as connection:
|
|
@@ -405,6 +433,7 @@ def alias_delete(client: api.FalServerlessClient, alias: str):
|
|
|
405
433
|
|
|
406
434
|
|
|
407
435
|
@alias_cli.command("list")
|
|
436
|
+
@debug_option()
|
|
408
437
|
@click.pass_obj
|
|
409
438
|
def alias_list(client: api.FalServerlessClient):
|
|
410
439
|
with client.connect() as connection:
|
|
@@ -426,6 +455,7 @@ def alias_list(client: api.FalServerlessClient):
|
|
|
426
455
|
# "auth_mode",
|
|
427
456
|
# type=click.Choice(ALIAS_AUTH_OPTIONS),
|
|
428
457
|
# )
|
|
458
|
+
@debug_option()
|
|
429
459
|
@click.pass_obj
|
|
430
460
|
def alias_update(
|
|
431
461
|
client: api.FalServerlessClient,
|
|
@@ -459,6 +489,7 @@ def alias_update(
|
|
|
459
489
|
|
|
460
490
|
@alias_cli.command("runners")
|
|
461
491
|
@click.argument("alias", required=True)
|
|
492
|
+
@debug_option()
|
|
462
493
|
@click.pass_obj
|
|
463
494
|
def alias_list_runners(
|
|
464
495
|
client: api.FalServerlessClient,
|
|
@@ -489,15 +520,17 @@ def alias_list_runners(
|
|
|
489
520
|
|
|
490
521
|
|
|
491
522
|
##### Secrets group #####
|
|
492
|
-
@click.group
|
|
523
|
+
@click.group(cls=RichGroup)
|
|
493
524
|
@click.option("--host", default=DEFAULT_HOST, envvar=HOST_ENVVAR)
|
|
494
525
|
@click.option("--port", default=DEFAULT_PORT, envvar=PORT_ENVVAR, hidden=True)
|
|
526
|
+
@debug_option()
|
|
495
527
|
@click.pass_context
|
|
496
528
|
def secrets_cli(ctx, host: str, port: str):
|
|
497
529
|
ctx.obj = sdk.FalServerlessClient(f"{host}:{port}")
|
|
498
530
|
|
|
499
531
|
|
|
500
532
|
@secrets_cli.command("list")
|
|
533
|
+
@debug_option()
|
|
501
534
|
@click.pass_obj
|
|
502
535
|
def list_secrets(client: api.FalServerlessClient):
|
|
503
536
|
table = Table(title="Secrets")
|
|
@@ -514,6 +547,7 @@ def list_secrets(client: api.FalServerlessClient):
|
|
|
514
547
|
@secrets_cli.command("set")
|
|
515
548
|
@click.argument("secret_name", required=True)
|
|
516
549
|
@click.argument("secret_value", required=True)
|
|
550
|
+
@debug_option()
|
|
517
551
|
@click.pass_obj
|
|
518
552
|
def set_secret(client: api.FalServerlessClient, secret_name: str, secret_value: str):
|
|
519
553
|
with client.connect() as connection:
|
|
@@ -523,6 +557,7 @@ def set_secret(client: api.FalServerlessClient, secret_name: str, secret_value:
|
|
|
523
557
|
|
|
524
558
|
@secrets_cli.command("delete")
|
|
525
559
|
@click.argument("secret_name", required=True)
|
|
560
|
+
@debug_option()
|
|
526
561
|
@click.pass_obj
|
|
527
562
|
def delete_secret(client: api.FalServerlessClient, secret_name: str):
|
|
528
563
|
with client.connect() as connection:
|
|
@@ -574,11 +609,10 @@ def _get_user_id() -> str:
|
|
|
574
609
|
raise api.FalServerlessError(content["detail"])
|
|
575
610
|
try:
|
|
576
611
|
full_user_id = user_details_response.parsed.user_id
|
|
577
|
-
user_id = full_user_id.
|
|
612
|
+
_provider, _, user_id = full_user_id.partition("|")
|
|
613
|
+
if not user_id:
|
|
614
|
+
user_id = full_user_id
|
|
615
|
+
|
|
578
616
|
return user_id
|
|
579
617
|
except Exception as e:
|
|
580
618
|
raise api.FalServerlessError(f"Could not parse the user data: {e}")
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
if __name__ == "__main__":
|
|
584
|
-
cli()
|
fal/console/ux.py
CHANGED
|
@@ -3,15 +3,12 @@ from __future__ import annotations
|
|
|
3
3
|
import webbrowser
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
def
|
|
7
|
-
"""Gets a reference to the default browser, if available.
|
|
8
|
-
|
|
9
|
-
This allows us to decide on a flow before showing the actual browser window.
|
|
10
|
-
It also avoids unwanted output in the console from the standard `webbrowser.open()`.
|
|
11
|
-
|
|
12
|
-
See https://stackoverflow.com/a/19199794
|
|
13
|
-
"""
|
|
6
|
+
def maybe_open_browser_tab(url) -> None:
|
|
14
7
|
try:
|
|
15
|
-
|
|
8
|
+
# Avoids unwanted output in the console from the standard `webbrowser.open()`.
|
|
9
|
+
# See https://stackoverflow.com/a/19199794
|
|
10
|
+
browser = webbrowser.get()
|
|
11
|
+
|
|
12
|
+
browser.open_new_tab(url)
|
|
16
13
|
except webbrowser.Error:
|
|
17
|
-
|
|
14
|
+
pass
|
fal/workflows.py
CHANGED
|
@@ -12,6 +12,7 @@ import rich
|
|
|
12
12
|
from openapi_fal_rest.api.workflows import (
|
|
13
13
|
create_or_update_workflow_workflows_post as publish_workflow,
|
|
14
14
|
)
|
|
15
|
+
from openapi_fal_rest.models.http_validation_error import HTTPValidationError
|
|
15
16
|
from pydantic import BaseModel
|
|
16
17
|
from rich.syntax import Syntax
|
|
17
18
|
|
|
@@ -363,7 +364,7 @@ class Workflow:
|
|
|
363
364
|
|
|
364
365
|
to_dict = to_json
|
|
365
366
|
|
|
366
|
-
def publish(self, title: str, *, is_public: bool = True)
|
|
367
|
+
def publish(self, title: str, *, is_public: bool = True):
|
|
367
368
|
workflow_contents = publish_workflow.TypedWorkflow(
|
|
368
369
|
name=self.name,
|
|
369
370
|
title=title,
|
|
@@ -376,14 +377,14 @@ class Workflow:
|
|
|
376
377
|
)
|
|
377
378
|
if isinstance(published_workflow, Exception):
|
|
378
379
|
raise published_workflow
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
380
|
+
if isinstance(published_workflow, HTTPValidationError):
|
|
381
|
+
raise RuntimeError(published_workflow.detail)
|
|
382
|
+
if not published_workflow:
|
|
383
|
+
raise RuntimeError("Failed to publish the workflow")
|
|
384
|
+
|
|
385
|
+
# NOTE: dropping the provider prefix from the user_id
|
|
386
|
+
user_id_part = published_workflow.user_id.split("|")[-1]
|
|
387
|
+
return f"{user_id_part}/{published_workflow.name}"
|
|
387
388
|
|
|
388
389
|
|
|
389
390
|
def create_workflow(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fal
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.6
|
|
4
4
|
Summary: fal is an easy-to-use Serverless Python Framework
|
|
5
5
|
Author: Features & Labels
|
|
6
6
|
Author-email: hello@fal.ai
|
|
@@ -29,15 +29,19 @@ Requires-Dist: pathspec (>=0.11.1,<0.12.0)
|
|
|
29
29
|
Requires-Dist: pillow (>=10.2.0,<11.0.0)
|
|
30
30
|
Requires-Dist: portalocker (>=2.7.0,<3.0.0)
|
|
31
31
|
Requires-Dist: pydantic (<2.0)
|
|
32
|
-
Requires-Dist: pyjwt (>=2.8.0,<3.0.0)
|
|
32
|
+
Requires-Dist: pyjwt[crypto] (>=2.8.0,<3.0.0)
|
|
33
33
|
Requires-Dist: python-dateutil (>=2.8.0,<3.0.0)
|
|
34
34
|
Requires-Dist: rich (>=13.3.2,<14.0.0)
|
|
35
|
+
Requires-Dist: rich_click
|
|
35
36
|
Requires-Dist: structlog (>=22.3.0,<23.0.0)
|
|
36
37
|
Requires-Dist: types-python-dateutil (>=2.8.0,<3.0.0)
|
|
37
38
|
Requires-Dist: typing-extensions (>=4.7.1,<5.0.0)
|
|
38
39
|
Requires-Dist: websockets (>=12.0,<13.0)
|
|
39
40
|
Description-Content-Type: text/markdown
|
|
40
41
|
|
|
42
|
+
[](https://pypi.org/project/fal)
|
|
43
|
+
[](https://github.com/fal-ai/fal/actions)
|
|
44
|
+
|
|
41
45
|
# fal
|
|
42
46
|
|
|
43
47
|
fal is a serverless Python runtime that lets you run and scale code in the cloud with no infra management.
|
|
@@ -41,17 +41,18 @@ openapi_fal_rest/models/workflow_schema_output.py,sha256=EblwSPAGfWfYVWw_WSSaBzQ
|
|
|
41
41
|
openapi_fal_rest/py.typed,sha256=8ZJUsxZiuOy1oJeVhsTWQhTG_6pTVHVXk5hJL79ebTk,25
|
|
42
42
|
openapi_fal_rest/types.py,sha256=GLwJwOotUOdfqryo_r0naw55-dh6Ilm4IvxePekSACk,994
|
|
43
43
|
fal/__init__.py,sha256=6SvCuotCb0tuqSWDZSFDjtySktJ5m1QpVIlefumJpvM,1199
|
|
44
|
+
fal/__main__.py,sha256=8hDtWlaFZK24KhfNq_ZKgtXqYHsDQDetukOCMlsbW0Q,59
|
|
44
45
|
fal/_serialization.py,sha256=l_dZuSX5BT7SogXw1CalYLfT2H3zy3tfq4y6jHuxZqQ,4201
|
|
45
46
|
fal/api.py,sha256=Qack_oYNkvF4qown3P_oKvyvRfTJkhOG7PL1xpa8FUQ,32872
|
|
46
47
|
fal/app.py,sha256=KAIgvBBpvzp6oY8BpH5hFOLDUpG4bjtwlV5jPGj2IE0,12487
|
|
47
|
-
fal/apps.py,sha256=
|
|
48
|
+
fal/apps.py,sha256=UhR6mq8jBiTAp-QvUnvbnMNcuJ5wHIKSqdlfyx8aBQ8,6829
|
|
48
49
|
fal/auth/__init__.py,sha256=ZnR1fxonzDk0UhS3-i33Kq2xOrN-leYXvJ-Ddnj94xc,3594
|
|
49
|
-
fal/auth/auth0.py,sha256=
|
|
50
|
+
fal/auth/auth0.py,sha256=5y4-9udOSX2-N_zvinLCpFwl10MdaPydZX2v9GQMZEE,5406
|
|
50
51
|
fal/auth/local.py,sha256=lZqp4j32l2xFpY8zYvLoIHHyJrNAJDcm5MxgsLpY_pw,1786
|
|
51
|
-
fal/cli.py,sha256
|
|
52
|
+
fal/cli.py,sha256=bzoN2_oMgSldNQqJH7TCD_uokmH0-gGrdYCciA-EAVk,18338
|
|
52
53
|
fal/console/__init__.py,sha256=ernZ4bzvvliQh5SmrEqQ7lA5eVcbw6Ra2jalKtA7dxg,132
|
|
53
54
|
fal/console/icons.py,sha256=De9MfFaSkO2Lqfne13n3PrYfTXJVIzYZVqYn5BWsdrA,108
|
|
54
|
-
fal/console/ux.py,sha256=
|
|
55
|
+
fal/console/ux.py,sha256=KMQs3UHQvVHDxDQQqlot-WskVKoMQXOE3jiVkkfmIMY,356
|
|
55
56
|
fal/env.py,sha256=-fA8x62BbOX3MOuO0maupa-_QJ9PNwr8ogfeG11QUyQ,53
|
|
56
57
|
fal/exceptions/__init__.py,sha256=Q4LCSqIrJ8GFQZWH5BvWL5mDPR0HwYQuIhNvsdiOkEU,938
|
|
57
58
|
fal/exceptions/_base.py,sha256=LeQmx-soL_-s1742WKN18VwTVjUuYP0L0BdQHPJBpM4,460
|
|
@@ -81,8 +82,8 @@ fal/toolkit/mainify.py,sha256=E7gE45nZQZoaJdSlIq0mqajcH-IjcuPBWFmKm5hvhAU,406
|
|
|
81
82
|
fal/toolkit/optimize.py,sha256=OIhX0T-efRMgUJDpvL0bujdun5SovZgTdKxNOv01b_Y,1394
|
|
82
83
|
fal/toolkit/utils/__init__.py,sha256=b3zVpm50Upx1saXU7RiV9r9in6-Chs4OU9KRjBv7MYI,83
|
|
83
84
|
fal/toolkit/utils/download_utils.py,sha256=bigcLJjLK1OBAGxpYisJ0-5vcQCh0HAPuCykPrcCNd0,15596
|
|
84
|
-
fal/workflows.py,sha256=
|
|
85
|
-
fal-0.12.
|
|
86
|
-
fal-0.12.
|
|
87
|
-
fal-0.12.
|
|
88
|
-
fal-0.12.
|
|
85
|
+
fal/workflows.py,sha256=hkyDk5KQCDcjyUbo_IhQePGP8t4nxzZ7Uw6rVbLtdq4,14448
|
|
86
|
+
fal-0.12.6.dist-info/entry_points.txt,sha256=nE9GBVV3PdBosudFwbIzZQUe_9lfPR6EH8K_FdDASnM,62
|
|
87
|
+
fal-0.12.6.dist-info/METADATA,sha256=qbt8-SaiKeEfaFR1BqOnIt5Kau6by-Q5NU3kViGwez8,3212
|
|
88
|
+
fal-0.12.6.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
|
|
89
|
+
fal-0.12.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|