diff options
Diffstat (limited to 'docs/source/pluginwriter')
-rw-r--r-- | docs/source/pluginwriter/api.rst | 124 | ||||
-rw-r--r-- | docs/source/pluginwriter/database.rst | 9 | ||||
-rw-r--r-- | docs/source/pluginwriter/quickstart.rst | 6 | ||||
-rw-r--r-- | docs/source/pluginwriter/tests.rst | 64 |
4 files changed, 197 insertions, 6 deletions
diff --git a/docs/source/pluginwriter/api.rst b/docs/source/pluginwriter/api.rst index 44411965..66def173 100644 --- a/docs/source/pluginwriter/api.rst +++ b/docs/source/pluginwriter/api.rst @@ -11,6 +11,7 @@ Dedication along with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. +.. _plugin-api-chapter: ========== Plugin API @@ -23,7 +24,27 @@ Authors are encouraged to develop plugins and work with the MediaGoblin community to keep them up to date, but this API will be a moving target for a few releases. -Please check the release notes for updates! +Please check the :ref:`release-notes` for updates! + + +How are hooks added? Where do I find them? +------------------------------------------- + +Much of this document talks about hooks, both as in terms of regular +hooks and template hooks. But where do they come from, and how can +you find a list of them? + +For the moment, the best way to find available hooks is to check the +source code itself. (Yes, we should start a more official hook +listing with descriptions soon.) But many hooks you may need do not +exist yet: what to do then? + +The plan at present is that we are adding hooks as people need them, +with community discussion. If you find that you need a hook and +MediaGoblin at present doesn't provide it at present, please +`http://mediagoblin.org/pages/join.html <talk to us>`_! We'll +evaluate what to do from there. + :mod:`pluginapi` Module ----------------------- @@ -172,3 +193,104 @@ object, so you can access this in your templates like: <img alt="A funny bunny" src="{{ request.staticdirect('images/funnybunny.png', 'mystaticname') }}" /> + + +Additional hook tips +-------------------- + +This section aims to explain some tips in regards to adding hooks to +the MediaGoblin repository. + +WTForms hooks ++++++++++++++ + +We haven't totally settled on a way to tranform wtforms form objects, +but here's one way. In your view:: + + from mediagoblin.foo.forms import SomeForm + + def some_view(request) + form_class = hook_transform('some_form_transform', SomeForm) + form = form_class(request.form) + +Then to hook into this form, do something in your plugin like:: + + import wtforms + + class SomeFormAdditions(wtforms.Form): + new_datefield = wtforms.DateField() + + def transform_some_form(orig_form): + class ModifiedForm(orig_form, SomeFormAdditions) + return ModifiedForm + + hooks = { + 'some_form_transform': transform_some_form} + + +Interfaces +++++++++++ + +If you want to add a pseudo-interface, it's not difficult to do so. +Just write the interface like so:: + + class FrobInterface(object): + """ + Interface for Frobbing. + + Classes implementing this interface should provide defrob and frob. + They may also implement double_frob, but it is not required; if + not provided, we will use a general technique. + """ + + def defrob(self, frobbed_obj): + """ + Take a frobbed_obj and defrob it. Returns the defrobbed object. + """ + raise NotImplementedError() + + def frob(self, normal_obj): + """ + Take a normal object and frob it. Returns the frobbed object. + """ + raise NotImplementedError() + + def double_frob(self, normal_obj): + """ + Frob this object and return it multiplied by two. + """ + return self.frob(normal_obj) * 2 + + + def some_frob_using_method(): + # something something something + frobber = hook_handle(FrobInterface) + frobber.frob(blah) + + # alternately you could have a default + frobber = hook_handle(FrobInterface) or DefaultFrobber + frobber.defrob(foo) + + +It's fine to use your interface as the key instead of a string if you +like. (Usually this is messy, but since interfaces are public and +since you need to import them into your plugin anyway, interfaces +might as well be keys.) + +Then a plugin providing your interface can be like:: + + from mediagoblin.foo.frobfrogs import FrobInterface + from frogfrobber import utils + + class FrogFrobber(FrobInterface): + """ + Takes a frogputer science approach to frobbing. + """ + def defrob(self, frobbed_obj): + return utils.frog_defrob(frobbed_obj) + + def frob(self, normal_obj): + return utils.frog_frob(normal_obj) + + hooks = { + FrobInterface: lambda: return FrogFrobber} diff --git a/docs/source/pluginwriter/database.rst b/docs/source/pluginwriter/database.rst index 58edf3a0..603a19eb 100644 --- a/docs/source/pluginwriter/database.rst +++ b/docs/source/pluginwriter/database.rst @@ -12,9 +12,12 @@ <http://creativecommons.org/publicdomain/zero/1.0/>. -======== -Database -======== +.. _plugin-database-chapter: + + +=========================== +Database models for plugins +=========================== Accessing Existing Data diff --git a/docs/source/pluginwriter/quickstart.rst b/docs/source/pluginwriter/quickstart.rst index b5a63f79..6d45ea36 100644 --- a/docs/source/pluginwriter/quickstart.rst +++ b/docs/source/pluginwriter/quickstart.rst @@ -178,8 +178,10 @@ That's it for the quick start! Where to go from here ===================== -See the documentation on the plugin API for code samples and other -things you can use when building your plugin. +See the documentation on the :ref:`plugin-api-chapter` for code +samples and other things you can use when building your plugin. If +your plugin needs its own database models, see +:ref:`plugin-database-chapter`. See `Hitchhiker's Guide to Packaging <http://guide.python-distribute.org/>`_ for more information on diff --git a/docs/source/pluginwriter/tests.rst b/docs/source/pluginwriter/tests.rst new file mode 100644 index 00000000..fe99688f --- /dev/null +++ b/docs/source/pluginwriter/tests.rst @@ -0,0 +1,64 @@ +.. MediaGoblin Documentation + + Written in 2013 by MediaGoblin contributors + + To the extent possible under law, the author(s) have dedicated all + copyright and related and neighboring rights to this software to + the public domain worldwide. This software is distributed without + any warranty. + + You should have received a copy of the CC0 Public Domain + Dedication along with this software. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + +============================== +Writing unit tests for plugins +============================== + +Here's a brief guide to writing unit tests for plugins. However, it +isn't really ideal. It also hasn't been well tested... yes, there's +some irony there :) + +Some notes: we're using py.test and webtest for unit testing stuff. +Keep that in mind. + +My suggestion is to mime the behavior of `mediagoblin/tests/` and put +that in your own plugin, like `myplugin/tests/`. Copy over +`conftest.py` and `pytest.ini` to your tests directory, but possibly +change the `test_app` fixture to match your own tests' config needs. +For example:: + + import pkg_resources + # [...] + + @pytest.fixture() + def test_app(request): + return get_app( + request, + mgoblin_config=pkg_resources.resource_filename( + 'myplugin.tests', 'myplugin_mediagoblin.ini')) + +In any test module in your tests directory you can then do:: + + def test_somethingorother(test_app): + # real code goes here + pass + +And you'll get a mediagoblin application wrapped in webtest passed in +to your environment. + +If your plugin needs to define multiple configuration setups, you can +actually set up multiple fixtures very easily for this. You can just +set up multiple fixtures with different names that point to different +configs and pass them in as that named argument. + +To run the tests, from mediagoblin's directory (make sure that your +plugin has been added to your mediagoblin checkout's virtualenv!) do:: + + ./runtests.sh /path/to/myplugin/tests/ + +replacing `/path/to/myplugin/` with the actual path to your plugin. + +NOTE: again, the above is untested, but it should probably work. If +you run into trouble, `contact us +<http://mediagoblin.org/pages/join.html>`_, preferably on IRC! |