Skip to content

Commit

Permalink
Remove a few references to 'Stub' (#2542)
Browse files Browse the repository at this point in the history
* Remove a few references to 'Stub'

* Remove auto-import of objects named `stub`

* Update CLI tests / no longer test for `stub` imports

* Fix an errant docs crosslink to Stub

* Remove another test for old magical stub behavior

* Simplify and fix typo
  • Loading branch information
mwaskom authored Nov 20, 2024
1 parent 9f29bb5 commit cce7a1a
Show file tree
Hide file tree
Showing 8 changed files with 9 additions and 88 deletions.
6 changes: 3 additions & 3 deletions modal/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,7 @@ def f(x, y):


class _App:
"""A Modal app (prior to April 2024 a "stub") is a group of functions and classes
deployed together.
"""A Modal App is a group of functions and classes that are deployed together.
The app serves at least three purposes:
Expand Down Expand Up @@ -1083,7 +1082,8 @@ def _reset_container_app(cls):


class _Stub(_App):
"""This enables using an "Stub" class instead of "App".
"""mdmd:hidden
This enables using a "Stub" class instead of "App".
For most of Modal's history, the app class was called "Stub", so this exists for
backwards compatibility, in order to facilitate moving from "Stub" to "App".
Expand Down
42 changes: 4 additions & 38 deletions modal/cli/import_refs.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from rich.markdown import Markdown

from modal.app import App, LocalEntrypoint
from modal.exception import InvalidError, _CliUserExecutionError, deprecation_warning
from modal.exception import InvalidError, _CliUserExecutionError
from modal.functions import Function


Expand Down Expand Up @@ -79,7 +79,7 @@ def import_file_or_module(file_or_module: str):
return module


def get_by_object_path(obj: Any, obj_path: Optional[str]) -> Optional[Any]:
def get_by_object_path(obj: Any, obj_path: str) -> Optional[Any]:
# Try to evaluate a `.`-delimited object path in a Modal context
# With the caveat that some object names can actually have `.` in their name (lifecycled methods' tags)

Expand Down Expand Up @@ -107,35 +107,6 @@ def get_by_object_path(obj: Any, obj_path: Optional[str]) -> Optional[Any]:
return obj


def get_by_object_path_try_possible_app_names(obj: Any, obj_path: Optional[str]) -> Optional[Any]:
"""This just exists as a dumb workaround to support both "stub" and "app" """

if obj_path:
return get_by_object_path(obj, obj_path)
else:
app = get_by_object_path(obj, DEFAULT_APP_NAME)
stub = get_by_object_path(obj, "stub")
if isinstance(app, App):
return app
elif app is not None and isinstance(stub, App):
deprecation_warning(
(2024, 4, 20),
"The symbol `app` is present at the module level but it's not a Modal app."
" We will use `stub` instead, but this will not work in future Modal versions."
" Suggestion: change the name of `app` to something else.",
)
return stub
elif isinstance(stub, App):
deprecation_warning(
(2024, 5, 1),
"The symbol `app` is not present but `stub` is. This will not work in future"
" Modal versions. Suggestion: change the name of `stub` to `app`.",
)
return stub
else:
return None


def _infer_function_or_help(
app: App, module, accept_local_entrypoint: bool, accept_webhook: bool
) -> Union[Function, LocalEntrypoint]:
Expand Down Expand Up @@ -210,7 +181,7 @@ def import_app(app_ref: str) -> App:
import_ref = parse_import_ref(app_ref)

module = import_file_or_module(import_ref.file_or_module)
app = get_by_object_path_try_possible_app_names(module, import_ref.object_path)
app = get_by_object_path(module, import_ref.object_path or DEFAULT_APP_NAME)

if app is None:
_show_no_auto_detectable_app(import_ref)
Expand Down Expand Up @@ -258,7 +229,7 @@ def import_function(
import_ref = parse_import_ref(func_ref)

module = import_file_or_module(import_ref.file_or_module)
app_or_function = get_by_object_path_try_possible_app_names(module, import_ref.object_path)
app_or_function = get_by_object_path(module, import_ref.object_path or DEFAULT_APP_NAME)

if app_or_function is None:
_show_function_ref_help(import_ref, base_cmd)
Expand All @@ -279,8 +250,3 @@ def import_function(
return app_or_function
else:
raise click.UsageError(f"{app_or_function} is not a Modal entity (should be an App or Function)")


# For backwards compatibility - delete soon
# We use it in our internal intergration tests
import_stub = import_app
3 changes: 1 addition & 2 deletions modal/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
"""Functions are the basic units of serverless execution on Modal.
Generally, you will not construct a `Function` directly. Instead, use the
`@app.function()` decorator on the `App` object (formerly called "Stub")
for your application.
`App.function()` decorator to register your Python functions with your App.
"""

# TODO: more type annotations
Expand Down
2 changes: 1 addition & 1 deletion modal/gpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def __repr__(self):
**GPU configuration shortcodes**
The following are the valid `str` values for the `gpu` parameter of
[`@app.function`](/docs/reference/modal.Stub#function).
[`@app.function`](/docs/reference/modal.App#function).
{display_string_to_config}
Expand Down
18 changes: 0 additions & 18 deletions test/cli_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,28 +140,10 @@ def test_run(servicer, set_env_client, test_dir):

def test_run_stub(servicer, set_env_client, test_dir):
app_file = test_dir / "supports" / "app_run_tests" / "app_was_once_stub.py"
with pytest.warns(match="App"):
_run(["run", app_file.as_posix()])
with pytest.warns(match="App"):
_run(["run", app_file.as_posix() + "::foo"])


def test_run_stub_2(servicer, set_env_client, test_dir):
app_file = test_dir / "supports" / "app_run_tests" / "app_was_once_stub_2.py"
with pytest.warns(match="`app`"):
_run(["run", app_file.as_posix()])
_run(["run", app_file.as_posix() + "::stub"])
_run(["run", app_file.as_posix() + "::foo"])


def test_run_stub_with_app(servicer, set_env_client, test_dir):
app_file = test_dir / "supports" / "app_run_tests" / "app_and_stub.py"
with pytest.warns(match="`app`"):
_run(["run", app_file.as_posix()])
_run(["run", app_file.as_posix() + "::stub"])
_run(["run", app_file.as_posix() + "::foo"])


def test_run_async(servicer, set_env_client, test_dir):
sync_fn = test_dir / "supports" / "app_run_tests" / "local_entrypoint.py"
res = _run(["run", sync_fn.as_posix()])
Expand Down
13 changes: 0 additions & 13 deletions test/supports/app_run_tests/app_and_stub.py

This file was deleted.

2 changes: 0 additions & 2 deletions test/supports/app_run_tests/app_was_once_stub.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# Copyright Modal Labs 2024
import modal

# Trigger the deprecation warning for the class itself,
# but not the symbol name (see app_was_once_stub_2 for the opposite)
app = modal.Stub()


Expand Down
11 changes: 0 additions & 11 deletions test/supports/app_run_tests/app_was_once_stub_2.py

This file was deleted.

0 comments on commit cce7a1a

Please sign in to comment.