fal 0.14.0__py3-none-any.whl → 0.15.2__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/__init__.py +1 -13
- fal/_serialization.py +151 -121
- fal/api.py +106 -61
- fal/app.py +25 -9
- fal/auth/__init__.py +2 -3
- fal/auth/auth0.py +4 -2
- fal/auth/local.py +2 -1
- fal/cli.py +10 -7
- fal/exceptions/__init__.py +3 -3
- fal/exceptions/_base.py +1 -12
- fal/exceptions/auth.py +2 -4
- fal/exceptions/handlers.py +8 -19
- fal/flags.py +0 -2
- fal/logging/isolate.py +4 -4
- fal/sdk.py +40 -5
- fal/sync.py +7 -3
- fal/toolkit/__init__.py +0 -2
- fal/toolkit/exceptions.py +0 -5
- fal/toolkit/file/file.py +61 -50
- fal/toolkit/file/providers/fal.py +20 -7
- fal/toolkit/file/providers/gcp.py +0 -2
- fal/toolkit/file/providers/r2.py +0 -2
- fal/toolkit/file/types.py +0 -4
- fal/toolkit/image/image.py +11 -15
- fal/toolkit/optimize.py +0 -3
- fal/toolkit/utils/download_utils.py +7 -17
- fal/workflows.py +9 -3
- fal-0.15.2.dist-info/METADATA +119 -0
- {fal-0.14.0.dist-info → fal-0.15.2.dist-info}/RECORD +50 -51
- {fal-0.14.0.dist-info → fal-0.15.2.dist-info}/WHEEL +2 -1
- fal-0.15.2.dist-info/entry_points.txt +2 -0
- fal-0.15.2.dist-info/top_level.txt +2 -0
- fal/env.py +0 -3
- fal/toolkit/mainify.py +0 -13
- fal-0.14.0.dist-info/METADATA +0 -89
- fal-0.14.0.dist-info/entry_points.txt +0 -4
|
@@ -10,8 +10,6 @@ from tempfile import TemporaryDirectory
|
|
|
10
10
|
from urllib.parse import urlparse
|
|
11
11
|
from urllib.request import Request, urlopen
|
|
12
12
|
|
|
13
|
-
from fal.toolkit.mainify import mainify
|
|
14
|
-
|
|
15
13
|
FAL_PERSISTENT_DIR = PurePath("/data")
|
|
16
14
|
FAL_REPOSITORY_DIR = FAL_PERSISTENT_DIR / ".fal" / "repos"
|
|
17
15
|
FAL_MODEL_WEIGHTS_DIR = FAL_PERSISTENT_DIR / ".fal" / "model_weights"
|
|
@@ -19,16 +17,17 @@ FAL_MODEL_WEIGHTS_DIR = FAL_PERSISTENT_DIR / ".fal" / "model_weights"
|
|
|
19
17
|
|
|
20
18
|
# TODO: how can we randomize the user agent to avoid being blocked?
|
|
21
19
|
TEMP_HEADERS = {
|
|
22
|
-
"User-Agent":
|
|
20
|
+
"User-Agent": (
|
|
21
|
+
"Mozilla/5.0 (Macintosh; "
|
|
22
|
+
"Intel Mac OS X 10.8; rv:21.0) Gecko/20100101 Firefox/21.0"
|
|
23
|
+
),
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
|
|
26
|
-
@mainify
|
|
27
27
|
class DownloadError(Exception):
|
|
28
28
|
pass
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
@mainify
|
|
32
31
|
def _hash_url(url: str) -> str:
|
|
33
32
|
"""Hashes a URL using SHA-256.
|
|
34
33
|
|
|
@@ -41,7 +40,6 @@ def _hash_url(url: str) -> str:
|
|
|
41
40
|
return hashlib.sha256(url.encode("utf-8")).hexdigest()
|
|
42
41
|
|
|
43
42
|
|
|
44
|
-
@mainify
|
|
45
43
|
@lru_cache
|
|
46
44
|
def _get_remote_file_properties(url: str) -> tuple[str, int]:
|
|
47
45
|
"""Retrieves the file name and content length of a remote file.
|
|
@@ -83,7 +81,6 @@ def _get_remote_file_properties(url: str) -> tuple[str, int]:
|
|
|
83
81
|
return file_name, content_length
|
|
84
82
|
|
|
85
83
|
|
|
86
|
-
@mainify
|
|
87
84
|
def _file_content_length_matches(url: str, file_path: Path) -> bool:
|
|
88
85
|
"""Check if the local file's content length matches the expected remote
|
|
89
86
|
file's content length.
|
|
@@ -100,8 +97,8 @@ def _file_content_length_matches(url: str, file_path: Path) -> bool:
|
|
|
100
97
|
file_path: The local path to the file being compared.
|
|
101
98
|
|
|
102
99
|
Returns:
|
|
103
|
-
bool
|
|
104
|
-
|
|
100
|
+
bool: `True` if the local file's content length matches the remote file's
|
|
101
|
+
content length, `False` otherwise.
|
|
105
102
|
"""
|
|
106
103
|
local_file_content_length = file_path.stat().st_size
|
|
107
104
|
remote_file_content_length = _get_remote_file_properties(url)[1]
|
|
@@ -109,7 +106,6 @@ def _file_content_length_matches(url: str, file_path: Path) -> bool:
|
|
|
109
106
|
return local_file_content_length == remote_file_content_length
|
|
110
107
|
|
|
111
108
|
|
|
112
|
-
@mainify
|
|
113
109
|
def download_file(
|
|
114
110
|
url: str,
|
|
115
111
|
target_dir: str | Path,
|
|
@@ -154,7 +150,7 @@ def download_file(
|
|
|
154
150
|
|
|
155
151
|
# If target_dir is not an absolute path, use "/data" as the relative directory
|
|
156
152
|
if not target_dir_path.is_absolute():
|
|
157
|
-
target_dir_path = FAL_PERSISTENT_DIR / target_dir_path # type: ignore[assignment]
|
|
153
|
+
target_dir_path = Path(FAL_PERSISTENT_DIR / target_dir_path) # type: ignore[assignment]
|
|
158
154
|
|
|
159
155
|
target_path = target_dir_path.resolve() / file_name
|
|
160
156
|
|
|
@@ -185,7 +181,6 @@ def download_file(
|
|
|
185
181
|
return target_path
|
|
186
182
|
|
|
187
183
|
|
|
188
|
-
@mainify
|
|
189
184
|
def _download_file_python(url: str, target_path: Path | str) -> Path:
|
|
190
185
|
"""Download a file from a given URL and save it to a specified path using a
|
|
191
186
|
Python interface.
|
|
@@ -224,7 +219,6 @@ def _download_file_python(url: str, target_path: Path | str) -> Path:
|
|
|
224
219
|
return Path(target_path)
|
|
225
220
|
|
|
226
221
|
|
|
227
|
-
@mainify
|
|
228
222
|
def _stream_url_data_to_file(url: str, file_path: str, chunk_size_in_mb: int = 64):
|
|
229
223
|
"""Download data from a URL and stream it to a file.
|
|
230
224
|
|
|
@@ -273,7 +267,6 @@ def _stream_url_data_to_file(url: str, file_path: str, chunk_size_in_mb: int = 6
|
|
|
273
267
|
raise DownloadError("Received less data than expected from the server.")
|
|
274
268
|
|
|
275
269
|
|
|
276
|
-
@mainify
|
|
277
270
|
def download_model_weights(url: str, force: bool = False):
|
|
278
271
|
"""Downloads model weights from the specified URL and saves them to a
|
|
279
272
|
predefined directory.
|
|
@@ -313,7 +306,6 @@ def download_model_weights(url: str, force: bool = False):
|
|
|
313
306
|
)
|
|
314
307
|
|
|
315
308
|
|
|
316
|
-
@mainify
|
|
317
309
|
def clone_repository(
|
|
318
310
|
https_url: str,
|
|
319
311
|
*,
|
|
@@ -408,7 +400,6 @@ def clone_repository(
|
|
|
408
400
|
return local_repo_path
|
|
409
401
|
|
|
410
402
|
|
|
411
|
-
@mainify
|
|
412
403
|
def __add_local_path_to_sys_path(local_path: Path | str):
|
|
413
404
|
local_path_str = str(local_path)
|
|
414
405
|
|
|
@@ -416,7 +407,6 @@ def __add_local_path_to_sys_path(local_path: Path | str):
|
|
|
416
407
|
sys.path.insert(0, local_path_str)
|
|
417
408
|
|
|
418
409
|
|
|
419
|
-
@mainify
|
|
420
410
|
def _get_git_revision_hash(repo_path: Path) -> str:
|
|
421
411
|
import subprocess
|
|
422
412
|
|
fal/workflows.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import graphlib
|
|
4
3
|
import json
|
|
5
4
|
import webbrowser
|
|
6
5
|
from argparse import ArgumentParser
|
|
@@ -8,6 +7,7 @@ from collections import Counter
|
|
|
8
7
|
from dataclasses import dataclass, field
|
|
9
8
|
from typing import Any, Iterator, Union, cast
|
|
10
9
|
|
|
10
|
+
import graphlib
|
|
11
11
|
import rich
|
|
12
12
|
from openapi_fal_rest.api.workflows import (
|
|
13
13
|
create_or_update_workflow_workflows_post as publish_workflow,
|
|
@@ -18,6 +18,7 @@ from rich.syntax import Syntax
|
|
|
18
18
|
|
|
19
19
|
import fal
|
|
20
20
|
from fal import flags
|
|
21
|
+
from fal.exceptions import FalServerlessException
|
|
21
22
|
from fal.rest_client import REST_CLIENT
|
|
22
23
|
|
|
23
24
|
JSONType = Union[dict[str, Any], list[Any], str, int, float, bool, None, "Leaf"]
|
|
@@ -31,7 +32,7 @@ INPUT_VARIABLE_NAME = "input"
|
|
|
31
32
|
WORKFLOW_EXPORT_VERSION = "0.1"
|
|
32
33
|
|
|
33
34
|
|
|
34
|
-
class WorkflowSyntaxError(
|
|
35
|
+
class WorkflowSyntaxError(FalServerlessException):
|
|
35
36
|
pass
|
|
36
37
|
|
|
37
38
|
|
|
@@ -449,7 +450,12 @@ def main() -> None:
|
|
|
449
450
|
for event in handle.iter_events(logs=True):
|
|
450
451
|
if isinstance(event, fal.apps.Queued):
|
|
451
452
|
status.update(
|
|
452
|
-
status=
|
|
453
|
+
status=(
|
|
454
|
+
"Queued for "
|
|
455
|
+
f"{node_id!r} "
|
|
456
|
+
f"(position={event.position}) "
|
|
457
|
+
f"({n}/{len(workflow.nodes)})",
|
|
458
|
+
),
|
|
453
459
|
spinner="dots",
|
|
454
460
|
)
|
|
455
461
|
elif isinstance(event, fal.apps.InProgress):
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: fal
|
|
3
|
+
Version: 0.15.2
|
|
4
|
+
Summary: fal is an easy-to-use Serverless Python Framework
|
|
5
|
+
Author: Features & Labels <hello@fal.ai>
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: isolate[build] <1.0,>=0.12.3
|
|
9
|
+
Requires-Dist: isolate-proto ==0.4.0
|
|
10
|
+
Requires-Dist: grpcio <2,>=1.50.0
|
|
11
|
+
Requires-Dist: dill ==0.3.7
|
|
12
|
+
Requires-Dist: cloudpickle ==3.0.0
|
|
13
|
+
Requires-Dist: typing-extensions <5,>=4.7.1
|
|
14
|
+
Requires-Dist: click <9,>=8.1.3
|
|
15
|
+
Requires-Dist: structlog <23,>=22.3.0
|
|
16
|
+
Requires-Dist: opentelemetry-api <2,>=1.15.0
|
|
17
|
+
Requires-Dist: opentelemetry-sdk <2,>=1.15.0
|
|
18
|
+
Requires-Dist: grpc-interceptor <1,>=0.15.0
|
|
19
|
+
Requires-Dist: colorama <1,>=0.4.6
|
|
20
|
+
Requires-Dist: portalocker <3,>=2.7.0
|
|
21
|
+
Requires-Dist: rich <14,>=13.3.2
|
|
22
|
+
Requires-Dist: rich-click
|
|
23
|
+
Requires-Dist: packaging <22,>=21.3
|
|
24
|
+
Requires-Dist: pathspec <1,>=0.11.1
|
|
25
|
+
Requires-Dist: pydantic !=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,<3
|
|
26
|
+
Requires-Dist: fastapi <1,>=0.99.1
|
|
27
|
+
Requires-Dist: starlette-exporter >=0.21.0
|
|
28
|
+
Requires-Dist: httpx >=0.15.4
|
|
29
|
+
Requires-Dist: attrs >=21.3.0
|
|
30
|
+
Requires-Dist: python-dateutil <3,>=2.8.0
|
|
31
|
+
Requires-Dist: types-python-dateutil <3,>=2.8.0
|
|
32
|
+
Requires-Dist: msgpack <2,>=1.0.7
|
|
33
|
+
Requires-Dist: websockets <13,>=12.0
|
|
34
|
+
Requires-Dist: pillow <11,>=10.2.0
|
|
35
|
+
Requires-Dist: pyjwt[crypto] <3,>=2.8.0
|
|
36
|
+
Requires-Dist: uvicorn <1,>=0.29.0
|
|
37
|
+
Requires-Dist: importlib-metadata >=4.4 ; python_version < "3.10"
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
Requires-Dist: fal[test] ; extra == 'dev'
|
|
40
|
+
Requires-Dist: openapi-python-client <1,>=0.14.1 ; extra == 'dev'
|
|
41
|
+
Provides-Extra: test
|
|
42
|
+
Requires-Dist: pytest <8 ; extra == 'test'
|
|
43
|
+
Requires-Dist: pytest-asyncio ; extra == 'test'
|
|
44
|
+
Requires-Dist: pytest-xdist ; extra == 'test'
|
|
45
|
+
Requires-Dist: flaky ; extra == 'test'
|
|
46
|
+
|
|
47
|
+
[](https://pypi.org/project/fal)
|
|
48
|
+
[](https://github.com/fal-ai/fal/actions)
|
|
49
|
+
|
|
50
|
+
# fal
|
|
51
|
+
|
|
52
|
+
fal is a serverless Python runtime that lets you run and scale code in the cloud with no infra management.
|
|
53
|
+
|
|
54
|
+
With fal, you can build pipelines, serve ML models and scale them up to many users. You scale down to 0 when you don't use any resources.
|
|
55
|
+
|
|
56
|
+
## Quickstart
|
|
57
|
+
|
|
58
|
+
First, you need to install the `fal` package. You can do so using pip:
|
|
59
|
+
```shell
|
|
60
|
+
pip install fal
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Then you need to authenticate:
|
|
64
|
+
```shell
|
|
65
|
+
fal auth login
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
You can also use fal keys that you can get from [our dashboard](https://fal.ai/dashboard/keys).
|
|
69
|
+
|
|
70
|
+
Now can use the fal package in your Python scripts as follows:
|
|
71
|
+
|
|
72
|
+
```py
|
|
73
|
+
import fal
|
|
74
|
+
|
|
75
|
+
@fal.function(
|
|
76
|
+
"virtualenv",
|
|
77
|
+
requirements=["pyjokes"],
|
|
78
|
+
)
|
|
79
|
+
def tell_joke() -> str:
|
|
80
|
+
import pyjokes
|
|
81
|
+
|
|
82
|
+
joke = pyjokes.get_joke()
|
|
83
|
+
return joke
|
|
84
|
+
|
|
85
|
+
print("Joke from the clouds: ", tell_joke())
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
A new virtual environment will be created by fal in the cloud and the set of requirements that we passed will be installed as soon as this function is called. From that point on, our code will be executed as if it were running locally, and the joke prepared by the pyjokes library will be returned.
|
|
89
|
+
|
|
90
|
+
## Next steps
|
|
91
|
+
|
|
92
|
+
If you would like to find out more about the capabilities of fal, check out to the [docs](https://fal.ai/docs). You can learn more about persistent storage, function caches and deploying your functions as API endpoints.
|
|
93
|
+
|
|
94
|
+
## Contributing
|
|
95
|
+
|
|
96
|
+
### Installing in editable mode with dev dependencies
|
|
97
|
+
|
|
98
|
+
```py
|
|
99
|
+
pip install -e 'projects/fal[dev]'
|
|
100
|
+
pip install -e 'projects/fal_client[dev]'
|
|
101
|
+
pip install -e 'projects/isolate_proto[dev]'
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Running tests
|
|
105
|
+
|
|
106
|
+
```py
|
|
107
|
+
pytest
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Pre-commit
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
cd projects/fal
|
|
114
|
+
pre-commit install
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Commit format
|
|
118
|
+
|
|
119
|
+
Please follow [conventional commits specification](https://www.conventionalcommits.org/) for descriptions/messages.
|
|
@@ -1,4 +1,49 @@
|
|
|
1
|
+
fal/__init__.py,sha256=unz75H_W1OpXsdkjHqjJs_GrA_BzwHaXImRH-pekaL0,617
|
|
2
|
+
fal/__main__.py,sha256=8hDtWlaFZK24KhfNq_ZKgtXqYHsDQDetukOCMlsbW0Q,59
|
|
3
|
+
fal/_serialization.py,sha256=Tx_c_mpJ8dYAVmPwdLkwgozSqfdvdFyWRYx3lH3-koQ,7595
|
|
4
|
+
fal/api.py,sha256=Nqs8qhYHRpCit1DiXqfFCacSnpUnI3__bssqcx5eVPc,36095
|
|
5
|
+
fal/app.py,sha256=bo8NbJTCjbIoeMVyW5YBxGljzDAKAqOjOJwP5erT2GM,13129
|
|
6
|
+
fal/apps.py,sha256=UhR6mq8jBiTAp-QvUnvbnMNcuJ5wHIKSqdlfyx8aBQ8,6829
|
|
7
|
+
fal/cli.py,sha256=2sPCP4G_y3aUX0SKVSOTkTaLdYJpcm9B6FYDqIVhx-8,18431
|
|
8
|
+
fal/flags.py,sha256=aWzOn3Ynl1s-eACerj1ZnRwlj3CvaGu0wIFcp7YXqX4,887
|
|
9
|
+
fal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
fal/rest_client.py,sha256=kGBGmuyHfX1lR910EoKCYPjsyU8MdXawT_cW2q8Sajc,568
|
|
11
|
+
fal/sdk.py,sha256=4aQikS2xH90xZpphKljml6cG38aahK2gcVSLTBQQCBY,19925
|
|
12
|
+
fal/sync.py,sha256=ZuIJA2-hTPNANG9B_NNJZUsO68EIdTH0dc9MzeVE2VU,4340
|
|
13
|
+
fal/workflows.py,sha256=4rjqL4xB6GHLJsqTplJmAvpd6uHZJ28sc8su33BFXEo,14682
|
|
14
|
+
fal/auth/__init__.py,sha256=r8iA2-5ih7-Fik3gEC4HEWNFbGoxpYnXpZu1icPIoS0,3561
|
|
15
|
+
fal/auth/auth0.py,sha256=rSG1mgH-QGyKfzd7XyAaj1AYsWt-ho8Y_LZ-FUVWzh4,5421
|
|
16
|
+
fal/auth/local.py,sha256=sndkM6vKpeVny6NHTacVlTbiIFqaksOmw0Viqs_RN1U,1790
|
|
17
|
+
fal/console/__init__.py,sha256=ernZ4bzvvliQh5SmrEqQ7lA5eVcbw6Ra2jalKtA7dxg,132
|
|
18
|
+
fal/console/icons.py,sha256=De9MfFaSkO2Lqfne13n3PrYfTXJVIzYZVqYn5BWsdrA,108
|
|
19
|
+
fal/console/ux.py,sha256=KMQs3UHQvVHDxDQQqlot-WskVKoMQXOE3jiVkkfmIMY,356
|
|
20
|
+
fal/exceptions/__init__.py,sha256=yAPFUv-RZCFi8joRVOE1hV79bb8WFHnj1zslF_zhYxw,996
|
|
21
|
+
fal/exceptions/_base.py,sha256=U3n_4OtUx5MvfT2eol_a-N0dV9_eYFMvdbrhP-b_NXg,160
|
|
22
|
+
fal/exceptions/auth.py,sha256=gxRago5coI__vSIcdcsqhhq1lRPkvCnwPAueIaXTAdw,329
|
|
23
|
+
fal/exceptions/handlers.py,sha256=nZCmmWU47k4P9NBISNqn0b6-L53KMoNuuGBW4G9Bweo,1674
|
|
24
|
+
fal/logging/__init__.py,sha256=snqprf7-sKw6oAATS_Yxklf-a3XhLg0vIHICPwLp6TM,1583
|
|
25
|
+
fal/logging/isolate.py,sha256=Gj_xylXc0ulGIyozLwTWisIclP7-du4tvhJWyPilrgo,1742
|
|
26
|
+
fal/logging/style.py,sha256=ckIgHzvF4DShM5kQh8F133X53z_vF46snuDHVmo_h9g,386
|
|
27
|
+
fal/logging/trace.py,sha256=OhzB6d4rQZimBc18WFLqH_9BGfqFFumKKTAGSsmWRMg,1904
|
|
28
|
+
fal/logging/user.py,sha256=0Xvb8n6tSb9l_V51VDzv6SOdYEFNouV_6nF_W9e7uNQ,642
|
|
29
|
+
fal/toolkit/__init__.py,sha256=sV95wiUzKoiDqF9vDgq4q-BLa2sD6IpuKSqp5kdTQNE,658
|
|
30
|
+
fal/toolkit/exceptions.py,sha256=elHZ7dHCJG5zlHGSBbz-ilkZe9QUvQMomJFi8Pt91LA,198
|
|
31
|
+
fal/toolkit/optimize.py,sha256=p75sovF0SmRP6zxzpIaaOmqlxvXB_xEz3XPNf59EF7w,1339
|
|
32
|
+
fal/toolkit/file/__init__.py,sha256=FbNl6wD-P0aSSTUwzHt4HujBXrbC3ABmaigPQA4hRfg,70
|
|
33
|
+
fal/toolkit/file/file.py,sha256=r8PzNCgv8Gkj6s1zM0yW-pcMKIouyaiEH06iBue8MwM,6066
|
|
34
|
+
fal/toolkit/file/types.py,sha256=9CqDh8SmNJNzfsrvtj468uo2SprJH9rOk8KMhhfU73c,1050
|
|
35
|
+
fal/toolkit/file/providers/fal.py,sha256=AfNwdnvt_IIFrzvNZPFjGwfVOQ2OzPfG1ySz6-2tnvc,3690
|
|
36
|
+
fal/toolkit/file/providers/gcp.py,sha256=7Lg7BXoHKkFu0jkGv3_vKh2Ks6eRfDMbw31N3mvDUtk,1913
|
|
37
|
+
fal/toolkit/file/providers/r2.py,sha256=YW5aJBOX41MQxfx1rA_f-IiJhAPMZ5md0cxBcg3y08I,2537
|
|
38
|
+
fal/toolkit/image/__init__.py,sha256=qNLyXsBWysionUjbeWbohLqWlw3G_UpzunamkZd_JLQ,71
|
|
39
|
+
fal/toolkit/image/image.py,sha256=2q1ZCBSSdmDx9q1S4ahoCOniNaRcfSFnCS31f3b8ZZ0,4252
|
|
40
|
+
fal/toolkit/utils/__init__.py,sha256=CrmM9DyCz5-SmcTzRSm5RaLgxy3kf0ZsSEN9uhnX2Xo,97
|
|
41
|
+
fal/toolkit/utils/download_utils.py,sha256=M-xUAV8kX6o1zcojozSTaArGIC_LgQriagCC8AoG0mM,15487
|
|
1
42
|
openapi_fal_rest/__init__.py,sha256=ziculmF_i6trw63LzZGFX-6W3Lwq9mCR8_UpkpvpaHI,152
|
|
43
|
+
openapi_fal_rest/client.py,sha256=G6BpJg9j7-JsrAUGddYwkzeWRYickBjPdcVgXoPzxuE,2817
|
|
44
|
+
openapi_fal_rest/errors.py,sha256=8mXSxdfSGzxT82srdhYbR0fHfgenxJXaUtMkaGgb6iU,470
|
|
45
|
+
openapi_fal_rest/py.typed,sha256=8ZJUsxZiuOy1oJeVhsTWQhTG_6pTVHVXk5hJL79ebTk,25
|
|
46
|
+
openapi_fal_rest/types.py,sha256=GLwJwOotUOdfqryo_r0naw55-dh6Ilm4IvxePekSACk,994
|
|
2
47
|
openapi_fal_rest/api/__init__.py,sha256=87ApBzKyGb5zsgTMOkQXDqsLZCmaSFoJMwbGzCDQZMw,47
|
|
3
48
|
openapi_fal_rest/api/applications/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
49
|
openapi_fal_rest/api/applications/app_metadata.py,sha256=GqG6Q7jt8Jcyhb3ms_6i0M1B3cy205y3_A8W-AGEapY,5120
|
|
@@ -13,8 +58,6 @@ openapi_fal_rest/api/workflows/delete_workflow_workflows_user_id_workflow_name_d
|
|
|
13
58
|
openapi_fal_rest/api/workflows/execute_workflow_workflows_user_id_workflow_name_post.py,sha256=kofDDU3TEVQ8Fmua_K2-lk5xh16g6_FNFHQ0KzoFMcM,8743
|
|
14
59
|
openapi_fal_rest/api/workflows/get_workflow_workflows_user_id_workflow_name_get.py,sha256=-E-TELi9Q_-yqobdHAcTHVm-8HithJRUGk7wc1mLA18,4763
|
|
15
60
|
openapi_fal_rest/api/workflows/get_workflows_workflows_get.py,sha256=iJF3lNYp22p8-JbbBMDoHO9iXQB8779lSnH2fNimYP4,5242
|
|
16
|
-
openapi_fal_rest/client.py,sha256=G6BpJg9j7-JsrAUGddYwkzeWRYickBjPdcVgXoPzxuE,2817
|
|
17
|
-
openapi_fal_rest/errors.py,sha256=8mXSxdfSGzxT82srdhYbR0fHfgenxJXaUtMkaGgb6iU,470
|
|
18
61
|
openapi_fal_rest/models/__init__.py,sha256=pGB91qXG3VDxob4DPAh3OMa2fyJFYBxc-jQ-9A4y3Gs,2037
|
|
19
62
|
openapi_fal_rest/models/app_metadata_response_app_metadata.py,sha256=1vx_5cp8V0jyE8iBRIe8TfngaeXMojfEpMCpT6i3qvs,1252
|
|
20
63
|
openapi_fal_rest/models/body_upload_local_file.py,sha256=rOTEbYBXfwZk8TsywZWSPPQQEfJgvsLIufT6A40RJZs,1980
|
|
@@ -38,52 +81,8 @@ openapi_fal_rest/models/workflow_node_type.py,sha256=-FzyeY2bxcNmizKbJI8joG7byRi
|
|
|
38
81
|
openapi_fal_rest/models/workflow_schema.py,sha256=4K5gsv9u9pxx2ItkffoyHeNjBBYf6ur5bN4m_zePZNY,2019
|
|
39
82
|
openapi_fal_rest/models/workflow_schema_input.py,sha256=2OkOXWHTNsCXHWS6EGDFzcJKkW5FIap-2gfO233EvZQ,1191
|
|
40
83
|
openapi_fal_rest/models/workflow_schema_output.py,sha256=EblwSPAGfWfYVWw_WSSaBzQVju296is9o28rMBAd0mc,1196
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
fal/
|
|
44
|
-
fal/
|
|
45
|
-
fal/
|
|
46
|
-
fal/api.py,sha256=7vQeYSorzazO0NR-zjWZ2KKxYEs32v7pTWeSg3OqCe4,34676
|
|
47
|
-
fal/app.py,sha256=xB5IeFrCYmXRhdvW6-UvoSfsHjiQkAs4IUWAfmcPsjg,12480
|
|
48
|
-
fal/apps.py,sha256=UhR6mq8jBiTAp-QvUnvbnMNcuJ5wHIKSqdlfyx8aBQ8,6829
|
|
49
|
-
fal/auth/__init__.py,sha256=uxfRLKgdboEWSuFDw5yrU_UVbI1h8Zk6L152X7JhKB8,3604
|
|
50
|
-
fal/auth/auth0.py,sha256=5y4-9udOSX2-N_zvinLCpFwl10MdaPydZX2v9GQMZEE,5406
|
|
51
|
-
fal/auth/local.py,sha256=lZqp4j32l2xFpY8zYvLoIHHyJrNAJDcm5MxgsLpY_pw,1786
|
|
52
|
-
fal/cli.py,sha256=rjtvqtrz3Cv68wazwlf5c9Ts2WGox9cDXNGryVH9AEo,18376
|
|
53
|
-
fal/console/__init__.py,sha256=ernZ4bzvvliQh5SmrEqQ7lA5eVcbw6Ra2jalKtA7dxg,132
|
|
54
|
-
fal/console/icons.py,sha256=De9MfFaSkO2Lqfne13n3PrYfTXJVIzYZVqYn5BWsdrA,108
|
|
55
|
-
fal/console/ux.py,sha256=KMQs3UHQvVHDxDQQqlot-WskVKoMQXOE3jiVkkfmIMY,356
|
|
56
|
-
fal/env.py,sha256=-fA8x62BbOX3MOuO0maupa-_QJ9PNwr8ogfeG11QUyQ,53
|
|
57
|
-
fal/exceptions/__init__.py,sha256=A8oJQQQlb8WQieusFK6O4CBc4s6CUSiNgj0xVKJKvgg,1012
|
|
58
|
-
fal/exceptions/_base.py,sha256=LeQmx-soL_-s1742WKN18VwTVjUuYP0L0BdQHPJBpM4,460
|
|
59
|
-
fal/exceptions/auth.py,sha256=01Ro7SyGJpwchubdHe14Cl6-Al1jUj16Sy4BvakNWf4,384
|
|
60
|
-
fal/exceptions/handlers.py,sha256=3z4DGTErw0zW3UW4p3JltlqpsMV10kqMtFOxpniMSBU,2105
|
|
61
|
-
fal/flags.py,sha256=AATQO65M4C87dGp0j7o6cSQWcr62xE-8DnJYsUjFFbw,942
|
|
62
|
-
fal/logging/__init__.py,sha256=snqprf7-sKw6oAATS_Yxklf-a3XhLg0vIHICPwLp6TM,1583
|
|
63
|
-
fal/logging/isolate.py,sha256=rQbM-wwsCO3ddIFyEo34GBWxDWkDzw3x0iSK79D0yKk,1742
|
|
64
|
-
fal/logging/style.py,sha256=ckIgHzvF4DShM5kQh8F133X53z_vF46snuDHVmo_h9g,386
|
|
65
|
-
fal/logging/trace.py,sha256=OhzB6d4rQZimBc18WFLqH_9BGfqFFumKKTAGSsmWRMg,1904
|
|
66
|
-
fal/logging/user.py,sha256=0Xvb8n6tSb9l_V51VDzv6SOdYEFNouV_6nF_W9e7uNQ,642
|
|
67
|
-
fal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
68
|
-
fal/rest_client.py,sha256=kGBGmuyHfX1lR910EoKCYPjsyU8MdXawT_cW2q8Sajc,568
|
|
69
|
-
fal/sdk.py,sha256=NIEXgkNon331XJ57ZuhhYboVuF_NOrBOHAY8pnJRgMU,18811
|
|
70
|
-
fal/sync.py,sha256=Ljet584PVFz4r888-0bwV1Kio-tTneF_85TnHvBPvJw,4277
|
|
71
|
-
fal/toolkit/__init__.py,sha256=JDNBT_duflp93geeAzw2kFmGzG5odWnPJEXFLXE2nF4,713
|
|
72
|
-
fal/toolkit/exceptions.py,sha256=--WKKYxUop6WFy_vqAPXK6uH8C-JR98gnNXwhHNCb7E,258
|
|
73
|
-
fal/toolkit/file/__init__.py,sha256=FbNl6wD-P0aSSTUwzHt4HujBXrbC3ABmaigPQA4hRfg,70
|
|
74
|
-
fal/toolkit/file/file.py,sha256=C3tJxWHSHh3e75pDKtJupi4YkMECcS22dmUuMfnEff4,5925
|
|
75
|
-
fal/toolkit/file/providers/fal.py,sha256=kQ3Q0vcgi6w7RHe5K4Y93jp7XDZ7g7PBNDFsdpb3OHw,3381
|
|
76
|
-
fal/toolkit/file/providers/gcp.py,sha256=Bq5SJSghXF8YfFnbZ83_mPdrWs2dFhi8ytODp92USgk,1962
|
|
77
|
-
fal/toolkit/file/providers/r2.py,sha256=xJtZfX3cfzJgLXS3F8mHArbrHi0_QBpIMy5M4-tS8H8,2586
|
|
78
|
-
fal/toolkit/file/types.py,sha256=MTIj6Y_ioL4CiMZXMiqx74vlmUifc3SNvcrWAXQfULE,1109
|
|
79
|
-
fal/toolkit/image/__init__.py,sha256=qNLyXsBWysionUjbeWbohLqWlw3G_UpzunamkZd_JLQ,71
|
|
80
|
-
fal/toolkit/image/image.py,sha256=ETuHx1DlhK4DYOkbUrgKz0pNRX0sgI476wk_TwhseZI,4339
|
|
81
|
-
fal/toolkit/mainify.py,sha256=E7gE45nZQZoaJdSlIq0mqajcH-IjcuPBWFmKm5hvhAU,406
|
|
82
|
-
fal/toolkit/optimize.py,sha256=FeCYxfyOcnJTrbMn5H7XZg8ZDWW-kfym5G_-q8vJa_U,1389
|
|
83
|
-
fal/toolkit/utils/__init__.py,sha256=CrmM9DyCz5-SmcTzRSm5RaLgxy3kf0ZsSEN9uhnX2Xo,97
|
|
84
|
-
fal/toolkit/utils/download_utils.py,sha256=aIww9MPemWNmvr8GIAWjU3NNFsJAgXg7_q8FxRNLXP0,15594
|
|
85
|
-
fal/workflows.py,sha256=rsc8FPi6auExNNKVQOp0yTlOnfk50jDZo-OFzBKmkIY,14447
|
|
86
|
-
fal-0.14.0.dist-info/METADATA,sha256=O3b1-tE2mi4tv4yLSgl8E6bAabByi-XuXZOxZmkykcM,3263
|
|
87
|
-
fal-0.14.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
88
|
-
fal-0.14.0.dist-info/entry_points.txt,sha256=nE9GBVV3PdBosudFwbIzZQUe_9lfPR6EH8K_FdDASnM,62
|
|
89
|
-
fal-0.14.0.dist-info/RECORD,,
|
|
84
|
+
fal-0.15.2.dist-info/METADATA,sha256=SfYdtZgpSWTSE3GKU-rqZc5fAi7XGwSM1AB1ZJdqoHM,3738
|
|
85
|
+
fal-0.15.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
86
|
+
fal-0.15.2.dist-info/entry_points.txt,sha256=1GadEh1IgXO5Bb42Xo9lwNsJnm9Xjfo3qIdqwbfdV8Q,36
|
|
87
|
+
fal-0.15.2.dist-info/top_level.txt,sha256=r257X1L57oJL8_lM0tRrfGuXFwm66i1huwQygbpLmHw,21
|
|
88
|
+
fal-0.15.2.dist-info/RECORD,,
|
fal/env.py
DELETED
fal/toolkit/mainify.py
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
# HACK: make classes dillable https://github.com/uqfoundation/dill/issues/424
|
|
5
|
-
# Only works for classes for now, must be outer-most decorator in most cases
|
|
6
|
-
def mainify(obj):
|
|
7
|
-
if hasattr(obj, "__module__") and obj.__module__.startswith("fal"):
|
|
8
|
-
obj.__module__ = "__main__"
|
|
9
|
-
|
|
10
|
-
for inner in obj.__dict__.values():
|
|
11
|
-
mainify(inner)
|
|
12
|
-
|
|
13
|
-
return obj
|
fal-0.14.0.dist-info/METADATA
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: fal
|
|
3
|
-
Version: 0.14.0
|
|
4
|
-
Summary: fal is an easy-to-use Serverless Python Framework
|
|
5
|
-
Author: Features & Labels
|
|
6
|
-
Author-email: hello@fal.ai
|
|
7
|
-
Requires-Python: >=3.8,<4.0
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
-
Requires-Dist: attrs (>=21.3.0)
|
|
15
|
-
Requires-Dist: click (>=8.1.3,<9.0.0)
|
|
16
|
-
Requires-Dist: colorama (>=0.4.6,<0.5.0)
|
|
17
|
-
Requires-Dist: dill (==0.3.7)
|
|
18
|
-
Requires-Dist: fastapi (==0.99.1)
|
|
19
|
-
Requires-Dist: grpc-interceptor (>=0.15.0,<0.16.0)
|
|
20
|
-
Requires-Dist: grpcio (>=1.50.0,<2.0.0)
|
|
21
|
-
Requires-Dist: httpx (>=0.15.4)
|
|
22
|
-
Requires-Dist: importlib-metadata (>=4.4) ; python_version < "3.10"
|
|
23
|
-
Requires-Dist: isolate-proto (>=0.3.4,<0.4.0)
|
|
24
|
-
Requires-Dist: isolate[build] (>=0.12.3,<1.0)
|
|
25
|
-
Requires-Dist: msgpack (>=1.0.7,<2.0.0)
|
|
26
|
-
Requires-Dist: opentelemetry-api (>=1.15.0,<2.0.0)
|
|
27
|
-
Requires-Dist: opentelemetry-sdk (>=1.15.0,<2.0.0)
|
|
28
|
-
Requires-Dist: packaging (>=21.3)
|
|
29
|
-
Requires-Dist: pathspec (>=0.11.1,<0.12.0)
|
|
30
|
-
Requires-Dist: pillow (>=10.2.0,<11.0.0)
|
|
31
|
-
Requires-Dist: portalocker (>=2.7.0,<3.0.0)
|
|
32
|
-
Requires-Dist: pydantic (<2.0)
|
|
33
|
-
Requires-Dist: pyjwt[crypto] (>=2.8.0,<3.0.0)
|
|
34
|
-
Requires-Dist: python-dateutil (>=2.8.0,<3.0.0)
|
|
35
|
-
Requires-Dist: rich (>=13.3.2,<14.0.0)
|
|
36
|
-
Requires-Dist: rich_click
|
|
37
|
-
Requires-Dist: structlog (>=22.3.0,<23.0.0)
|
|
38
|
-
Requires-Dist: types-python-dateutil (>=2.8.0,<3.0.0)
|
|
39
|
-
Requires-Dist: typing-extensions (>=4.7.1,<5.0.0)
|
|
40
|
-
Requires-Dist: websockets (>=12.0,<13.0)
|
|
41
|
-
Description-Content-Type: text/markdown
|
|
42
|
-
|
|
43
|
-
[](https://pypi.org/project/fal)
|
|
44
|
-
[](https://github.com/fal-ai/fal/actions)
|
|
45
|
-
|
|
46
|
-
# fal
|
|
47
|
-
|
|
48
|
-
fal is a serverless Python runtime that lets you run and scale code in the cloud with no infra management.
|
|
49
|
-
|
|
50
|
-
With fal, you can build pipelines, serve ML models and scale them up to many users. You scale down to 0 when you don't use any resources.
|
|
51
|
-
|
|
52
|
-
## Quickstart
|
|
53
|
-
|
|
54
|
-
First, you need to install the `fal` package. You can do so using pip:
|
|
55
|
-
```shell
|
|
56
|
-
pip install fal
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Then you need to authenticate:
|
|
60
|
-
```shell
|
|
61
|
-
fal auth login
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
You can also use fal keys that you can get from [our dashboard](https://fal.ai/dashboard/keys).
|
|
65
|
-
|
|
66
|
-
Now can use the fal package in your Python scripts as follows:
|
|
67
|
-
|
|
68
|
-
```py
|
|
69
|
-
import fal
|
|
70
|
-
|
|
71
|
-
@fal.function(
|
|
72
|
-
"virtualenv",
|
|
73
|
-
requirements=["pyjokes"],
|
|
74
|
-
)
|
|
75
|
-
def tell_joke() -> str:
|
|
76
|
-
import pyjokes
|
|
77
|
-
|
|
78
|
-
joke = pyjokes.get_joke()
|
|
79
|
-
return joke
|
|
80
|
-
|
|
81
|
-
print("Joke from the clouds: ", tell_joke())
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
A new virtual environment will be created by fal in the cloud and the set of requirements that we passed will be installed as soon as this function is called. From that point on, our code will be executed as if it were running locally, and the joke prepared by the pyjokes library will be returned.
|
|
85
|
-
|
|
86
|
-
## Next steps
|
|
87
|
-
|
|
88
|
-
If you would like to find out more about the capabilities of fal, check out to the [docs](https://fal.ai/docs). You can learn more about persistent storage, function caches and deploying your functions as API endpoints.
|
|
89
|
-
|