In order to use cone.app
, an integration package must be created. This
package contains the application code and configuration.
cone.app
extensions are organized as Plugins. Thus, the integration
package may contain the Plugin code directly, or the Plugin is created as
seperate package.
In this documentation a package named cone.example
is created, which
contains both the integration and plugin code.
Note
The example package created in this documentation can be found in the Github repository.
First thing to do is to create a Python Package.
Create a directory named cone.example
with the following structure:
cone.example
├── bootstrap.sh
├── example.ini
├── setup.py
└── src
└── cone
├── example
│ ├── browser
│ │ ├── __init__.py
│ │ ├── static
│ │ │ ├── example.css
│ │ │ └── example.js
│ │ └── templates
│ │ └── example.pt
│ ├── configure.zcml
│ ├── __init__.py
│ └── model.py
└── __init__.py
The package must depend on cone.app
and waitress
as installation
dependency. Add the following to setup.py
.
from setuptools import find_packages
from setuptools import setup
version = '0.1'
shortdesc = 'Example cone plugin'
setup(
name='cone.example',
version=version,
description=shortdesc,
packages=find_packages('src'),
package_dir={'': 'src'},
namespace_packages=['cone'],
include_package_data=True,
zip_safe=False,
install_requires=[
'waitress',
'cone.app'
]
)
The package hooks up to the namespace package
cone
, so src/cone/__init__.py
must contain:
__import__('pkg_resources').declare_namespace(__name__)
Virtualenv is used to setup the
application. Add a bootstrap.sh
script, which creates the isolated python
environment, and installs the dependencies.
#!/bin/sh
set -e
for dir in lib include local bin share; do
if [ -d "$dir" ]; then
rm -r "$dir"
fi
done
python3 -m venv .
./bin/pip install pyramid==1.9.4
./bin/pip install repoze.zcml==1.1
./bin/pip install repoze.workflow==1.1
./bin/pip install -e .
Make this script executable.
chmod +x bootstrap.sh
cone.app
uses PasteDeploy
for application configuration. PasteDeploy defines a way to declare WSGI
application configuration in an .ini
file.
Create example.ini
and add:
[DEFAULT]
debug = true
[server:main]
use = egg:waitress#main
host = 0.0.0.0
port = 8081
[app:example]
use = egg:cone.app#main
# pyramid related configuration useful for development
pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.debug_templates = true
# default language
pyramid.default_locale_name = en
# available languages
#cone.available_languages = en, de
# cone.app admin user and password
cone.admin_user = admin
cone.admin_password = admin
#cone.authenticator =
# cone.app auth tkt settings
cone.auth_secret = 12345
#cone.auth_cookie_name =
#cone.auth_secure =
#cone.auth_include_ip =
#cone.auth_timeout =
#cone.auth_reissue_time =
#cone.auth_max_age =
#cone.auth_http_only =
#cone.auth_path =
#cone.auth_wild_domain =
# application main template
#cone.main_template = package.browser:templates/main.pt
# plugins to be loaded
cone.plugins = cone.example
# application root node settings
cone.root.title = cone.example
cone.root.default_child = example
#cone.root.default_content_tile =
#cone.root.mainmenu_empty_title = false
[pipeline:main]
pipeline =
example
Details about the available cone.app
dedicated configuration options can be
found in the Application Configuration documentation.
Plugins may contain a ZCML configuration which
contains ZCML configuration directives. If desired, add
src/cone/example/configure.zcml
containing:
<?xml version="1.0" encoding="utf-8" ?>
<configure xmlns="http://pylonshq.com/pyramid">
<!-- configuration directives goes here -->
</configure>
Delivering static resources is done by registering a directory for serving the assets and telling the application which files to deliver to the browser.
Create src/cone/example/browser/static
directory containing example.css
and example.js
.
Create a static view for the static
directory in
src/cone/example/browser/__init__.py
:
from pyramid.static import static_view
static_resources = static_view('static', use_subpath=True)
Register the static view and tell the application to deliver the CSS and JS file to the browser. This is done inside the Plugin main hook function.
Add the plugin main hook function in src/cone/example/__init__.py
containing.
from cone.app import main_hook
from cone.example.browser import static_resources
import cone.app
@main_hook
def example_main_hook(config, global_config, local_config):
"""Function which gets called at application startup to initialize
this plugin.
"""
# register static resources view
config.add_view(static_resources, name='example-static')
# register static resources to be delivered
cone.app.cfg.css.public.append('example-static/example.css')
cone.app.cfg.js.public.append('example-static/example.js')
cone.app
uses the traversal mechanism of Pyramid and utilize
node package for publishing.
Publishable nodes are expected to implement
cone.app.interfaces.IApplicationNode
. A basic application node is shipped
with cone.app
which can be used to start implementing the application model
from.
Detailed information about the application model can be found in the Application Model documentation.
Create plugin entry node in src/cone/example/model.py
.
from cone.app.model import BaseNode
class ExamplePlugin(BaseNode):
pass
The application needs to know about the application model entry node. This is
done by registering it with register_entry
inside the
Plugin main hook function.
Extend the main hook function in src/cone/example/__init__.py
and register
the model.
from cone.app import main_hook
from cone.app import register_entry
from cone.example.model import ExamplePlugin
@main_hook
def example_main_hook(config, global_config, local_config):
# register plugin entry node
register_entry('example', ExamplePlugin)
cone.app
follows the concept of tiles in it’s UI. Each part of the
application is represented by a tile, i.e. main menu, navigation tree, site
content area, etc.
The implementation and more documentation about tiles can be found here.
Detailed information about the available UI elements can be found in the UI Widgets documentation.
To render the Content Area of the UI for the ExamplePlugin
node, a tile
named content
must be created. Add src/cone/example/browser/__init__.py
and register it like so:
from cone.app.browser.layout import ProtectedContentTile
from cone.example.model import ExamplePlugin
from cone.tile import tile
@tile(name='content',
path='templates/example.pt',
interface=ExamplePlugin,
permission='login')
class ExamplePluginContent(ProtectedContentTile):
pass
Also create the corresponding page template in
src/cone/example/browser/templates/example.pt
containing:
<div>
Example app content.
</div>
Tell your plugin to scan the browser package inside the Plugin main hook function to ensure tile registration gets executed.
from cone.app import main_hook
@main_hook
def example_main_hook(config, global_config, local_config):
# scan browser package
config.scan('cone.example.browser')