fal 0.11.3__tar.gz → 0.11.5__tar.gz
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-0.11.3 → fal-0.11.5}/PKG-INFO +1 -1
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/__init__.py +3 -1
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/grouped_usage_detail.py +6 -6
- {fal-0.11.3 → fal-0.11.5}/pyproject.toml +1 -1
- {fal-0.11.3 → fal-0.11.5}/setup.py +1 -1
- {fal-0.11.3 → fal-0.11.5}/src/fal/__init__.py +2 -28
- {fal-0.11.3 → fal-0.11.5}/src/fal/api.py +5 -1
- fal-0.11.5/src/fal/app.py +162 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/cli.py +34 -42
- {fal-0.11.3 → fal-0.11.5}/src/fal/exceptions/_base.py +1 -1
- {fal-0.11.3 → fal-0.11.5}/src/fal/exceptions/auth.py +1 -1
- {fal-0.11.3 → fal-0.11.5}/README.md +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/admin/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/admin/get_usage_per_user.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/admin/handle_user_lock.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/applications/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/applications/get_status_applications_app_user_id_app_alias_or_id_status_get.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/delete_payment_method.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/get_setup_intent_key.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_details.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_invoices.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_payment_methods.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_price.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_spending.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/handle_stripe_webhook.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/upcoming_invoice.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/update_customer_budget.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/files/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/files/check_dir_hash.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/files/delete.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/files/download.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/files/file_exists.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/files/list_directory.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/files/list_root.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/files/upload_from_url.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/files/upload_local_file.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/health/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/health/check.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/keys/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/keys/create_key.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/keys/delete_key.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/keys/list_keys.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/logs/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/logs/list_since.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/requests/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/requests/requests.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/storage/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/storage/get_file_link.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/storage/initiate_upload.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/storage/upload_file.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/tokens/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/tokens/create_token.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/usage/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/usage/get_custom_usage_per_machine.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/usage/get_gateway_request_stats.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/usage/get_gateway_request_stats_by_time.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/usage/get_shared_usage_per_app.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/usage/get_usage_records.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/usage/per_machine_usage.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/usage/per_machine_usage_details.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/client.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/errors.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/app_metadata_response_app_metadata.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/body_create_token.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/body_upload_file.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/customer_details.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/file_spec.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/gateway_stats_by_time.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/gateway_usage_stats.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/get_gateway_request_stats_by_time_response_get_gateway_request_stats_by_time.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/handle_stripe_webhook_response_handle_stripe_webhook.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/hash_check.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/http_validation_error.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/initiate_upload_info.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/invoice.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/invoice_item.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/key_scope.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/log_entry.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/log_entry_labels.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/new_user_key.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/payment_method.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/persisted_usage_record.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/persisted_usage_record_meta.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/presigned_upload_url.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/request_io.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/request_io_json_input.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/request_io_json_output.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/run_type.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/stats_timeframe.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/status.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/status_health.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/uploaded_file_result.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/url_file_upload.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/usage_per_machine_type.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/usage_per_user.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/usage_run_detail.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/user_key_info.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/validation_error.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/py.typed +0 -0
- {fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/types.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/_serialization.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/apps.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/auth/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/auth/auth0.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/auth/local.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/console/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/console/icons.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/console/ux.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/env.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/exceptions/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/exceptions/handlers.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/flags.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/logging/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/logging/datadog.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/logging/isolate.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/logging/style.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/logging/trace.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/logging/user.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/rest_client.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/sdk.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/sync.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/toolkit/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/toolkit/exceptions.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/toolkit/file/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/toolkit/file/file.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/toolkit/file/providers/fal.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/toolkit/file/providers/gcp.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/toolkit/file/providers/r2.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/toolkit/file/types.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/toolkit/image/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/toolkit/image/image.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/toolkit/mainify.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/toolkit/utils/__init__.py +0 -0
- {fal-0.11.3 → fal-0.11.5}/src/fal/toolkit/utils/download_utils.py +0 -0
|
@@ -12,7 +12,9 @@ from .get_gateway_request_stats_by_time_response_get_gateway_request_stats_by_ti
|
|
|
12
12
|
GetGatewayRequestStatsByTimeResponseGetGatewayRequestStatsByTime,
|
|
13
13
|
)
|
|
14
14
|
from .grouped_usage_detail import GroupedUsageDetail
|
|
15
|
-
from .handle_stripe_webhook_response_handle_stripe_webhook import
|
|
15
|
+
from .handle_stripe_webhook_response_handle_stripe_webhook import (
|
|
16
|
+
HandleStripeWebhookResponseHandleStripeWebhook,
|
|
17
|
+
)
|
|
16
18
|
from .hash_check import HashCheck
|
|
17
19
|
from .http_validation_error import HTTPValidationError
|
|
18
20
|
from .initiate_upload_info import InitiateUploadInfo
|
|
@@ -12,14 +12,14 @@ class GroupedUsageDetail:
|
|
|
12
12
|
model_id (str):
|
|
13
13
|
machine_type (str):
|
|
14
14
|
request_count (int):
|
|
15
|
-
|
|
15
|
+
median_duration (float):
|
|
16
16
|
total_duration (float):
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
19
|
model_id: str
|
|
20
20
|
machine_type: str
|
|
21
21
|
request_count: int
|
|
22
|
-
|
|
22
|
+
median_duration: float
|
|
23
23
|
total_duration: float
|
|
24
24
|
additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict)
|
|
25
25
|
|
|
@@ -27,7 +27,7 @@ class GroupedUsageDetail:
|
|
|
27
27
|
model_id = self.model_id
|
|
28
28
|
machine_type = self.machine_type
|
|
29
29
|
request_count = self.request_count
|
|
30
|
-
|
|
30
|
+
median_duration = self.median_duration
|
|
31
31
|
total_duration = self.total_duration
|
|
32
32
|
|
|
33
33
|
field_dict: Dict[str, Any] = {}
|
|
@@ -37,7 +37,7 @@ class GroupedUsageDetail:
|
|
|
37
37
|
"model_id": model_id,
|
|
38
38
|
"machine_type": machine_type,
|
|
39
39
|
"request_count": request_count,
|
|
40
|
-
"
|
|
40
|
+
"median_duration": median_duration,
|
|
41
41
|
"total_duration": total_duration,
|
|
42
42
|
}
|
|
43
43
|
)
|
|
@@ -53,7 +53,7 @@ class GroupedUsageDetail:
|
|
|
53
53
|
|
|
54
54
|
request_count = d.pop("request_count")
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
median_duration = d.pop("median_duration")
|
|
57
57
|
|
|
58
58
|
total_duration = d.pop("total_duration")
|
|
59
59
|
|
|
@@ -61,7 +61,7 @@ class GroupedUsageDetail:
|
|
|
61
61
|
model_id=model_id,
|
|
62
62
|
machine_type=machine_type,
|
|
63
63
|
request_count=request_count,
|
|
64
|
-
|
|
64
|
+
median_duration=median_duration,
|
|
65
65
|
total_duration=total_duration,
|
|
66
66
|
)
|
|
67
67
|
|
|
@@ -82,7 +82,7 @@ entry_points = \
|
|
|
82
82
|
|
|
83
83
|
setup_kwargs = {
|
|
84
84
|
'name': 'fal',
|
|
85
|
-
'version': '0.11.
|
|
85
|
+
'version': '0.11.5',
|
|
86
86
|
'description': 'fal is an easy-to-use Serverless Python Framework',
|
|
87
87
|
'long_description': '# fal\n\nfal is a serverless Python runtime that lets you run and scale code in the cloud with no infra management.\n\nWith 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.\n\n## Quickstart\n\nFirst, you need to install the `fal` package. You can do so using pip:\n```shell\npip install fal\n```\n\nThen you need to authenticate:\n```shell\nfal auth login\n```\n\nYou can also use fal keys that you can get from [our dashboard](https://fal.ai/dashboard/keys).\n\nNow can use the fal package in your Python scripts as follows:\n\n```py\nimport fal\n\n@fal.function(\n "virtualenv",\n requirements=["pyjokes"],\n)\ndef tell_joke() -> str:\n import pyjokes\n\n joke = pyjokes.get_joke()\n return joke\n\nprint("Joke from the clouds: ", tell_joke())\n```\n\nA 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.\n\n## Next steps\n\nIf 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.\n',
|
|
88
88
|
'author': 'Features & Labels',
|
|
@@ -6,6 +6,7 @@ from fal import apps
|
|
|
6
6
|
from fal.api import FalServerlessHost, LocalHost, cached
|
|
7
7
|
from fal.api import function
|
|
8
8
|
from fal.api import function as isolated
|
|
9
|
+
from fal.app import App, endpoint, wrap_app
|
|
9
10
|
from fal.sdk import FalServerlessKeyCredentials
|
|
10
11
|
from fal.sync import sync_dir
|
|
11
12
|
|
|
@@ -15,35 +16,8 @@ serverless = FalServerlessHost()
|
|
|
15
16
|
# DEPRECATED - use serverless instead
|
|
16
17
|
cloud = FalServerlessHost()
|
|
17
18
|
|
|
18
|
-
DBT_FAL_IMPORT_NOTICE = """
|
|
19
|
-
The dbt tool `fal` and `dbt-fal` adapter have been merged into a single tool.
|
|
20
|
-
Please import from the `fal.dbt` module instead.
|
|
21
|
-
Running `pip install dbt-fal` will install the new tool and the adapter alongside.
|
|
22
|
-
Then import from the `fal.dbt` module like
|
|
23
|
-
|
|
24
|
-
from fal.dbt import {name}
|
|
25
|
-
|
|
26
|
-
"""
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
# Avoid printing on non-direct imports
|
|
30
|
-
def __getattr__(name: str):
|
|
31
|
-
if name in (
|
|
32
|
-
"NodeStatus",
|
|
33
|
-
"FalDbt",
|
|
34
|
-
"DbtModel",
|
|
35
|
-
"DbtSource",
|
|
36
|
-
"DbtTest",
|
|
37
|
-
"DbtGenericTest",
|
|
38
|
-
"DbtSingularTest",
|
|
39
|
-
"Context",
|
|
40
|
-
"CurrentModel",
|
|
41
|
-
):
|
|
42
|
-
raise ImportError(DBT_FAL_IMPORT_NOTICE.format(name=name))
|
|
43
|
-
|
|
44
|
-
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
45
|
-
|
|
46
19
|
|
|
20
|
+
# NOTE: This makes `import fal.dbt` import the `dbt-fal` module and `import fal` import the `fal` module
|
|
47
21
|
# NOTE: taken from dbt-core: https://github.com/dbt-labs/dbt-core/blob/ac539fd5cf325cfb5315339077d03399d575f570/core/dbt/adapters/__init__.py#L1-L7
|
|
48
22
|
# N.B.
|
|
49
23
|
# This will add to the package’s __path__ all subdirectories of directories on sys.path named after the package which effectively combines both modules into a single namespace (dbt.adapters)
|
|
@@ -552,6 +552,7 @@ def function(
|
|
|
552
552
|
exposed_port: int | None = None,
|
|
553
553
|
max_concurrency: int | None = None,
|
|
554
554
|
# FalServerlessHost options
|
|
555
|
+
metadata: dict[str, Any] | None = None,
|
|
555
556
|
machine_type: str = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
|
|
556
557
|
keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
|
|
557
558
|
max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
|
|
@@ -576,6 +577,7 @@ def function(
|
|
|
576
577
|
exposed_port: int | None = None,
|
|
577
578
|
max_concurrency: int | None = None,
|
|
578
579
|
# FalServerlessHost options
|
|
580
|
+
metadata: dict[str, Any] | None = None,
|
|
579
581
|
machine_type: str = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
|
|
580
582
|
keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
|
|
581
583
|
max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
|
|
@@ -652,6 +654,7 @@ def function(
|
|
|
652
654
|
exposed_port: int | None = None,
|
|
653
655
|
max_concurrency: int | None = None,
|
|
654
656
|
# FalServerlessHost options
|
|
657
|
+
metadata: dict[str, Any] | None = None,
|
|
655
658
|
machine_type: str = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
|
|
656
659
|
keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
|
|
657
660
|
max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
|
|
@@ -681,6 +684,7 @@ def function(
|
|
|
681
684
|
exposed_port: int | None = None,
|
|
682
685
|
max_concurrency: int | None = None,
|
|
683
686
|
# FalServerlessHost options
|
|
687
|
+
metadata: dict[str, Any] | None = None,
|
|
684
688
|
machine_type: str = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
|
|
685
689
|
keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
|
|
686
690
|
max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
|
|
@@ -788,7 +792,7 @@ class ServeWrapper:
|
|
|
788
792
|
if "properties" in schema:
|
|
789
793
|
mark_order(schema, "properties")
|
|
790
794
|
|
|
791
|
-
for key in spec
|
|
795
|
+
for key in spec.get("components", {}).get("schemas") or {}:
|
|
792
796
|
order_schema_object(spec["components"]["schemas"][key])
|
|
793
797
|
|
|
794
798
|
return spec
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
import os
|
|
5
|
+
import fal.api
|
|
6
|
+
from fal.toolkit import mainify
|
|
7
|
+
from fastapi import FastAPI
|
|
8
|
+
from typing import Any, NamedTuple, Callable, TypeVar, ClassVar
|
|
9
|
+
from fal.logging import get_logger
|
|
10
|
+
|
|
11
|
+
EndpointT = TypeVar("EndpointT", bound=Callable[..., Any])
|
|
12
|
+
logger = get_logger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def wrap_app(cls: type[App], **kwargs) -> fal.api.IsolatedFunction:
|
|
16
|
+
def initialize_and_serve():
|
|
17
|
+
app = cls()
|
|
18
|
+
app.serve()
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
app = cls(_allow_init=True)
|
|
22
|
+
metadata = app.openapi()
|
|
23
|
+
except Exception as exc:
|
|
24
|
+
logger.warning("Failed to build OpenAPI specification for %s", cls.__name__)
|
|
25
|
+
metadata = {}
|
|
26
|
+
|
|
27
|
+
wrapper = fal.api.function(
|
|
28
|
+
"virtualenv",
|
|
29
|
+
requirements=cls.requirements,
|
|
30
|
+
machine_type=cls.machine_type,
|
|
31
|
+
**cls.host_kwargs,
|
|
32
|
+
**kwargs,
|
|
33
|
+
metadata=metadata,
|
|
34
|
+
serve=True,
|
|
35
|
+
)
|
|
36
|
+
return wrapper(initialize_and_serve).on(
|
|
37
|
+
serve=False,
|
|
38
|
+
exposed_port=8080,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@mainify
|
|
43
|
+
class RouteSignature(NamedTuple):
|
|
44
|
+
path: str
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@mainify
|
|
48
|
+
class App:
|
|
49
|
+
requirements: ClassVar[list[str]] = []
|
|
50
|
+
machine_type: ClassVar[str] = "S"
|
|
51
|
+
host_kwargs: ClassVar[dict[str, Any]] = {}
|
|
52
|
+
|
|
53
|
+
def __init_subclass__(cls, **kwargs):
|
|
54
|
+
cls.host_kwargs = kwargs
|
|
55
|
+
|
|
56
|
+
if cls.__init__ is not App.__init__:
|
|
57
|
+
raise ValueError(
|
|
58
|
+
"App classes should not override __init__ directly. "
|
|
59
|
+
"Use setup() instead."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def __init__(self, *, _allow_init: bool = False):
|
|
63
|
+
if not _allow_init and not os.getenv("IS_ISOLATE_AGENT"):
|
|
64
|
+
raise NotImplementedError(
|
|
65
|
+
"Running apps through SDK is not implemented yet."
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def setup(self):
|
|
69
|
+
"""Setup the application before serving."""
|
|
70
|
+
|
|
71
|
+
def serve(self) -> None:
|
|
72
|
+
import uvicorn
|
|
73
|
+
|
|
74
|
+
app = self._build_app()
|
|
75
|
+
self.setup()
|
|
76
|
+
uvicorn.run(app, host="0.0.0.0", port=8080)
|
|
77
|
+
|
|
78
|
+
def _build_app(self) -> FastAPI:
|
|
79
|
+
from fastapi import FastAPI
|
|
80
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
81
|
+
|
|
82
|
+
_app = FastAPI()
|
|
83
|
+
|
|
84
|
+
_app.add_middleware(
|
|
85
|
+
CORSMiddleware,
|
|
86
|
+
allow_credentials=True,
|
|
87
|
+
allow_headers=("*"),
|
|
88
|
+
allow_methods=("*"),
|
|
89
|
+
allow_origins=("*"),
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
routes: dict[RouteSignature, Callable[..., Any]] = {
|
|
93
|
+
signature: endpoint
|
|
94
|
+
for _, endpoint in inspect.getmembers(self, inspect.ismethod)
|
|
95
|
+
if (signature := getattr(endpoint, "route_signature", None))
|
|
96
|
+
}
|
|
97
|
+
if not routes:
|
|
98
|
+
raise ValueError("An application must have at least one route!")
|
|
99
|
+
|
|
100
|
+
for signature, endpoint in routes.items():
|
|
101
|
+
_app.add_api_route(
|
|
102
|
+
signature.path,
|
|
103
|
+
endpoint,
|
|
104
|
+
name=endpoint.__name__,
|
|
105
|
+
methods=["POST"],
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
return _app
|
|
109
|
+
|
|
110
|
+
def openapi(self) -> dict[str, Any]:
|
|
111
|
+
"""
|
|
112
|
+
Build the OpenAPI specification for the served function.
|
|
113
|
+
Attach needed metadata for a better integration to fal.
|
|
114
|
+
"""
|
|
115
|
+
app = self._build_app()
|
|
116
|
+
spec = app.openapi()
|
|
117
|
+
self._mark_order_openapi(spec)
|
|
118
|
+
return spec
|
|
119
|
+
|
|
120
|
+
def _mark_order_openapi(self, spec: dict[str, Any]):
|
|
121
|
+
"""
|
|
122
|
+
Add x-fal-order-* keys to the OpenAPI specification to help the rendering of UI.
|
|
123
|
+
|
|
124
|
+
NOTE: We rely on the fact that fastapi and Python dicts keep the order of properties.
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
def mark_order(obj: dict[str, Any], key: str):
|
|
128
|
+
obj[f"x-fal-order-{key}"] = list(obj[key].keys())
|
|
129
|
+
|
|
130
|
+
mark_order(spec, "paths")
|
|
131
|
+
|
|
132
|
+
def order_schema_object(schema: dict[str, Any]):
|
|
133
|
+
"""
|
|
134
|
+
Mark the order of properties in the schema object.
|
|
135
|
+
They can have 'allOf', 'properties' or '$ref' key.
|
|
136
|
+
"""
|
|
137
|
+
if "allOf" in schema:
|
|
138
|
+
for sub_schema in schema["allOf"]:
|
|
139
|
+
order_schema_object(sub_schema)
|
|
140
|
+
if "properties" in schema:
|
|
141
|
+
mark_order(schema, "properties")
|
|
142
|
+
|
|
143
|
+
for key in spec["components"].get("schemas") or {}:
|
|
144
|
+
order_schema_object(spec["components"]["schemas"][key])
|
|
145
|
+
|
|
146
|
+
return spec
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@mainify
|
|
150
|
+
def endpoint(path: str) -> Callable[[EndpointT], EndpointT]:
|
|
151
|
+
"""Designate the decorated function as an application endpoint."""
|
|
152
|
+
|
|
153
|
+
def marker_fn(callable: EndpointT) -> EndpointT:
|
|
154
|
+
if hasattr(callable, "route_signature"):
|
|
155
|
+
raise ValueError(
|
|
156
|
+
f"Can't set multiple routes for the same function: {callable.__name__}"
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
callable.route_signature = RouteSignature(path=path) # type: ignore
|
|
160
|
+
return callable
|
|
161
|
+
|
|
162
|
+
return marker_fn
|
|
@@ -9,7 +9,7 @@ from uuid import uuid4
|
|
|
9
9
|
|
|
10
10
|
import click
|
|
11
11
|
import fal.auth as auth
|
|
12
|
-
import
|
|
12
|
+
import fal
|
|
13
13
|
from fal import api, sdk
|
|
14
14
|
from fal.console import console
|
|
15
15
|
from fal.exceptions import ApplicationExceptionHandler
|
|
@@ -145,15 +145,6 @@ def auth_cli():
|
|
|
145
145
|
@auth_cli.command(name="login")
|
|
146
146
|
def auth_login():
|
|
147
147
|
auth.login()
|
|
148
|
-
try:
|
|
149
|
-
client = sdk.FalServerlessClient(f"{DEFAULT_HOST}:{DEFAULT_PORT}")
|
|
150
|
-
with client.connect() as connection:
|
|
151
|
-
connection.list_aliases()
|
|
152
|
-
except grpc.RpcError as e:
|
|
153
|
-
if "Insufficient permissions" in e.details():
|
|
154
|
-
console.print(e.details())
|
|
155
|
-
else:
|
|
156
|
-
raise e
|
|
157
148
|
|
|
158
149
|
|
|
159
150
|
@auth_cli.command(name="logout")
|
|
@@ -244,6 +235,28 @@ def function_cli(ctx, host: str, port: str):
|
|
|
244
235
|
ctx.obj = api.FalServerlessHost(f"{host}:{port}")
|
|
245
236
|
|
|
246
237
|
|
|
238
|
+
def load_function_from(
|
|
239
|
+
host: api.FalServerlessHost,
|
|
240
|
+
file_path: str,
|
|
241
|
+
function_name: str,
|
|
242
|
+
) -> api.IsolatedFunction:
|
|
243
|
+
import runpy
|
|
244
|
+
|
|
245
|
+
module = runpy.run_path(file_path)
|
|
246
|
+
if function_name not in module:
|
|
247
|
+
raise api.FalServerlessError(f"Function '{function_name}' not found in module")
|
|
248
|
+
|
|
249
|
+
target = module[function_name]
|
|
250
|
+
if isinstance(target, type) and issubclass(target, fal.App):
|
|
251
|
+
target = fal.wrap_app(target, host=host)
|
|
252
|
+
|
|
253
|
+
if not isinstance(target, api.IsolatedFunction):
|
|
254
|
+
raise api.FalServerlessError(
|
|
255
|
+
f"Function '{function_name}' is not a fal.function or a fal.App"
|
|
256
|
+
)
|
|
257
|
+
return target
|
|
258
|
+
|
|
259
|
+
|
|
247
260
|
@function_cli.command("serve")
|
|
248
261
|
@click.option("--alias", default=None)
|
|
249
262
|
@click.option(
|
|
@@ -262,15 +275,9 @@ def register_application(
|
|
|
262
275
|
alias: str | None,
|
|
263
276
|
auth_mode: ALIAS_AUTH_TYPE,
|
|
264
277
|
):
|
|
265
|
-
import runpy
|
|
266
|
-
|
|
267
278
|
user_id = _get_user_id()
|
|
268
279
|
|
|
269
|
-
|
|
270
|
-
if function_name not in module:
|
|
271
|
-
raise api.FalServerlessError(f"Function '{function_name}' not found in module")
|
|
272
|
-
|
|
273
|
-
isolated_function: api.IsolatedFunction = module[function_name]
|
|
280
|
+
isolated_function = load_function_from(host, file_path, function_name)
|
|
274
281
|
gateway_options = isolated_function.options.gateway
|
|
275
282
|
if "serve" not in gateway_options and "exposed_port" not in gateway_options:
|
|
276
283
|
raise api.FalServerlessError(
|
|
@@ -289,7 +296,7 @@ def register_application(
|
|
|
289
296
|
options=isolated_function.options,
|
|
290
297
|
application_name=alias,
|
|
291
298
|
application_auth_mode=auth_mode,
|
|
292
|
-
metadata={},
|
|
299
|
+
metadata=isolated_function.options.host.get("metadata", {}),
|
|
293
300
|
)
|
|
294
301
|
|
|
295
302
|
if id:
|
|
@@ -307,6 +314,15 @@ def register_application(
|
|
|
307
314
|
console.print(f"URL: https://{user_id}-{id}.{gateway_host}")
|
|
308
315
|
|
|
309
316
|
|
|
317
|
+
@function_cli.command("run")
|
|
318
|
+
@click.argument("file_path", required=True)
|
|
319
|
+
@click.argument("function_name", required=True)
|
|
320
|
+
@click.pass_obj
|
|
321
|
+
def run(host: api.FalServerlessHost, file_path: str, function_name: str):
|
|
322
|
+
isolated_function = load_function_from(host, file_path, function_name)
|
|
323
|
+
isolated_function()
|
|
324
|
+
|
|
325
|
+
|
|
310
326
|
@function_cli.command("logs")
|
|
311
327
|
@click.option("--lines", default=100)
|
|
312
328
|
@click.option("--url", default=None)
|
|
@@ -520,30 +536,6 @@ def remove_http_and_port_from_url(url):
|
|
|
520
536
|
return url
|
|
521
537
|
|
|
522
538
|
|
|
523
|
-
# dbt-fal commands to be errored out
|
|
524
|
-
DBT_FAL_COMMAND_NOTICE = """
|
|
525
|
-
The dbt tool `fal` and `dbt-fal` adapter have been merged into a single tool.
|
|
526
|
-
Please use the new `dbt-fal` command line tool instead.
|
|
527
|
-
Running `pip install dbt-fal` will install the new tool and the adapter alongside.
|
|
528
|
-
Then run your command like
|
|
529
|
-
|
|
530
|
-
dbt-fal <command>
|
|
531
|
-
|
|
532
|
-
"""
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
@cli.command("run", context_settings={"ignore_unknown_options": True})
|
|
536
|
-
@click.argument("any", nargs=-1, type=click.UNPROCESSED)
|
|
537
|
-
def dbt_run(any):
|
|
538
|
-
raise click.BadArgumentUsage(DBT_FAL_COMMAND_NOTICE)
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
@cli.command("flow", context_settings={"ignore_unknown_options": True})
|
|
542
|
-
@click.argument("any", nargs=-1, type=click.UNPROCESSED)
|
|
543
|
-
def dbt_flow(any):
|
|
544
|
-
raise click.BadArgumentUsage(DBT_FAL_COMMAND_NOTICE)
|
|
545
|
-
|
|
546
|
-
|
|
547
539
|
def _get_user_id() -> str:
|
|
548
540
|
try:
|
|
549
541
|
user_details_response = get_user_details.sync_detailed(
|
|
@@ -9,5 +9,5 @@ class UnauthenticatedException(FalServerlessException):
|
|
|
9
9
|
def __init__(self) -> None:
|
|
10
10
|
super().__init__(
|
|
11
11
|
message="You must be authenticated.",
|
|
12
|
-
hint="Login via `fal auth login`",
|
|
12
|
+
hint="Login via `fal auth login` or make sure to setup fal keys correctly.",
|
|
13
13
|
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/delete_payment_method.py
RENAMED
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/get_setup_intent_key.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_invoices.py
RENAMED
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_payment_methods.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_spending.py
RENAMED
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/handle_stripe_webhook.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/billing/update_customer_budget.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/usage/get_gateway_request_stats.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/usage/get_shared_usage_per_app.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/api/usage/per_machine_usage_details.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/persisted_usage_record.py
RENAMED
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/persisted_usage_record_meta.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/request_io_json_output.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-0.11.3 → fal-0.11.5}/openapi-fal-rest/openapi_fal_rest/models/usage_per_machine_type.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|