fal 1.15.1__py3-none-any.whl → 1.16.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/_fal_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '1.15.1'
21
- __version_tuple__ = version_tuple = (1, 15, 1)
20
+ __version__ = version = '1.16.1'
21
+ __version_tuple__ = version_tuple = (1, 16, 1)
fal/_serialization.py CHANGED
@@ -6,7 +6,7 @@ from typing import Any, Callable
6
6
  import cloudpickle
7
7
 
8
8
 
9
- def _register_pickle_by_value(name) -> None:
9
+ def include_module(name) -> None:
10
10
  # cloudpickle.register_pickle_by_value wants an imported module object,
11
11
  # but there is really no reason to go through that complication, as
12
12
  # it might be prone to errors.
@@ -22,7 +22,7 @@ def include_package_from_path(raw_path: str) -> None:
22
22
  parent = parent.parent
23
23
 
24
24
  if parent != path:
25
- _register_pickle_by_value(parent.name)
25
+ include_module(parent.name)
26
26
 
27
27
 
28
28
  def include_modules_from(obj: Any) -> None:
@@ -33,7 +33,7 @@ def include_modules_from(obj: Any) -> None:
33
33
  if "." in module_name:
34
34
  # Just include the whole package
35
35
  package_name, *_ = module_name.partition(".")
36
- _register_pickle_by_value(package_name)
36
+ include_module(package_name)
37
37
  return
38
38
 
39
39
  if module_name == "__main__":
@@ -44,7 +44,7 @@ def include_modules_from(obj: Any) -> None:
44
44
  include_package_from_path(__main__.__file__)
45
45
  return
46
46
 
47
- _register_pickle_by_value(module_name)
47
+ include_module(module_name)
48
48
 
49
49
 
50
50
  def _register(cls: Any, func: Callable) -> None:
@@ -230,4 +230,4 @@ def patch_pickle() -> None:
230
230
  _patch_console_thread_locals()
231
231
  _patch_exceptions()
232
232
 
233
- _register_pickle_by_value("fal")
233
+ include_module("fal")
fal/_version.py CHANGED
@@ -1,6 +1,89 @@
1
+ import json
2
+ import os
3
+ import tempfile
4
+ from typing import Any, Dict, Optional
5
+
1
6
  try:
2
7
  from ._fal_version import version as __version__ # type: ignore[import]
3
8
  from ._fal_version import version_tuple # type: ignore[import]
4
9
  except ImportError:
5
10
  __version__ = "UNKNOWN"
6
11
  version_tuple = (0, 0, __version__) # type: ignore[assignment]
12
+
13
+
14
+ _PYPI_URL = "https://pypi.org/pypi/fal/json"
15
+ _PYPI_CACHE_TTL = 60 * 60 # 1 hour
16
+ _PYPI_CACHE_PATH = os.path.expanduser("~/.fal/cache/pypi.json")
17
+ _URLOPEN_TIMEOUT = 1
18
+
19
+
20
+ def _write_pypi_cache(data: Dict[str, Any]) -> None:
21
+ cache_dir = os.path.dirname(_PYPI_CACHE_PATH)
22
+ os.makedirs(cache_dir, exist_ok=True)
23
+ prefix = os.path.basename(_PYPI_CACHE_PATH) + ".tmp."
24
+ with tempfile.NamedTemporaryFile(
25
+ mode="w",
26
+ dir=cache_dir,
27
+ prefix=prefix,
28
+ delete=False,
29
+ ) as fobj:
30
+ fobj.write(json.dumps(data))
31
+ os.rename(fobj.name, _PYPI_CACHE_PATH)
32
+
33
+
34
+ def _get_pypi_cache() -> Optional[Dict[str, Any]]:
35
+ import time
36
+
37
+ try:
38
+ mtime = os.path.getmtime(_PYPI_CACHE_PATH)
39
+ except FileNotFoundError:
40
+ return None
41
+
42
+ if mtime + _PYPI_CACHE_TTL < time.time():
43
+ return None
44
+
45
+ with open(_PYPI_CACHE_PATH) as fobj:
46
+ try:
47
+ return json.load(fobj)
48
+ except ValueError:
49
+ return None
50
+
51
+
52
+ def _fetch_pypi_data() -> Dict[str, Any]:
53
+ from urllib.request import urlopen
54
+
55
+ response = urlopen(_PYPI_URL, timeout=_URLOPEN_TIMEOUT)
56
+ if response.status != 200:
57
+ raise Exception(f"Failed to fetch {_PYPI_URL}")
58
+
59
+ data = response.read()
60
+ return json.loads(data)
61
+
62
+
63
+ def get_latest_version() -> str:
64
+ from fal.logging import get_logger
65
+
66
+ logger = get_logger(__name__)
67
+
68
+ try:
69
+ data = _get_pypi_cache()
70
+ except Exception:
71
+ logger.warning("Failed to get pypi cache", exc_info=True)
72
+ data = None
73
+
74
+ if data is None:
75
+ try:
76
+ data = _fetch_pypi_data()
77
+ except Exception:
78
+ logger.warning("Failed to get latest fal version", exc_info=True)
79
+ data = {}
80
+
81
+ try:
82
+ _write_pypi_cache(data)
83
+ except Exception:
84
+ logger.warning("Failed to write pypi cache", exc_info=True)
85
+
86
+ try:
87
+ return data["info"]["version"]
88
+ except KeyError:
89
+ return "0.0.0"
fal/api.py CHANGED
@@ -39,7 +39,7 @@ from pydantic import __version__ as pydantic_version
39
39
  from typing_extensions import Concatenate, ParamSpec
40
40
 
41
41
  import fal.flags as flags
42
- from fal._serialization import include_modules_from, patch_pickle
42
+ from fal._serialization import include_module, include_modules_from, patch_pickle
43
43
  from fal.container import ContainerImage
44
44
  from fal.exceptions import (
45
45
  AppException,
@@ -501,12 +501,7 @@ class FalServerlessHost(Host):
501
501
  if isinstance(func, ServeWrapper):
502
502
  # Assigning in a separate property leaving a place for the user
503
503
  # to add more metadata in the future
504
- try:
505
- metadata["openapi"] = func.openapi()
506
- except Exception as e:
507
- print(
508
- f"[warning] Failed to generate OpenAPI metadata for function: {e}"
509
- )
504
+ metadata["openapi"] = func.openapi()
510
505
 
511
506
  for partial_result in self._connection.register(
512
507
  partial_func,
@@ -694,6 +689,7 @@ def function(
694
689
  serve: Literal[False] = False,
695
690
  exposed_port: int | None = None,
696
691
  max_concurrency: int | None = None,
692
+ local_python_modules: list[str] | None = None,
697
693
  ) -> Callable[
698
694
  [Callable[Concatenate[ArgsT], ReturnT]], IsolatedFunction[ArgsT, ReturnT]
699
695
  ]: ...
@@ -710,6 +706,7 @@ def function(
710
706
  serve: Literal[True],
711
707
  exposed_port: int | None = None,
712
708
  max_concurrency: int | None = None,
709
+ local_python_modules: list[str] | None = None,
713
710
  ) -> Callable[
714
711
  [Callable[Concatenate[ArgsT], ReturnT]], ServedIsolatedFunction[ArgsT, ReturnT]
715
712
  ]: ...
@@ -727,6 +724,7 @@ def function(
727
724
  serve: Literal[False] = False,
728
725
  exposed_port: int | None = None,
729
726
  max_concurrency: int | None = None,
727
+ local_python_modules: list[str] | None = None,
730
728
  # FalServerlessHost options
731
729
  metadata: dict[str, Any] | None = None,
732
730
  machine_type: str | list[str] = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
@@ -756,6 +754,7 @@ def function(
756
754
  serve: Literal[True],
757
755
  exposed_port: int | None = None,
758
756
  max_concurrency: int | None = None,
757
+ local_python_modules: list[str] | None = None,
759
758
  # FalServerlessHost options
760
759
  metadata: dict[str, Any] | None = None,
761
760
  machine_type: str | list[str] = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
@@ -792,6 +791,7 @@ def function(
792
791
  serve: Literal[False] = False,
793
792
  exposed_port: int | None = None,
794
793
  max_concurrency: int | None = None,
794
+ local_python_modules: list[str] | None = None,
795
795
  ) -> Callable[
796
796
  [Callable[Concatenate[ArgsT], ReturnT]], IsolatedFunction[ArgsT, ReturnT]
797
797
  ]: ...
@@ -813,6 +813,7 @@ def function(
813
813
  serve: Literal[True],
814
814
  exposed_port: int | None = None,
815
815
  max_concurrency: int | None = None,
816
+ local_python_modules: list[str] | None = None,
816
817
  ) -> Callable[
817
818
  [Callable[Concatenate[ArgsT], ReturnT]], ServedIsolatedFunction[ArgsT, ReturnT]
818
819
  ]: ...
@@ -835,6 +836,7 @@ def function(
835
836
  serve: Literal[False] = False,
836
837
  exposed_port: int | None = None,
837
838
  max_concurrency: int | None = None,
839
+ local_python_modules: list[str] | None = None,
838
840
  # FalServerlessHost options
839
841
  metadata: dict[str, Any] | None = None,
840
842
  machine_type: str | list[str] = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
@@ -869,6 +871,7 @@ def function(
869
871
  serve: Literal[True],
870
872
  exposed_port: int | None = None,
871
873
  max_concurrency: int | None = None,
874
+ local_python_modules: list[str] | None = None,
872
875
  # FalServerlessHost options
873
876
  metadata: dict[str, Any] | None = None,
874
877
  machine_type: str | list[str] = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
@@ -897,6 +900,7 @@ def function(
897
900
  serve: Literal[False] = False,
898
901
  exposed_port: int | None = None,
899
902
  max_concurrency: int | None = None,
903
+ local_python_modules: list[str] | None = None,
900
904
  # FalServerlessHost options
901
905
  metadata: dict[str, Any] | None = None,
902
906
  machine_type: str | list[str] = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
@@ -925,6 +929,7 @@ def function(
925
929
  serve: Literal[True],
926
930
  exposed_port: int | None = None,
927
931
  max_concurrency: int | None = None,
932
+ local_python_modules: list[str] | None = None,
928
933
  # FalServerlessHost options
929
934
  metadata: dict[str, Any] | None = None,
930
935
  machine_type: str | list[str] = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
@@ -948,6 +953,7 @@ def function( # type: ignore
948
953
  kind: str = "virtualenv",
949
954
  *,
950
955
  host: Host | None = None,
956
+ local_python_modules: list[str] | None = None,
951
957
  **config: Any,
952
958
  ):
953
959
  if host is None:
@@ -956,6 +962,10 @@ def function( # type: ignore
956
962
 
957
963
  def wrapper(func: Callable[ArgsT, ReturnT]):
958
964
  include_modules_from(func)
965
+
966
+ for module_name in local_python_modules or []:
967
+ include_module(module_name)
968
+
959
969
  proxy = IsolatedFunction(
960
970
  host=host, # type: ignore
961
971
  raw_func=func, # type: ignore
@@ -1154,7 +1164,12 @@ class BaseServable:
1154
1164
  Build the OpenAPI specification for the served function.
1155
1165
  Attach needed metadata for a better integration to fal.
1156
1166
  """
1157
- return self._build_app().openapi()
1167
+ try:
1168
+ return self._build_app().openapi()
1169
+ except Exception as e:
1170
+ raise FalServerlessException(
1171
+ "Failed to generate OpenAPI metadata for function"
1172
+ ) from e
1158
1173
 
1159
1174
  def serve(self) -> None:
1160
1175
  import asyncio
fal/app.py CHANGED
@@ -105,15 +105,12 @@ def wrap_app(cls: type[App], **kwargs) -> IsolatedFunction:
105
105
  app.serve()
106
106
 
107
107
  metadata = {}
108
- try:
109
- app = cls(_allow_init=True)
110
- metadata["openapi"] = app.openapi()
111
- except Exception:
112
- logger.warning("Failed to build OpenAPI specification for %s", cls.__name__)
113
- realtime_app = False
114
- else:
115
- routes = app.collect_routes()
116
- realtime_app = any(route.is_websocket for route in routes)
108
+ app = cls(_allow_init=True)
109
+
110
+ metadata["openapi"] = app.openapi()
111
+
112
+ routes = app.collect_routes()
113
+ realtime_app = any(route.is_websocket for route in routes)
117
114
 
118
115
  kind = cls.host_kwargs.pop("kind", "virtualenv")
119
116
  if kind == "container":
@@ -122,6 +119,7 @@ def wrap_app(cls: type[App], **kwargs) -> IsolatedFunction:
122
119
  wrapper = fal_function(
123
120
  kind,
124
121
  requirements=cls.requirements,
122
+ local_python_modules=cls.local_python_modules,
125
123
  machine_type=cls.machine_type,
126
124
  num_gpus=cls.num_gpus,
127
125
  **cls.host_kwargs,
@@ -265,6 +263,7 @@ def _print_python_packages() -> None:
265
263
 
266
264
  class App(BaseServable):
267
265
  requirements: ClassVar[list[str]] = []
266
+ local_python_modules: ClassVar[list[str]] = []
268
267
  machine_type: ClassVar[str] = "S"
269
268
  num_gpus: ClassVar[int | None] = None
270
269
  host_kwargs: ClassVar[dict[str, Any]] = {
fal/auth/__init__.py CHANGED
@@ -63,8 +63,13 @@ def key_credentials() -> tuple[str, str] | None:
63
63
 
64
64
  key = os.environ.get("FAL_KEY") or config.get("key") or get_colab_token()
65
65
  if key:
66
- key_id, key_secret = key.split(":", 1)
67
- return (key_id, key_secret)
66
+ try:
67
+ key_id, key_secret = key.split(":", 1)
68
+ return (key_id, key_secret)
69
+ except ValueError:
70
+ print(f"Invalid key format: {key}")
71
+ return None
72
+
68
73
  elif "FAL_KEY_ID" in os.environ and "FAL_KEY_SECRET" in os.environ:
69
74
  return (os.environ["FAL_KEY_ID"], os.environ["FAL_KEY_SECRET"])
70
75
  else:
fal/cli/main.py CHANGED
@@ -77,11 +77,48 @@ def _print_error(msg):
77
77
  console.print(f"{CROSS_ICON} {msg}")
78
78
 
79
79
 
80
+ def _check_latest_version():
81
+ from packaging.version import parse
82
+ from rich.emoji import Emoji
83
+ from rich.panel import Panel
84
+ from rich.text import Text
85
+
86
+ from fal._version import get_latest_version, version_tuple
87
+
88
+ latest_version = get_latest_version()
89
+ parsed = parse(latest_version)
90
+ latest_version_tuple = (parsed.major, parsed.minor, parsed.micro)
91
+ if latest_version_tuple <= version_tuple:
92
+ return
93
+
94
+ if not console.is_terminal:
95
+ return
96
+
97
+ line1 = Text.assemble(
98
+ (Emoji.replace(":warning-emoji: "), "bold white"),
99
+ ("A new version of fal is available: ", "bold white"),
100
+ (latest_version, "bold green"),
101
+ )
102
+ line2 = Text.assemble(("pip install --upgrade fal", "bold cyan"))
103
+ line2.align("center", width=len(line1))
104
+
105
+ panel = Panel(
106
+ line1 + "\n\n" + line2,
107
+ border_style="yellow",
108
+ padding=(1, 2),
109
+ highlight=True,
110
+ expand=False,
111
+ )
112
+ console.print(panel)
113
+
114
+
80
115
  def main(argv=None) -> int:
81
116
  import grpc
82
117
 
83
118
  from fal.api import UserFunctionException
84
119
 
120
+ _check_latest_version()
121
+
85
122
  ret = 1
86
123
  try:
87
124
  args = parse_args(argv)
fal/cli/profile.py CHANGED
@@ -55,12 +55,18 @@ def _key_set(args):
55
55
  args.console.print(f"Key set for profile [cyan]{config.profile}[/].")
56
56
 
57
57
 
58
+ def _host_set(args):
59
+ with Config().edit() as config:
60
+ config.set("host", args.HOST)
61
+ args.console.print(f"Fal host set to [cyan]{args.HOST}[/].")
62
+
63
+
58
64
  def _delete(args):
59
65
  with Config().edit() as config:
60
66
  if config.profile == args.PROFILE:
61
67
  config.set_internal("profile", None)
62
68
 
63
- config.delete(args.PROFILE)
69
+ config.delete_profile(args.PROFILE)
64
70
  args.console.print(f"Profile [cyan]{args.PROFILE}[/] deleted.")
65
71
 
66
72
 
@@ -121,6 +127,19 @@ def add_parser(main_subparsers, parents):
121
127
  )
122
128
  key_set_parser.set_defaults(func=_key_set)
123
129
 
130
+ host_set_help = "Set fal host."
131
+ host_set_parser = subparsers.add_parser(
132
+ "host",
133
+ description=host_set_help,
134
+ help=host_set_help,
135
+ parents=parents,
136
+ )
137
+ host_set_parser.add_argument(
138
+ "HOST",
139
+ help="Fal host.",
140
+ )
141
+ host_set_parser.set_defaults(func=_host_set)
142
+
124
143
  delete_help = "Delete profile."
125
144
  delete_parser = subparsers.add_parser(
126
145
  "delete",
fal/cli/runners.py CHANGED
@@ -21,17 +21,21 @@ def runners_table(runners: List[RunnerInfo]):
21
21
  table.add_column("Revision")
22
22
 
23
23
  for runner in runners:
24
+ external_metadata = runner.external_metadata
25
+ present = external_metadata.get("present_in_group", True)
26
+
24
27
  num_leases_with_request = len(
25
28
  [
26
29
  lease
27
- for lease in runner.external_metadata.get("leases", [])
30
+ for lease in external_metadata.get("leases", [])
28
31
  if lease.get("request_id") is not None
29
32
  ]
30
33
  )
31
34
 
32
35
  table.add_row(
33
36
  runner.alias,
34
- runner.runner_id,
37
+ # Mark lost runners in red
38
+ runner.runner_id if present else f"[red]{runner.runner_id}[/]",
35
39
  str(runner.in_flight_requests),
36
40
  str(runner.in_flight_requests - num_leases_with_request),
37
41
  (
fal/config.py CHANGED
@@ -99,7 +99,7 @@ class Config:
99
99
  def unset_internal(self, key: str) -> None:
100
100
  self._config.get(SETTINGS_SECTION, {}).pop(key, None)
101
101
 
102
- def delete(self, profile: str) -> None:
102
+ def delete_profile(self, profile: str) -> None:
103
103
  del self._config[profile]
104
104
 
105
105
  @contextmanager
fal/flags.py CHANGED
@@ -2,6 +2,8 @@ from __future__ import annotations
2
2
 
3
3
  import os
4
4
 
5
+ from fal.config import Config
6
+
5
7
 
6
8
  def bool_envvar(name: str):
7
9
  if name in os.environ:
@@ -14,7 +16,10 @@ DEBUG = bool_envvar("DEBUG")
14
16
  TEST_MODE = bool_envvar("ISOLATE_TEST_MODE")
15
17
  AUTH_DISABLED = bool_envvar("ISOLATE_AUTH_DISABLED")
16
18
 
17
- GRPC_HOST = os.getenv("FAL_HOST", "api.alpha.fal.ai")
19
+ config = Config()
20
+ config_host = config.get("host")
21
+
22
+ GRPC_HOST = config_host or os.getenv("FAL_HOST") or "api.alpha.fal.ai"
18
23
  if not TEST_MODE:
19
24
  assert GRPC_HOST.startswith("api"), "FAL_HOST must start with 'api'"
20
25
 
@@ -0,0 +1,29 @@
1
+ from contextlib import asynccontextmanager
2
+
3
+ from anyio import create_task_group
4
+ from fastapi import Request
5
+
6
+
7
+ @asynccontextmanager
8
+ async def cancel_on_disconnect(request: Request):
9
+ """
10
+ Async context manager for async code that needs to be cancelled if client
11
+ disconnects prematurely.
12
+ The client disconnect is monitored through the Request object.
13
+ """
14
+ async with create_task_group() as tg:
15
+
16
+ async def watch_disconnect():
17
+ while True:
18
+ message = await request.receive()
19
+
20
+ if message["type"] == "http.disconnect":
21
+ tg.cancel_scope.cancel()
22
+ break
23
+
24
+ tg.start_soon(watch_disconnect)
25
+
26
+ try:
27
+ yield
28
+ finally:
29
+ tg.cancel_scope.cancel()
fal/utils.py CHANGED
@@ -21,8 +21,11 @@ def load_function_from(
21
21
  file_path: str,
22
22
  function_name: str | None = None,
23
23
  ) -> LoadedFunction:
24
+ import os
24
25
  import runpy
26
+ import sys
25
27
 
28
+ sys.path.append(os.getcwd())
26
29
  module = runpy.run_path(file_path)
27
30
  if function_name is None:
28
31
  fal_objects = {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fal
3
- Version: 1.15.1
3
+ Version: 1.16.1
4
4
  Summary: fal is an easy-to-use Serverless Python Framework
5
5
  Author: Features & Labels <support@fal.ai>
6
6
  Requires-Python: >=3.8
@@ -1,23 +1,23 @@
1
1
  fal/__init__.py,sha256=wXs1G0gSc7ZK60-bHe-B2m0l_sA6TrFk4BxY0tMoLe8,784
2
2
  fal/__main__.py,sha256=4JMK66Wj4uLZTKbF-sT3LAxOsr6buig77PmOkJCRRxw,83
3
- fal/_fal_version.py,sha256=u2kvcE5eJlQ5arI8vANUY9cq2C_oRgBLSNFx24U4PgU,513
4
- fal/_serialization.py,sha256=rD2YiSa8iuzCaZohZwN_MPEB-PpSKbWRDeaIDpTEjyY,7653
5
- fal/_version.py,sha256=EBGqrknaf1WygENX-H4fBefLvHryvJBBGtVJetaB0NY,266
6
- fal/api.py,sha256=gVZKtdMRNKacBCNVmdZZRGMyF3hrR2bqGiAzUBstkDM,45661
7
- fal/app.py,sha256=aRb8t-5QCrIPeKHY39yJ3231T5uHGZLhSurkRBtzyu8,24216
3
+ fal/_fal_version.py,sha256=fHsj4qb8quZFYixIg7OlfrAd4kLbNz0T5Cu5K-h6vsE,513
4
+ fal/_serialization.py,sha256=npXNsFJ5G7jzBeBIyVMH01Ww34mGY4XWhHpRbSrTtnQ,7598
5
+ fal/_version.py,sha256=1BbTFnucNC_6ldKJ_ZoC722_UkW4S9aDBSW9L0fkKAw,2315
6
+ fal/api.py,sha256=moDNT8wt20uzsI-NTEsbVTpjFXFkSuuRXJx7Apux3SI,46329
7
+ fal/app.py,sha256=S5VHxDaj5J9YVC8ECenHCZJlTHalapHyOyHbCBNsDfs,24153
8
8
  fal/apps.py,sha256=pzCd2mrKl5J_4oVc40_pggvPtFahXBCdrZXWpnaEJVs,12130
9
- fal/config.py,sha256=19Q7fymEkfxCd9AIy8SxhaQaRvb_vKvYAG3AeZAI6uk,3116
9
+ fal/config.py,sha256=BEMH10B2bfWJ9yNawnLG6v3kBLnLmkhMe201EAODzs4,3124
10
10
  fal/container.py,sha256=OvR-Zq-NPbYFHTnw0SBUUFxr890Fgbe68J2kSJEpLOk,1905
11
11
  fal/files.py,sha256=LHJxT4fs2jDs1hH26YoXdq77hUQp4IiaNJ0TE2-RFjo,2773
12
- fal/flags.py,sha256=oWN_eidSUOcE9wdPK_77si3A1fpgOC0UEERPsvNLIMc,842
12
+ fal/flags.py,sha256=48pgtc9xb4LMpR9RE5KG2A2sH7zQRk_VjrgpND-H4Tc,942
13
13
  fal/project.py,sha256=QgfYfMKmNobMPufrAP_ga1FKcIAlSbw18Iar1-0qepo,2650
14
14
  fal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  fal/rest_client.py,sha256=kGBGmuyHfX1lR910EoKCYPjsyU8MdXawT_cW2q8Sajc,568
16
16
  fal/sdk.py,sha256=OvNgoV6ERnFup7ulylBDSohiXQpBa1ycqNuycPZb1-Q,25816
17
17
  fal/sync.py,sha256=ZuIJA2-hTPNANG9B_NNJZUsO68EIdTH0dc9MzeVE2VU,4340
18
- fal/utils.py,sha256=9q_QrQBlQN3nZYA1kEGRfhJWi4RjnO4H1uQswfaei9w,2146
18
+ fal/utils.py,sha256=iQTBG3-i6JZgHkkwbY_I4210g0xoW-as51yrke608u0,2208
19
19
  fal/workflows.py,sha256=Zl4f6Bs085hY40zmqScxDUyCu7zXkukDbW02iYOLTTI,14805
20
- fal/auth/__init__.py,sha256=2tki_o_IaQbaZeCTDAS1wBtrvcAOPRTQMtPSXAqk_Ig,6157
20
+ fal/auth/__init__.py,sha256=2mEKdk6_1GclF3cPC3uWSRKFf0KHNIUNAi0xYRbdJ1A,6278
21
21
  fal/auth/auth0.py,sha256=g5OgEKe4rsbkLQp6l7EauOAVL6WsmKjuA1wmzmyvvhc,5354
22
22
  fal/auth/local.py,sha256=sndkM6vKpeVny6NHTacVlTbiIFqaksOmw0Viqs_RN1U,1790
23
23
  fal/cli/__init__.py,sha256=padK4o0BFqq61kxAA1qQ0jYr2SuhA2mf90B3AaRkmJA,37
@@ -32,11 +32,11 @@ fal/cli/deploy.py,sha256=CWf0Y56w-hNCrht-qrfgiOi9nuvve1Kl5NFZJpt_oRA,7770
32
32
  fal/cli/doctor.py,sha256=U4ne9LX5gQwNblsYQ27XdO8AYDgbYjTO39EtxhwexRM,983
33
33
  fal/cli/files.py,sha256=zOJeRy1W1CsNw0QMxt2vT8Q352phh3l4lZSOLiTQa2w,1968
34
34
  fal/cli/keys.py,sha256=7Sf4DT4le89G42eAOt0ltRjbZAtE70AVQ62hmjZhUy0,3059
35
- fal/cli/main.py,sha256=CNh-i1xL0G2pbYMsk0VUC6qsxBT9rrQuLCIeDSiRuQs,2260
35
+ fal/cli/main.py,sha256=ao8EEV_Fkd7AdN5En6k_dZWp158Et5DrqNRutl98MHY,3273
36
36
  fal/cli/parser.py,sha256=jYsGQ0BLQuKI7KtN1jnLVYKMbLtez7hPjwTNfG3UPSk,2964
37
- fal/cli/profile.py,sha256=9i0pY0Jhm_ziEDdSXgFMGuXUh3Xx3f5S1xBkuuUbH2I,3448
37
+ fal/cli/profile.py,sha256=lYOz0S1kr5DW4_r5pB5cEaCHsUEbiPQFmm8HT6_bx9k,3945
38
38
  fal/cli/run.py,sha256=nAC12Qss4Fg1XmV0qOS9RdGNLYcdoHeRgQMvbTN4P9I,1202
39
- fal/cli/runners.py,sha256=z7WkZZC9rCW2mU5enowVQsxd1W18iBtLNOnPjrzhEf0,3491
39
+ fal/cli/runners.py,sha256=7efNX9vm6D1aBlg0M5-u5plw3HHC41Sj-N7eRNIHnqw,3689
40
40
  fal/cli/secrets.py,sha256=QKSmazu-wiNF6fOpGL9v2TDYxAjX9KTi7ot7vnv6f5E,2474
41
41
  fal/cli/teams.py,sha256=6fR2rKJtiUJPThP7QsO4NLo9UdhUxraGvQZk3_Di6Ow,1218
42
42
  fal/console/__init__.py,sha256=ernZ4bzvvliQh5SmrEqQ7lA5eVcbw6Ra2jalKtA7dxg,132
@@ -72,6 +72,7 @@ fal/toolkit/image/nsfw_filter/model.py,sha256=63mu8D15z_IosoRUagRLGHy6VbLqFmrG-y
72
72
  fal/toolkit/image/nsfw_filter/requirements.txt,sha256=3Pmrd0Ny6QAeBqUNHCgffRyfaCARAPJcfSCX5cRYpbM,37
73
73
  fal/toolkit/utils/__init__.py,sha256=CrmM9DyCz5-SmcTzRSm5RaLgxy3kf0ZsSEN9uhnX2Xo,97
74
74
  fal/toolkit/utils/download_utils.py,sha256=NgOMNs-bQGSg3gWnu123BgZitJgJrvtRexIefTMuylY,19739
75
+ fal/toolkit/utils/endpoint.py,sha256=5EXoshA2PD_brjEfhNWAWasjqLOCRrjBnfhj6QGuMt8,782
75
76
  fal/toolkit/utils/retry.py,sha256=mHcQvvNIpu-Hi29P1HXSZuyvolRd48dMaJToqzlG0NY,1353
76
77
  openapi_fal_rest/__init__.py,sha256=ziculmF_i6trw63LzZGFX-6W3Lwq9mCR8_UpkpvpaHI,152
77
78
  openapi_fal_rest/client.py,sha256=G6BpJg9j7-JsrAUGddYwkzeWRYickBjPdcVgXoPzxuE,2817
@@ -136,8 +137,8 @@ openapi_fal_rest/models/workflow_node_type.py,sha256=-FzyeY2bxcNmizKbJI8joG7byRi
136
137
  openapi_fal_rest/models/workflow_schema.py,sha256=4K5gsv9u9pxx2ItkffoyHeNjBBYf6ur5bN4m_zePZNY,2019
137
138
  openapi_fal_rest/models/workflow_schema_input.py,sha256=2OkOXWHTNsCXHWS6EGDFzcJKkW5FIap-2gfO233EvZQ,1191
138
139
  openapi_fal_rest/models/workflow_schema_output.py,sha256=EblwSPAGfWfYVWw_WSSaBzQVju296is9o28rMBAd0mc,1196
139
- fal-1.15.1.dist-info/METADATA,sha256=kEoBe0iKdW2G8ypAPAjVn78pPkYFxhKy8Ykw14AB5Wo,4084
140
- fal-1.15.1.dist-info/WHEEL,sha256=QZxptf4Y1BKFRCEDxD4h2V0mBFQOVFLFEpvxHmIs52A,91
141
- fal-1.15.1.dist-info/entry_points.txt,sha256=32zwTUC1U1E7nSTIGCoANQOQ3I7-qHG5wI6gsVz5pNU,37
142
- fal-1.15.1.dist-info/top_level.txt,sha256=r257X1L57oJL8_lM0tRrfGuXFwm66i1huwQygbpLmHw,21
143
- fal-1.15.1.dist-info/RECORD,,
140
+ fal-1.16.1.dist-info/METADATA,sha256=KIyDdj36vshtcq463l_DSZU49gm6optvf9wvVqX8-BQ,4084
141
+ fal-1.16.1.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
142
+ fal-1.16.1.dist-info/entry_points.txt,sha256=32zwTUC1U1E7nSTIGCoANQOQ3I7-qHG5wI6gsVz5pNU,37
143
+ fal-1.16.1.dist-info/top_level.txt,sha256=r257X1L57oJL8_lM0tRrfGuXFwm66i1huwQygbpLmHw,21
144
+ fal-1.16.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.6.0)
2
+ Generator: setuptools (80.7.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5