fal 1.19.2__py3-none-any.whl → 1.20.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.19.2'
21
- __version_tuple__ = version_tuple = (1, 19, 2)
20
+ __version__ = version = '1.20.1'
21
+ __version_tuple__ = version_tuple = (1, 20, 1)
fal/api.py CHANGED
@@ -1183,6 +1183,9 @@ class BaseServable:
1183
1183
  app_info.labels(version=self.version).set(1)
1184
1184
 
1185
1185
  app = self._build_app()
1186
+
1187
+ # We use the default workers=1 config because setup function can be heavy
1188
+ # and it runs once per worker.
1186
1189
  server = Server(
1187
1190
  config=Config(app, host="0.0.0.0", port=8080, timeout_keep_alive=300)
1188
1191
  )
fal/cli/files.py CHANGED
@@ -48,11 +48,19 @@ def add_parser(main_subparsers, parents):
48
48
  subparsers = parser.add_subparsers(
49
49
  title="Commands",
50
50
  metavar="command",
51
+ dest="cmd",
51
52
  required=True,
52
53
  parser_class=FalClientParser,
53
54
  )
54
55
 
55
- list_parser = subparsers.add_parser("list", aliases=["ls"], parents=parents)
56
+ list_help = "List files."
57
+ list_parser = subparsers.add_parser(
58
+ "list",
59
+ aliases=["ls"],
60
+ description=list_help,
61
+ help=list_help,
62
+ parents=parents,
63
+ )
56
64
  list_parser.add_argument(
57
65
  "path",
58
66
  nargs="?",
@@ -62,7 +70,13 @@ def add_parser(main_subparsers, parents):
62
70
  )
63
71
  list_parser.set_defaults(func=_list)
64
72
 
65
- download_parser = subparsers.add_parser("download", parents=parents)
73
+ download_help = "Download files."
74
+ download_parser = subparsers.add_parser(
75
+ "download",
76
+ description=download_help,
77
+ help=download_help,
78
+ parents=parents,
79
+ )
66
80
  download_parser.add_argument(
67
81
  "remote_path", type=str, help="Remote path to download"
68
82
  )
@@ -71,12 +85,24 @@ def add_parser(main_subparsers, parents):
71
85
  )
72
86
  download_parser.set_defaults(func=_download)
73
87
 
74
- upload_parser = subparsers.add_parser("upload", parents=parents)
88
+ upload_help = "Upload files."
89
+ upload_parser = subparsers.add_parser(
90
+ "upload",
91
+ description=upload_help,
92
+ help=upload_help,
93
+ parents=parents,
94
+ )
75
95
  upload_parser.add_argument("local_path", type=str, help="Local path to upload")
76
96
  upload_parser.add_argument("remote_path", type=str, help="Remote path to upload to")
77
97
  upload_parser.set_defaults(func=_upload)
78
98
 
79
- upload_url_parser = subparsers.add_parser("upload-url", parents=parents)
99
+ upload_url_help = "Upload file from URL."
100
+ upload_url_parser = subparsers.add_parser(
101
+ "upload-url",
102
+ description=upload_url_help,
103
+ help=upload_url_help,
104
+ parents=parents,
105
+ )
80
106
  upload_url_parser.add_argument("url", type=str, help="URL to upload")
81
107
  upload_url_parser.add_argument(
82
108
  "remote_path", type=str, help="Remote path to upload to"
@@ -9,7 +9,7 @@ from contextlib import contextmanager
9
9
  from dataclasses import dataclass
10
10
  from datetime import datetime, timezone
11
11
  from pathlib import Path
12
- from typing import Generator, Generic, TypeVar
12
+ from typing import Any, Generator, Generic, TypeVar
13
13
  from urllib.error import HTTPError
14
14
  from urllib.parse import urlparse, urlunparse
15
15
  from urllib.request import Request, urlopen
@@ -26,15 +26,46 @@ _FAL_CDN_V3 = "https://v3.fal.media"
26
26
  DEFAULT_REQUEST_TIMEOUT = 10
27
27
  PUT_REQUEST_TIMEOUT = 5 * 60
28
28
 
29
+ MAX_ATTEMPTS = 5
30
+ BASE_DELAY = 0.1
31
+ MAX_DELAY = 30
32
+ RETRY_CODES = [408, 409, 429, 500, 502, 503, 504]
33
+
29
34
 
30
35
  @contextmanager
31
36
  def _urlopen(
32
- request: Request, timeout: int = DEFAULT_REQUEST_TIMEOUT
37
+ request: Request,
38
+ timeout: int = DEFAULT_REQUEST_TIMEOUT,
33
39
  ) -> Generator[addinfourl, None, None]:
34
40
  with urlopen(request, timeout=timeout) as response:
35
41
  yield response
36
42
 
37
43
 
44
+ def _should_retry(exc: Exception) -> bool:
45
+ if isinstance(exc, HTTPError) and exc.code in RETRY_CODES:
46
+ return True
47
+
48
+ return False
49
+
50
+
51
+ @contextmanager
52
+ def _maybe_retry_request(
53
+ request: Request,
54
+ **kwargs: Any,
55
+ ) -> Generator[addinfourl, None, None]:
56
+ _urlopen_with_retry = retry(
57
+ max_retries=MAX_ATTEMPTS,
58
+ base_delay=BASE_DELAY,
59
+ max_delay=MAX_DELAY,
60
+ backoff_type="exponential",
61
+ jitter=True,
62
+ should_retry=_should_retry,
63
+ )(_urlopen)
64
+
65
+ with _urlopen_with_retry(request, **kwargs) as response:
66
+ yield response
67
+
68
+
38
69
  @dataclass
39
70
  class FalV2Token:
40
71
  token: str
@@ -92,7 +123,7 @@ class FalV2TokenManager:
92
123
  data=b"{}",
93
124
  method="POST",
94
125
  )
95
- with _urlopen(req) as response:
126
+ with _maybe_retry_request(req) as response:
96
127
  result = json.load(response)
97
128
 
98
129
  parsed_base_url = urlparse(result["base_url"])
@@ -137,7 +168,6 @@ LIFECYCLE_PREFERENCE: VariableReference[dict[str, str] | None] = VariableReferen
137
168
 
138
169
  @dataclass
139
170
  class FalFileRepositoryBase(FileRepository):
140
- @retry(max_retries=3, base_delay=1, backoff_type="exponential", jitter=True)
141
171
  def _save(
142
172
  self, file: FileData, storage_type: str, headers: dict[str, str] | None = None
143
173
  ) -> str:
@@ -171,7 +201,7 @@ class FalFileRepositoryBase(FileRepository):
171
201
  headers=headers,
172
202
  method="POST",
173
203
  )
174
- with _urlopen(req) as response:
204
+ with _maybe_retry_request(req) as response:
175
205
  result = json.load(response)
176
206
 
177
207
  upload_url = result["upload_url"]
@@ -188,7 +218,7 @@ class FalFileRepositoryBase(FileRepository):
188
218
  headers={"Content-Type": file.content_type},
189
219
  )
190
220
 
191
- with _urlopen(req, timeout=PUT_REQUEST_TIMEOUT):
221
+ with _maybe_retry_request(req, timeout=PUT_REQUEST_TIMEOUT):
192
222
  pass
193
223
 
194
224
  return result["file_url"]
@@ -265,7 +295,7 @@ class MultipartUploadGCS:
265
295
  ).encode(),
266
296
  )
267
297
 
268
- with _urlopen(req) as response:
298
+ with _maybe_retry_request(req) as response:
269
299
  result = json.load(response)
270
300
  self._access_url = result["file_url"]
271
301
  self._upload_url = result["upload_url"]
@@ -275,7 +305,6 @@ class MultipartUploadGCS:
275
305
  f"Error initiating upload. Status {exc.status}: {exc.reason}"
276
306
  )
277
307
 
278
- @retry(max_retries=5, base_delay=1, backoff_type="exponential", jitter=True)
279
308
  def upload_part(self, part_number: int, data: bytes) -> None:
280
309
  initiate_upload_url = self.upload_url + f"/{part_number}"
281
310
  req = Request(
@@ -285,7 +314,7 @@ class MultipartUploadGCS:
285
314
  )
286
315
 
287
316
  try:
288
- with _urlopen(req) as response:
317
+ with _maybe_retry_request(req) as response:
289
318
  result = json.load(response)
290
319
  upload_url = result["upload_url"]
291
320
  except HTTPError as exc:
@@ -301,7 +330,7 @@ class MultipartUploadGCS:
301
330
  )
302
331
 
303
332
  try:
304
- with _urlopen(req, timeout=PUT_REQUEST_TIMEOUT) as resp:
333
+ with _maybe_retry_request(req, timeout=PUT_REQUEST_TIMEOUT) as resp:
305
334
  self._parts.append(
306
335
  {
307
336
  "part_number": part_number,
@@ -331,7 +360,7 @@ class MultipartUploadGCS:
331
360
  }
332
361
  ).encode(),
333
362
  )
334
- with _urlopen(req):
363
+ with _maybe_retry_request(req):
335
364
  pass
336
365
  except HTTPError as e:
337
366
  raise FileUploadException(
@@ -427,7 +456,6 @@ class FalFileRepository(FalFileRepositoryBase):
427
456
  if object_lifecycle_preference:
428
457
  headers["X-Fal-Object-Lifecycle"] = json.dumps(object_lifecycle_preference)
429
458
 
430
- @retry(max_retries=3, base_delay=1, backoff_type="exponential", jitter=True)
431
459
  def save(
432
460
  self,
433
461
  file: FileData,
@@ -536,7 +564,7 @@ class MultipartUpload:
536
564
  }
537
565
  ).encode(),
538
566
  )
539
- with _urlopen(req) as response:
567
+ with _maybe_retry_request(req) as response:
540
568
  result = json.load(response)
541
569
  self._upload_url = result["upload_url"]
542
570
  self._file_url = result["file_url"]
@@ -556,7 +584,7 @@ class MultipartUpload:
556
584
  )
557
585
 
558
586
  try:
559
- with _urlopen(req, timeout=PUT_REQUEST_TIMEOUT) as resp:
587
+ with _maybe_retry_request(req, timeout=PUT_REQUEST_TIMEOUT) as resp:
560
588
  self._parts.append(
561
589
  {
562
590
  "part_number": part_number,
@@ -581,7 +609,7 @@ class MultipartUpload:
581
609
  },
582
610
  data=json.dumps({"parts": self._parts}).encode(),
583
611
  )
584
- with _urlopen(req):
612
+ with _maybe_retry_request(req):
585
613
  pass
586
614
  except HTTPError as e:
587
615
  raise FileUploadException(
@@ -734,7 +762,7 @@ class MultipartUploadV3:
734
762
  ).encode(),
735
763
  )
736
764
 
737
- with _urlopen(req) as response:
765
+ with _maybe_retry_request(req) as response:
738
766
  result = json.load(response)
739
767
  self._access_url = result["file_url"]
740
768
  self._upload_url = result["upload_url"]
@@ -744,7 +772,6 @@ class MultipartUploadV3:
744
772
  f"Error initiating upload. Status {exc.status}: {exc.reason}"
745
773
  )
746
774
 
747
- @retry(max_retries=5, base_delay=1, backoff_type="exponential", jitter=True)
748
775
  def upload_part(self, part_number: int, data: bytes) -> None:
749
776
  parsed = urlparse(self.upload_url)
750
777
  part_path = parsed.path + f"/{part_number}"
@@ -760,7 +787,7 @@ class MultipartUploadV3:
760
787
  )
761
788
 
762
789
  try:
763
- with _urlopen(req, timeout=PUT_REQUEST_TIMEOUT) as resp:
790
+ with _maybe_retry_request(req, timeout=PUT_REQUEST_TIMEOUT) as resp:
764
791
  self._parts.append(
765
792
  {
766
793
  "partNumber": part_number,
@@ -788,7 +815,7 @@ class MultipartUploadV3:
788
815
  },
789
816
  data=json.dumps({"parts": self._parts}).encode(),
790
817
  )
791
- with _urlopen(req):
818
+ with _maybe_retry_request(req):
792
819
  pass
793
820
  except HTTPError as e:
794
821
  raise FileUploadException(
@@ -928,7 +955,7 @@ class InternalMultipartUploadV3:
928
955
  "X-Fal-File-Name": self.file_name,
929
956
  },
930
957
  )
931
- with _urlopen(req) as response:
958
+ with _maybe_retry_request(req) as response:
932
959
  result = json.load(response)
933
960
  self._access_url = result["access_url"]
934
961
  self._upload_id = result["uploadId"]
@@ -938,7 +965,6 @@ class InternalMultipartUploadV3:
938
965
  f"Error initiating upload. Status {exc.status}: {exc.reason}"
939
966
  )
940
967
 
941
- @retry(max_retries=5, base_delay=1, backoff_type="exponential", jitter=True)
942
968
  def upload_part(self, part_number: int, data: bytes) -> None:
943
969
  url = f"{self.access_url}/multipart/{self.upload_id}/{part_number}"
944
970
 
@@ -953,7 +979,7 @@ class InternalMultipartUploadV3:
953
979
  )
954
980
 
955
981
  try:
956
- with _urlopen(req, timeout=PUT_REQUEST_TIMEOUT) as resp:
982
+ with _maybe_retry_request(req, timeout=PUT_REQUEST_TIMEOUT) as resp:
957
983
  self._parts.append(
958
984
  {
959
985
  "partNumber": part_number,
@@ -979,7 +1005,7 @@ class InternalMultipartUploadV3:
979
1005
  },
980
1006
  data=json.dumps({"parts": self._parts}).encode(),
981
1007
  )
982
- with _urlopen(req):
1008
+ with _maybe_retry_request(req):
983
1009
  pass
984
1010
  except HTTPError as e:
985
1011
  raise FileUploadException(
@@ -1067,7 +1093,6 @@ class InternalMultipartUploadV3:
1067
1093
 
1068
1094
  @dataclass
1069
1095
  class FalFileRepositoryV2(FalFileRepositoryBase):
1070
- @retry(max_retries=3, base_delay=1, backoff_type="exponential", jitter=True)
1071
1096
  def save(
1072
1097
  self,
1073
1098
  file: FileData,
@@ -1105,7 +1130,7 @@ class FalFileRepositoryV2(FalFileRepositoryBase):
1105
1130
  headers=headers,
1106
1131
  method="PUT",
1107
1132
  )
1108
- with _urlopen(req, timeout=PUT_REQUEST_TIMEOUT) as response:
1133
+ with _maybe_retry_request(req, timeout=PUT_REQUEST_TIMEOUT) as response:
1109
1134
  result = json.load(response)
1110
1135
 
1111
1136
  return result["file_url"]
@@ -1177,7 +1202,6 @@ class FalCDNFileRepository(FileRepository):
1177
1202
  object_lifecycle_preference
1178
1203
  )
1179
1204
 
1180
- @retry(max_retries=3, base_delay=1, backoff_type="exponential", jitter=True)
1181
1205
  def save(
1182
1206
  self,
1183
1207
  file: FileData,
@@ -1199,7 +1223,7 @@ class FalCDNFileRepository(FileRepository):
1199
1223
  url = os.getenv("FAL_CDN_HOST", _FAL_CDN) + "/files/upload"
1200
1224
  request = Request(url, headers=headers, method="POST", data=file.data)
1201
1225
  try:
1202
- with _urlopen(request) as response:
1226
+ with _maybe_retry_request(request) as response:
1203
1227
  result = json.load(response)
1204
1228
  except HTTPError as e:
1205
1229
  raise FileUploadException(
@@ -1236,7 +1260,6 @@ class FalFileRepositoryV3(FileRepository):
1236
1260
  "User-Agent": "fal/0.1.0",
1237
1261
  }
1238
1262
 
1239
- @retry(max_retries=3, base_delay=1, backoff_type="exponential", jitter=True)
1240
1263
  def save(
1241
1264
  self,
1242
1265
  file: FileData,
@@ -1279,7 +1302,7 @@ class FalFileRepositoryV3(FileRepository):
1279
1302
  ).encode(),
1280
1303
  )
1281
1304
  try:
1282
- with _urlopen(request) as response:
1305
+ with _maybe_retry_request(request) as response:
1283
1306
  result = json.load(response)
1284
1307
  file_url = result["file_url"]
1285
1308
  upload_url = result["upload_url"]
@@ -1295,7 +1318,7 @@ class FalFileRepositoryV3(FileRepository):
1295
1318
  data=file.data,
1296
1319
  )
1297
1320
  try:
1298
- with _urlopen(request, timeout=PUT_REQUEST_TIMEOUT):
1321
+ with _maybe_retry_request(request, timeout=PUT_REQUEST_TIMEOUT):
1299
1322
  pass
1300
1323
  except HTTPError as e:
1301
1324
  raise FileUploadException(
@@ -1358,7 +1381,6 @@ class InternalFalFileRepositoryV3(FileRepository):
1358
1381
  if object_lifecycle_preference:
1359
1382
  headers["X-Fal-Object-Lifecycle"] = json.dumps(object_lifecycle_preference)
1360
1383
 
1361
- @retry(max_retries=3, base_delay=1, backoff_type="exponential", jitter=True)
1362
1384
  def save(
1363
1385
  self,
1364
1386
  file: FileData,
@@ -1393,7 +1415,7 @@ class InternalFalFileRepositoryV3(FileRepository):
1393
1415
  url = os.getenv("FAL_CDN_V3_HOST", _FAL_CDN_V3) + "/files/upload"
1394
1416
  request = Request(url, headers=headers, method="POST", data=file.data)
1395
1417
  try:
1396
- with _urlopen(request) as response:
1418
+ with _maybe_retry_request(request) as response:
1397
1419
  result = json.load(response)
1398
1420
  except HTTPError as e:
1399
1421
  raise FileUploadException(
@@ -2,7 +2,7 @@ import functools
2
2
  import random
3
3
  import time
4
4
  import traceback
5
- from typing import Any, Callable, Literal
5
+ from typing import Any, Callable, Literal, Optional
6
6
 
7
7
  BackoffType = Literal["exponential", "fixed"]
8
8
 
@@ -13,6 +13,7 @@ def retry(
13
13
  max_delay: float = 60.0,
14
14
  backoff_type: BackoffType = "exponential",
15
15
  jitter: bool = False,
16
+ should_retry: Optional[Callable[[Exception], bool]] = None,
16
17
  ) -> Callable:
17
18
  def decorator(func: Callable) -> Callable:
18
19
  @functools.wraps(func)
@@ -22,6 +23,9 @@ def retry(
22
23
  try:
23
24
  return func(*args, **kwargs)
24
25
  except Exception as e:
26
+ if should_retry is not None and not should_retry(e):
27
+ raise
28
+
25
29
  retries += 1
26
30
  print(f"Retrying {retries} of {max_retries}...")
27
31
  if retries == max_retries:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fal
3
- Version: 1.19.2
3
+ Version: 1.20.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,9 +1,9 @@
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=lOkMpxEMF6MuTuk4IHw6fbD9GVcMBZ3mwFzM45QwTSY,513
3
+ fal/_fal_version.py,sha256=TOsa2f3CpFu7MvtteZ8unn1Fm7CcduyKVyG9QWXEcj8,513
4
4
  fal/_serialization.py,sha256=npXNsFJ5G7jzBeBIyVMH01Ww34mGY4XWhHpRbSrTtnQ,7598
5
5
  fal/_version.py,sha256=1BbTFnucNC_6ldKJ_ZoC722_UkW4S9aDBSW9L0fkKAw,2315
6
- fal/api.py,sha256=moDNT8wt20uzsI-NTEsbVTpjFXFkSuuRXJx7Apux3SI,46329
6
+ fal/api.py,sha256=_TaUcdTUNz5GnjGd3On1FeDSJ0zVJwZQZqAMn3_Yddw,46451
7
7
  fal/app.py,sha256=S5VHxDaj5J9YVC8ECenHCZJlTHalapHyOyHbCBNsDfs,24153
8
8
  fal/apps.py,sha256=pzCd2mrKl5J_4oVc40_pggvPtFahXBCdrZXWpnaEJVs,12130
9
9
  fal/config.py,sha256=BEMH10B2bfWJ9yNawnLG6v3kBLnLmkhMe201EAODzs4,3124
@@ -30,7 +30,7 @@ fal/cli/create.py,sha256=a8WDq-nJLFTeoIXqpb5cr7GR7YR9ZZrQCawNm34KXXE,627
30
30
  fal/cli/debug.py,sha256=u_urnyFzSlNnrq93zz_GXE9FX4VyVxDoamJJyrZpFI0,1312
31
31
  fal/cli/deploy.py,sha256=CWf0Y56w-hNCrht-qrfgiOi9nuvve1Kl5NFZJpt_oRA,7770
32
32
  fal/cli/doctor.py,sha256=U4ne9LX5gQwNblsYQ27XdO8AYDgbYjTO39EtxhwexRM,983
33
- fal/cli/files.py,sha256=DnCVWUFmdxVU-ADIAOjG8mFcnc7xjOTuliFJHNYJZzo,2424
33
+ fal/cli/files.py,sha256=pSgAnTm2eHdP-IPkMIVfnK_Ii7mkSSOVgvbsiFUVBC0,2936
34
34
  fal/cli/keys.py,sha256=7Sf4DT4le89G42eAOt0ltRjbZAtE70AVQ62hmjZhUy0,3059
35
35
  fal/cli/main.py,sha256=ao8EEV_Fkd7AdN5En6k_dZWp158Et5DrqNRutl98MHY,3273
36
36
  fal/cli/parser.py,sha256=jYsGQ0BLQuKI7KtN1jnLVYKMbLtez7hPjwTNfG3UPSk,2964
@@ -60,7 +60,7 @@ fal/toolkit/audio/audio.py,sha256=_o5zCqBOppmX6_N_vtDkiW6e35XklOMvW71ELo6gfEE,34
60
60
  fal/toolkit/file/__init__.py,sha256=FbNl6wD-P0aSSTUwzHt4HujBXrbC3ABmaigPQA4hRfg,70
61
61
  fal/toolkit/file/file.py,sha256=QITEtOyevDVOjv9iwUEWId7edQ6EBx6Uz6CgqWWJJ-U,9568
62
62
  fal/toolkit/file/types.py,sha256=MMAH_AyLOhowQPesOv1V25wB4qgbJ3vYNlnTPbdSv1M,2304
63
- fal/toolkit/file/providers/fal.py,sha256=cbND8tjEJvKklrmYgrjr6RtAcVLJIQ9VwhBhNCqgKc8,46992
63
+ fal/toolkit/file/providers/fal.py,sha256=vt4Mznbfca6blfk0psF1ix-zB6309kpIA0_5Qh7bmFw,47217
64
64
  fal/toolkit/file/providers/gcp.py,sha256=DKeZpm1MjwbvEsYvkdXUtuLIJDr_UNbqXj_Mfv3NTeo,2437
65
65
  fal/toolkit/file/providers/r2.py,sha256=YqnYkkAo_ZKIa-xoSuDnnidUFwJWHdziAR34PE6irdI,3061
66
66
  fal/toolkit/file/providers/s3.py,sha256=EI45T54Mox7lHZKROss_O8o0DIn3CHP9k1iaNYVrxvg,2714
@@ -75,7 +75,7 @@ fal/toolkit/image/nsfw_filter/requirements.txt,sha256=3Pmrd0Ny6QAeBqUNHCgffRyfaC
75
75
  fal/toolkit/utils/__init__.py,sha256=CrmM9DyCz5-SmcTzRSm5RaLgxy3kf0ZsSEN9uhnX2Xo,97
76
76
  fal/toolkit/utils/download_utils.py,sha256=IIb8eLsoFg4Gy-2N0M4trnxFUF75f1pWtjOX_50vRNM,19983
77
77
  fal/toolkit/utils/endpoint.py,sha256=5EXoshA2PD_brjEfhNWAWasjqLOCRrjBnfhj6QGuMt8,782
78
- fal/toolkit/utils/retry.py,sha256=mHcQvvNIpu-Hi29P1HXSZuyvolRd48dMaJToqzlG0NY,1353
78
+ fal/toolkit/utils/retry.py,sha256=0pnKqs1Y2dADMAk2944FZr68ZL3wQC_5hqApfgyMf_8,1531
79
79
  fal/toolkit/video/__init__.py,sha256=YV0jWpuvoA_CDFQXhd3zOvilFLKH7DYARrbzR7hWhpE,35
80
80
  fal/toolkit/video/video.py,sha256=U2hIIaIKCB_ZStYgQjpMTNrVONklq6fcqj-IT9jA7nE,344
81
81
  openapi_fal_rest/__init__.py,sha256=ziculmF_i6trw63LzZGFX-6W3Lwq9mCR8_UpkpvpaHI,152
@@ -141,8 +141,8 @@ openapi_fal_rest/models/workflow_node_type.py,sha256=-FzyeY2bxcNmizKbJI8joG7byRi
141
141
  openapi_fal_rest/models/workflow_schema.py,sha256=4K5gsv9u9pxx2ItkffoyHeNjBBYf6ur5bN4m_zePZNY,2019
142
142
  openapi_fal_rest/models/workflow_schema_input.py,sha256=2OkOXWHTNsCXHWS6EGDFzcJKkW5FIap-2gfO233EvZQ,1191
143
143
  openapi_fal_rest/models/workflow_schema_output.py,sha256=EblwSPAGfWfYVWw_WSSaBzQVju296is9o28rMBAd0mc,1196
144
- fal-1.19.2.dist-info/METADATA,sha256=dlSJr_jIsRzpHdOPNuwn7vW9VesVA8Jx-d437ZSv22k,4085
145
- fal-1.19.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
146
- fal-1.19.2.dist-info/entry_points.txt,sha256=32zwTUC1U1E7nSTIGCoANQOQ3I7-qHG5wI6gsVz5pNU,37
147
- fal-1.19.2.dist-info/top_level.txt,sha256=r257X1L57oJL8_lM0tRrfGuXFwm66i1huwQygbpLmHw,21
148
- fal-1.19.2.dist-info/RECORD,,
144
+ fal-1.20.1.dist-info/METADATA,sha256=wIvviHSTRAlZps2vuoaqrOMhMc9fu0LxQg6izAEAcrM,4085
145
+ fal-1.20.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
146
+ fal-1.20.1.dist-info/entry_points.txt,sha256=32zwTUC1U1E7nSTIGCoANQOQ3I7-qHG5wI6gsVz5pNU,37
147
+ fal-1.20.1.dist-info/top_level.txt,sha256=r257X1L57oJL8_lM0tRrfGuXFwm66i1huwQygbpLmHw,21
148
+ fal-1.20.1.dist-info/RECORD,,
File without changes