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.

@@ -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": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:21.0) Gecko/20100101 Firefox/21.0"
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:`True` if the local file's content length matches the remote file's content length,
104
- `False` otherwise.
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(Exception):
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=f"Queued for {node_id!r} (position={event.position}) ({n}/{len(workflow.nodes)})",
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
+ [![PyPI](https://img.shields.io/pypi/v/fal.svg?logo=PyPI)](https://pypi.org/project/fal)
48
+ [![Tests](https://img.shields.io/github/actions/workflow/status/fal-ai/fal/integration_tests.yaml?label=Tests)](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
- openapi_fal_rest/py.typed,sha256=8ZJUsxZiuOy1oJeVhsTWQhTG_6pTVHVXk5hJL79ebTk,25
42
- openapi_fal_rest/types.py,sha256=GLwJwOotUOdfqryo_r0naw55-dh6Ilm4IvxePekSACk,994
43
- fal/__init__.py,sha256=XOobhu3D94O9K9ka_AJh6sw3K7lV-s_NuSto_fx9TXg,1255
44
- fal/__main__.py,sha256=8hDtWlaFZK24KhfNq_ZKgtXqYHsDQDetukOCMlsbW0Q,59
45
- fal/_serialization.py,sha256=L0KpyGHqTyqcV5mNCWJgQ1UG9BMwFj395B3blaBjV7c,5627
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,,
@@ -1,4 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.0
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ fal = fal.cli:cli
@@ -0,0 +1,2 @@
1
+ fal
2
+ openapi_fal_rest
fal/env.py DELETED
@@ -1,3 +0,0 @@
1
- from __future__ import annotations
2
-
3
- CLI_ENV = "prod"
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
@@ -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
- [![PyPI](https://img.shields.io/pypi/v/fal.svg?logo=PyPI)](https://pypi.org/project/fal)
44
- [![Tests](https://img.shields.io/github/actions/workflow/status/fal-ai/fal/integration_tests.yaml?label=Tests)](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
-
@@ -1,4 +0,0 @@
1
- [console_scripts]
2
- fal=fal.cli:cli
3
- fal-serverless=fal.cli:cli
4
-