mirror of
https://github.com/datafolklabs/cement.git
synced 2026-02-06 14:26:55 +00:00
reorganizing files, including devtools/test
This commit is contained in:
parent
befba3ead2
commit
2a10982704
@ -3,6 +3,8 @@
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
+ Development Release 0.8.13
|
||||
+ Moving cement.devtools and cement.test back under main project
|
||||
+ Reorganized project files, python packages are under ./src
|
||||
|
||||
|
||||
0.8.12 - Dec 06, 2010
|
||||
|
||||
1
LICENSE
1
LICENSE
@ -20,3 +20,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
14
README
14
README
@ -63,16 +63,6 @@ Development versions of Cement can be checked out of Git:
|
||||
::
|
||||
$ git clone git://github.com/derks/cement.git
|
||||
|
||||
$ cd cement
|
||||
|
||||
$ python setup.py install
|
||||
|
||||
$ git clone git://github.com/derks/cement.devtools.git
|
||||
|
||||
$ cd cement.devtools
|
||||
|
||||
$ python setup.py install
|
||||
|
||||
|
||||
With the 'devtools' package, Cement applications, and plugins can be
|
||||
created via PasteScript. Once cement and cement.devtools are installed,
|
||||
@ -86,7 +76,3 @@ The following command will create an external plugin for your application:
|
||||
::
|
||||
$ paster cement-plugin myapp myplugin
|
||||
|
||||
|
||||
Have an external helper library you want to make plugable?
|
||||
::
|
||||
$ paster cement-helper myapp myhelper
|
||||
|
||||
23
src/cement.devtools/LICENSE
Normal file
23
src/cement.devtools/LICENSE
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
The MIT License:
|
||||
|
||||
Copyright (c) 2009-2010 BJ Dierkes
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
1
src/cement.devtools/MANIFEST.in
Normal file
1
src/cement.devtools/MANIFEST.in
Normal file
@ -0,0 +1 @@
|
||||
recursive-include cement/paste/templates *
|
||||
40
src/cement.devtools/README
Normal file
40
src/cement.devtools/README
Normal file
@ -0,0 +1,40 @@
|
||||
NAME: cement.devtools
|
||||
|
||||
CREATOR/MAINTAINER: BJ Dierkes <wdierkes@5dollarwhitebox.org>
|
||||
|
||||
DESCRIPTION:
|
||||
|
||||
Cement is an advanced CLI Application Framework for Python. The 'devtools'
|
||||
package provides tools and libraries needed for developing applications that
|
||||
are built on Cement.
|
||||
|
||||
The Cement CLI Application Framework is Open Source and is distributed under
|
||||
The MIT License.
|
||||
|
||||
|
||||
GETTING STARTED:
|
||||
|
||||
Stable versions of Cement can be installed via the cheeze shop:
|
||||
::
|
||||
$ easy_install cement
|
||||
|
||||
$ easy_install cement.devtools
|
||||
|
||||
|
||||
Development versions of Cement can be checked out of Git:
|
||||
::
|
||||
$ git clone git://github.com/derks/cement.git
|
||||
|
||||
|
||||
With the 'devtools' package, Cement applications, and plugins can be
|
||||
created via PasteScript. Once cement.core and cement.devtools are installed,
|
||||
the following command will create a command line application built on top of
|
||||
the Cement Framework:
|
||||
::
|
||||
$ paster cement-app myapp
|
||||
|
||||
|
||||
The following command will create an external plugin for your application:
|
||||
::
|
||||
$ paster cement-plugin myapp myplugin
|
||||
|
||||
2
src/cement.devtools/cement/__init__.py
Normal file
2
src/cement.devtools/cement/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
|
||||
25
src/cement.devtools/cement/paste/__init__.py
Normal file
25
src/cement.devtools/cement/paste/__init__.py
Normal file
@ -0,0 +1,25 @@
|
||||
"""
|
||||
The module handles the integration with PasteScript enabling the following
|
||||
plugins to the 'paste' command line utility:
|
||||
|
||||
cement-app
|
||||
Generates a base application built on Cement.
|
||||
|
||||
cement-plugin
|
||||
Generates an external plugin for an application built on Cement.
|
||||
|
||||
cement-helper
|
||||
Generates an external helper for an application built on Cement.
|
||||
|
||||
Usage:
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ paster cement-app helloworld
|
||||
|
||||
$ paster cement-plugin helloworld myplugin
|
||||
|
||||
$ paster cement-helper helloworld myhelper
|
||||
|
||||
"""
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
272
src/cement.devtools/cement/paste/commands.py
Normal file
272
src/cement.devtools/cement/paste/commands.py
Normal file
@ -0,0 +1,272 @@
|
||||
"""
|
||||
A significant portion of this file was derived from the tg.devtools software
|
||||
which is licensed under the MIT license. The following license applies to
|
||||
the work in *this* file only, and not any other part of the Cement Framework
|
||||
unless otherwise noted:
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
Copyright (c) 2008 TurboGears Team
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
Paste commands to generate a new Cement projects and plugins.
|
||||
|
||||
"""
|
||||
|
||||
# Taken mostly from tg.devtools... Thank you!
|
||||
|
||||
import sys, os
|
||||
import re
|
||||
import pkg_resources
|
||||
import optparse
|
||||
from paste.script import command
|
||||
from paste.script import create_distro
|
||||
|
||||
beginning_letter = re.compile(r"^[^a-z]*")
|
||||
valid_only = re.compile(r"[^a-z0-9_\.]")
|
||||
|
||||
CEMENT_VERSION = pkg_resources.get_distribution('cement').version
|
||||
|
||||
(base, major) = CEMENT_VERSION.split('.')[:2]
|
||||
CEMENT_MAJOR_VERSION = '.'.join(CEMENT_VERSION.split('.')[:2])
|
||||
|
||||
if int(major)%2==0:
|
||||
CEMENT_NEXT_VERSION = float(CEMENT_MAJOR_VERSION) + 0.1
|
||||
else:
|
||||
CEMENT_NEXT_VERSION = float(CEMENT_MAJOR_VERSION) + 0.2
|
||||
|
||||
class CementAppCommand(command.Command):
|
||||
"""Create a new CLI Application using the Cement Framework.
|
||||
|
||||
Example usage::
|
||||
|
||||
$ paster cement-app yourproject
|
||||
|
||||
"""
|
||||
version = CEMENT_VERSION
|
||||
summary = __doc__.splitlines()[0]
|
||||
usage = '\n' + __doc__
|
||||
name = None
|
||||
group_name = "Cement"
|
||||
dry_run = False
|
||||
templates = "cementapp"
|
||||
|
||||
parser = command.Command.standard_parser(quiet=True)
|
||||
parser = optparse.OptionParser(
|
||||
usage="%prog cement-app [options] [project name]",
|
||||
version="%prog " + version
|
||||
)
|
||||
parser.add_option("-t", "--templates",
|
||||
help="user specific templates",
|
||||
dest="templates", default=templates
|
||||
)
|
||||
parser.add_option("--dry-run",
|
||||
help="dry run (don't actually do anything)",
|
||||
action="store_true", dest="dry_run"
|
||||
)
|
||||
|
||||
def command(self):
|
||||
"""LayCement for the new project."""
|
||||
|
||||
self.__dict__.update(self.options.__dict__)
|
||||
|
||||
if self.args:
|
||||
self.name = self.args[0]
|
||||
|
||||
while not self.name:
|
||||
self.name = raw_input("Enter project name: ").strip()
|
||||
|
||||
self.name = pkg_resources.safe_name(self.name)
|
||||
|
||||
package = self.name.lower()
|
||||
package = beginning_letter.sub("", package)
|
||||
package = valid_only.sub("_", package)
|
||||
self.package = raw_input(
|
||||
"Enter module name [%s]: " % package).strip() or package
|
||||
|
||||
self.description = raw_input(
|
||||
"Project Description: ").strip()
|
||||
self.creator = raw_input(
|
||||
"Project Creator: ").strip()
|
||||
self.creator_email = raw_input(
|
||||
"Project Creator Email: ").strip()
|
||||
self.url = raw_input(
|
||||
"Project URL: ").strip()
|
||||
self.license = raw_input(
|
||||
"Project License: ").strip()
|
||||
|
||||
env = pkg_resources.Environment()
|
||||
if self.name.lower() in env:
|
||||
print 'The name "%s" is already in use by ' % self.name,
|
||||
for dist in env[self.name]:
|
||||
print dist
|
||||
return
|
||||
|
||||
import imp
|
||||
try:
|
||||
if imp.find_module(self.package):
|
||||
print 'The package name "%s" is already in use' % self.package
|
||||
return
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
if os.path.exists(self.name):
|
||||
print 'A directory called "%s" already exists. Exiting.' % self.name
|
||||
return
|
||||
|
||||
command = create_distro.CreateDistroCommand("create")
|
||||
cmd_args = []
|
||||
for template in self.templates.split():
|
||||
cmd_args.append("--template=%s" % template)
|
||||
|
||||
cmd_args.append(self.name)
|
||||
cmd_args.append("package=%s" % self.package)
|
||||
cmd_args.append("cement_version=%s" % CEMENT_VERSION)
|
||||
cmd_args.append("cement_next_version=%s" % CEMENT_NEXT_VERSION)
|
||||
cmd_args.append("description=%s" % self.description)
|
||||
cmd_args.append("creator=%s" % self.creator)
|
||||
cmd_args.append("creator_email=%s" % self.creator_email)
|
||||
cmd_args.append("url=%s" % self.url)
|
||||
cmd_args.append("license=%s" % self.license)
|
||||
|
||||
command.run(cmd_args)
|
||||
|
||||
if not self.dry_run:
|
||||
sys.argv = ["setup.py", "egg_info"]
|
||||
|
||||
# dirty hack to allow "empty" dirs
|
||||
for base, path, files in os.walk("./"):
|
||||
for file in files:
|
||||
if file == "empty":
|
||||
os.remove(os.path.join(base, file))
|
||||
|
||||
|
||||
class CementPluginCommand(command.Command):
|
||||
"""Create a plugin for an application using the Cement Framework.
|
||||
|
||||
Example usage::
|
||||
|
||||
$ paster cement-plugin yourproject yourplugin
|
||||
"""
|
||||
version = CEMENT_VERSION
|
||||
summary = __doc__.splitlines()[0]
|
||||
usage = '\n' + __doc__
|
||||
name = None
|
||||
group_name = "Cement"
|
||||
dry_run = False
|
||||
templates = "cementplugin"
|
||||
project = None
|
||||
plugin = None
|
||||
|
||||
parser = command.Command.standard_parser(quiet=True)
|
||||
parser = optparse.OptionParser(
|
||||
usage="%prog cement-plugin [options] [project name] [plugin_name]",
|
||||
version="%prog " + version
|
||||
)
|
||||
parser.add_option("-t", "--templates",
|
||||
help="user specific templates",
|
||||
dest="templates", default=templates
|
||||
)
|
||||
parser.add_option("--dry-run",
|
||||
help="dry run (don't actually do anything)",
|
||||
action="store_true", dest="dry_run"
|
||||
)
|
||||
|
||||
def command(self):
|
||||
"""LayCement for the new project plugin."""
|
||||
|
||||
self.__dict__.update(self.options.__dict__)
|
||||
|
||||
if self.args:
|
||||
try:
|
||||
self.project = self.args[0].lower()
|
||||
self.plugin = self.args[1].lower()
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
while not self.project:
|
||||
self.project = raw_input("Enter project name: ").lower()
|
||||
|
||||
package = "%s" % self.project
|
||||
package = beginning_letter.sub("", package)
|
||||
package = valid_only.sub("_", package)
|
||||
|
||||
self.package = raw_input(
|
||||
"Enter module name [%s]: " % package).strip() or package
|
||||
|
||||
while not self.plugin:
|
||||
self.plugin = raw_input("Enter plugin name: ").lower()
|
||||
|
||||
self.plugin = beginning_letter.sub("", self.plugin)
|
||||
self.plugin = valid_only.sub("_", self.plugin)
|
||||
|
||||
self.creator = raw_input(
|
||||
"Project Creator: ").strip()
|
||||
self.creator_email = raw_input(
|
||||
"Project Creator Email: ").strip()
|
||||
self.url = raw_input(
|
||||
"Project URL: ").strip()
|
||||
self.license = raw_input(
|
||||
"Project License: ").strip()
|
||||
|
||||
name = "%s.%s" % (self.project, self.plugin)
|
||||
self.name = pkg_resources.safe_name(name)
|
||||
|
||||
env = pkg_resources.Environment()
|
||||
if self.name.lower() in env:
|
||||
print 'The name "%s" is already in use by' % self.name,
|
||||
for dist in env[self.name]:
|
||||
print dist
|
||||
return
|
||||
|
||||
if os.path.exists(self.name):
|
||||
print 'A directory called "%s" already exists. Exiting.' % self.name
|
||||
return
|
||||
|
||||
command = create_distro.CreateDistroCommand("create")
|
||||
cmd_args = []
|
||||
for template in self.templates.split():
|
||||
cmd_args.append("--template=%s" % template)
|
||||
cmd_args.append(self.name)
|
||||
cmd_args.append("project=%s" % self.project)
|
||||
cmd_args.append("package=%s" % self.package)
|
||||
cmd_args.append("plugin=%s" % self.plugin)
|
||||
cmd_args.append("cement_version=%s" % CEMENT_VERSION)
|
||||
cmd_args.append("cement_next_version=%s" % CEMENT_NEXT_VERSION)
|
||||
cmd_args.append("creator=%s" % self.creator)
|
||||
cmd_args.append("creator_email=%s" % self.creator_email)
|
||||
cmd_args.append("url=%s" % self.url)
|
||||
cmd_args.append("license=%s" % self.license)
|
||||
|
||||
command.run(cmd_args)
|
||||
|
||||
if not self.dry_run:
|
||||
sys.argv = ["setup.py", "egg_info"]
|
||||
|
||||
# dirty hack to allow "empty" dirs
|
||||
for base, path, files in os.walk("./"):
|
||||
for file in files:
|
||||
if file == "empty":
|
||||
os.remove(os.path.join(base, file))
|
||||
|
||||
89
src/cement.devtools/cement/paste/template.py
Normal file
89
src/cement.devtools/cement/paste/template.py
Normal file
@ -0,0 +1,89 @@
|
||||
"""
|
||||
Definition for Cement laycement templates.
|
||||
|
||||
A significant portion of this file was derived from the tg.devtools software
|
||||
which is licensed under the MIT license. The following license applies to
|
||||
the work in *this* file only, and not any other part of the Cement Framework
|
||||
unless otherwise noted:
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
Copyright (c) 2008 TurboGears Team
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
-----------------------------------------------------------------------------
|
||||
"""
|
||||
|
||||
from paste.script import templates
|
||||
from tempita import paste_script_template_renderer
|
||||
|
||||
import pkg_resources
|
||||
from pkg_resources import get_distribution
|
||||
|
||||
class CementAppTemplate(templates.Template):
|
||||
"""
|
||||
Cement default paste template class
|
||||
"""
|
||||
_template_dir = 'templates/cementapp'
|
||||
template_renderer = staticmethod(paste_script_template_renderer)
|
||||
summary = 'Cement Standard Template'
|
||||
egg_plugins = ['PasteScript', 'Cement']
|
||||
vars = [
|
||||
templates.var("package", "Package module name", default=''),
|
||||
templates.var("cement_version", "Cement version", default=None),
|
||||
templates.var("cement_next_version", "Cement Next Version",
|
||||
default=None),
|
||||
templates.var("description", "Description", default=''),
|
||||
templates.var("creator", "Creator", default=''),
|
||||
templates.var("creator_email", "Creator Email", default=''),
|
||||
templates.var("url", "URL", default=''),
|
||||
templates.var("license", "License", default=''),
|
||||
]
|
||||
|
||||
def pre(self, command, output_dir, vars):
|
||||
"""Called before template is applied."""
|
||||
pass
|
||||
|
||||
class CementPluginTemplate(templates.Template):
|
||||
"""
|
||||
Cement plugin default paste template class.
|
||||
"""
|
||||
_template_dir = 'templates/cementplugin'
|
||||
template_renderer = staticmethod(paste_script_template_renderer)
|
||||
summary = 'Cement Plugin Standard Template'
|
||||
egg_plugins = ['PasteScript', 'Cement']
|
||||
vars = [
|
||||
templates.var("plugin", "cement plugin name", default=None),
|
||||
templates.var("project", "Parent application this plugin is for",
|
||||
default=None),
|
||||
templates.var("package", "Package module name", default=''),
|
||||
templates.var("cement_version", "Cement version", default=None),
|
||||
templates.var("cement_next_version", "Cement Next Version",
|
||||
default=None),
|
||||
templates.var("creator", "Creator", default=''),
|
||||
templates.var("creator_email", "Creator Email", default=''),
|
||||
templates.var("url", "URL", default=''),
|
||||
templates.var("license", "License", default=''),
|
||||
]
|
||||
|
||||
def pre(self, command, output_dir, vars):
|
||||
"""Called before template is applied."""
|
||||
pass
|
||||
1
src/cement.devtools/cement/paste/templates/__init__.py
Normal file
1
src/cement.devtools/cement/paste/templates/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1,39 @@
|
||||
|
||||
from cement.core.hook import define_hook
|
||||
from cement.core.namespace import CementNamespace, register_namespace
|
||||
|
||||
define_hook('my_example_hook')
|
||||
|
||||
# Setup the 'example' namespace object
|
||||
example = CementNamespace(
|
||||
label='example',
|
||||
controller='ExampleController',
|
||||
description='Example Plugin for {{project}}',
|
||||
provider='{{project}}'
|
||||
)
|
||||
|
||||
# Example namespace default configurations, overwritten by the [example]
|
||||
# section of the applications config file(s). Once registered, this dict is
|
||||
# accessible as:
|
||||
#
|
||||
# from cement.core.namespace import get_config
|
||||
# example_config = get_config('example')
|
||||
#
|
||||
# Or simply as:
|
||||
#
|
||||
# root_config = get_config()
|
||||
# root_config['example']
|
||||
#
|
||||
example.config['foo'] = 'bar'
|
||||
|
||||
# Example namespace options. These options show up under:
|
||||
#
|
||||
# $ {{package}} example --help
|
||||
#
|
||||
example.options.add_option('-F', '--foo', action='store',
|
||||
dest='foo', default=None, help='Example Foo Option'
|
||||
)
|
||||
|
||||
# Officialize and register the namespace
|
||||
register_namespace(example)
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
"""
|
||||
The bootstrap module should be used to setup parts of your application
|
||||
that need to exist before all controllers are loaded. It is best used to
|
||||
define hooks, setup namespaces, and the like. The root namespace is
|
||||
already bootstrapped by Cement, however you can extend that functionality
|
||||
by importing additional bootstrap files here.
|
||||
"""
|
||||
|
||||
from cement.core.opt import init_parser
|
||||
from cement.core.hook import register_hook
|
||||
|
||||
# Register root options
|
||||
@register_hook()
|
||||
def options_hook(*args, **kwargs):
|
||||
# This hook allows us to append options to the root namespace
|
||||
root_options = init_parser()
|
||||
root_options.add_option('-R', '--root-option', action ='store_true',
|
||||
dest='root_option', default=None, help='Example root option')
|
||||
root_options.add_option('--json', action='store_true',
|
||||
dest='enable_json', default=None,
|
||||
help='render output as json (CLI-API)')
|
||||
root_options.add_option('--debug', action='store_true',
|
||||
dest='debug', default=None, help='toggle debug output')
|
||||
root_options.add_option('--quiet', action='store_true',
|
||||
dest='quiet', default=None, help='disable console logging')
|
||||
return ('root', root_options)
|
||||
|
||||
# Import all additional (non-plugin) bootstrap libraries here
|
||||
#
|
||||
# from {{package}}.bootstrap import example
|
||||
#
|
||||
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1,17 @@
|
||||
"""{{package}} controller."""
|
||||
|
||||
from cement.core.namespace import get_config
|
||||
from cement.core.log import get_logger
|
||||
from cement.core.controller import CementController, expose
|
||||
from cement.core.hook import run_hooks
|
||||
|
||||
from {{package}}.model.example import ExampleModel
|
||||
|
||||
log = get_logger(__name__)
|
||||
config = get_config()
|
||||
|
||||
class ExampleController(CementController):
|
||||
@expose('{{package}}.templates.example.cmd', namespace='example')
|
||||
def cmd(self):
|
||||
# do something here
|
||||
pass
|
||||
@ -0,0 +1,108 @@
|
||||
"""
|
||||
This is the ExampleController for the {{project}} application. This can be used
|
||||
to expose commands to the example namespace which will be accessible under:
|
||||
|
||||
$ {{package}} example --help
|
||||
|
||||
"""
|
||||
|
||||
from cement.core.namespace import get_config
|
||||
from cement.core.log import get_logger
|
||||
from cement.core.controller import CementController, expose
|
||||
from cement.core.hook import run_hooks
|
||||
|
||||
from {{package}}.model.example import ExampleModel
|
||||
|
||||
log = get_logger(__name__)
|
||||
|
||||
class ExampleController(CementController):
|
||||
@expose(namespace='example') # no template
|
||||
def ex1(self):
|
||||
"""
|
||||
This is how to expose a subcommand because it will be under the
|
||||
'example' namespace. You would access this subcommand as:
|
||||
|
||||
$ {{package}} example ex1
|
||||
|
||||
"""
|
||||
|
||||
# You can get the root application config like this:
|
||||
config = get_config('root')
|
||||
|
||||
# Or you can get your example namespace config like this:
|
||||
config = get_config('example')
|
||||
|
||||
# You can print or log output however you like since this function
|
||||
# does not render out to a template.
|
||||
|
||||
# Controllers are all passed the opts and args from the command line.
|
||||
# So if you have added cli options in your {{project}}.bootstrap.example
|
||||
# file, you could access them here as:
|
||||
#
|
||||
# self.cli_opts.<your_option>
|
||||
# self.cli_args[0] # first argument *after* your command
|
||||
#
|
||||
|
||||
# Here we show how to run a hook that we've defined in
|
||||
# {{package}}.bootstrap.example:
|
||||
for res in run_hooks('my_example_hook'):
|
||||
print res
|
||||
|
||||
# This command has no template, but if we return something we
|
||||
# can still access the json output via --json.
|
||||
return dict(foo='bar')
|
||||
|
||||
@expose(namespace='example')
|
||||
def ex1_help(self):
|
||||
"""
|
||||
Help methods are found by way of <command>_help. This would be
|
||||
executed when you run:
|
||||
|
||||
$ {{package}} example ex1-help
|
||||
|
||||
"""
|
||||
print "This is the help method for ex1."
|
||||
|
||||
@expose('{{package}}.templates.example.ex2', namespace='example')
|
||||
def ex2(self):
|
||||
"""
|
||||
This is another command, also in the 'example' namespace but that is
|
||||
rendered by a genshi template.
|
||||
|
||||
Notice that you can specify the namespace via the decorator parameters.
|
||||
If a plugin has any non-root commands they are grouped under a
|
||||
single command to the base cli application. For example, you will
|
||||
see root commands and namespaces* when you execute:
|
||||
|
||||
$ {{package}} --help
|
||||
|
||||
|
||||
If 'example' has local commands, you will see 'example*' show up in
|
||||
the root commands list, and then the subcommands will be seen under:
|
||||
|
||||
$ {{package}} myplugin --help
|
||||
|
||||
|
||||
This is done to give different options in how your application works.
|
||||
|
||||
"""
|
||||
|
||||
# Here we are using our Example model, and then returning a dictionary
|
||||
# to our @expose() decorator where it will be rendered with Genshi.
|
||||
example = ExampleModel()
|
||||
example.label = 'This is my Example Model'
|
||||
|
||||
# You can see if options where passed. These are set in
|
||||
# {{package}}/bootstrap/example.py:
|
||||
if self.cli_opts.foo:
|
||||
# --foo was passed, do something
|
||||
log.info('%s passed by --foo option' % self.cli_opts.foo)
|
||||
|
||||
return dict(foo=self.cli_opts.foo, example=example, items=['one', 'two', 'three'])
|
||||
|
||||
@expose(namespace='root')
|
||||
def cmd2(self):
|
||||
"""This command will be displayed under the root namespace."""
|
||||
foo = "In {{package}}.controllers.example.cmd2()"
|
||||
print foo
|
||||
return dict(foo=foo)
|
||||
@ -0,0 +1,93 @@
|
||||
"""
|
||||
This is the RootController for the {{project}} application. This can be used
|
||||
to expose commands to the root namespace which will be accessible under:
|
||||
|
||||
$ {{package}} --help
|
||||
|
||||
"""
|
||||
|
||||
from cement.core.controller import CementController, expose
|
||||
from cement.core.namespace import get_config
|
||||
from cement.core.log import get_logger
|
||||
|
||||
from {{package}}.core.exc import {{package.capitalize()}}ArgumentError
|
||||
|
||||
log = get_logger(__name__)
|
||||
config = get_config()
|
||||
|
||||
class RootController(CementController):
|
||||
@expose('{{package}}.templates.root.error', is_hidden=True)
|
||||
def error(self, errors=[]):
|
||||
"""
|
||||
This can be called when catching exceptions giving the developer a
|
||||
clean way of presenting errors to the user.
|
||||
|
||||
Required Arguments:
|
||||
|
||||
errors
|
||||
A list of tuples in the form of [('ErrorCode', 'Error message')].
|
||||
|
||||
|
||||
The best way to use this is with an 'abort' function... something like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from cement.core.controller import run_controller_command
|
||||
|
||||
def abort(errors):
|
||||
run_controller_command('root', 'error', errors=errors)
|
||||
|
||||
errors = []
|
||||
# do something, if error
|
||||
errors.append(('MyErrorCode', 'My Error Message'))
|
||||
|
||||
abort(errors)
|
||||
|
||||
# continue work (no errors)
|
||||
|
||||
"""
|
||||
return dict(errors=errors)
|
||||
|
||||
@expose(is_hidden=True)
|
||||
def nosetests(self):
|
||||
"""This method is added for nose testing."""
|
||||
pass
|
||||
|
||||
@expose(is_hidden=True)
|
||||
def default(self):
|
||||
"""
|
||||
This is the default command method. If no commands are passed to
|
||||
{{package}}, this one will be executed. By default it raises an
|
||||
exception.
|
||||
|
||||
"""
|
||||
raise {{project.capitalize()}}ArgumentError, "A command is required. See --help?"
|
||||
|
||||
@expose('{{package}}.templates.root.cmd1')
|
||||
def cmd1(self):
|
||||
"""This is an example 'root' command."""
|
||||
foo = 'bar'
|
||||
items = ['one', 'two', 'three']
|
||||
return dict(foo=foo, items=items)
|
||||
|
||||
@expose()
|
||||
def cmd1_help(self):
|
||||
"""This is an example 'root' -help command. It should be replaced."""
|
||||
foo = 'In {{package}}.controllers.root.cmd1_help()'
|
||||
return dict(foo=foo)
|
||||
|
||||
@expose('{{package}}.templates.root.get-started')
|
||||
def get_started(self):
|
||||
features = [
|
||||
'Multiple Configuration file parsing (default: /etc, ~/)',
|
||||
'Command line argument and option parsing',
|
||||
'Dual Console/File Logging Support',
|
||||
'Full Internal and External (3rd Party) Plugin support',
|
||||
'Basic "hook" support',
|
||||
'Full MVC support for advanced application design',
|
||||
'Text output rendering with Genshi templates',
|
||||
'Json output rendering allows other programs to access your CLI-API',
|
||||
]
|
||||
|
||||
genshi_link = "http://genshi.edgewall.org/wiki/Documentation/text-templates.html"
|
||||
return dict(config=config, features=features, genshi_link=genshi_link)
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1,100 @@
|
||||
"""
|
||||
This is the application's core code. Unless you know the "ins-and-outs" of
|
||||
The Cement CLI Application Framework, you probably should not modify the
|
||||
main() function of this file.
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pkg_resources import get_distribution
|
||||
|
||||
from cement.core.exc import CementArgumentError, CementConfigError
|
||||
from cement.core.exc import CementRuntimeError
|
||||
from cement.core.log import get_logger
|
||||
from cement.core.app_setup import lay_cement
|
||||
from cement.core.command import run_command
|
||||
|
||||
from {{package}}.core.config import default_config
|
||||
from {{package}}.core.exc import {{package.capitalize()}}ArgumentError, {{package.capitalize()}}ConfigError
|
||||
from {{package}}.core.exc import {{package.capitalize()}}RuntimeError
|
||||
|
||||
VERSION = get_distribution('{{project}}').version
|
||||
BANNER = """
|
||||
{{project}} version %s
|
||||
""" % VERSION
|
||||
|
||||
def main(args=None):
|
||||
try:
|
||||
if not args:
|
||||
args = sys.argv
|
||||
|
||||
lay_cement(config=default_config, banner=BANNER, args=args,
|
||||
version=VERSION)
|
||||
|
||||
log = get_logger(__name__)
|
||||
log.debug("Cement Framework Initialized!")
|
||||
|
||||
if not len(args) > 1:
|
||||
args.append('default')
|
||||
|
||||
run_command(args[1])
|
||||
|
||||
except CementArgumentError, e:
|
||||
# Display the apps exception names instead for the Cement exceptions.
|
||||
print("{{package.capitalize()}}ArgumentError > %s" % e)
|
||||
sys.exit(e.code)
|
||||
except CementConfigError, e:
|
||||
print("{{package.capitalize()}}ConfigError > %s" % e)
|
||||
sys.exit(e.code)
|
||||
except CementRuntimeError, e:
|
||||
print("{{package.capitalize()}}RuntimeError > %s" % e)
|
||||
sys.exit(e.code)
|
||||
except {{package.capitalize()}}ArgumentError, e:
|
||||
print("{{package.capitalize()}}ArgumentError > %s" % e)
|
||||
sys.exit(e.code)
|
||||
except {{package.capitalize()}}ConfigError, e:
|
||||
print("{{package.capitalize()}}ConfigError > %s" % e)
|
||||
sys.exit(e.code)
|
||||
except {{package.capitalize()}}RuntimeError, e:
|
||||
print("{{package.capitalize()}}RuntimeError > %s" % e)
|
||||
sys.exit(e.code)
|
||||
sys.exit(0)
|
||||
|
||||
def nose_main(args, test_config):
|
||||
"""
|
||||
This function provides an alternative to main() that is more friendly for
|
||||
nose tests as it doesn't catch any exceptions.
|
||||
|
||||
Required Arguments:
|
||||
|
||||
args
|
||||
The args to pass to lay_cement
|
||||
|
||||
test_config
|
||||
A test config to pass to lay_cement
|
||||
|
||||
Usage:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from {{package}}.core.appmain import nose_main
|
||||
from {{package}}.core.config import get_nose_config
|
||||
|
||||
args = [__file__, 'nosetests', '--quiet']
|
||||
(res_dict, output_text) = nose_main(args, get_nose_config())
|
||||
|
||||
"""
|
||||
|
||||
lay_cement(config=test_config, banner=BANNER, args=args)
|
||||
log = get_logger(__name__)
|
||||
log.debug("Cement Framework Initialized!")
|
||||
|
||||
if not len(args) > 1:
|
||||
args.append('default')
|
||||
|
||||
(res, output_txt) = run_command(args[1])
|
||||
return (res, output_txt)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
"""
|
||||
This is the applications default configuration. You can feel free to alter
|
||||
this file to your needs, however it should be noted that all these variables
|
||||
are overridden by settings in /etc/{{package}}/{{package}}.conf and/or
|
||||
~/.{{package}}.conf (by default) and therefore, any default configurations
|
||||
you want to make obvious to your users should be set in your default config
|
||||
file as packaged with the software.
|
||||
"""
|
||||
|
||||
import os
|
||||
from configobj import ConfigObj
|
||||
|
||||
from cement.core.exc import CementConfigError
|
||||
|
||||
# This is a sane default for development/no config
|
||||
prefix = os.path.join(os.environ['HOME'], '.{{package}}')
|
||||
|
||||
|
||||
dcf = ConfigObj() # default config
|
||||
dcf['config_source'] = ['defaults']
|
||||
dcf['app_name'] = '{{project}}' # name for cli like /etc/<app_name>
|
||||
dcf['app_egg_name'] = '{{project}}' # name from setup.py
|
||||
dcf['app_module'] = '{{package}}' # name of the library dir
|
||||
|
||||
dcf['enabled_plugins'] = [] # no default plugins, add via the config file
|
||||
dcf['debug'] = False
|
||||
dcf['datadir'] = os.path.join(prefix, 'data')
|
||||
dcf['tmpdir'] = os.path.join(prefix, 'tmp')
|
||||
dcf['log_file'] = os.path.join(prefix, 'log', dcf['app_name'])
|
||||
dcf['plugin_config_dir'] = os.path.join(prefix, 'etc', 'plugins.d')
|
||||
dcf['log_to_console'] = True
|
||||
dcf['output_handler'] = 'genshi'
|
||||
dcf['show_plugin_load'] = False
|
||||
|
||||
# By default look in /etc and ~/ for config files. Developers for non *nix
|
||||
# audiences will want to change this.
|
||||
dcf['config_files'] = [
|
||||
os.path.join('/etc', dcf['app_name'], '%s.conf' % dcf['app_name']),
|
||||
os.path.join(prefix, 'etc', '%s.conf' % dcf['app_name']),
|
||||
os.path.join(os.environ['HOME'], '.%s.conf' % dcf['app_name']),
|
||||
]
|
||||
|
||||
default_config = dcf
|
||||
|
||||
def get_default_config():
|
||||
"""Return the default application config."""
|
||||
return default_config
|
||||
|
||||
def get_nose_config(prefix=None):
|
||||
if not prefix:
|
||||
from tempfile import mkdtemp
|
||||
prefix = mkdtemp()
|
||||
|
||||
tcf = ConfigObj() # test config
|
||||
tcf['config_files'] = [os.path.abspath('./config/{{package}}.conf-test')]
|
||||
tcf['config_source'] = ['defaults']
|
||||
tcf['app_name'] = '{{project}}'
|
||||
tcf['app_egg_name'] = '{{project}}'
|
||||
tcf['app_module'] = '{{package}}'
|
||||
tcf['enabled_plugins'] = []
|
||||
tcf['debug'] = False
|
||||
tcf['datadir'] = '%s/data' % prefix
|
||||
tcf['tmpdir'] = '%s/tmp' % prefix
|
||||
tcf['log_file'] = '%s/log/%s.log' % (prefix, tcf['app_name'])
|
||||
tcf['plugin_config_dir'] = './config/plugins.d'
|
||||
tcf['log_to_console'] = False
|
||||
tcf['output_engine'] = 'genshi'
|
||||
tcf['show_plugin_load'] = False
|
||||
return tcf
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
"""{{project}} exception classes."""
|
||||
|
||||
class {{package.capitalize()}}Error(Exception):
|
||||
"""Generic errors."""
|
||||
def __init__(self, value, code=1):
|
||||
Exception.__init__(self)
|
||||
self.msg = value
|
||||
self.code = code
|
||||
|
||||
def __str__(self):
|
||||
return self.msg
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.msg)
|
||||
|
||||
class {{package.capitalize()}}ConfigError({{package.capitalize()}}Error):
|
||||
"""Config parsing and setup errors."""
|
||||
def __init__(self, value):
|
||||
code = 10
|
||||
{{package.capitalize()}}Error.__init__(self, value, code)
|
||||
|
||||
class {{package.capitalize()}}RuntimeError({{package.capitalize()}}Error):
|
||||
"""Runtime errors."""
|
||||
def __init__(self, value):
|
||||
code = 20
|
||||
{{package.capitalize()}}Error.__init__(self, value, code)
|
||||
|
||||
class {{package.capitalize()}}ArgumentError({{package.capitalize()}}Error):
|
||||
"""Argument errors."""
|
||||
def __init__(self, value):
|
||||
code = 40
|
||||
{{package.capitalize()}}Error.__init__(self, value, code)
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1,13 @@
|
||||
"""
|
||||
This is an example model. This can be anything, just a straight class
|
||||
or perhaps an SQLAlchemy DeclarativeBase, etc.
|
||||
"""
|
||||
|
||||
from cement.core.log import get_logger
|
||||
|
||||
log = get_logger(__name__)
|
||||
|
||||
class ExampleModel(object):
|
||||
id = int()
|
||||
label = u''
|
||||
description = u''
|
||||
@ -0,0 +1,28 @@
|
||||
"""
|
||||
The root model can be used to consolidate all of your models under one.
|
||||
|
||||
A recommended way of accessing your model throughout your application is to
|
||||
import all model classes into the 'root' model file like so:
|
||||
|
||||
**helloworld/model/root.py**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from helloworld.model.example import Example
|
||||
from helloworld.model.user import User
|
||||
from helloworld.model.product import Product
|
||||
|
||||
|
||||
Then, throughout your application you can access all of you module objects
|
||||
like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from helloworld.model import root as model
|
||||
|
||||
user = model.User()
|
||||
product = model.Product()
|
||||
|
||||
"""
|
||||
|
||||
# from helloworld.model.example import Example
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1,28 @@
|
||||
{# This is an example Genshi Text Template. Documentation is available #}\
|
||||
{# at: #}\
|
||||
{# #}\
|
||||
{# http://genshi.edgewall.org/wiki/Documentation/text-templates.html #}\
|
||||
{# #}\
|
||||
\
|
||||
\
|
||||
{# --------------------- 78 character baseline --------------------------- #}\
|
||||
|
||||
There are a number of things you can do such as conditional statements:
|
||||
|
||||
{% if foo %}\
|
||||
Label: ${example.label}
|
||||
{% end %}\
|
||||
|
||||
Or a for loop:
|
||||
|
||||
{% for item in items %}\
|
||||
* ${item}
|
||||
{% end %}\
|
||||
|
||||
And functions:
|
||||
|
||||
{% def greeting(name) %}\
|
||||
Hello, ${name}!
|
||||
{% end %}\
|
||||
${greeting('World')}\
|
||||
${greeting('Edward')}
|
||||
@ -0,0 +1,2 @@
|
||||
{# --------------------- 78 character baseline --------------------------- #}\
|
||||
$foo
|
||||
@ -0,0 +1,7 @@
|
||||
{# --------------------- 78 character baseline --------------------------- #}\
|
||||
|
||||
The following errors were encountered:
|
||||
-----------------------------------------------------------------------------
|
||||
{% for error in errors %}\
|
||||
* ${error[0]} => ${error[1]}
|
||||
{% end %}
|
||||
@ -0,0 +1,62 @@
|
||||
{# --------------------- 78 character baseline --------------------------- #}\
|
||||
Welcome to ${config['app_name']}.
|
||||
|
||||
This application is built on Cement, and is ready to rock! Out of the box you
|
||||
already have:
|
||||
|
||||
{% for feature in features %}\
|
||||
* $feature
|
||||
{% end %}\
|
||||
|
||||
If your config file is setup right, you should notice that your app is already
|
||||
loading an 'example' plugin. Plugins are enabled by adding a plugin config
|
||||
file in your plugin_config_dir (see {{package}}.conf). The plugin config
|
||||
must have a [<plugin_name>] section and under that section you must set the
|
||||
following setting
|
||||
|
||||
* enable_plugin=true
|
||||
|
||||
This will tell Cement to load that plugin. You can also load plugins from
|
||||
other projects built on Cement by also adding the following setting:
|
||||
|
||||
* provider = someotherapp
|
||||
|
||||
Where 'someotherapp' is the package name of the application providing the
|
||||
plugin.
|
||||
|
||||
The included example plugin is a great starting point to learn how to build on
|
||||
top of the Cement Framework. The following files and directories should be
|
||||
explored:
|
||||
|
||||
* ./{{package}}/bootstrap/example.py
|
||||
* ./{{package}}/controllers/example.py
|
||||
* ./{{package}}/model/example.py
|
||||
* ./{{package}}/templates/example/
|
||||
|
||||
|
||||
This command is defined in the RootController in:
|
||||
|
||||
{{package}}/controllers/root.py
|
||||
|
||||
|
||||
Additionally, the output of this command is rendered by the Genshi templating
|
||||
engine. The template is at {{package}}/templates/root/get-started.txt.
|
||||
You can find documentation here on the template syntax here:
|
||||
|
||||
* $genshi_link
|
||||
|
||||
|
||||
That said, you can also render the output of commands as JSON. Don't believe
|
||||
me? Just run it again with the --json flag.
|
||||
|
||||
To make the included 'example' plugin a permanent part of your application you
|
||||
simply need to add the following to {{package}}/bootstrap/root.py:
|
||||
|
||||
from {{package}}.bootstrap import example
|
||||
|
||||
|
||||
That said, by following the example plugin you can easily create built in code
|
||||
or additional plugins in the same fashion.
|
||||
|
||||
Go forth, and code!
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
|
||||
SOURCE INSTALLATION:
|
||||
|
||||
$ sudo python setup.py install
|
||||
|
||||
$ sudo cp -a ./etc /etc/{{package}}
|
||||
|
||||
|
||||
USAGE:
|
||||
|
||||
$ {{package}} --help
|
||||
@ -0,0 +1,2 @@
|
||||
recursive-include {{package}}/templates *
|
||||
recursive-include tests *
|
||||
@ -0,0 +1,64 @@
|
||||
NAME: {{package}}
|
||||
|
||||
AUTHOR:
|
||||
|
||||
DESCRIPTION:
|
||||
|
||||
Describe your application here.
|
||||
|
||||
{{project}} is built on the Cement CLI Application Framework.
|
||||
|
||||
|
||||
USAGE:
|
||||
|
||||
$ {{package}} --help
|
||||
|
||||
|
||||
CONFIGURATION:
|
||||
|
||||
Application configuration files are parsed in the following order:
|
||||
|
||||
* /etc/{{package}}/{{package}}.conf
|
||||
* ~/.{{package}}.conf
|
||||
|
||||
|
||||
PLUGIN DEVELOPMENT:
|
||||
|
||||
{{project}} supports external plugins via the Cement Framework. To quick
|
||||
start a new plugin for {{project}} you can use the paster utility.
|
||||
|
||||
Setup a virtual environment for development:
|
||||
|
||||
$ virtualenv --no-site-package /path/to/env
|
||||
|
||||
$ source /path/to/env/bin/activate
|
||||
|
||||
|
||||
Install {{project}}:
|
||||
|
||||
$ cd /path/to/{{project}}
|
||||
|
||||
$ python setup.py develop
|
||||
|
||||
|
||||
Create and install the plugin:
|
||||
|
||||
$ mkdir plugins
|
||||
|
||||
$ cd plugins
|
||||
|
||||
$ paster cement-plugin {{package}} myplugin
|
||||
|
||||
$ cd {{package}}.myplugin
|
||||
|
||||
$ python setup.py develop
|
||||
|
||||
|
||||
Once your plugin is installed, you can enable it by adding a [plugin] block
|
||||
to a plugin config in /etc/{{package}}/plugins.d/myplugin.conf. You should
|
||||
then see some example commands/options show up with:
|
||||
|
||||
$ {{package}} --help
|
||||
|
||||
|
||||
Then, code away!
|
||||
@ -0,0 +1,67 @@
|
||||
[root]
|
||||
# This is an example application config using cement.
|
||||
|
||||
# PLUGINS
|
||||
#
|
||||
# Plugins are enabled under their [plugin] config either in this
|
||||
# file or in the plugins.d config file for that plugin. An example plugin
|
||||
# config looks like:
|
||||
#
|
||||
# [example]
|
||||
# enable_plugin = true
|
||||
# provider = rosendale
|
||||
#
|
||||
#
|
||||
# The 'provider' is the package that provides it. If it is an internal plugin
|
||||
# this can be left blank.
|
||||
#
|
||||
|
||||
# DIRECTORIES
|
||||
#
|
||||
# these should probably be changed for production installations if you
|
||||
# follow the FHS (and you should).
|
||||
datadir = ~/{{project}}/data
|
||||
tmpdir = ~/{{project}}/tmp
|
||||
|
||||
# This should be the path to your development tree ...
|
||||
#
|
||||
# i.e. /path/to/{{package}}/etc/plugins.d
|
||||
#
|
||||
plugin_config_dir = ~/devel/{{project}}/config/plugins.d
|
||||
|
||||
|
||||
# This is just a cosmetic option... whether to show 'loading plugin...'
|
||||
# on application startup.
|
||||
#
|
||||
show_plugin_load = false
|
||||
|
||||
# LOGGING
|
||||
#
|
||||
# Log file path, comment out if no log is required.
|
||||
log_file = ~/{{project}}/log/{{project}}.log
|
||||
|
||||
# Toggle debug output... can be true, false
|
||||
debug = false
|
||||
|
||||
# Toggle the log level... can be info, warn, error, fatal, debug
|
||||
log_level = warn
|
||||
|
||||
# Whether or not to log to console (this is overridden by 'debug')
|
||||
log_to_console = true
|
||||
|
||||
# Max bytes to rotate log file on. Comment out to not rotate log file.
|
||||
#
|
||||
# 512000000 = 512M
|
||||
#
|
||||
#log_max_bytes = 512000000
|
||||
#log_max_files = 4
|
||||
|
||||
# ROOT APPLICATION SETTINGS
|
||||
#
|
||||
# Add any config options you'd like here
|
||||
#
|
||||
# myoption = this is my option
|
||||
|
||||
|
||||
# [namespace]
|
||||
# Additional namespace/plugin configurations can go here.
|
||||
@ -0,0 +1,8 @@
|
||||
# This configuration is specifically meant to be used for testing
|
||||
[root]
|
||||
|
||||
# This is how you'd enable a plugin for testing
|
||||
[example]
|
||||
enable_plugin = true
|
||||
provider = {{package}}
|
||||
foo = 'some value'
|
||||
@ -0,0 +1,61 @@
|
||||
[root]
|
||||
# This is an example application config using cement.
|
||||
|
||||
# PLUGINS
|
||||
#
|
||||
# Plugins are enabled under their [plugin] config either in this
|
||||
# file or in the plugins.d config file for that plugin. An example plugin
|
||||
# config looks like:
|
||||
#
|
||||
# [example]
|
||||
# enable_plugin = true
|
||||
# provider = rosendale
|
||||
#
|
||||
#
|
||||
# The 'provider' is the package that provides it. If it is an internal plugin
|
||||
# this can be left blank.
|
||||
#
|
||||
|
||||
# DIRECTORIES
|
||||
#
|
||||
# These settings tend to follow the FHS, and may need to be modified for your
|
||||
# environment.
|
||||
datadir = /var/lib/{{project}}
|
||||
tmpdir = /tmp
|
||||
plugin_config_dir = /etc/{{project}}/plugins.d
|
||||
|
||||
|
||||
# This is just a cosmetic option... whether to show 'loading plugin...'
|
||||
# on application startup.
|
||||
#
|
||||
show_plugin_load = false
|
||||
|
||||
# LOGGING
|
||||
#
|
||||
# Log file path, comment out if no log is required.
|
||||
log_file = /var/log/{{project}}/{{project}}.log
|
||||
|
||||
# Toggle debug output... can be true, false
|
||||
debug = false
|
||||
|
||||
# Toggle the log level... can be info, warn, error, fatal, debug
|
||||
log_level = warn
|
||||
|
||||
# Whether or not to log to console (this is overridden by 'debug')
|
||||
log_to_console = true
|
||||
|
||||
# Max bytes to rotate log file on. Comment out to not rotate log file.
|
||||
#
|
||||
# 512000000 = 512M
|
||||
#
|
||||
#log_max_bytes = 512000000
|
||||
#log_max_files = 4
|
||||
|
||||
# ROOT APPLICATION SETTINGS
|
||||
#
|
||||
# Add any config options you'd like here
|
||||
#
|
||||
# myoption = this is my option
|
||||
|
||||
# [namespace]
|
||||
# Additional namespace/plugin configurations can go here.
|
||||
@ -0,0 +1,29 @@
|
||||
[example]
|
||||
# This is an example of a cement plugin configuration file. Once parsed, the
|
||||
# values from here will be accessible from:
|
||||
#
|
||||
# namespaces[{{plugin}}].config['param'] = value
|
||||
#
|
||||
#
|
||||
# Some options are built into cement (such as merge_root_options) and
|
||||
# some are not.
|
||||
#
|
||||
|
||||
# Whether to enable plugin or not
|
||||
enable_plugin = true
|
||||
|
||||
# Whether or not to merge root options
|
||||
merge_root_options = true
|
||||
|
||||
debug = false
|
||||
param1 = value1
|
||||
param2 = value two
|
||||
|
||||
# equates to True in Python
|
||||
param3 = true
|
||||
|
||||
# equates to False in python
|
||||
param4 = false
|
||||
|
||||
# equates to ['my', 'list', 'of', 'values']
|
||||
param5 = my, list, of, values,
|
||||
@ -0,0 +1,40 @@
|
||||
from setuptools import setup, find_packages
|
||||
import sys, os
|
||||
|
||||
setup(name='{{project}}',
|
||||
version='0.1',
|
||||
description='{{description}}',
|
||||
classifiers=[],
|
||||
keywords='',
|
||||
author='{{creator}}',
|
||||
author_email='{{creator_email}}',
|
||||
url='{{url}}',
|
||||
license='{{license}}',
|
||||
packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
install_requires=[
|
||||
"configobj",
|
||||
# remove if not using genshi templating
|
||||
"genshi",
|
||||
"cement >={{cement_version}}, <{{cement_next_version}}",
|
||||
],
|
||||
setup_requires=[
|
||||
# uncomment for nose testing
|
||||
# "nose",
|
||||
],
|
||||
test_suite='nose.collector',
|
||||
entry_points="""
|
||||
[console_scripts]
|
||||
{{project}} = {{package}}.core.appmain:main
|
||||
""",
|
||||
namespace_packages=[
|
||||
'{{package}}',
|
||||
'{{package}}.lib',
|
||||
'{{package}}.bootstrap',
|
||||
'{{package}}.controllers',
|
||||
'{{package}}.model',
|
||||
'{{package}}.helpers',
|
||||
'{{package}}.templates',
|
||||
],
|
||||
)
|
||||
@ -0,0 +1,19 @@
|
||||
"""
|
||||
Initialize the application for nose testing, must be loaded first before
|
||||
other tests.
|
||||
"""
|
||||
|
||||
from tempfile import mkdtemp
|
||||
|
||||
from {{package}}.core.config import get_nose_config
|
||||
from {{package}}.core.appmain import nose_main
|
||||
|
||||
# use an altername config for testing
|
||||
config = get_nose_config(mkdtemp())
|
||||
|
||||
# run the initial main, which bootstraps the base application
|
||||
nose_main([__file__, 'nosetests', '--quiet'], config)
|
||||
|
||||
def test_initialize():
|
||||
# We put this here just to ensure nose picks up this file.
|
||||
pass
|
||||
@ -0,0 +1,64 @@
|
||||
"""
|
||||
The purpose of this module is to test application functionality. It is here
|
||||
as an example of how one might perform nose testing on an application built
|
||||
on top of the Cement Framework. It is not a fully comprehensive test, of the
|
||||
application... and needs to be expanded as the application grows.
|
||||
|
||||
The initial file loaded by nose runs the application. Additional calls are
|
||||
then made via the 'simulate' function rather than needing to reload the
|
||||
application for every test.
|
||||
"""
|
||||
|
||||
import os
|
||||
from nose.tools import raises, with_setup, eq_, ok_
|
||||
|
||||
from cement import namespaces
|
||||
from cement.core.namespace import get_config
|
||||
from cement.core.testing import simulate
|
||||
from cement.core.exc import CementRuntimeError
|
||||
|
||||
from {{package}}.core.exc import {{project.capitalize()}}ArgumentError
|
||||
|
||||
config = get_config()
|
||||
|
||||
def setup_func():
|
||||
"""Setup operations before every test."""
|
||||
pass
|
||||
|
||||
def teardown_func():
|
||||
"""Teardown operations after every test."""
|
||||
pass
|
||||
|
||||
@with_setup(setup_func, teardown_func)
|
||||
def test_cmd1_output():
|
||||
# Simulate returns the result dictionary, and the render output when
|
||||
# running the controller command. This can be used to validate that the
|
||||
# command ran successfully.
|
||||
(res_dict, output_txt) = simulate([__file__, 'cmd1'])
|
||||
|
||||
# You can test that the rendered output is what we expected
|
||||
eq_(output_txt, 'bar')
|
||||
|
||||
# You can test values in the result dictionary directly
|
||||
ok_(res_dict['foo'])
|
||||
|
||||
@raises({{project.capitalize()}}ArgumentError)
|
||||
@with_setup(setup_func, teardown_func)
|
||||
def test_default_cmd():
|
||||
# The default action is to raise an application error if an unknown
|
||||
# command is called. This is how we test that the exception is raised.
|
||||
simulate([__file__, 'default'])
|
||||
|
||||
@with_setup(setup_func, teardown_func)
|
||||
def test_config_cli_options():
|
||||
# Using the test configuration file in ./config we can test config options
|
||||
# this way. We are also using the example plugin for this test
|
||||
|
||||
# First it is set by what is in the config file
|
||||
eq_(config['example']['foo'], 'some value')
|
||||
|
||||
# Then overridden by cli_opts
|
||||
simulate([__file__, 'example', 'ex1', '--foo=bar'])
|
||||
|
||||
# now we validate that the config option was set by the cli_opt --foo
|
||||
eq_(config['example']['foo'], 'bar')
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1,34 @@
|
||||
"""
|
||||
This bootstrap module should be used to setup parts of the {{plugin}} plugin
|
||||
that need to exist before all controllers are loaded. It is best used to
|
||||
define/register hooks, setup namespaces, and the like.
|
||||
|
||||
"""
|
||||
|
||||
from pkg_resources import get_distribution
|
||||
from cement.core.namespace import CementNamespace, register_namespace
|
||||
|
||||
VERSION = get_distribution('{{project}}.{{plugin}}').version
|
||||
|
||||
# Setup the '{{plugin}}' namespace object
|
||||
{{plugin}} = CementNamespace(
|
||||
label='{{plugin}}',
|
||||
description='{{plugin.capitalize()}} Plugin for {{project.capitalize()}}',
|
||||
version=VERSION,
|
||||
controller='{{plugin.capitalize()}}Controller',
|
||||
provider='{{package}}'
|
||||
)
|
||||
|
||||
# Add a config option to the {{plugin}} namespace. This is effectively the
|
||||
# default setting for the config option. Overridden by config files, and then
|
||||
# cli options.
|
||||
{{plugin}}.config['foo'] = 'bar'
|
||||
|
||||
# Add a cli option to the {{plugin}} namespace. This overrides the
|
||||
# coresponding config option if passed
|
||||
{{plugin}}.options.add_option('-F', '--foo', action='store', dest='foo',
|
||||
help='example {{plugin}} option')
|
||||
|
||||
# Officialize and register the namespace
|
||||
register_namespace({{plugin}})
|
||||
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1,35 @@
|
||||
"""{{plugin}} controller class to expose commands for {{project}}."""
|
||||
|
||||
from cement.core.controller import CementController, expose
|
||||
|
||||
from {{package}}.model.{{plugin}} import {{plugin.capitalize()}}Model
|
||||
|
||||
class {{plugin.capitalize()}}Controller(CementController):
|
||||
@expose()
|
||||
def {{plugin}}_command(self):
|
||||
"""Register root command that doesn't use a template."""
|
||||
foo = 'bar'
|
||||
|
||||
# Even if you're not using a template, return relevant data so that
|
||||
# you can still use the --json engine, or similar.
|
||||
return dict(foo=foo)
|
||||
|
||||
@expose()
|
||||
def {{plugin}}_command_help(self):
|
||||
"""help methods are accessed as 'command-help'."""
|
||||
print "{{plugin}} root command help method."
|
||||
|
||||
@expose('{{project}}.templates.{{plugin}}.{{plugin}}_command')
|
||||
def {{plugin}}_command2(self, *args, **kw):
|
||||
"""Register root command, with Genshi templating."""
|
||||
foo = "Hello"
|
||||
bar = "World"
|
||||
return dict(foo=foo, bar=bar)
|
||||
|
||||
@expose(namespace='{{plugin}}')
|
||||
def {{plugin}}_sub_command(self):
|
||||
"""Register sub command for the {{plugin}} namespace."""
|
||||
foo = 'bar'
|
||||
print foo
|
||||
return dict(foo=foo)
|
||||
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1,5 @@
|
||||
"""{{plugin}} model classes."""
|
||||
|
||||
class {{plugin.capitalize()}}Model(object):
|
||||
# define model class
|
||||
pass
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1,9 @@
|
||||
{# This is an example Genshi Text Template. Documentation is available #}\
|
||||
{# at: #}\
|
||||
{# #}\
|
||||
{# http://genshi.edgewall.org/wiki/Documentation/text-templates.html #}\
|
||||
{# #}\
|
||||
\
|
||||
\
|
||||
{# --------------------- 78 character baseline --------------------------- #}\
|
||||
${foo} ${bar}
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
@ -0,0 +1,15 @@
|
||||
|
||||
SOURCE INSTALLATION:
|
||||
|
||||
$ sudo python setup.py install
|
||||
|
||||
# The following is one command
|
||||
$ sudo cp -a ./etc/{{project}}/plugins.d/{{plugin}}.conf \
|
||||
/etc/{{project}}/plugins.d/
|
||||
|
||||
|
||||
USAGE:
|
||||
|
||||
$ {{project}} --help
|
||||
|
||||
$ {{project}} {{plugin}} --help
|
||||
@ -0,0 +1,2 @@
|
||||
recursive-include {{project}}/templates/{{plugin}} *
|
||||
recursive-include tests *
|
||||
@ -0,0 +1 @@
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
# This configuration is specifically meant to be used for testing
|
||||
[root]
|
||||
|
||||
# This is how you'd enable a plugin for testing
|
||||
[{{plugin}}]
|
||||
enable_plugin = true
|
||||
provider = {{package}}
|
||||
foo = 'some value'
|
||||
@ -0,0 +1,14 @@
|
||||
# {{plugin.capitalize()}} Configuration Settings
|
||||
#
|
||||
# Note: Default values can be set via <yourapp>.bootstrap.<plugin>.py
|
||||
#
|
||||
|
||||
[{{plugin}}]
|
||||
enable_plugin = true
|
||||
|
||||
# The module name of the provider application
|
||||
provider = {{package}}
|
||||
|
||||
# Add any configurations here, note that defaults should also be added
|
||||
# to this plugins bootstrap file.
|
||||
foo = 'some value'
|
||||
@ -0,0 +1,36 @@
|
||||
from setuptools import setup, find_packages
|
||||
import sys, os
|
||||
|
||||
# You probably want to change the name, this is a healthy default for paster
|
||||
setup(name='{{project}}.{{plugin}}',
|
||||
version='0.1',
|
||||
description='{{plugin.capitalize()}} plugin for {{project.capitalize()}}',
|
||||
classifiers=[],
|
||||
keywords='',
|
||||
author='{{creator}}',
|
||||
author_email='{{creator_email}}',
|
||||
url='{{url}}',
|
||||
license='{{license}}',
|
||||
packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
install_requires=[
|
||||
"genshi",
|
||||
"cement >={{cement_version}}, <{{cement_next_version}}",
|
||||
"{{project}}",
|
||||
],
|
||||
setup_requires=[
|
||||
],
|
||||
test_suite='nose.collector',
|
||||
entry_points="""
|
||||
""",
|
||||
namespace_packages=[
|
||||
'{{package}}',
|
||||
'{{package}}.lib',
|
||||
'{{package}}.bootstrap',
|
||||
'{{package}}.controllers',
|
||||
'{{package}}.model',
|
||||
'{{package}}.helpers',
|
||||
'{{package}}.templates',
|
||||
],
|
||||
)
|
||||
@ -0,0 +1,65 @@
|
||||
"""
|
||||
The purpose of this module is to test plugin functionality. It is here
|
||||
as an example of how one might perform nose testing on an application built
|
||||
on top of the Cement Framework. It is not a fully comprehensive test, of the
|
||||
application... and needs to be expanded as the application and plugin grow.
|
||||
|
||||
The initial file loaded by nose runs the application. Additional calls are
|
||||
then made via the 'simulate' function rather than needing to reload the
|
||||
application for every test.
|
||||
"""
|
||||
|
||||
import os
|
||||
from nose.tools import raises, with_setup, eq_, ok_
|
||||
|
||||
from cement import namespaces
|
||||
from cement.core.namespace import get_config
|
||||
from cement.core.testing import simulate
|
||||
from cement.core.exc import CementRuntimeError
|
||||
|
||||
from {{package}}.core.exc import {{project.capitalize()}}ArgumentError
|
||||
|
||||
config = get_config()
|
||||
|
||||
def setup_func():
|
||||
"""Setup operations before every test."""
|
||||
pass
|
||||
|
||||
def teardown_func():
|
||||
"""Teardown operations after every test."""
|
||||
pass
|
||||
|
||||
@with_setup(setup_func, teardown_func)
|
||||
def test_{{plugin}}_cmd_output():
|
||||
# Simulate returns the result dictionary, and the render output when
|
||||
# running the controller command. This can be used to validate that the
|
||||
# command ran successfully.
|
||||
(res_dict, output_txt) = simulate([__file__, '{{plugin}}-command2'])
|
||||
|
||||
# You can test that the rendered output is what we expected
|
||||
eq_(output_txt, 'Hello World\n')
|
||||
|
||||
# You can test values in the result dictionary directly
|
||||
ok_(res_dict['foo'])
|
||||
|
||||
@raises({{project.capitalize()}}ArgumentError)
|
||||
@with_setup(setup_func, teardown_func)
|
||||
def test_default_cmd():
|
||||
# The default action is to raise an application error if an unknown
|
||||
# command is called. This is how we test that the exception is raised.
|
||||
simulate([__file__, 'default'])
|
||||
|
||||
@with_setup(setup_func, teardown_func)
|
||||
def test_config_cli_options():
|
||||
# Using the test configuration file in ./config dir of the base
|
||||
# application we can test config options this way. We are also using the
|
||||
# example plugin for this test
|
||||
|
||||
# First it is set by what is in the config file
|
||||
eq_(config['{{plugin}}']['foo'], 'some value')
|
||||
|
||||
# Then overridden by cli_opts
|
||||
simulate([__file__, '{{plugin}}', '{{plugin}}-sub-command', '--foo=bar'])
|
||||
|
||||
# now we validate that the config option was set by the cli_opt --foo
|
||||
eq_(config['{{plugin}}']['foo'], 'bar')
|
||||
@ -0,0 +1,19 @@
|
||||
"""
|
||||
Initialize the base application for nose testing, must be loaded first before
|
||||
other tests.
|
||||
"""
|
||||
|
||||
from tempfile import mkdtemp
|
||||
|
||||
from {{package}}.core.config import get_nose_config
|
||||
from {{package}}.core.appmain import nose_main
|
||||
|
||||
# use an altername config for testing
|
||||
config = get_nose_config(mkdtemp())
|
||||
|
||||
# run the initial main, which bootstraps the base application
|
||||
nose_main([__file__, 'nosetests', '--quiet'], config)
|
||||
|
||||
def test_initialize():
|
||||
# We put this here just to ensure nose picks up this file.
|
||||
pass
|
||||
84
src/cement.devtools/setup.py
Normal file
84
src/cement.devtools/setup.py
Normal file
@ -0,0 +1,84 @@
|
||||
from setuptools import setup, find_packages
|
||||
import sys, os
|
||||
|
||||
VERSION = '0.8.13'
|
||||
|
||||
LONG = """
|
||||
Cement is an advanced CLI Application Framework for Python. The 'devtools'
|
||||
package provides tools and libraries needed for developing applications that
|
||||
are built on Cement.
|
||||
|
||||
The Cement CLI Application Framework is Open Source and is distributed under
|
||||
The MIT License.
|
||||
|
||||
|
||||
GETTING STARTED:
|
||||
|
||||
Stable versions of Cement can be installed via the cheeze shop:
|
||||
::
|
||||
$ easy_install cement
|
||||
|
||||
$ easy_install cement.devtools
|
||||
|
||||
|
||||
Development versions of Cement can be checked out of Git:
|
||||
::
|
||||
$ git clone git://github.com/derks/cement.git
|
||||
|
||||
$ cd cement/
|
||||
|
||||
$ python setup.py install
|
||||
|
||||
$ git clone git://github.com/derks/cement.devtools.git
|
||||
|
||||
$ cd cement.devtools/
|
||||
|
||||
$ python setup.py install
|
||||
|
||||
|
||||
With the 'devtools' package, Cement applications, and plugins can be
|
||||
created via PasteScript. Once cement.core and cement.devtools are installed,
|
||||
the following command will create a command line application built on top of
|
||||
the Cement Framework:
|
||||
::
|
||||
$ paster cement-app myapp
|
||||
|
||||
|
||||
The following command will create an external plugin for your application:
|
||||
::
|
||||
$ paster cement-plugin myapp myplugin
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
setup(name='cement.devtools',
|
||||
version=VERSION,
|
||||
description="Development Tools for the Cement CLI Application Framework",
|
||||
long_description=LONG,
|
||||
classifiers=[],
|
||||
keywords='cli framework',
|
||||
author='BJ Dierkes',
|
||||
author_email='wdierkes@5dollarwhitebox.org',
|
||||
url='http://builtoncement.org',
|
||||
license='MIT',
|
||||
packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
install_requires=[
|
||||
"PasteScript",
|
||||
"tempita",
|
||||
"cement == %s" % VERSION,
|
||||
],
|
||||
setup_requires=[
|
||||
],
|
||||
entry_points="""
|
||||
[paste.global_paster_command]
|
||||
cement-app = cement.paste.commands:CementAppCommand
|
||||
cement-plugin = cement.paste.commands:CementPluginCommand
|
||||
[paste.paster_create_template]
|
||||
cementapp = cement.paste.template:CementAppTemplate
|
||||
cementplugin = cement.paste.template:CementPluginTemplate
|
||||
""",
|
||||
namespace_packages=[],
|
||||
)
|
||||
23
src/cement.test/LICENSE
Normal file
23
src/cement.test/LICENSE
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
The MIT License:
|
||||
|
||||
Copyright (c) 2009-2010 BJ Dierkes
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
2
src/cement.test/MANIFEST.in
Normal file
2
src/cement.test/MANIFEST.in
Normal file
@ -0,0 +1,2 @@
|
||||
recursive-include cement_test/templates *
|
||||
recursive-include tests *
|
||||
36
src/cement.test/README
Normal file
36
src/cement.test/README
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
NAME: cement-test
|
||||
|
||||
AUTHOR: BJ Dierkes <wdierkes@5dollarwhitebox.org>
|
||||
|
||||
DESCRIPTION:
|
||||
|
||||
The Cement Test application was created to facilitate proper testing of the
|
||||
Cement CLI Application Framework. Most of the features in Cement rely on
|
||||
a loaded application to be access them, making testing a bit more
|
||||
complex than simply running nose on the cement module.
|
||||
|
||||
The Cement Test application is simply a generic/useless application created
|
||||
via the cement.devtools paster template, with a few added lines of code to
|
||||
reach more of the framework and assist in testing coverage. The primary
|
||||
use of cement-test is for the nose tests in ./tests.
|
||||
|
||||
The Cement Test application is Open Source and is distributed under
|
||||
The MIT License.
|
||||
|
||||
|
||||
USAGE:
|
||||
|
||||
From within the cement.test source directory execute:
|
||||
|
||||
$ nosetests --verbosity 3
|
||||
|
||||
|
||||
If testing for coverage run:
|
||||
|
||||
$ coverage run /path/to/nosetests && coverage html
|
||||
|
||||
|
||||
CONFIGURATION:
|
||||
|
||||
The application is configured to only read './config/cement-test.conf'.
|
||||
1
src/cement.test/cement_test/__init__.py
Normal file
1
src/cement.test/cement_test/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
1
src/cement.test/cement_test/bootstrap/__init__.py
Normal file
1
src/cement.test/cement_test/bootstrap/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
33
src/cement.test/cement_test/bootstrap/example.py
Normal file
33
src/cement.test/cement_test/bootstrap/example.py
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
from cement.core.hook import register_hook, define_hook
|
||||
from cement.core.namespace import CementNamespace, register_namespace
|
||||
|
||||
# Setup the 'example' namespace object
|
||||
example = CementNamespace(
|
||||
label='example',
|
||||
controller='ExampleController',
|
||||
description='Example Plugin for Cement Test',
|
||||
required_api='0.7-0.8:20100210',
|
||||
provider='cement_test'
|
||||
)
|
||||
example.config['foo'] = 'bar'
|
||||
example.options.add_option('-F', '--foo', action='store',
|
||||
dest='foo', default=None, help='Example Foo Option'
|
||||
)
|
||||
|
||||
register_namespace(example)
|
||||
|
||||
@register_hook(weight=99)
|
||||
def my_example_hook():
|
||||
return 99
|
||||
|
||||
@register_hook(name='my_example_hook')
|
||||
def some_other_hook_name():
|
||||
return 0
|
||||
|
||||
@register_hook(weight=-100)
|
||||
def my_example_hook():
|
||||
return -100
|
||||
|
||||
|
||||
|
||||
34
src/cement.test/cement_test/bootstrap/example2.py
Normal file
34
src/cement.test/cement_test/bootstrap/example2.py
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
from cement.core.hook import register_hook, define_hook
|
||||
from cement.core.namespace import CementNamespace, register_namespace
|
||||
|
||||
# Setup the 'example' namespace object
|
||||
example = CementNamespace(
|
||||
label='example2',
|
||||
controller='Example2Controller',
|
||||
description='Example Plugin for Cement Test',
|
||||
required_api='0.7-0.8:20100210',
|
||||
provider='cement_test',
|
||||
is_hidden=True,
|
||||
)
|
||||
example.config['foo'] = 'bar'
|
||||
example.options.add_option('-F', '--foo', action='store',
|
||||
dest='foo', default=None, help='Example Foo Option'
|
||||
)
|
||||
|
||||
register_namespace(example)
|
||||
|
||||
@register_hook(weight=99)
|
||||
def my_example_hook():
|
||||
return 99
|
||||
|
||||
@register_hook(name='my_example_hook')
|
||||
def some_other_hook_name():
|
||||
return 0
|
||||
|
||||
@register_hook(weight=-100)
|
||||
def my_example_hook():
|
||||
return -100
|
||||
|
||||
|
||||
|
||||
33
src/cement.test/cement_test/bootstrap/example3.py
Normal file
33
src/cement.test/cement_test/bootstrap/example3.py
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
from cement.core.hook import register_hook, define_hook
|
||||
from cement.core.namespace import CementNamespace, register_namespace
|
||||
|
||||
# Setup the 'example' namespace object
|
||||
example = CementNamespace(
|
||||
label='example3',
|
||||
controller='Example3Controller',
|
||||
description='Example Plugin for Cement Test',
|
||||
required_api='0.7-0.8:20100210',
|
||||
provider='cement_test'
|
||||
)
|
||||
example.config['foo'] = 'bar'
|
||||
example.options.add_option('-F', '--foo', action='store',
|
||||
dest='foo', default=None, help='Example Foo Option'
|
||||
)
|
||||
|
||||
register_namespace(example)
|
||||
|
||||
@register_hook(weight=99)
|
||||
def my_example_hook():
|
||||
return 99
|
||||
|
||||
@register_hook(name='my_example_hook')
|
||||
def some_other_hook_name():
|
||||
return 0
|
||||
|
||||
@register_hook(weight=-100)
|
||||
def my_example_hook():
|
||||
return -100
|
||||
|
||||
|
||||
|
||||
33
src/cement.test/cement_test/bootstrap/example4.py
Normal file
33
src/cement.test/cement_test/bootstrap/example4.py
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
from cement.core.hook import register_hook, define_hook
|
||||
from cement.core.namespace import CementNamespace, register_namespace
|
||||
|
||||
# Setup the 'example' namespace object
|
||||
example = CementNamespace(
|
||||
label='example4',
|
||||
controller='Example4Controller',
|
||||
description='Example Plugin for Cement Test',
|
||||
required_api='0.7-0.8:20100210',
|
||||
provider='cement_test'
|
||||
)
|
||||
example.config['foo'] = 'bar'
|
||||
example.options.add_option('-F', '--foo', action='store',
|
||||
dest='foo', default=None, help='Example Foo Option'
|
||||
)
|
||||
|
||||
register_namespace(example)
|
||||
|
||||
@register_hook(weight=99)
|
||||
def my_example_hook():
|
||||
return 99
|
||||
|
||||
@register_hook(name='my_example_hook')
|
||||
def some_other_hook_name():
|
||||
return 0
|
||||
|
||||
@register_hook(weight=-100)
|
||||
def my_example_hook():
|
||||
return -100
|
||||
|
||||
|
||||
|
||||
32
src/cement.test/cement_test/bootstrap/example_five.py
Normal file
32
src/cement.test/cement_test/bootstrap/example_five.py
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
from cement.core.hook import register_hook, define_hook
|
||||
from cement.core.namespace import CementNamespace, register_namespace
|
||||
|
||||
# Setup the 'example' namespace object
|
||||
example = CementNamespace(
|
||||
label='example_five',
|
||||
controller='ExampleFiveController',
|
||||
description='Example Plugin for Cement Test',
|
||||
provider='cement_test'
|
||||
)
|
||||
example.config['foo'] = 'bar'
|
||||
example.options.add_option('-F', '--foo', action='store',
|
||||
dest='foo', default=None, help='Example Foo Option'
|
||||
)
|
||||
|
||||
register_namespace(example)
|
||||
|
||||
@register_hook(weight=99)
|
||||
def my_example_hook():
|
||||
return 99
|
||||
|
||||
@register_hook(name='my_example_hook')
|
||||
def some_other_hook_name():
|
||||
return 0
|
||||
|
||||
@register_hook(weight=-100)
|
||||
def my_example_hook():
|
||||
return -100
|
||||
|
||||
|
||||
|
||||
61
src/cement.test/cement_test/bootstrap/root.py
Normal file
61
src/cement.test/cement_test/bootstrap/root.py
Normal file
@ -0,0 +1,61 @@
|
||||
"""
|
||||
The bootstrap module should be used to setup parts of your application
|
||||
that need to exist before all controllers are loaded. It is best used to
|
||||
define hooks, setup namespaces, and the like. The root namespace is
|
||||
already bootstrapped by Cement, however you can extend that functionality
|
||||
by importing additional bootstrap files here.
|
||||
"""
|
||||
|
||||
from cement.core.opt import init_parser
|
||||
from cement.core.hook import register_hook, define_hook
|
||||
|
||||
define_hook('my_example_hook')
|
||||
|
||||
# Register root options
|
||||
@register_hook()
|
||||
def options_hook(*args, **kwargs):
|
||||
# This hook allows us to append options to the root namespace
|
||||
root_options = init_parser()
|
||||
root_options.add_option('-R', '--root-option', action ='store_true',
|
||||
dest='root_option', default=None, help='Example root option')
|
||||
root_options.add_option('--json', action='store_true',
|
||||
dest='enable_json', default=None,
|
||||
help='render output as json (CLI-API)')
|
||||
root_options.add_option('--debug', action='store_true',
|
||||
dest='debug', default=None, help='toggle debug output')
|
||||
root_options.add_option('--quiet', action='store_true',
|
||||
dest='quiet', default=None, help='disable console logging')
|
||||
root_options.add_option('--test-option', action='store',
|
||||
dest='test_option', default=None, help='test option')
|
||||
return ('root', root_options)
|
||||
|
||||
@register_hook()
|
||||
def post_bootstrap_hook():
|
||||
pass
|
||||
|
||||
@register_hook()
|
||||
def validate_config_hook(config):
|
||||
pass
|
||||
|
||||
@register_hook()
|
||||
def pre_plugins_hook():
|
||||
pass
|
||||
|
||||
#@register_hook(name='options_hook')
|
||||
#def bogus_namespace():
|
||||
# parser = init_parser()
|
||||
# parser.add_option('--bogus-option', action='store', dest='bogus_option')
|
||||
# return ('bogus_namespace', parser)
|
||||
|
||||
@register_hook()
|
||||
def post_plugins_hook():
|
||||
pass
|
||||
|
||||
@register_hook()
|
||||
def post_options_hook(cli_opts, cli_args):
|
||||
pass
|
||||
|
||||
# Import all additional (non-plugin) bootstrap libraries here
|
||||
#
|
||||
# from cement_test.bootstrap import example
|
||||
|
||||
1
src/cement.test/cement_test/controllers/__init__.py
Normal file
1
src/cement.test/cement_test/controllers/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
28
src/cement.test/cement_test/controllers/example.py
Normal file
28
src/cement.test/cement_test/controllers/example.py
Normal file
@ -0,0 +1,28 @@
|
||||
"""
|
||||
This is the ExampleController for the cement_test application. This can be used
|
||||
to expose commands to the example namespace which will be accessible under:
|
||||
|
||||
$ cement_test example --help
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
from cement.core.namespace import get_config
|
||||
from cement.core.log import get_logger
|
||||
from cement.core.controller import CementController, expose
|
||||
from cement.core.hook import run_hooks
|
||||
|
||||
from cement_test.model.example import ExampleModel
|
||||
|
||||
log = get_logger(__name__)
|
||||
|
||||
class ExampleController(CementController):
|
||||
@expose(namespace='example')
|
||||
def cmd1(self):
|
||||
foo='bar'
|
||||
print foo
|
||||
return dict(foo=foo)
|
||||
|
||||
|
||||
|
||||
23
src/cement.test/cement_test/controllers/example2.py
Normal file
23
src/cement.test/cement_test/controllers/example2.py
Normal file
@ -0,0 +1,23 @@
|
||||
"""
|
||||
This is the ExampleController for the cement_test application. This can be used
|
||||
to expose commands to the example namespace which will be accessible under:
|
||||
|
||||
$ cement_test example --help
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
from cement.core.namespace import get_config
|
||||
from cement.core.log import get_logger
|
||||
from cement.core.controller import CementController, expose
|
||||
from cement.core.hook import run_hooks
|
||||
|
||||
log = get_logger(__name__)
|
||||
|
||||
class Example2Controller(CementController):
|
||||
@expose(namespace='example2')
|
||||
def cmd1(self):
|
||||
foo='bar'
|
||||
print foo
|
||||
return dict(foo=foo)
|
||||
24
src/cement.test/cement_test/controllers/example3.py
Normal file
24
src/cement.test/cement_test/controllers/example3.py
Normal file
@ -0,0 +1,24 @@
|
||||
"""
|
||||
This is the ExampleController for the cement_test application. This can be used
|
||||
to expose commands to the example namespace which will be accessible under:
|
||||
|
||||
$ cement_test example --help
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
from cement.core.namespace import get_config
|
||||
from cement.core.log import get_logger
|
||||
from cement.core.controller import CementController, expose
|
||||
from cement.core.hook import run_hooks
|
||||
|
||||
log = get_logger(__name__)
|
||||
|
||||
class Example3Controller(CementController):
|
||||
@expose(namespace='example3')
|
||||
def cmd1(self):
|
||||
foo='bar'
|
||||
print foo
|
||||
return dict(foo=foo)
|
||||
|
||||
24
src/cement.test/cement_test/controllers/example4.py
Normal file
24
src/cement.test/cement_test/controllers/example4.py
Normal file
@ -0,0 +1,24 @@
|
||||
"""
|
||||
This is the ExampleController for the cement_test application. This can be used
|
||||
to expose commands to the example namespace which will be accessible under:
|
||||
|
||||
$ cement_test example --help
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
from cement.core.namespace import get_config
|
||||
from cement.core.log import get_logger
|
||||
from cement.core.controller import CementController, expose
|
||||
from cement.core.hook import run_hooks
|
||||
|
||||
log = get_logger(__name__)
|
||||
|
||||
class Example4Controller(CementController):
|
||||
@expose(namespace='example4', is_hidden=True)
|
||||
def cmd1(self):
|
||||
foo='bar'
|
||||
print foo
|
||||
return dict(foo=foo)
|
||||
|
||||
24
src/cement.test/cement_test/controllers/example_five.py
Normal file
24
src/cement.test/cement_test/controllers/example_five.py
Normal file
@ -0,0 +1,24 @@
|
||||
"""
|
||||
This is the ExampleController for the cement_test application. This can be used
|
||||
to expose commands to the example namespace which will be accessible under:
|
||||
|
||||
$ cement_test example --help
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
from cement.core.namespace import get_config
|
||||
from cement.core.log import get_logger
|
||||
from cement.core.controller import CementController, expose
|
||||
from cement.core.hook import run_hooks
|
||||
|
||||
log = get_logger(__name__)
|
||||
|
||||
class ExampleFiveController(CementController):
|
||||
@expose(namespace='example_five', is_hidden=False)
|
||||
def cmd1(self):
|
||||
foo='bar'
|
||||
print foo
|
||||
return dict(foo=foo)
|
||||
|
||||
99
src/cement.test/cement_test/controllers/root.py
Normal file
99
src/cement.test/cement_test/controllers/root.py
Normal file
@ -0,0 +1,99 @@
|
||||
"""
|
||||
This is the RootController for the cement_test application. This can be used
|
||||
to expose commands to the root namespace which will be accessible under:
|
||||
|
||||
$ cement_test --help
|
||||
|
||||
"""
|
||||
|
||||
from tempfile import mkstemp
|
||||
from cement.core.controller import CementController, expose
|
||||
from cement.core.namespace import get_config
|
||||
from cement.core.log import get_logger
|
||||
|
||||
from cement_test.core.exc import CementTestArgumentError
|
||||
|
||||
log = get_logger(__name__)
|
||||
config = get_config()
|
||||
|
||||
class RootController(CementController):
|
||||
@expose(is_hidden=True)
|
||||
def nosetests(self, *args, **kw):
|
||||
pass
|
||||
|
||||
@expose('cement_test.templates.root.error', is_hidden=True)
|
||||
def error(self, errors=[]):
|
||||
"""
|
||||
This can be called when catching exceptions giving the developer a
|
||||
clean way of presenting errors to the user.
|
||||
|
||||
Required Arguments:
|
||||
|
||||
errors
|
||||
A list of tuples in the form of [('ErrorCode', 'Error message')].
|
||||
|
||||
|
||||
The best way to use this is with an 'abort' function, such as the one
|
||||
provided by the Rosendale Project.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from rosendale.helpers.error import abort_on_error
|
||||
|
||||
errors = []
|
||||
# do something, if error
|
||||
errors.append(('MyErrorCode', 'My Error Message'))
|
||||
|
||||
abort_on_error(errors)
|
||||
|
||||
# continue work (no errors)
|
||||
|
||||
"""
|
||||
return dict(errors=errors)
|
||||
|
||||
@expose(is_hidden=True)
|
||||
def default(self):
|
||||
"""
|
||||
This is the default command method. If no commands are passed to
|
||||
cement_test, this one will be executed. By default it raises an
|
||||
exception.
|
||||
|
||||
"""
|
||||
raise CementTestArgumentError, "A command is required. See --help?"
|
||||
|
||||
@expose('cement_test.templates.root.cmd1')
|
||||
def cmd1(self):
|
||||
"""This is an example 'root' command. It should be replaced."""
|
||||
items = ['one', 'two', 'three']
|
||||
return dict(items=items)
|
||||
|
||||
@expose()
|
||||
def send_to_file(self):
|
||||
f = mkstemp()[1]
|
||||
return dict(output_file=f, foo='bar')
|
||||
|
||||
@expose()
|
||||
def cmd1_help(self):
|
||||
"""This is an example 'root' -help command. It should be replaced."""
|
||||
foo = 'In cement_test.controllers.root.cmd1_help()'
|
||||
return dict(foo=foo)
|
||||
|
||||
@expose('genshi:cement_test.templates.root.get-started')
|
||||
def get_started(self):
|
||||
features = [
|
||||
'Multiple Configuration file parsing (default: /etc, ~/)',
|
||||
'Command line argument and option parsing',
|
||||
'Dual Console/File Logging Support',
|
||||
'Full Internal and External (3rd Party) Plugin support',
|
||||
'Basic "hook" support',
|
||||
'Full MVC support for advanced application design',
|
||||
'Text output rendering with Genshi templates',
|
||||
'Json output rendering allows other programs to access your CLI-API',
|
||||
]
|
||||
|
||||
genshi_link = "http://genshi.edgewall.org/wiki/Documentation/text-templates.html"
|
||||
return dict(config=config, features=features, genshi_link=genshi_link)
|
||||
|
||||
@expose('bogus_handler:cement_test.templates.root.cmd1')
|
||||
def bogus_cmd1(self):
|
||||
pass
|
||||
1
src/cement.test/cement_test/core/__init__.py
Normal file
1
src/cement.test/cement_test/core/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
78
src/cement.test/cement_test/core/appmain.py
Normal file
78
src/cement.test/cement_test/core/appmain.py
Normal file
@ -0,0 +1,78 @@
|
||||
"""
|
||||
This is the application's core code. Unless you know the "ins-and-outs" of
|
||||
The Cement CLI Application Framework, you probably should not modify the
|
||||
main() function of this file.
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pkg_resources import get_distribution
|
||||
|
||||
from cement.core.exc import CementArgumentError, CementConfigError, \
|
||||
CementRuntimeError
|
||||
from cement.core.log import get_logger
|
||||
from cement.core.app_setup import lay_cement
|
||||
from cement.core.configuration import ensure_api_compat
|
||||
from cement.core.command import run_command
|
||||
|
||||
from cement_test.core.config import default_config
|
||||
from cement_test.core.exc import CementTestArgumentError, CementTestConfigError, \
|
||||
CementTestRuntimeError
|
||||
|
||||
VERSION = get_distribution('cement_test').version
|
||||
BANNER = """
|
||||
cement_test version %s
|
||||
""" % VERSION
|
||||
|
||||
def main(args=None):
|
||||
try:
|
||||
lay_cement(config=default_config, banner=BANNER, args=args)
|
||||
|
||||
log = get_logger(__name__)
|
||||
log.debug("Cement Framework Initialized!")
|
||||
|
||||
if not len(sys.argv) > 1:
|
||||
sys.argv.append('default')
|
||||
|
||||
run_command(sys.argv[1])
|
||||
|
||||
except CementArgumentError, e:
|
||||
# Display the apps exception names instead for the Cement exceptions.
|
||||
print("CementTestArgumentError > %s" % e)
|
||||
sys.exit(e.code)
|
||||
except CementConfigError, e:
|
||||
print("CementTestConfigError > %s" % e)
|
||||
sys.exit(e.code)
|
||||
except CementRuntimeError, e:
|
||||
print("CementTestRuntimeError > %s" % e)
|
||||
sys.exit(e.code)
|
||||
except CementTestArgumentError, e:
|
||||
print("CementTestArgumentError > %s" % e)
|
||||
sys.exit(e.code)
|
||||
except CementTestConfigError, e:
|
||||
print("CementTestConfigError > %s" % e)
|
||||
sys.exit(e.code)
|
||||
except CementTestRuntimeError, e:
|
||||
print("CementTestRuntimeError > %s" % e)
|
||||
sys.exit(e.code)
|
||||
sys.exit(0)
|
||||
|
||||
def nose_main(args, test_config):
|
||||
"""
|
||||
This function provides an alternative to main() that is more friendly for
|
||||
nose tests as it doesn't catch any exceptions.
|
||||
"""
|
||||
|
||||
lay_cement(config=test_config, banner=BANNER, args=args)
|
||||
log = get_logger(__name__)
|
||||
log.debug("Cement Framework Initialized!")
|
||||
|
||||
if not len(args) > 1:
|
||||
args.append('default')
|
||||
|
||||
(res, output_txt) = run_command(args[1])
|
||||
return (res, output_txt)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
67
src/cement.test/cement_test/core/config.py
Normal file
67
src/cement.test/cement_test/core/config.py
Normal file
@ -0,0 +1,67 @@
|
||||
"""
|
||||
This is the applications default configuration. You can feel free to alter
|
||||
this file to your needs, however it should be noted that all these variables
|
||||
are overridden by settings in /etc/cement_test/cement_test.conf and/or
|
||||
~/.cement_test.conf (by default) and therefore, any default configurations
|
||||
you want to make obvious to your users should be set in your default config
|
||||
file as packaged with the software.
|
||||
"""
|
||||
|
||||
import os
|
||||
from tempfile import mkdtemp
|
||||
from configobj import ConfigObj
|
||||
|
||||
from cement.core.exc import CementConfigError
|
||||
|
||||
# This is a sane default for development/no config
|
||||
prefix = os.path.join(os.environ['HOME'], '.cement_test')
|
||||
|
||||
dcf = ConfigObj() # default config
|
||||
dcf['config_source'] = ['defaults']
|
||||
dcf['app_name'] = 'cement-test' # name for cli like /etc/<app_name>
|
||||
dcf['app_egg_name'] = 'cement-test' # name from setup.py
|
||||
dcf['app_module'] = 'cement_test' # name of the library dir
|
||||
|
||||
dcf['enabled_plugins'] = [] # no default plugins, add via the config file
|
||||
dcf['debug'] = False
|
||||
dcf['datadir'] = '%s/data' % prefix
|
||||
dcf['tmpdir'] = '%s/tmp' % prefix
|
||||
dcf['log_file'] = '%s/log/%s.log' % (prefix, dcf['app_name'])
|
||||
dcf['plugin_config_dir'] = '%s/etc/plugins.d' % prefix
|
||||
dcf['log_to_console'] = True
|
||||
dcf['output_engine'] = 'genshi'
|
||||
dcf['show_plugin_load'] = False
|
||||
|
||||
# By default look in /etc and ~/ for config files. You should probably
|
||||
# symlink /etc/<your_app> => ./etc/<your_app> for easy development.
|
||||
dcf['config_files'] = [
|
||||
os.path.join('/etc', dcf['app_name'], '%s.conf' % dcf['app_name']),
|
||||
os.path.join(prefix, 'etc', '%s.conf' % dcf['app_name']),
|
||||
os.path.join(os.environ['HOME'], '.%s.conf' % dcf['app_name']),
|
||||
]
|
||||
|
||||
default_config = dcf
|
||||
|
||||
def get_nose_config(prefix=None):
|
||||
if not prefix:
|
||||
prefix = mkdtemp()
|
||||
|
||||
tcf = ConfigObj() # test config
|
||||
tcf['config_files'] = [os.path.abspath('./config/cement-test.conf')]
|
||||
tcf['config_source'] = ['defaults']
|
||||
tcf['app_name'] = 'cement_test'
|
||||
tcf['app_egg_name'] = 'cement_test'
|
||||
tcf['app_module'] = 'cement_test'
|
||||
tcf['app_basepath'] = os.path.dirname(__file__)
|
||||
tcf['nosetests'] = True
|
||||
tcf['enabled_plugins'] = []
|
||||
tcf['debug'] = False
|
||||
tcf['datadir'] = '%s/data' % prefix
|
||||
tcf['tmpdir'] = '%s/tmp' % prefix
|
||||
tcf['log_file'] = '%s/log/%s.log' % (prefix, tcf['app_name'])
|
||||
tcf['plugin_config_dir'] = './config/plugins.d'
|
||||
tcf['log_to_console'] = False
|
||||
tcf['output_engine'] = 'genshi'
|
||||
tcf['show_plugin_load'] = False
|
||||
tcf['ignore_duplicate_framework_exceptions'] = True
|
||||
return tcf
|
||||
32
src/cement.test/cement_test/core/exc.py
Normal file
32
src/cement.test/cement_test/core/exc.py
Normal file
@ -0,0 +1,32 @@
|
||||
"""cement_test exception classes."""
|
||||
|
||||
class CementTestError(Exception):
|
||||
"""Generic errors."""
|
||||
def __init__(self, value, code=1):
|
||||
Exception.__init__(self)
|
||||
self.msg = value
|
||||
self.code = code
|
||||
|
||||
def __str__(self):
|
||||
return self.msg
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.msg)
|
||||
|
||||
class CementTestConfigError(CementTestError):
|
||||
"""Config parsing and setup errors."""
|
||||
def __init__(self, value):
|
||||
code = 10
|
||||
CementTestError.__init__(self, value, code)
|
||||
|
||||
class CementTestRuntimeError(CementTestError):
|
||||
"""Runtime errors."""
|
||||
def __init__(self, value):
|
||||
code = 20
|
||||
CementTestError.__init__(self, value, code)
|
||||
|
||||
class CementTestArgumentError(CementTestError):
|
||||
"""Argument errors."""
|
||||
def __init__(self, value):
|
||||
code = 40
|
||||
CementTestError.__init__(self, value, code)
|
||||
16
src/cement.test/cement_test/core/testing.py
Normal file
16
src/cement.test/cement_test/core/testing.py
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from tempfile import mkdtemp
|
||||
from cement import namespaces
|
||||
|
||||
def setup_func():
|
||||
"""Setup operations before every test."""
|
||||
namespaces['root'].config['datadir'] = mkdtemp()
|
||||
if not os.path.exists(namespaces['root'].config['datadir']):
|
||||
os.makedirs(namespaces['root'].config['datadir'])
|
||||
|
||||
def teardown_func():
|
||||
"""Teardown operations after every test."""
|
||||
if os.path.exists(namespaces['root'].config['datadir']):
|
||||
shutil.rmtree(namespaces['root'].config['datadir'])
|
||||
1
src/cement.test/cement_test/helpers/__init__.py
Normal file
1
src/cement.test/cement_test/helpers/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
1
src/cement.test/cement_test/lib/__init__.py
Normal file
1
src/cement.test/cement_test/lib/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
1
src/cement.test/cement_test/model/__init__.py
Normal file
1
src/cement.test/cement_test/model/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
13
src/cement.test/cement_test/model/example.py
Normal file
13
src/cement.test/cement_test/model/example.py
Normal file
@ -0,0 +1,13 @@
|
||||
"""
|
||||
This is an example model. This can be anything, just a straight class
|
||||
or perhaps an SQLAlchemy DeclarativeBase, etc.
|
||||
"""
|
||||
|
||||
from cement.core.log import get_logger
|
||||
|
||||
log = get_logger(__name__)
|
||||
|
||||
class ExampleModel(object):
|
||||
id = int()
|
||||
label = u''
|
||||
description = u''
|
||||
28
src/cement.test/cement_test/model/root.py
Normal file
28
src/cement.test/cement_test/model/root.py
Normal file
@ -0,0 +1,28 @@
|
||||
"""
|
||||
The root model can be used to consolidate all of your models under one.
|
||||
|
||||
A recommended way of accessing your model throughout your application is to
|
||||
import all model classes into the 'root' model file like so:
|
||||
|
||||
**helloworld/model/root.py**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from helloworld.model.example import Example
|
||||
from helloworld.model.user import User
|
||||
from helloworld.model.product import Product
|
||||
|
||||
|
||||
Then, throughout your application you can access all of you module objects
|
||||
like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from helloworld.model import root as model
|
||||
|
||||
user = model.User()
|
||||
product = model.Product()
|
||||
|
||||
"""
|
||||
|
||||
# from helloworld.model.example import Example
|
||||
1
src/cement.test/cement_test/templates/__init__.py
Normal file
1
src/cement.test/cement_test/templates/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user