Skip to content

Commit 206f874

Browse files
Viicospre-commit-ci[bot]jsonvillanueva
authored
Remove support for dynamic plugin imports (#3524)
* Remove call to deprecated `pkg_resources` * Remove support for dynamic plugin imports, update plugin utilities * fix affected tests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * more fixes * Last fix * Fix import * Update docs --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Jason Villanueva <[email protected]>
1 parent fcd81b2 commit 206f874

File tree

8 files changed

+32
-212
lines changed

8 files changed

+32
-212
lines changed

docs/source/plugins.rst

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -99,40 +99,18 @@ directory structure, build system, and naming are completely up to your
9999
discretion as an author. The aforementioned template plugin is only a model
100100
using Poetry since this is the build system Manim uses. The plugin's `entry
101101
point <https://packaging.python.org/specifications/entry-points/>`_ can be
102-
specified in poetry as:
102+
specified in Poetry as:
103103

104104
.. code-block:: toml
105105
106106
[tool.poetry.plugins."manim.plugins"]
107107
"name" = "object_reference"
108108
109-
Here ``name`` is the name of the module of the plugin.
109+
.. versionremoved:: 0.19.0
110110

111-
Here ``object_reference`` can point to either a function in a module or a module
112-
itself. For example,
113-
114-
.. code-block:: toml
115-
116-
[tool.poetry.plugins."manim.plugins"]
117-
"manim_plugintemplate" = "manim_plugintemplate"
118-
119-
Here a module is used as ``object_reference``, and when this plugin is enabled,
120-
Manim will look for ``__all__`` keyword defined in ``manim_plugintemplate`` and
121-
everything as a global variable one by one.
122-
123-
If ``object_reference`` is a function, Manim calls the function and expects the
124-
function to return a list of modules or functions that need to be defined globally.
125-
126-
For example,
127-
128-
.. code-block:: toml
129-
130-
[tool.poetry.plugins."manim.plugins"]
131-
"manim_plugintemplate" = "manim_awesomeplugin.imports:setup_things"
132-
133-
Here, Manim will call the function ``setup_things`` defined in
134-
``manim_awesomeplugin.imports`` and calls that. It returns a list of function or
135-
modules which will be imported globally.
111+
Plugins should be imported explicitly to be usable in user code. The plugin
112+
system will probably be refactored in the future to provide a more structured
113+
interface.
136114

137115
A note on Renderer Compatibility
138116
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

manim/plugins/__init__.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
11
from __future__ import annotations
22

3-
from .import_plugins import *
3+
from manim import config, logger
4+
5+
from .plugins_flags import get_plugins, list_plugins
6+
7+
__all__ = [
8+
"get_plugins",
9+
"list_plugins",
10+
]
11+
12+
requested_plugins: set[str] = set(config["plugins"])
13+
missing_plugins = requested_plugins - set(get_plugins().keys())
14+
15+
16+
if missing_plugins:
17+
logger.warning("Missing Plugins: %s", missing_plugins)

manim/plugins/import_plugins.py

Lines changed: 0 additions & 43 deletions
This file was deleted.

manim/plugins/plugins_flags.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,28 @@
22

33
from __future__ import annotations
44

5-
import pkg_resources
5+
import sys
6+
from typing import Any
7+
8+
if sys.version_info < (3, 10):
9+
from importlib_metadata import entry_points
10+
else:
11+
from importlib.metadata import entry_points
612

713
from manim import console
814

915
__all__ = ["list_plugins"]
1016

1117

12-
def get_plugins():
13-
plugins = {
18+
def get_plugins() -> dict[str, Any]:
19+
plugins: dict[str, Any] = {
1420
entry_point.name: entry_point.load()
15-
for entry_point in pkg_resources.iter_entry_points("manim.plugins")
21+
for entry_point in entry_points(group="manim.plugins")
1622
}
1723
return plugins
1824

1925

20-
def list_plugins():
26+
def list_plugins() -> None:
2127
console.print("[green bold]Plugins:[/green bold]", justify="left")
2228

2329
plugins = get_plugins()

poetry.lock

Lines changed: 0 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ click = ">=8.0"
3232
cloup = ">=2.0.0"
3333
dearpygui = { version = ">=1.0.0", optional = true }
3434
decorator = ">=4.3.2"
35+
importlib-metadata = {version = ">=3.6", python = "<=3.9"} # Required to discover plugins
3536
isosurfaces = ">=0.1.0"
3637
jupyterlab = { version = ">=3.0.0", optional = true }
3738
manimpango = ">=0.5.0,<1.0.0" # Complete API change in 1.0.0

tests/test_plugins/simple_scenes.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,3 @@ def construct(self):
88
square = Square()
99
circle = Circle()
1010
self.play(Transform(square, circle))
11-
12-
13-
class FunctionLikeTest(Scene):
14-
def construct(self):
15-
assert "FunctionLike" in globals()
16-
a = FunctionLike()
17-
self.play(FadeIn(a))
18-
19-
20-
class WithAllTest(Scene):
21-
def construct(self):
22-
assert "WithAll" in globals()
23-
a = WithAll()
24-
self.play(FadeIn(a))

tests/test_plugins/test_plugins.py

Lines changed: 0 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import random
44
import string
5-
import tempfile
65
import textwrap
76
from pathlib import Path
87

@@ -142,116 +141,3 @@ def _create_plugin(entry_point, class_name, function_name, all_dec=""):
142141
out, err, exit_code = capture(command)
143142
print(out)
144143
assert exit_code == 0, err
145-
146-
147-
@pytest.mark.slow
148-
def test_plugin_function_like(
149-
tmp_path,
150-
create_plugin,
151-
python_version,
152-
simple_scenes_path,
153-
):
154-
function_like_plugin = create_plugin(
155-
"{plugin_name}.__init__:import_all",
156-
"FunctionLike",
157-
"import_all",
158-
)
159-
cfg_file = cfg_file_create(
160-
cfg_file_contents.format(plugin_name=function_like_plugin["plugin_name"]),
161-
tmp_path,
162-
)
163-
scene_name = "FunctionLikeTest"
164-
command = [
165-
python_version,
166-
"-m",
167-
"manim",
168-
"-ql",
169-
"--media_dir",
170-
str(cfg_file.parent),
171-
"--config_file",
172-
str(cfg_file),
173-
str(simple_scenes_path),
174-
scene_name,
175-
]
176-
out, err, exit_code = capture(command, cwd=str(cfg_file.parent))
177-
print(out)
178-
print(err)
179-
assert exit_code == 0, err
180-
181-
182-
@pytest.mark.slow
183-
def test_plugin_no_all(tmp_path, create_plugin, python_version):
184-
create_plugin = create_plugin("{plugin_name}", "NoAll", "import_all")
185-
plugin_name = create_plugin["plugin_name"]
186-
cfg_file = cfg_file_create(
187-
cfg_file_contents.format(plugin_name=plugin_name),
188-
tmp_path,
189-
)
190-
test_class = textwrap.dedent(
191-
f"""\
192-
from manim import *
193-
class NoAllTest(Scene):
194-
def construct(self):
195-
assert "{plugin_name}" in globals()
196-
a = {plugin_name}.NoAll()
197-
self.play(FadeIn(a))
198-
""",
199-
)
200-
201-
with tempfile.NamedTemporaryFile(
202-
mode="w",
203-
encoding="utf-8",
204-
suffix=".py",
205-
delete=False,
206-
) as tmpfile:
207-
tmpfile.write(test_class)
208-
scene_name = "NoAllTest"
209-
command = [
210-
python_version,
211-
"-m",
212-
"manim",
213-
"-ql",
214-
"--media_dir",
215-
str(cfg_file.parent),
216-
"--config_file",
217-
str(cfg_file),
218-
tmpfile.name,
219-
scene_name,
220-
]
221-
out, err, exit_code = capture(command, cwd=str(cfg_file.parent))
222-
print(out)
223-
print(err)
224-
assert exit_code == 0, err
225-
Path(tmpfile.name).unlink()
226-
227-
228-
@pytest.mark.slow
229-
def test_plugin_with_all(tmp_path, create_plugin, python_version, simple_scenes_path):
230-
create_plugin = create_plugin(
231-
"{plugin_name}",
232-
"WithAll",
233-
"import_all",
234-
all_dec="__all__=['WithAll']",
235-
)
236-
plugin_name = create_plugin["plugin_name"]
237-
cfg_file = cfg_file_create(
238-
cfg_file_contents.format(plugin_name=plugin_name),
239-
tmp_path,
240-
)
241-
scene_name = "WithAllTest"
242-
command = [
243-
python_version,
244-
"-m",
245-
"manim",
246-
"-ql",
247-
"--media_dir",
248-
str(cfg_file.parent),
249-
"--config_file",
250-
str(cfg_file),
251-
str(simple_scenes_path),
252-
scene_name,
253-
]
254-
out, err, exit_code = capture(command, cwd=str(cfg_file.parent))
255-
print(out)
256-
print(err)
257-
assert exit_code == 0, err

0 commit comments

Comments
 (0)