.. _plugins_creating_plugins:

Creating Plugins
================

Plugins can be created by exposing an importable class that inherits from 
``otter.plugins.AbstractOtterPlugin``. This class defines the base implementations of the plugin 
event methods and sets up the other information needed to run the plugin.


Plugin Configurations
---------------------

When instantiated, plugins will receive three arguments: ``submission_path``, the absolute path to 
the submission being executed, ``submission_metadata``, the information about the submission as read 
in from |submission_metadata.json|_, and ``plugin_config``, the parsed configurations from the 
user-specified list of plugins in the ``plugins`` key of ``otter_config.json``. The default 
implementation of ``__init__``, which should have the signature shown :ref:`below 
<plugins_creating_plugins_abstract_reference>`, sets these two values to the instance variables 
``self.submission_metadata`` and ``self.plugin_config``, respectively. *Note that some events are 
executed in contexts in which some or all of these variables are unavailable, and so these events 
should not rely on the use of these instance variables.* In cases in which these are unavailable, 
they will be set for the falsey version of their type, e.g. ``{}`` for ``self.submission_metadata``.

.. |submission_metadata.json| replace:: ``submission_metadata.json``
.. _submission_metadata.json: https://gradescope-autograders.readthedocs.io/en/latest/submission_metadata/


Plugin Events
-------------

Plugins currently support five events. Most events are expected to modify the state of the 
autograder and should not return anything, unless otherwise noted. Any plugins not supported should 
raise a ``otter.plugins.PluginEventNotSupportedException``, as the default implementations in
``AbstractOtterPlugin`` do. Note that all methods should have the signatures described :ref:`below 
<plugins_creating_plugins_abstract_reference>`.


``during_assign``
+++++++++++++++++

The ``during_assign`` method will be called when Otter Assign is run. It will receive the 
``otter.assign.assignment.Assignment`` instance with configurations for this assignment. The plugin 
is run after output directories are written.


``during_generate``
+++++++++++++++++++

The ``during_generate`` method will be called when Otter Generate is run. It will receive the parsed 
dictionary of configurations from ``otter_config.json`` as its argument. Any changes made to the 
configurations will be written to the ``otter_config.json`` that will be stored in the configuration 
zip file generated by Otter Generate.


``from_notebook``
+++++++++++++++++

The ``from_notebook`` method will be called when a student makes a call to 
``otter.Notebook.run_plugin`` with the plugin name. Any additional args and kwargs passed to 
``Notebook.run_plugin`` will be passed to the plugin method. This method should not return anything 
but can modify state or provide feedback to students. **Note that because this plugin is not run in 
the grading environment, it will *not* be passed the submission path, submission metadata, or a 
plugin config.** All information needed to run this plugin event must be gathered from the arguments 
passed to it.


``notebook_export``
+++++++++++++++++++

The ``notebook_export`` method will be called when a student makes a call to 
``otter.Notebook.add_plugin_files`` with the plugin name. Any additional args and kwargs passed to 
``Notebook.add_plugin_files`` will be passed to the plugin mtehod. This method should return a list 
of strings that correspond to file paths that should be included in the zip file generated by 
``otter.Notebook.export`` when it is run. The ``Notebook`` instance tracks these files in a list. 
**Note that because this plugin is not run in the grading environment, it will *not* be passed the 
submission path, submission metadata, or a plugin config.** All information needed to run this 
plugin event must be gathered from the arguments passed to it.


``before_grading``
++++++++++++++++++

The ``before_grading`` method will be called before grading occurs, just after the plugins are 
instantiated, and will be passed an instance of the
``otter.run.run_autograder.autograder_config.AutograderConfig`` class, a fica_ configurations class.
Any changes made to the options will be used during grading.

.. _fica: https://fica.readthedocs.io/


``before_execution``
++++++++++++++++++++

The ``before_execution`` method will be called before execution occurs and will be passed the 
student's submission. If the submission is a notebook, the object passed will be a 
``nbformat.NotebookNode`` from the parsed JSON. If the submission is a script, the objet passed will 
be a string containing the file text. This method should return a properly-formatted 
``NotebookNode`` or string that will be executed in place of the student's original submission.


``after_grading``
+++++++++++++++++

The ``after_grading`` method will be called after grading has occurred (meaning all tests have been 
run and the results object has been created). It will be passed the 
``otter.test_files.GradingResults`` object that contains the results of the student's submission 
against the tests. Any changes made to this object will be reflected in the results returned by the 
autograder. For more information about this object, see 
:ref:`workflow_executing_submissions_otter_run`.


``generate_report``
+++++++++++++++++++

The ``generate_report`` method will be called after results have been written. It receives no 
arguments but should **return a value**. The return value of this method should be a string that 
will be printed to stdout by Otter as part of the grading report.


.. _plugins_creating_plugins_abstract_reference:

``AbstractOtterPlugin`` Reference
---------------------------------

.. autoclass:: otter.plugins.AbstractOtterPlugin
    :members:
