Skip to content
Permalink
Browse files

Add function to explicitly load SchemaDef plugins (#511)

* Add module_from_name to schemadef

- An easy way to force loading a schemadef plugin
- returns the module object from the plugin
- Also clarifies that from_name returns the plugin
	object itself

* Add documentation for loading schemadefs.

* Add unit tests for explicitly loading schemadef

- Add testing for both the module_from_name() path and implicit loading
  by reading a file containing the schemadef.
- Clarify the existing tests by manually loading the plugin.
  • Loading branch information...
ssteinbach committed May 7, 2019
1 parent d77adfe commit 929149e97333edb61a18e53de2cb4ac40bc6a10d
Showing with 71 additions and 3 deletions.
  1. +14 −2 docs/tutorials/write-a-schemadef.md
  2. +11 −1 opentimelineio/schema/schemadef.py
  3. +46 −0 tests/test_schemadef_plugin.py
@@ -91,8 +91,20 @@ Then you need to add this manifest to your `$OTIO_PLUGIN_MANIFEST_PATH` environm

Now that we've defined a new otio schema, how can we create an instance of the
schema class in our code (for instance, in an adapter or media linker)?
SchemaDef plugins are magically loaded into a namespace called ``otio.schemadef``,
so you can create a class instance just like this:

SchemaDef plugins are loaded in a deferred way. The load is triggered either
by reading a file that contains the schema or by manually asking the plugin for
its module object. For example, if you have a `my_thing` schemadef module:

```python
import opentimelineio as otio
my_thing = otio.schema.schemadef.module_from_name('my_thing')
```

Once the plugin has been loaded, SchemaDef plugin modules are magically inserted
into a namespace called ``otio.schemadef``, so you can create a class instance
just like this:

```
import opentimelineio as otio
@@ -42,7 +42,7 @@ def available_schemadef_names():


def from_name(name):
"""Fetch the schemadef object by the name of the schema directly."""
"""Fetch the schemadef plugin object by the name of the schema directly."""

try:
return plugins.ActiveManifest().from_name(name, kind_list="schemadefs")
@@ -53,3 +53,13 @@ def from_name(name):
available_schemadef_names()
)
)


def module_from_name(name):
"""Fetch the plugin's module by the name of the schemadef.
Will load the plugin if it has not already been loaded. Reading a file that
contains the schemadef will also trigger a load of the plugin.
"""
plugin = from_name(name)
return plugin.module()
@@ -33,6 +33,28 @@
SCHEMADEF_NAME = "schemadef_example"
EXAMPLE_ARG = "exampleArg"
EXCLASS = "<class 'opentimelineio.schemadef.example_schemadef.exampleSchemaDef'>"
TEST_STRING = """
{
"OTIO_SCHEMA": "exampleSchemaDef.1",
"exampleArg": "foobar"
}
"""


def _clean_plugin_module():
"""Remove the example_schemadef if its already been loaded to test
autoload/explicit load behavior.
"""
try:
del otio.schemadef.example_schemadef
except AttributeError:
pass

try:
plugin = otio.schema.schemadef.from_name("example_schemadef")
plugin._module = None
except otio.exceptions.NotSupportedError:
pass


class TestPluginSchemadefs(unittest.TestCase):
@@ -43,6 +65,7 @@ def setUp(self):
self.manifest_path = baseline_reader.path_to_baseline(SCHEMADEF_NAME)
os.environ['OTIO_PLUGIN_MANIFEST_PATH'] = self.manifest_path
otio.plugins.manifest.ActiveManifest(force_reload=True)
_clean_plugin_module()

def tearDown(self):
# restore original state
@@ -52,7 +75,21 @@ def tearDown(self):
del os.environ['OTIO_PLUGIN_MANIFEST_PATH']
otio.plugins.manifest._MANIFEST = self.save_manifest

_clean_plugin_module()

def test_autoloaded_plugin(self):
with self.assertRaises(AttributeError):
otio.schemadef.example_schemadef
# should force an autoload
thing = otio.adapters.read_from_string(TEST_STRING, "otio_json")
self.assertEqual(thing.exampleArg, "foobar")

def test_plugin_schemadef(self):
with self.assertRaises(AttributeError):
otio.schemadef.example_schemadef
# force loading the module
otio.schema.schemadef.module_from_name("example_schemadef")

# Our test manifest should have been loaded, including
# the example_schemadef.
# Try creating a schema object using the instance_from_schema method.
@@ -65,9 +102,18 @@ def test_plugin_schemadef(self):
self.assertEqual(example.exampleArg, peculiar_value)

def test_plugin_schemadef_namespace(self):
with self.assertRaises(AttributeError):
otio.schemadef.example_schemadef

# force loading the module
plugin_module = otio.schema.schemadef.module_from_name(
"example_schemadef"
)

# Try creating schema object with the direct class definition method:
peculiar_value = "something Two-derful"
example = otio.schemadef.example_schemadef.exampleSchemaDef(peculiar_value)
self.assertEqual(plugin_module, otio.schemadef.example_schemadef)
self.assertEqual(str(type(example)), EXCLASS)
self.assertEqual(example.exampleArg, peculiar_value)

0 comments on commit 929149e

Please sign in to comment.
You can’t perform that action at this time.