fal 1.4.1__py3-none-any.whl → 1.5.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
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '1.4.1'
16
- __version_tuple__ = version_tuple = (1, 4, 1)
15
+ __version__ = version = '1.5.1'
16
+ __version_tuple__ = version_tuple = (1, 5, 1)
fal/api.py CHANGED
@@ -397,6 +397,7 @@ class FalServerlessHost(Host):
397
397
  "max_multiplexing",
398
398
  "setup_function",
399
399
  "metadata",
400
+ "request_timeout",
400
401
  "_base_image",
401
402
  "_scheduler",
402
403
  "_scheduler_options",
@@ -444,6 +445,7 @@ class FalServerlessHost(Host):
444
445
  scheduler = options.host.get("_scheduler", None)
445
446
  scheduler_options = options.host.get("_scheduler_options", None)
446
447
  exposed_port = options.get_exposed_port()
448
+ request_timeout = options.host.get("request_timeout")
447
449
 
448
450
  machine_requirements = MachineRequirements(
449
451
  machine_types=machine_type, # type: ignore
@@ -456,6 +458,7 @@ class FalServerlessHost(Host):
456
458
  max_multiplexing=max_multiplexing,
457
459
  max_concurrency=max_concurrency,
458
460
  min_concurrency=min_concurrency,
461
+ request_timeout=request_timeout,
459
462
  )
460
463
 
461
464
  partial_func = _prepare_partial_func(func)
@@ -516,6 +519,7 @@ class FalServerlessHost(Host):
516
519
  scheduler_options = options.host.get("_scheduler_options", None)
517
520
  exposed_port = options.get_exposed_port()
518
521
  setup_function = options.host.get("setup_function", None)
522
+ request_timeout = options.host.get("request_timeout")
519
523
 
520
524
  machine_requirements = MachineRequirements(
521
525
  machine_types=machine_type, # type: ignore
@@ -528,6 +532,7 @@ class FalServerlessHost(Host):
528
532
  max_multiplexing=max_multiplexing,
529
533
  max_concurrency=max_concurrency,
530
534
  min_concurrency=min_concurrency,
535
+ request_timeout=request_timeout,
531
536
  )
532
537
 
533
538
  return_value = _UNSET
@@ -693,6 +698,7 @@ def function(
693
698
  keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
694
699
  max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
695
700
  min_concurrency: int = FAL_SERVERLESS_DEFAULT_MIN_CONCURRENCY,
701
+ request_timeout: int | None = None,
696
702
  setup_function: Callable[..., None] | None = None,
697
703
  _base_image: str | None = None,
698
704
  _scheduler: str | None = None,
@@ -719,6 +725,7 @@ def function(
719
725
  keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
720
726
  max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
721
727
  min_concurrency: int = FAL_SERVERLESS_DEFAULT_MIN_CONCURRENCY,
728
+ request_timeout: int | None = None,
722
729
  setup_function: Callable[..., None] | None = None,
723
730
  _base_image: str | None = None,
724
731
  _scheduler: str | None = None,
@@ -795,6 +802,7 @@ def function(
795
802
  keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
796
803
  max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
797
804
  min_concurrency: int = FAL_SERVERLESS_DEFAULT_MIN_CONCURRENCY,
805
+ request_timeout: int | None = None,
798
806
  setup_function: Callable[..., None] | None = None,
799
807
  _base_image: str | None = None,
800
808
  _scheduler: str | None = None,
@@ -826,6 +834,7 @@ def function(
826
834
  keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
827
835
  max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
828
836
  min_concurrency: int = FAL_SERVERLESS_DEFAULT_MIN_CONCURRENCY,
837
+ request_timeout: int | None = None,
829
838
  setup_function: Callable[..., None] | None = None,
830
839
  _base_image: str | None = None,
831
840
  _scheduler: str | None = None,
@@ -851,6 +860,7 @@ def function(
851
860
  keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
852
861
  max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
853
862
  min_concurrency: int = FAL_SERVERLESS_DEFAULT_MIN_CONCURRENCY,
863
+ request_timeout: int | None = None,
854
864
  setup_function: Callable[..., None] | None = None,
855
865
  _base_image: str | None = None,
856
866
  _scheduler: str | None = None,
@@ -876,6 +886,7 @@ def function(
876
886
  keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
877
887
  max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
878
888
  min_concurrency: int = FAL_SERVERLESS_DEFAULT_MIN_CONCURRENCY,
889
+ request_timeout: int | None = None,
879
890
  setup_function: Callable[..., None] | None = None,
880
891
  _base_image: str | None = None,
881
892
  _scheduler: str | None = None,
@@ -960,6 +971,8 @@ class RouteSignature(NamedTuple):
960
971
 
961
972
 
962
973
  class BaseServable:
974
+ version: ClassVar[str] = "unknown"
975
+
963
976
  def collect_routes(self) -> dict[RouteSignature, Callable[..., Any]]:
964
977
  raise NotImplementedError
965
978
 
@@ -1088,9 +1101,14 @@ class BaseServable:
1088
1101
  def serve(self) -> None:
1089
1102
  import asyncio
1090
1103
 
1104
+ from prometheus_client import Gauge
1091
1105
  from starlette_exporter import handle_metrics
1092
1106
  from uvicorn import Config
1093
1107
 
1108
+ # NOTE: this uses the global prometheus registry
1109
+ app_info = Gauge("fal_app_info", "Fal application information", ["version"])
1110
+ app_info.labels(version=self.version).set(1)
1111
+
1094
1112
  app = self._build_app()
1095
1113
  server = Server(
1096
1114
  config=Config(app, host="0.0.0.0", port=8080, timeout_keep_alive=300)
fal/app.py CHANGED
@@ -189,11 +189,16 @@ class App(fal.api.BaseServable):
189
189
  }
190
190
  app_name: ClassVar[str]
191
191
  app_auth: ClassVar[Literal["private", "public", "shared"]] = "private"
192
+ request_timeout: ClassVar[int | None] = None
192
193
 
193
194
  def __init_subclass__(cls, **kwargs):
194
195
  app_name = kwargs.pop("name", None) or _to_fal_app_name(cls.__name__)
195
196
  parent_settings = getattr(cls, "host_kwargs", {})
196
197
  cls.host_kwargs = {**parent_settings, **kwargs}
198
+
199
+ if cls.request_timeout is not None:
200
+ cls.host_kwargs["request_timeout"] = cls.request_timeout
201
+
197
202
  cls.app_name = getattr(cls, "app_name", app_name)
198
203
 
199
204
  if cls.__init__ is not App.__init__:
@@ -232,7 +237,7 @@ class App(fal.api.BaseServable):
232
237
  await _call_any_fn(self.teardown)
233
238
 
234
239
  def health(self):
235
- return {}
240
+ return {"version": self.version}
236
241
 
237
242
  def setup(self):
238
243
  """Setup the application before serving."""
fal/cli/_utils.py CHANGED
@@ -34,5 +34,6 @@ def get_app_data_from_toml(app_name):
34
34
  app_ref = str(project_root / app_ref)
35
35
 
36
36
  app_auth = app_data.get("auth", "private")
37
+ app_deployment_strategy = app_data.get("deployment_strategy", "recreate")
37
38
 
38
- return app_ref, app_auth
39
+ return app_ref, app_auth, app_deployment_strategy
fal/cli/deploy.py CHANGED
@@ -65,8 +65,9 @@ def _get_user() -> User:
65
65
  def _deploy_from_reference(
66
66
  app_ref: Tuple[Optional[Union[Path, str]], ...],
67
67
  app_name: str,
68
- auth: Literal["public", "shared", "private"],
69
68
  args,
69
+ auth: Optional[Literal["public", "shared", "private"]] = None,
70
+ deployment_strategy: Optional[Literal["recreate", "rolling"]] = None,
70
71
  ):
71
72
  from fal.api import FalServerlessError, FalServerlessHost
72
73
  from fal.utils import load_function_from
@@ -96,7 +97,7 @@ def _deploy_from_reference(
96
97
  isolated_function = loaded.function
97
98
  app_name = app_name or loaded.app_name # type: ignore
98
99
  app_auth = auth or loaded.app_auth or "private"
99
- deployment_strategy = args.strategy or "recreate"
100
+ deployment_strategy = deployment_strategy or "recreate"
100
101
 
101
102
  app_id = host.register(
102
103
  func=isolated_function.func,
@@ -137,7 +138,7 @@ def _deploy(args):
137
138
  raise ValueError("Cannot use --app-name or --auth with app name reference.")
138
139
 
139
140
  app_name = args.app_ref[0]
140
- app_ref, app_auth = get_app_data_from_toml(app_name)
141
+ app_ref, app_auth, app_deployment_strategy = get_app_data_from_toml(app_name)
141
142
  file_path, func_name = RefAction.split_ref(app_ref)
142
143
 
143
144
  # path/to/myfile.py::MyApp
@@ -145,8 +146,15 @@ def _deploy(args):
145
146
  file_path, func_name = args.app_ref
146
147
  app_name = args.app_name
147
148
  app_auth = args.auth
148
-
149
- _deploy_from_reference((file_path, func_name), app_name, app_auth, args)
149
+ app_deployment_strategy = args.strategy
150
+
151
+ _deploy_from_reference(
152
+ (file_path, func_name),
153
+ app_name,
154
+ args,
155
+ app_auth,
156
+ app_deployment_strategy,
157
+ )
150
158
 
151
159
 
152
160
  def add_parser(main_subparsers, parents):
fal/cli/run.py CHANGED
@@ -10,7 +10,7 @@ def _run(args):
10
10
 
11
11
  if is_app_name(args.func_ref):
12
12
  app_name = args.func_ref[0]
13
- app_ref, _ = get_app_data_from_toml(app_name)
13
+ app_ref, _, _ = get_app_data_from_toml(app_name)
14
14
  file_path, func_name = RefAction.split_ref(app_ref)
15
15
  else:
16
16
  file_path, func_name = args.func_ref
fal/sdk.py CHANGED
@@ -399,6 +399,7 @@ class MachineRequirements:
399
399
  max_concurrency: int | None = None
400
400
  max_multiplexing: int | None = None
401
401
  min_concurrency: int | None = None
402
+ request_timeout: int | None = None
402
403
 
403
404
  def __post_init__(self):
404
405
  if isinstance(self.machine_types, str):
@@ -514,6 +515,7 @@ class FalServerlessConnection:
514
515
  max_concurrency=machine_requirements.max_concurrency,
515
516
  min_concurrency=machine_requirements.min_concurrency,
516
517
  max_multiplexing=machine_requirements.max_multiplexing,
518
+ request_timeout=machine_requirements.request_timeout,
517
519
  )
518
520
  else:
519
521
  wrapped_requirements = None
@@ -607,6 +609,7 @@ class FalServerlessConnection:
607
609
  max_concurrency=machine_requirements.max_concurrency,
608
610
  max_multiplexing=machine_requirements.max_multiplexing,
609
611
  min_concurrency=machine_requirements.min_concurrency,
612
+ request_timeout=machine_requirements.request_timeout,
610
613
  )
611
614
  else:
612
615
  wrapped_requirements = None
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fal
3
- Version: 1.4.1
3
+ Version: 1.5.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
7
7
  Description-Content-Type: text/markdown
8
8
  Requires-Dist: isolate[build]<1.14.0,>=0.13.0
9
- Requires-Dist: isolate-proto==0.5.3
9
+ Requires-Dist: isolate-proto==0.5.4
10
10
  Requires-Dist: grpcio==1.64.0
11
11
  Requires-Dist: dill==0.3.7
12
12
  Requires-Dist: cloudpickle==3.0.0
@@ -1,17 +1,17 @@
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=oFZsPxoSsCY6D2DiWMSueNvMDRRQN5ssWrPdQtlLJ_o,411
3
+ fal/_fal_version.py,sha256=W6YuN1JOd6M-rSt9HDXK91AutRDYXTjJT_LQg3rCsjk,411
4
4
  fal/_serialization.py,sha256=rD2YiSa8iuzCaZohZwN_MPEB-PpSKbWRDeaIDpTEjyY,7653
5
5
  fal/_version.py,sha256=EBGqrknaf1WygENX-H4fBefLvHryvJBBGtVJetaB0NY,266
6
- fal/api.py,sha256=EuHMoWJ-LUP46moTQCXoBlzXlXCfdb0YQR7zsM694jQ,42513
7
- fal/app.py,sha256=asJmz8gavn05s_gKXesosafw3F23zMuPUS50BX2HjI4,17712
6
+ fal/api.py,sha256=wmXywHvkdKe0AlsPmXt8_nidPhoC_Ho4BrUi7In4Hek,43278
7
+ fal/app.py,sha256=kzjHA325RDwUl-_9lTaL77L-DD1Lh-KEZFuJLPkOC9U,17899
8
8
  fal/apps.py,sha256=lge7-HITzI20l1oXdlkAzqxdMVtXRfnACIylKRWgCNQ,7151
9
9
  fal/container.py,sha256=V7riyyq8AZGwEX9QaqRQDZyDN_bUKeRKV1OOZArXjL0,622
10
10
  fal/files.py,sha256=QgfYfMKmNobMPufrAP_ga1FKcIAlSbw18Iar1-0qepo,2650
11
11
  fal/flags.py,sha256=oWN_eidSUOcE9wdPK_77si3A1fpgOC0UEERPsvNLIMc,842
12
12
  fal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  fal/rest_client.py,sha256=kGBGmuyHfX1lR910EoKCYPjsyU8MdXawT_cW2q8Sajc,568
14
- fal/sdk.py,sha256=Ve9X3WeoRBrAqP-HnJ7hdwmQzXYGU32wJMN3QPDw4yA,22081
14
+ fal/sdk.py,sha256=-I-vjO-PuvtnZedFLKys8FpQVsRwEzTPD6heRYPQCE4,22260
15
15
  fal/sync.py,sha256=ZuIJA2-hTPNANG9B_NNJZUsO68EIdTH0dc9MzeVE2VU,4340
16
16
  fal/utils.py,sha256=9q_QrQBlQN3nZYA1kEGRfhJWi4RjnO4H1uQswfaei9w,2146
17
17
  fal/workflows.py,sha256=jx3tGy2R7cN6lLvOzT6lhhlcjmiq64iZls2smVrmQj0,14657
@@ -19,17 +19,17 @@ fal/auth/__init__.py,sha256=r8iA2-5ih7-Fik3gEC4HEWNFbGoxpYnXpZu1icPIoS0,3561
19
19
  fal/auth/auth0.py,sha256=rSG1mgH-QGyKfzd7XyAaj1AYsWt-ho8Y_LZ-FUVWzh4,5421
20
20
  fal/auth/local.py,sha256=sndkM6vKpeVny6NHTacVlTbiIFqaksOmw0Viqs_RN1U,1790
21
21
  fal/cli/__init__.py,sha256=padK4o0BFqq61kxAA1qQ0jYr2SuhA2mf90B3AaRkmJA,37
22
- fal/cli/_utils.py,sha256=Fxq-tmYIgNDYwWtL7vMmJVDQn7Y2kA_ePmss48FPelo,1084
22
+ fal/cli/_utils.py,sha256=u__PSeNxSC_4Psi3ZwLjefgNQVkYRpVH--vmwK7ppro,1187
23
23
  fal/cli/apps.py,sha256=-DDp-Gvxz5kHho5YjAhbri8vOny_9cftAI_wP2KR5nU,8175
24
24
  fal/cli/auth.py,sha256=--MhfHGwxmtHbRkGioyn1prKn_U-pBzbz0G_QeZou-U,1352
25
25
  fal/cli/create.py,sha256=a8WDq-nJLFTeoIXqpb5cr7GR7YR9ZZrQCawNm34KXXE,627
26
26
  fal/cli/debug.py,sha256=u_urnyFzSlNnrq93zz_GXE9FX4VyVxDoamJJyrZpFI0,1312
27
- fal/cli/deploy.py,sha256=8iVTpkQPvKHGHEaxZLnCTftRSC0MuZYC94Xf-qG27p0,6857
27
+ fal/cli/deploy.py,sha256=uAMBMXpv3kYNJ3zeIWBL6xf83NpxvvPKOjeE95dOG5o,7099
28
28
  fal/cli/doctor.py,sha256=U4ne9LX5gQwNblsYQ27XdO8AYDgbYjTO39EtxhwexRM,983
29
29
  fal/cli/keys.py,sha256=trDpA3LJu9S27qE_K8Hr6fKLK4vwVzbxUHq8TFrV4pw,3157
30
30
  fal/cli/main.py,sha256=_Wh_DQc02qwh-ZN7v41lZm0lDR1WseViXVOcqUlyWLg,2009
31
31
  fal/cli/parser.py,sha256=edCqFWYAQSOhrxeEK9BtFRlTEUAlG2JUDjS_vhZ_nHE,2868
32
- fal/cli/run.py,sha256=uscbLBfTe8-UAbqh8h1iWuGD_G9UNNrj3k8bF5rtzy4,1201
32
+ fal/cli/run.py,sha256=J1lSZ_wJIhrygSduMr0Wf2pQ8OUJlFbyH5KKUjxDF6w,1204
33
33
  fal/cli/secrets.py,sha256=740msFm7d41HruudlcfqUXlFl53N-WmChsQP9B9M9Po,2572
34
34
  fal/console/__init__.py,sha256=ernZ4bzvvliQh5SmrEqQ7lA5eVcbw6Ra2jalKtA7dxg,132
35
35
  fal/console/icons.py,sha256=De9MfFaSkO2Lqfne13n3PrYfTXJVIzYZVqYn5BWsdrA,108
@@ -126,8 +126,8 @@ openapi_fal_rest/models/workflow_node_type.py,sha256=-FzyeY2bxcNmizKbJI8joG7byRi
126
126
  openapi_fal_rest/models/workflow_schema.py,sha256=4K5gsv9u9pxx2ItkffoyHeNjBBYf6ur5bN4m_zePZNY,2019
127
127
  openapi_fal_rest/models/workflow_schema_input.py,sha256=2OkOXWHTNsCXHWS6EGDFzcJKkW5FIap-2gfO233EvZQ,1191
128
128
  openapi_fal_rest/models/workflow_schema_output.py,sha256=EblwSPAGfWfYVWw_WSSaBzQVju296is9o28rMBAd0mc,1196
129
- fal-1.4.1.dist-info/METADATA,sha256=2ZAk-oh2yPEg9Ib638qsxPKm8HXkDtWJNRSq_mSNTwI,3787
130
- fal-1.4.1.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
131
- fal-1.4.1.dist-info/entry_points.txt,sha256=32zwTUC1U1E7nSTIGCoANQOQ3I7-qHG5wI6gsVz5pNU,37
132
- fal-1.4.1.dist-info/top_level.txt,sha256=r257X1L57oJL8_lM0tRrfGuXFwm66i1huwQygbpLmHw,21
133
- fal-1.4.1.dist-info/RECORD,,
129
+ fal-1.5.1.dist-info/METADATA,sha256=sQTFRl_qxwkO_g6moEVwRL4LRCSyrvkpuD_AHbUhwFI,3787
130
+ fal-1.5.1.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
131
+ fal-1.5.1.dist-info/entry_points.txt,sha256=32zwTUC1U1E7nSTIGCoANQOQ3I7-qHG5wI6gsVz5pNU,37
132
+ fal-1.5.1.dist-info/top_level.txt,sha256=r257X1L57oJL8_lM0tRrfGuXFwm66i1huwQygbpLmHw,21
133
+ fal-1.5.1.dist-info/RECORD,,
File without changes