Skip to content

Commit 98a671c

Browse files
markreidvfxMichaelPlug
authored andcommitted
Allow overriding builtin plugins via entrypoint method. (AcademySoftwareFoundation#1389)
* Load entrypoint plugins before builtin and contrib in order to allow overriding builtin plugins. Signed-off-by: Mark Reid <[email protected]> Signed-off-by: Michele Spina <[email protected]>
1 parent 643fb7f commit 98a671c

File tree

7 files changed

+91
-30
lines changed

7 files changed

+91
-30
lines changed

src/py-opentimelineio/opentimelineio/plugins/manifest.py

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,10 @@ def load_manifest():
202202
203203
The order of loading (and precedence) is:
204204
205-
1. manifests specfied via the ``OTIO_PLUGIN_MANIFEST_PATH`` variable
206-
2. builtin plugin manifest
207-
3. contrib plugin manifest
208-
4. ``setuptools.pkg_resources`` based plugin manifests
205+
1. Manifests specified via the ``OTIO_PLUGIN_MANIFEST_PATH`` variable
206+
2. Entrypoint based plugin manifests
207+
3. Builtin plugin manifest
208+
4. Contrib plugin manifest
209209
"""
210210

211211
result = Manifest()
@@ -232,32 +232,6 @@ def load_manifest():
232232

233233
result.extend(manifest_from_file(json_path))
234234

235-
# the builtin plugin manifest
236-
builtin_manifest_path = os.path.join(
237-
os.path.dirname(os.path.dirname(inspect.getsourcefile(core))),
238-
"adapters",
239-
"builtin_adapters.plugin_manifest.json"
240-
)
241-
if os.path.abspath(builtin_manifest_path) not in result.source_files:
242-
plugin_manifest = manifest_from_file(builtin_manifest_path)
243-
result.extend(plugin_manifest)
244-
245-
# the contrib plugin manifest (located in the opentimelineio_contrib package)
246-
try:
247-
import opentimelineio_contrib as otio_c
248-
249-
contrib_manifest_path = os.path.join(
250-
os.path.dirname(inspect.getsourcefile(otio_c)),
251-
"adapters",
252-
"contrib_adapters.plugin_manifest.json"
253-
)
254-
if os.path.abspath(contrib_manifest_path) not in result.source_files:
255-
contrib_manifest = manifest_from_file(contrib_manifest_path)
256-
result.extend(contrib_manifest)
257-
258-
except ImportError:
259-
pass
260-
261235
# setuptools.pkg_resources based plugins
262236
if pkg_resources:
263237
for plugin in pkg_resources.iter_entry_points(
@@ -324,6 +298,32 @@ def load_manifest():
324298
# available?
325299
pass
326300

301+
# the builtin plugin manifest
302+
builtin_manifest_path = os.path.join(
303+
os.path.dirname(os.path.dirname(inspect.getsourcefile(core))),
304+
"adapters",
305+
"builtin_adapters.plugin_manifest.json"
306+
)
307+
if os.path.abspath(builtin_manifest_path) not in result.source_files:
308+
plugin_manifest = manifest_from_file(builtin_manifest_path)
309+
result.extend(plugin_manifest)
310+
311+
# the contrib plugin manifest (located in the opentimelineio_contrib package)
312+
try:
313+
import opentimelineio_contrib as otio_c
314+
315+
contrib_manifest_path = os.path.join(
316+
os.path.dirname(inspect.getsourcefile(otio_c)),
317+
"adapters",
318+
"contrib_adapters.plugin_manifest.json"
319+
)
320+
if os.path.abspath(contrib_manifest_path) not in result.source_files:
321+
contrib_manifest = manifest_from_file(contrib_manifest_path)
322+
result.extend(contrib_manifest)
323+
324+
except ImportError:
325+
pass
326+
327327
# force the schemadefs to load and add to schemadef module namespace
328328
for s in result.schemadefs:
329329
s.module()
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Metadata-Version: 1.0
2+
Name: otio-override-adapter
3+
Version: 1.0.0
4+
Summary: Dummy Adapter used for testing.
5+
Home-page: http://opentimeline.io
6+
Author: Contributors to the OpenTimelineIO project
7+
Author-email: [email protected]
8+
License: Modified Apache 2.0 License
9+
Description-Content-Type: UNKNOWN
10+
Description: UNKNOWN
11+
Platform: any
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[opentimelineio.plugins]
2+
mock_plugin = otio_override_adapter
3+

tests/baselines/plugin_module/otio_override_adapter/__init__.py

Whitespace-only changes.

tests/baselines/plugin_module/otio_override_adapter/adapter.py

Whitespace-only changes.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"OTIO_SCHEMA" : "PluginManifest.1",
3+
"adapters": [
4+
{
5+
"OTIO_SCHEMA" : "Adapter.1",
6+
"name" : "cmx_3600",
7+
"execution_scope" : "in process",
8+
"filepath" : "adapter.py",
9+
"suffixes" : ["edl"]
10+
}
11+
]
12+
}

tests/test_plugin_detection.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ def setUp(self):
4949
"plugin_manifest.json"
5050
)
5151

52+
self.override_adapter_manifest_path = os.path.join(
53+
mock_module_path,
54+
"otio_override_adapter",
55+
"plugin_manifest.json"
56+
)
57+
5258
# Create a WorkingSet as if the module were installed
5359
entries = [mock_module_path] + pkg_resources.working_set.entries
5460

@@ -70,6 +76,9 @@ def tearDown(self):
7076
if 'otio_mockplugin' in sys.modules:
7177
del sys.modules['otio_mockplugin']
7278

79+
if 'otio_override_adapter' in sys.modules:
80+
del sys.modules['otio_override_adapter']
81+
7382
def test_detect_plugin(self):
7483
"""This manifest uses the plugin_manifest function"""
7584

@@ -91,6 +100,28 @@ def test_detect_plugin(self):
91100
for linker in man.media_linkers:
92101
self.assertIsInstance(linker, otio.media_linker.MediaLinker)
93102

103+
def test_overrride_adapter(self):
104+
# Test that entrypoint plugins load before builtin and contrib
105+
man = otio.plugins.manifest.load_manifest()
106+
107+
# The override_adapter creates another cmx_3600 adapter
108+
adapters = [adapter for adapter in man.adapters
109+
if adapter.name == "cmx_3600"]
110+
111+
# More then one cmx_3600 adapter should exist.
112+
self.assertTrue(len(adapters) > 1)
113+
114+
# Override adapter should be the first adapter found
115+
manifest = adapters[0].plugin_info_map().get('from manifest', None)
116+
self.assertEqual(manifest, os.path.abspath(self.override_adapter_manifest_path))
117+
118+
self.assertTrue(
119+
any(
120+
True for p in man.source_files
121+
if self.override_adapter_manifest_path in p
122+
)
123+
)
124+
94125
def test_pkg_resources_disabled(self):
95126
os.environ["OTIO_DISABLE_PKG_RESOURCE_PLUGINS"] = "1"
96127
import_reload(otio.plugins.manifest)
@@ -100,6 +131,10 @@ def test_pkg_resources_disabled(self):
100131
with self.assertRaises(AssertionError):
101132
self.test_detect_plugin()
102133

134+
# override adapter should not be loaded either
135+
with self.assertRaises(AssertionError):
136+
self.test_overrride_adapter()
137+
103138
# remove the environment variable and reload again for usage in the
104139
# other tests
105140
del os.environ["OTIO_DISABLE_PKG_RESOURCE_PLUGINS"]

0 commit comments

Comments
 (0)