Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation #7

Merged
merged 6 commits into from May 15, 2017
Merged

Documentation #7

merged 6 commits into from May 15, 2017

Conversation

meluru
Copy link

@meluru meluru commented Apr 20, 2017

API documentation is still WIP but it would be great if you could already check the installation, setup and example usage steps if they make sense.

@meluru
Copy link
Author

meluru commented Apr 24, 2017

Api documentation updated, let me know if I should add something more to it.

Copy link

@nop33 nop33 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job 👍 It's mainly syntactical mistakes, but the documentation looks great!

Creating a plugin
-----------------

Creating a plugin is simple. First of all you need to create a class for your plugin inheriting from Plugin::
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we also mention the file names? Does it play an important role? Like plugin.py, setup.py, etc. If not, nvm!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A folder structure would also be useful. If I start creating the plugin now for example, just by reading the doc, I have no idea how to structure the code you mentioned 😉

Current plugin
--------------

Very useful feature of Flask-PluginEngine is a ``current_plugin`` global value. It's a proxy to currently active plugin.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Very useful feature of Flask-PluginEngine is a the..."

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"It's a proxy to the currently active plugin."

Example plugin functionality
----------------------------

Now let's give our plugin some functionality to show how you can use the plugin. In this example we will render plugin's template from our application.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Now let's give our plugin some functionality to show how you can use the plugin it. In this example we will render the plugin's template from our application."


Now let's give our plugin some functionality to show how you can use the plugin. In this example we will render plugin's template from our application.

Let's create the templates folder with a simple Jinja template. For example displaying plugin's title and description::
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Let's create the templates folder with a simple Jinja template . For example displaying to display for example the plugin's title and description"

<div>{{ plugin.description }}</div>
{% endblock %}

If you documented plugin's class now you can access it as a ``name`` and ``description`` class properties.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am afraid I don't understand what this means.

---------------------------------

To understand the possibilities of Flask-PluginEngine we will create a Jinja template, where we will list all the plugins we are using.
Let's create two templates, the base one (base.html), for example::
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd reword it a bit to:
"Let's create two templates, base.html and index.html: " and add comments above each code block below, like this:

{# base.html #}

<!DOCTYPE html>
 
<html lang="en">
    <head>
        ...
{# index.html #}

<!DOCTYPE html>
 
<html lang="en">
    <head>
        ...

def hello():
return render_template('index.html', plugins=active_plugins)

Now what we also should do is register the blueprints of all our plugins, for instance::
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Now what we should also do is to register the blueprints of all our plugins..."

if __name__ == "__main__":
app.run()

Now when we will go to the index page of our application we will be able to access plugin's template.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Now, when we will go to the index page of our application we will be able to can access the plugin's template."


Now when we will go to the index page of our application we will be able to access plugin's template.

You can find the application in the source code in example folder.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"You can find the source code of the application in the example folder"


.. classmethod:: title()

Plugin's title from the docstring
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this supposed to be fetched automatically?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be, but due to the decorator problem I had to write it

@meluru
Copy link
Author

meluru commented Apr 26, 2017

Updated

@coveralls
Copy link

coveralls commented Apr 26, 2017

Coverage Status

Coverage remained the same at 87.321% when pulling 04467d9 on meluru:documentation into 14c7b97 on indico:master.

Copy link
Member

@mvidalgarcia mvidalgarcia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well done! 🎉

| setup.py
|
└───templates
| index.html
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This directory tree is a bit confusing IMO, what about this?

plugin
├── example_plugin.py
├── setup.py
└── templates
    └── index.html

from flask_pluginengine import Plugin

class ExamplePlugin(Plugin):
"""ExamplePlugin
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring here should be indented.

<div>{{ plugin.description }}</div>
{% endblock %}

Notice that the template extends a base.html. We are going to use the application's base template.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

base.html


@plugin_blueprint.route('/plugin')
def hello_plugin():
return render_template('example_plugin:index.html', plugin=current_plugin)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation.


@app.route("/")
def hello():
return render_template('index.html', plugins=active_plugins)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation.

Now what we should also do is to register the blueprints of all our plugins, for instance::

for plugin in active_plugins:
with plugin.plugin_context():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation.

<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it would look better "Flask-PluginEngine example" or similar?

if __name__ == "__main__":
app.run()

Now when we go to the index page of our application we can access the plugin's template.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's worth to mention here that you can also go to /plugin and access the template of the plugin itself via its blueprint so that you prove that the stuff implemented in the plugin can be used.


Now when we go to the index page of our application we can access the plugin's template.

You can find the source code of the application in the example folder.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd appreciate here a link to the example folder.

active_plugins = plugin_engine.get_active_plugins(app=app).values()


Example application functionality
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I started reading this section I didn't know where to write the fragments of code explained and I struggled a bit until I check the example folder. In my opinion would be useful here to either explain that the plugin will be in a separated folder and the app itself in a different one or show again a directory tree pointing where the code in this section should be written in.

@meluru
Copy link
Author

meluru commented Apr 28, 2017

Updated

Copy link

@DavidAndreev DavidAndreev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find anything else :) Great job ! Nice guide which is easy to understand ;)

@@ -26,17 +26,29 @@ You can install Flask-PluginEngine with the following command::
Creating a plugin
-----------------

Creating a plugin is simple. First of all you need to create a class for your plugin inheriting from Plugin::
Creating a plugin is simple. First of all you need to create necessary files: file for your plugin code (in our case: ``example_plugin.py``), ``setup.py`` and

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there should be a coma : First of all, you need ..

Copy link
Member

@pferreir pferreir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, just have a few suggestions!

Creating a plugin
-----------------

Creating a plugin is simple. First of all you need to create necessary files: file for your plugin code (in our case: ``example_plugin.py``), ``setup.py`` and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"create the necessary files: a file for [...] and a templates folder"

Just an example plugin
"""

Second, you need to fill the ``setup.py``. It's important to define a proper entry point to plugin's class. For example::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"point to the plugin's class"

def hello_plugin():
return render_template('example_plugin:index.html', plugin=current_plugin)

We can render any plugin template inside our application specifying the name of the plugin before the template name in ``render_template`` function, like above.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"in the render_template function"

return render_template('example_plugin:index.html', plugin=current_plugin)

We can render any plugin template inside our application specifying the name of the plugin before the template name in ``render_template`` function, like above.
We are also passing a current_plugin object to the template.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add double backticks around current_plugin.

Minimal application setup
-------------------------

To create a Flask application using Flask-PluginEngine we need to define it as ``PluginFlask`` application::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"as a PluginFlask application"


if __name__ == "__main__":
app.run()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would maybe mention that PluginFlask is just a regular Flask application object with some added plugin magic. It should be already quite clear, however.

name='Example-Plugin',
version='0.0.1',
py_modules=['example_plugin'],
entry_points={'example': {'example_plugin = example_plugin:ExamplePlugin'}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would mention that example is the namespace we're going to use below, in the application's config.

plugin_engine.load_plugins(app)

Then, we can access the loaded plugins by calling the :func:`get_active_plugins` method, which will return a dictionary containing the active plugins.
To check if all of the plugins were loaded correctly we can also call the :func:`get_failed_plugins` method that will return a dictionary with plugins that failed to load::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would perhaps move the part about get_failed_plugins below the example. It's a bit confusing to have an example that doesn't refer to it.

@meluru
Copy link
Author

meluru commented May 4, 2017

Updated

@ThiefMaster
Copy link
Member

Would it make sense to split the docs into multiple pages? When you want to write a plugin for some application you probably don't care about how to use this extension in your own app. OTOH, an application should have its own documentation on how to write plugins for it.


The Plugin instance used by the current app

.. classmethod:: title()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it show up as title() or title in the docs? Because it's a class-level property and using () wouldn't work for obvious reasons ;)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checked and it indeed shows up wrong.

app.register_blueprint(plugin.get_blueprint())


@app.route("/")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

single quotes

return render_template('index.html', plugins=active_plugins)


if __name__ == "__main__":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

single quotes

@@ -119,12 +119,14 @@ def instance(cls):
@classproperty
@classmethod
def title(cls):
"""Plugin's title from the docstring"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"""The title of the plugin.

Automatically retrieved from the docstring of the plugin class.
"""

parts = trim_docstring(cls.__doc__).split('\n', 1)
return parts[0].strip()

@classproperty
@classmethod
def description(cls):
"""Plugin's description from the docstring"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"""The description of the plugin.

Automatically retrieved from the docstring of the plugin class.
"""

@meluru
Copy link
Author

meluru commented May 10, 2017

Updated

@coveralls
Copy link

coveralls commented May 15, 2017

Coverage Status

Coverage remained the same at 87.321% when pulling e2922fd on meluru:documentation into c1d7234 on indico:master.

@meluru meluru merged commit 112a39d into indico:master May 15, 2017
@meluru meluru deleted the documentation branch May 15, 2017 12:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants