initial Pylons code (fixes #3)
git-svn-id: file:///var/www/wwwusers/usr01/svn/pyalchemybiz/trunk@5 389c73d4-bf09-4d3d-a15e-f94a37d0667a
This commit is contained in:
parent
38d4c952cf
commit
554276ed23
42 changed files with 930 additions and 47 deletions
2
MANIFEST.in
Normal file
2
MANIFEST.in
Normal file
|
@ -0,0 +1,2 @@
|
|||
recursive-include pyalchemybiz/public *
|
||||
recursive-include pyalchemybiz/templates *
|
19
README.txt
Normal file
19
README.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
This file is for you to describe the pyalchemybiz application. Typically
|
||||
you would include information such as the information below:
|
||||
|
||||
Installation and Setup
|
||||
======================
|
||||
|
||||
Install ``pyalchemybiz`` using easy_install::
|
||||
|
||||
easy_install pyalchemybiz
|
||||
|
||||
Make a config file as follows::
|
||||
|
||||
paster make-config pyalchemybiz config.ini
|
||||
|
||||
Tweak the config file as appropriate and then setup the application::
|
||||
|
||||
paster setup-app config.ini
|
||||
|
||||
Then you are ready to go.
|
45
data/templates/base.mako.py
Normal file
45
data/templates/base.mako.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
from mako import runtime, filters, cache
|
||||
UNDEFINED = runtime.UNDEFINED
|
||||
__M_dict_builtin = dict
|
||||
__M_locals_builtin = locals
|
||||
_magic_number = 4
|
||||
_modified_time = 1223071301.6449161
|
||||
_template_filename=u'/home/jan/src/pyalchemybiz/pyalchemybiz/templates/base.mako'
|
||||
_template_uri=u'/base.mako'
|
||||
_template_cache=cache.Cache(__name__, _modified_time)
|
||||
_source_encoding=None
|
||||
_exports = []
|
||||
|
||||
|
||||
def render_body(context,**pageargs):
|
||||
context.caller_stack._push_frame()
|
||||
try:
|
||||
__M_locals = __M_dict_builtin(pageargs=pageargs)
|
||||
h = context.get('h', UNDEFINED)
|
||||
next = context.get('next', UNDEFINED)
|
||||
__M_writer = context.writer()
|
||||
# SOURCE LINE 1
|
||||
__M_writer(u'<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.1//EN"\n "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n<html>\n <head>\n <title>PyAlchemyBiz</title>\n ')
|
||||
# SOURCE LINE 6
|
||||
__M_writer(unicode(h.stylesheet_link_tag('/pyalchemybiz.css')))
|
||||
__M_writer(u'\n ')
|
||||
# SOURCE LINE 7
|
||||
__M_writer(unicode(h.javascript_include_tag(
|
||||
'/javascripts/pyalchemybiz.js', builtins=True)))
|
||||
# SOURCE LINE 8
|
||||
__M_writer(u'\n </head>\n <body>\n <div class="content">\n ')
|
||||
# SOURCE LINE 12
|
||||
__M_writer(unicode(next.body()))
|
||||
__M_writer(u'')
|
||||
# SOURCE LINE 13
|
||||
__M_writer(u' <p class="footer">\n Return to the\n ')
|
||||
# SOURCE LINE 15
|
||||
__M_writer(unicode(h.link_to('FrontPage',
|
||||
h.url_for(action="index"))))
|
||||
# SOURCE LINE 16
|
||||
__M_writer(u'\n </p>\n </div>\n </body>\n</html>\n')
|
||||
return ''
|
||||
finally:
|
||||
context.caller_stack._pop_frame()
|
||||
|
||||
|
50
data/templates/customer.mako.py
Normal file
50
data/templates/customer.mako.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
from mako import runtime, filters, cache
|
||||
UNDEFINED = runtime.UNDEFINED
|
||||
__M_dict_builtin = dict
|
||||
__M_locals_builtin = locals
|
||||
_magic_number = 4
|
||||
_modified_time = 1223072023.421654
|
||||
_template_filename='/home/jan/src/pyalchemybiz/pyalchemybiz/templates/customer.mako'
|
||||
_template_uri='/customer.mako'
|
||||
_template_cache=cache.Cache(__name__, _modified_time)
|
||||
_source_encoding=None
|
||||
_exports = []
|
||||
|
||||
|
||||
def _mako_get_namespace(context, name):
|
||||
try:
|
||||
return context.namespaces[(__name__, name)]
|
||||
except KeyError:
|
||||
_mako_generate_namespaces(context)
|
||||
return context.namespaces[(__name__, name)]
|
||||
def _mako_generate_namespaces(context):
|
||||
pass
|
||||
def _mako_inherit(template, context):
|
||||
_mako_generate_namespaces(context)
|
||||
return runtime._inherit_from(context, u'base.mako', _template_uri)
|
||||
def render_body(context,**pageargs):
|
||||
context.caller_stack._push_frame()
|
||||
try:
|
||||
__M_locals = __M_dict_builtin(pageargs=pageargs)
|
||||
h = context.get('h', UNDEFINED)
|
||||
c = context.get('c', UNDEFINED)
|
||||
__M_writer = context.writer()
|
||||
# SOURCE LINE 1
|
||||
__M_writer(u'\n\n<h1>Hallo</h1>\n\n<ul id="customers">\n')
|
||||
# SOURCE LINE 6
|
||||
for customer in c.customers:
|
||||
# SOURCE LINE 7
|
||||
__M_writer(u' <li>')
|
||||
__M_writer(unicode(customer.firstname))
|
||||
__M_writer(u' ')
|
||||
__M_writer(unicode(customer.lastname))
|
||||
__M_writer(u' [')
|
||||
__M_writer(unicode(h.link_to('edit', h.url_for(id=customer.id, action="edit"))))
|
||||
__M_writer(u']</li>\n')
|
||||
# SOURCE LINE 9
|
||||
__M_writer(u'</ul>\n')
|
||||
return ''
|
||||
finally:
|
||||
context.caller_stack._pop_frame()
|
||||
|
||||
|
70
development.ini
Normal file
70
development.ini
Normal file
|
@ -0,0 +1,70 @@
|
|||
#
|
||||
# pyalchemybiz - Pylons development environment configuration
|
||||
#
|
||||
# The %(here)s variable will be replaced with the parent directory of this file
|
||||
#
|
||||
[DEFAULT]
|
||||
debug = true
|
||||
# Uncomment and replace with the address which should receive any error reports
|
||||
#email_to = you@yourdomain.com
|
||||
smtp_server = localhost
|
||||
error_email_from = paste@localhost
|
||||
|
||||
[server:main]
|
||||
use = egg:Paste#http
|
||||
host = 0.0.0.0
|
||||
port = 5000
|
||||
|
||||
[app:main]
|
||||
use = egg:pyalchemybiz
|
||||
full_stack = true
|
||||
cache_dir = %(here)s/data
|
||||
beaker.session.key = pyalchemybiz
|
||||
beaker.session.secret = somesecret
|
||||
|
||||
# If you'd like to fine-tune the individual locations of the cache data dirs
|
||||
# for the Cache data, or the Session saves, un-comment the desired settings
|
||||
# here:
|
||||
#beaker.cache.data_dir = %(here)s/data/cache
|
||||
#beaker.session.data_dir = %(here)s/data/sessions
|
||||
|
||||
# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*
|
||||
# Debug mode will enable the interactive debugging tool, allowing ANYONE to
|
||||
# execute malicious code after an exception is raised.
|
||||
#set debug = false
|
||||
|
||||
# Specify the database for SQLAlchemy to use.
|
||||
# %(here)s may include a ':' character on Windows environments; this can
|
||||
# invalidate the URI when specifying a SQLite db via path name
|
||||
sqlalchemy.default.url = sqlite:///%(here)s/pyalchemybiz.db
|
||||
sqlalchemy.default.echo = true
|
||||
|
||||
|
||||
# Logging configuration
|
||||
[loggers]
|
||||
keys = root, pyalchemybiz
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = INFO
|
||||
handlers = console
|
||||
|
||||
[logger_pyalchemybiz]
|
||||
level = DEBUG
|
||||
handlers =
|
||||
qualname = pyalchemybiz
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
|
||||
datefmt = %H:%M:%S
|
12
docs/index.txt
Normal file
12
docs/index.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
pyalchemybiz
|
||||
++++++++++++
|
||||
|
||||
This is the main index page of your documentation. It should be written in
|
||||
`reStructuredText format <http://docutils.sourceforge.net/rst.html>`_.
|
||||
|
||||
You can generate your documentation in HTML format by running this command::
|
||||
|
||||
setup.py pudge
|
||||
|
||||
For this to work you will need to download and install ``buildutils`` and
|
||||
``pudge``.
|
10
pyalchemybiz.egg-info/PKG-INFO
Normal file
10
pyalchemybiz.egg-info/PKG-INFO
Normal file
|
@ -0,0 +1,10 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: pyalchemybiz
|
||||
Version: 0.0.0dev
|
||||
Summary: UNKNOWN
|
||||
Home-page: UNKNOWN
|
||||
Author: UNKNOWN
|
||||
Author-email: UNKNOWN
|
||||
License: UNKNOWN
|
||||
Description: UNKNOWN
|
||||
Platform: UNKNOWN
|
29
pyalchemybiz.egg-info/SOURCES.txt
Normal file
29
pyalchemybiz.egg-info/SOURCES.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
MANIFEST.in
|
||||
README.txt
|
||||
setup.cfg
|
||||
setup.py
|
||||
pyalchemybiz/__init__.py
|
||||
pyalchemybiz/websetup.py
|
||||
pyalchemybiz.egg-info/PKG-INFO
|
||||
pyalchemybiz.egg-info/SOURCES.txt
|
||||
pyalchemybiz.egg-info/dependency_links.txt
|
||||
pyalchemybiz.egg-info/entry_points.txt
|
||||
pyalchemybiz.egg-info/paste_deploy_config.ini_tmpl
|
||||
pyalchemybiz.egg-info/requires.txt
|
||||
pyalchemybiz.egg-info/top_level.txt
|
||||
pyalchemybiz/config/__init__.py
|
||||
pyalchemybiz/config/environment.py
|
||||
pyalchemybiz/config/middleware.py
|
||||
pyalchemybiz/config/routing.py
|
||||
pyalchemybiz/controllers/__init__.py
|
||||
pyalchemybiz/controllers/error.py
|
||||
pyalchemybiz/controllers/template.py
|
||||
pyalchemybiz/lib/__init__.py
|
||||
pyalchemybiz/lib/app_globals.py
|
||||
pyalchemybiz/lib/base.py
|
||||
pyalchemybiz/lib/helpers.py
|
||||
pyalchemybiz/model/__init__.py
|
||||
pyalchemybiz/public/index.html
|
||||
pyalchemybiz/tests/__init__.py
|
||||
pyalchemybiz/tests/test_models.py
|
||||
pyalchemybiz/tests/functional/__init__.py
|
1
pyalchemybiz.egg-info/dependency_links.txt
Normal file
1
pyalchemybiz.egg-info/dependency_links.txt
Normal file
|
@ -0,0 +1 @@
|
|||
|
7
pyalchemybiz.egg-info/entry_points.txt
Normal file
7
pyalchemybiz.egg-info/entry_points.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
[paste.app_factory]
|
||||
main = pyalchemybiz.config.middleware:make_app
|
||||
|
||||
[paste.app_install]
|
||||
main = pylons.util:PylonsInstaller
|
||||
|
64
pyalchemybiz.egg-info/paste_deploy_config.ini_tmpl
Normal file
64
pyalchemybiz.egg-info/paste_deploy_config.ini_tmpl
Normal file
|
@ -0,0 +1,64 @@
|
|||
#
|
||||
# pyalchemybiz - Pylons configuration
|
||||
#
|
||||
# The %(here)s variable will be replaced with the parent directory of this file
|
||||
#
|
||||
[DEFAULT]
|
||||
debug = true
|
||||
email_to = you@yourdomain.com
|
||||
smtp_server = localhost
|
||||
error_email_from = paste@localhost
|
||||
|
||||
[server:main]
|
||||
use = egg:Paste#http
|
||||
host = 0.0.0.0
|
||||
port = 5000
|
||||
|
||||
[app:main]
|
||||
use = egg:pyalchemybiz
|
||||
full_stack = true
|
||||
cache_dir = %(here)s/data
|
||||
beaker.session.key = pyalchemybiz
|
||||
beaker.session.secret = ${app_instance_secret}
|
||||
app_instance_uuid = ${app_instance_uuid}
|
||||
|
||||
# If you'd like to fine-tune the individual locations of the cache data dirs
|
||||
# for the Cache data, or the Session saves, un-comment the desired settings
|
||||
# here:
|
||||
#beaker.cache.data_dir = %(here)s/data/cache
|
||||
#beaker.session.data_dir = %(here)s/data/sessions
|
||||
|
||||
# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*
|
||||
# Debug mode will enable the interactive debugging tool, allowing ANYONE to
|
||||
# execute malicious code after an exception is raised.
|
||||
set debug = false
|
||||
|
||||
# Specify the database for SQLAlchemy to use.
|
||||
# %(here)s may include a ':' character on Windows environments; this can
|
||||
# invalidate the URI when specifying a SQLite db via path name
|
||||
#sqlalchemy.default.url = sqlite:///%(here)s/pyalchemybiz.db
|
||||
#sqlalchemy.default.echo = false
|
||||
|
||||
|
||||
# Logging configuration
|
||||
[loggers]
|
||||
keys = root
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = INFO
|
||||
handlers = console
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(asctime)s %(levelname)-5.5s [%(name)s] %(message)s
|
2
pyalchemybiz.egg-info/paster_plugins.txt
Normal file
2
pyalchemybiz.egg-info/paster_plugins.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
Pylons
|
||||
WebHelpers
|
1
pyalchemybiz.egg-info/requires.txt
Normal file
1
pyalchemybiz.egg-info/requires.txt
Normal file
|
@ -0,0 +1 @@
|
|||
Pylons>=0.9.6.2
|
1
pyalchemybiz.egg-info/top_level.txt
Normal file
1
pyalchemybiz.egg-info/top_level.txt
Normal file
|
@ -0,0 +1 @@
|
|||
pyalchemybiz
|
|
@ -1,8 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Package pyalchemybiz
|
||||
#
|
||||
# Author: Jan Dittberner <jan@dittberner.info>
|
||||
# Version: $Id$
|
||||
#
|
||||
# This file is part of pyalchemybiz
|
0
pyalchemybiz/config/__init__.py
Normal file
0
pyalchemybiz/config/__init__.py
Normal file
38
pyalchemybiz/config/environment.py
Normal file
38
pyalchemybiz/config/environment.py
Normal file
|
@ -0,0 +1,38 @@
|
|||
"""Pylons environment configuration"""
|
||||
import os
|
||||
|
||||
from pylons import config
|
||||
from sqlalchemy import engine_from_config
|
||||
from pyalchemybiz.model import init_model
|
||||
|
||||
import pyalchemybiz.lib.app_globals as app_globals
|
||||
import pyalchemybiz.lib.helpers
|
||||
from pyalchemybiz.config.routing import make_map
|
||||
|
||||
def load_environment(global_conf, app_conf):
|
||||
"""Configure the Pylons environment via the ``pylons.config``
|
||||
object
|
||||
"""
|
||||
# Pylons paths
|
||||
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
paths = dict(root=root,
|
||||
controllers=os.path.join(root, 'controllers'),
|
||||
static_files=os.path.join(root, 'public'),
|
||||
templates=[os.path.join(root, 'templates')])
|
||||
|
||||
# Initialize config with the basic options
|
||||
config.init_app(global_conf, app_conf, package='pyalchemybiz',
|
||||
template_engine='mako', paths=paths)
|
||||
|
||||
config['routes.map'] = make_map()
|
||||
config['pylons.g'] = app_globals.Globals()
|
||||
config['pylons.h'] = pyalchemybiz.lib.helpers
|
||||
|
||||
# Customize templating options via this variable
|
||||
tmpl_options = config['buffet.template_options']
|
||||
|
||||
# CONFIGURATION OPTIONS HERE (note: all config options will override
|
||||
# any Pylons config options)
|
||||
engine = \
|
||||
engine_from_config(config, 'sqlalchemy.default.')
|
||||
init_model(engine)
|
57
pyalchemybiz/config/middleware.py
Normal file
57
pyalchemybiz/config/middleware.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
"""Pylons middleware initialization"""
|
||||
from paste.cascade import Cascade
|
||||
from paste.registry import RegistryManager
|
||||
from paste.urlparser import StaticURLParser
|
||||
from paste.deploy.converters import asbool
|
||||
|
||||
from pylons import config
|
||||
from pylons.error import error_template
|
||||
from pylons.middleware import error_mapper, ErrorDocuments, ErrorHandler, \
|
||||
StaticJavascripts
|
||||
from pylons.wsgiapp import PylonsApp
|
||||
|
||||
from pyalchemybiz.config.environment import load_environment
|
||||
|
||||
def make_app(global_conf, full_stack=True, **app_conf):
|
||||
"""Create a Pylons WSGI application and return it
|
||||
|
||||
``global_conf``
|
||||
The inherited configuration for this application. Normally from
|
||||
the [DEFAULT] section of the Paste ini file.
|
||||
|
||||
``full_stack``
|
||||
Whether or not this application provides a full WSGI stack (by
|
||||
default, meaning it handles its own exceptions and errors).
|
||||
Disable full_stack when this application is "managed" by
|
||||
another WSGI middleware.
|
||||
|
||||
``app_conf``
|
||||
The application's local configuration. Normally specified in the
|
||||
[app:<name>] section of the Paste ini file (where <name>
|
||||
defaults to main).
|
||||
"""
|
||||
# Configure the Pylons environment
|
||||
load_environment(global_conf, app_conf)
|
||||
|
||||
# The Pylons WSGI app
|
||||
app = PylonsApp()
|
||||
|
||||
# CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
|
||||
|
||||
if asbool(full_stack):
|
||||
# Handle Python exceptions
|
||||
app = ErrorHandler(app, global_conf, error_template=error_template,
|
||||
**config['pylons.errorware'])
|
||||
|
||||
# Display error documents for 401, 403, 404 status codes (and
|
||||
# 500 when debug is disabled)
|
||||
app = ErrorDocuments(app, global_conf, mapper=error_mapper, **app_conf)
|
||||
|
||||
# Establish the Registry for this application
|
||||
app = RegistryManager(app)
|
||||
|
||||
# Static files
|
||||
javascripts_app = StaticJavascripts()
|
||||
static_app = StaticURLParser(config['pylons.paths']['static_files'])
|
||||
app = Cascade([static_app, javascripts_app, app])
|
||||
return app
|
24
pyalchemybiz/config/routing.py
Normal file
24
pyalchemybiz/config/routing.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
"""Routes configuration
|
||||
|
||||
The more specific and detailed routes should be defined first so they
|
||||
may take precedent over the more generic routes. For more information
|
||||
refer to the routes manual at http://routes.groovie.org/docs/
|
||||
"""
|
||||
from pylons import config
|
||||
from routes import Mapper
|
||||
|
||||
def make_map():
|
||||
"""Create, configure and return the routes Mapper"""
|
||||
map = Mapper(directory=config['pylons.paths']['controllers'],
|
||||
always_scan=config['debug'])
|
||||
|
||||
# The ErrorController route (handles 404/500 error pages); it should
|
||||
# likely stay at the top, ensuring it can always be resolved
|
||||
map.connect('error/:action/:id', controller='error')
|
||||
|
||||
# CUSTOM ROUTES HERE
|
||||
|
||||
map.connect(':controller/:action/:id')
|
||||
map.connect('*url', controller='template', action='view')
|
||||
|
||||
return map
|
0
pyalchemybiz/controllers/__init__.py
Normal file
0
pyalchemybiz/controllers/__init__.py
Normal file
20
pyalchemybiz/controllers/customer.py
Normal file
20
pyalchemybiz/controllers/customer.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
import logging
|
||||
|
||||
from pyalchemybiz.lib.base import *
|
||||
from pyalchemybiz.model import customer, meta
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class CustomerController(BaseController):
|
||||
|
||||
def index(self):
|
||||
sess = meta.Session()
|
||||
cust_q = sess.query(customer.Customer)
|
||||
c.customers = cust_q.all()
|
||||
return render('/customer.mako')
|
||||
|
||||
def edit(self, id):
|
||||
sess = meta.Session()
|
||||
cust_q = sess.query(customer.Customer)
|
||||
c.customer = cust_q.filter(customer.Customer.id==id).one()
|
||||
return c.customer
|
41
pyalchemybiz/controllers/error.py
Normal file
41
pyalchemybiz/controllers/error.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
import cgi
|
||||
import os.path
|
||||
|
||||
from paste.urlparser import StaticURLParser
|
||||
from pylons.middleware import error_document_template, media_path
|
||||
|
||||
from pyalchemybiz.lib.base import *
|
||||
|
||||
class ErrorController(BaseController):
|
||||
"""Generates error documents as and when they are required.
|
||||
|
||||
The ErrorDocuments middleware forwards to ErrorController when error
|
||||
related status codes are returned from the application.
|
||||
|
||||
This behaviour can be altered by changing the parameters to the
|
||||
ErrorDocuments middleware in your config/middleware.py file.
|
||||
|
||||
"""
|
||||
def document(self):
|
||||
"""Render the error document"""
|
||||
page = error_document_template % \
|
||||
dict(prefix=request.environ.get('SCRIPT_NAME', ''),
|
||||
code=cgi.escape(request.params.get('code', '')),
|
||||
message=cgi.escape(request.params.get('message', '')))
|
||||
return page
|
||||
|
||||
def img(self, id):
|
||||
"""Serve Pylons' stock images"""
|
||||
return self._serve_file(os.path.join(media_path, 'img'), id)
|
||||
|
||||
def style(self, id):
|
||||
"""Serve Pylons' stock stylesheets"""
|
||||
return self._serve_file(os.path.join(media_path, 'style'), id)
|
||||
|
||||
def _serve_file(self, root, path):
|
||||
"""Call Paste's FileApp (a WSGI application) to serve the file
|
||||
at the specified path
|
||||
"""
|
||||
static = StaticURLParser(root)
|
||||
request.environ['PATH_INFO'] = '/%s' % path
|
||||
return static(request.environ, self.start_response)
|
27
pyalchemybiz/controllers/template.py
Normal file
27
pyalchemybiz/controllers/template.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
from pyalchemybiz.lib.base import *
|
||||
|
||||
class TemplateController(BaseController):
|
||||
|
||||
def view(self, url):
|
||||
"""By default, the final controller tried to fulfill the request
|
||||
when no other routes match. It may be used to display a template
|
||||
when all else fails, e.g.::
|
||||
|
||||
def view(self, url):
|
||||
return render('/%s' % url)
|
||||
|
||||
Or if you're using Mako and want to explicitly send a 404 (Not
|
||||
Found) response code when the requested template doesn't exist::
|
||||
|
||||
import mako.exceptions
|
||||
|
||||
def view(self, url):
|
||||
try:
|
||||
return render('/%s' % url)
|
||||
except mako.exceptions.TopLevelLookupException:
|
||||
abort(404)
|
||||
|
||||
By default this controller aborts the request with a 404 (Not
|
||||
Found)
|
||||
"""
|
||||
abort(404)
|
0
pyalchemybiz/lib/__init__.py
Normal file
0
pyalchemybiz/lib/__init__.py
Normal file
14
pyalchemybiz/lib/app_globals.py
Normal file
14
pyalchemybiz/lib/app_globals.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
"""The application's Globals object"""
|
||||
from pylons import config
|
||||
|
||||
class Globals(object):
|
||||
"""Globals acts as a container for objects available throughout the
|
||||
life of the application
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""One instance of Globals is created during application
|
||||
initialization and is available during requests via the 'g'
|
||||
variable
|
||||
"""
|
||||
pass
|
36
pyalchemybiz/lib/base.py
Normal file
36
pyalchemybiz/lib/base.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
"""The base Controller API
|
||||
|
||||
Provides the BaseController class for subclassing, and other objects
|
||||
utilized by Controllers.
|
||||
"""
|
||||
from pylons import c, cache, config, g, request, response, session
|
||||
from pylons.controllers import WSGIController
|
||||
from pylons.controllers.util import abort, etag_cache, redirect_to
|
||||
from pylons.decorators import jsonify, validate
|
||||
from pylons.i18n import _, ungettext, N_
|
||||
from pylons.templating import render
|
||||
|
||||
import pyalchemybiz.lib.helpers as h
|
||||
import pyalchemybiz.model as model
|
||||
|
||||
from pyalchemybiz.model import meta
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
class BaseController(WSGIController):
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
"""Invoke the Controller"""
|
||||
# WSGIController.__call__ dispatches to the Controller method
|
||||
# the request is routed to. This routing information is
|
||||
# available in environ['pylons.routes_dict']
|
||||
conn = meta.engine.connect()
|
||||
meta.Session.configure(bind=conn)
|
||||
try:
|
||||
return WSGIController.__call__(self, environ, start_response)
|
||||
finally:
|
||||
meta.Session.remove()
|
||||
conn.close()
|
||||
|
||||
# Include the '_' function in the public names
|
||||
__all__ = [__name for __name in locals().keys() if not __name.startswith('_') \
|
||||
or __name == '_']
|
7
pyalchemybiz/lib/helpers.py
Normal file
7
pyalchemybiz/lib/helpers.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
"""Helper functions
|
||||
|
||||
Consists of functions to typically be used within templates, but also
|
||||
available to Controllers. This module is available to both as 'h'.
|
||||
"""
|
||||
from webhelpers.rails.wrapped import *
|
||||
from routes import url_for, redirect_to
|
17
pyalchemybiz/model/__init__.py
Normal file
17
pyalchemybiz/model/__init__.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
import sqlalchemy as sa
|
||||
from sqlalchemy import orm
|
||||
|
||||
from pyalchemybiz.model import meta
|
||||
from pyalchemybiz.model import customer
|
||||
|
||||
def init_model(engine):
|
||||
"""Call me before using any of the tables or classes in the model."""
|
||||
|
||||
sm = orm.sessionmaker(autoflush=True, transactional=True, bind=engine)
|
||||
|
||||
meta.engine = engine
|
||||
meta.Session = orm.scoped_session(sm)
|
||||
|
||||
customer.t_customer = sa.Table('customer', meta.metadata,
|
||||
autoload=True, autoload_with=engine)
|
||||
orm.mapper(customer.Customer, customer.t_customer)
|
5
pyalchemybiz/model/customer.py
Normal file
5
pyalchemybiz/model/customer.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
t_customer = None
|
||||
|
||||
class Customer(object):
|
||||
def __str__(self):
|
||||
return "%s %s" % (self.firstname, self.lastname)
|
14
pyalchemybiz/model/meta.py
Normal file
14
pyalchemybiz/model/meta.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
"""SQLAlchemy Metadata and Session object"""
|
||||
from sqlalchemy import MetaData
|
||||
|
||||
__all__ = ['engine', 'metadata', 'Session']
|
||||
|
||||
# SQLAlchemy database engine. Updated by model.init_model().
|
||||
engine = None
|
||||
|
||||
# SQLAlchemy session manager. Updated by model.init_model().
|
||||
Session = None
|
||||
|
||||
# Global metadata. If you have multiple databases with overlapping table
|
||||
# names, you'll need a metadata for each database.
|
||||
metadata = MetaData()
|
|
@ -1,20 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Package pyalchemybiz
|
||||
#
|
||||
# Author: Jan Dittberner <jan@dittberner.info>
|
||||
# Version: $Id$
|
||||
#
|
||||
# This file is part of pyalchemybiz
|
||||
from sqlalchemy import *
|
||||
|
||||
def create_schema(metadata):
|
||||
"""Create the database schema for products."""
|
||||
product_table = Table(
|
||||
'product', metadata,
|
||||
Column('product_id', Integer, primary_key=True),
|
||||
Column('name', String(100), nullable=False),
|
||||
Column('description', String(4096), nullable=False),
|
||||
Column('product_type', Integer, nullable=False)
|
||||
)
|
||||
product_table.create()
|
108
pyalchemybiz/public/index.html
Normal file
108
pyalchemybiz/public/index.html
Normal file
|
@ -0,0 +1,108 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Pylons Default Page</title>
|
||||
<style>
|
||||
body { background-color: #fff; color: #333; }
|
||||
|
||||
body, p {
|
||||
font-family: verdana, arial, helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
pre {
|
||||
background-color: #eee;
|
||||
padding: 10px;
|
||||
font-size: 11px;
|
||||
line-height: 13px;
|
||||
}
|
||||
|
||||
a { color: #000; }
|
||||
a:visited { color: #666; }
|
||||
a:hover { color: #fff; background-color:#000; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Welcome to your Pylons Web Application</h1>
|
||||
|
||||
<h2>Weren't expecting to see this page?</h2>
|
||||
|
||||
<p>The <tt>pyalchemybiz/public/</tt> directory is searched for static files
|
||||
<i>before</i> your controllers are run. Remove this file (<tt>pyalchemybiz/public/index.html</tt>)
|
||||
and edit the routes in <tt>pyalchemybiz/config/routing.py</tt> to point the
|
||||
<a href="/">root path</a> to a 'hello' controller we'll create below:
|
||||
<pre> map.connect('', controller='hello', action='index')</pre>
|
||||
</p>
|
||||
|
||||
<h2>Getting Started</h2>
|
||||
<p>You're now ready to start creating your own web application. To create a 'hello' controller,
|
||||
run the following command in your project's root directory:
|
||||
<pre>
|
||||
pyalchemybiz$ paster controller hello
|
||||
</pre>
|
||||
|
||||
This generates the following the following code in <tt>pyalchemybiz/controllers/hello.py</tt>:
|
||||
<pre>
|
||||
import logging
|
||||
|
||||
from pyalchemybiz.lib.base import *
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class HelloController(BaseController):
|
||||
|
||||
def index(self):
|
||||
# Return a rendered template
|
||||
# return render('/some/template.mako)
|
||||
# or, Return a response
|
||||
return 'Hello World'
|
||||
</pre>
|
||||
</p>
|
||||
<p>This controller simply prints out 'Hello World' to the browser. Pylons' default routes
|
||||
automatically set up this controller to respond at the <a href="/hello">/hello</a> URL.
|
||||
With the additional route described above, this controller will also respond at the
|
||||
<a href="/">root path</a>.
|
||||
</p>
|
||||
|
||||
<h3>Using a template</h3>
|
||||
<p>To call a template and do something a little more complex, this following example
|
||||
shows how to print out some request information from a
|
||||
<a href="http://www.makotemplates.org">Mako</a> template.
|
||||
</p>
|
||||
<p>Create a <tt>serverinfo.mako</tt> file in your project's <tt>pyalchemybiz/templates/</tt>
|
||||
directory with the following contents:
|
||||
</p>
|
||||
<pre>
|
||||
<h2>
|
||||
Server info for ${request.host}
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
The URL you called: ${h.url_for()}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The name you set: ${c.name}
|
||||
</p>
|
||||
|
||||
<p>The WSGI environ:<br />
|
||||
<pre>${c.pretty_environ}</pre>
|
||||
</p>
|
||||
</pre>
|
||||
|
||||
Then add the following to your 'hello' controller class:
|
||||
<pre>
|
||||
def serverinfo(self):
|
||||
import cgi
|
||||
import pprint
|
||||
c.pretty_environ = cgi.escape(pprint.pformat(request.environ))
|
||||
c.name = 'The Black Knight'
|
||||
return render('/serverinfo.mako')
|
||||
</pre>
|
||||
|
||||
You can now view the page at: <tt><a href="/hello/serverinfo">/hello/serverinfo</a></tt>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
20
pyalchemybiz/templates/base.mako
Normal file
20
pyalchemybiz/templates/base.mako
Normal file
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>PyAlchemyBiz</title>
|
||||
${h.stylesheet_link_tag('/pyalchemybiz.css')}
|
||||
${h.javascript_include_tag(
|
||||
'/javascripts/pyalchemybiz.js', builtins=True)}
|
||||
</head>
|
||||
<body>
|
||||
<div class="content">
|
||||
${next.body()}\
|
||||
<p class="footer">
|
||||
Return to the
|
||||
${h.link_to('FrontPage',
|
||||
h.url_for(action="index"))}
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
pyalchemybiz/templates/customer.mako
Normal file
9
pyalchemybiz/templates/customer.mako
Normal file
|
@ -0,0 +1,9 @@
|
|||
<%inherit file="base.mako" />
|
||||
|
||||
<h1>Hallo</h1>
|
||||
|
||||
<ul id="customers">
|
||||
% for customer in c.customers:
|
||||
<li>${customer.firstname} ${customer.lastname} [${h.link_to('edit', h.url_for(id=customer.id, action="edit"))}]</li>
|
||||
% endfor
|
||||
</ul>
|
40
pyalchemybiz/tests/__init__.py
Normal file
40
pyalchemybiz/tests/__init__.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
"""Pylons application test package
|
||||
|
||||
When the test runner finds and executes tests within this directory,
|
||||
this file will be loaded to setup the test environment.
|
||||
|
||||
It registers the root directory of the project in sys.path and
|
||||
pkg_resources, in case the project hasn't been installed with
|
||||
setuptools. It also initializes the application via websetup (paster
|
||||
setup-app) with the project's test.ini configuration file.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
from unittest import TestCase
|
||||
|
||||
import pkg_resources
|
||||
import paste.fixture
|
||||
import paste.script.appinstall
|
||||
from paste.deploy import loadapp
|
||||
from routes import url_for
|
||||
|
||||
__all__ = ['url_for', 'TestController']
|
||||
|
||||
here_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
conf_dir = os.path.dirname(os.path.dirname(here_dir))
|
||||
|
||||
sys.path.insert(0, conf_dir)
|
||||
pkg_resources.working_set.add_entry(conf_dir)
|
||||
pkg_resources.require('Paste')
|
||||
pkg_resources.require('PasteScript')
|
||||
|
||||
test_file = os.path.join(conf_dir, 'test.ini')
|
||||
cmd = paste.script.appinstall.SetupCommand('setup-app')
|
||||
cmd.run([test_file])
|
||||
|
||||
class TestController(TestCase):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wsgiapp = loadapp('config:test.ini', relative_to=conf_dir)
|
||||
self.app = paste.fixture.TestApp(wsgiapp)
|
||||
TestCase.__init__(self, *args, **kwargs)
|
0
pyalchemybiz/tests/functional/__init__.py
Normal file
0
pyalchemybiz/tests/functional/__init__.py
Normal file
7
pyalchemybiz/tests/functional/test_customer.py
Normal file
7
pyalchemybiz/tests/functional/test_customer.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
from pyalchemybiz.tests import *
|
||||
|
||||
class TestCustomerController(TestController):
|
||||
|
||||
def test_index(self):
|
||||
response = self.app.get(url_for(controller='customer'))
|
||||
# Test response...
|
0
pyalchemybiz/tests/test_models.py
Normal file
0
pyalchemybiz/tests/test_models.py
Normal file
22
pyalchemybiz/websetup.py
Normal file
22
pyalchemybiz/websetup.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
"""Setup the pyalchemybiz application"""
|
||||
import logging
|
||||
|
||||
from paste.deploy import appconfig
|
||||
from pylons import config
|
||||
|
||||
from pyalchemybiz.config.environment import load_environment
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def setup_config(command, filename, section, vars):
|
||||
"""Place any commands to setup pyalchemybiz here"""
|
||||
conf = appconfig('config:' + filename)
|
||||
load_environment(conf.global_conf, conf.local_conf)
|
||||
|
||||
# Populate the DB on 'paster setup-app'
|
||||
import pyalchemybiz.model as model
|
||||
|
||||
log.info("Setting up database connectivity...")
|
||||
log.info("Creating tables...")
|
||||
model.meta.metadata.create_all(bind=model.meta.engine)
|
||||
log.info("Successfully set up.")
|
59
setup.cfg
Normal file
59
setup.cfg
Normal file
|
@ -0,0 +1,59 @@
|
|||
[egg_info]
|
||||
tag_build = dev
|
||||
tag_svn_revision = true
|
||||
|
||||
[easy_install]
|
||||
find_links = http://www.pylonshq.com/download/
|
||||
|
||||
[pudge]
|
||||
theme = pythonpaste.org
|
||||
|
||||
# Add extra doc files here with spaces between them
|
||||
docs = docs/index.txt
|
||||
|
||||
# Doc Settings
|
||||
doc_base = docs/
|
||||
dest = docs/html
|
||||
|
||||
# Add extra modules here separated with commas
|
||||
modules = pyalchemybiz
|
||||
title = Pyalchemybiz
|
||||
organization = Pylons
|
||||
|
||||
# Highlight code-block sections with Pygments
|
||||
highlighter = pygments
|
||||
|
||||
# Optionally add extra links
|
||||
#organization_url = http://pylonshq.com/
|
||||
#trac_url = http://pylonshq.com/project
|
||||
settings = no_about=true
|
||||
|
||||
# Optionally add extra settings
|
||||
# link1=/community/ Community
|
||||
# link2=/download/ Download
|
||||
|
||||
[publish]
|
||||
doc-dir=docs/html
|
||||
make-dirs=1
|
||||
|
||||
# Babel configuration
|
||||
[compile_catalog]
|
||||
domain = pyalchemybiz
|
||||
directory = pyalchemybiz/i18n
|
||||
statistics = true
|
||||
|
||||
[extract_messages]
|
||||
add_comments = TRANSLATORS:
|
||||
output_file = pyalchemybiz/i18n/pyalchemybiz.pot
|
||||
width = 80
|
||||
|
||||
[init_catalog]
|
||||
domain = pyalchemybiz
|
||||
input_file = pyalchemybiz/i18n/pyalchemybiz.pot
|
||||
output_dir = pyalchemybiz/i18n
|
||||
|
||||
[update_catalog]
|
||||
domain = pyalchemybiz
|
||||
input_file = pyalchemybiz/i18n/pyalchemybiz.pot
|
||||
output_dir = pyalchemybiz/i18n
|
||||
previous = true
|
46
setup.py
46
setup.py
|
@ -1,19 +1,31 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Author: Jan Dittberner <jan@dittberner.info>
|
||||
# Version: $Id$
|
||||
#
|
||||
# This file is part of pyalchemybiz
|
||||
#
|
||||
from setuptools import setup
|
||||
setup(name='pyalchemybiz',
|
||||
description='Python SQLAlchemy Business',
|
||||
version='0.1dev',
|
||||
try:
|
||||
from setuptools import setup, find_packages
|
||||
except ImportError:
|
||||
from ez_setup import use_setuptools
|
||||
use_setuptools()
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name='pyalchemybiz',
|
||||
version="0.1",
|
||||
description='python based small business suite.',
|
||||
author='Jan Dittberner',
|
||||
author_email='jan@dittberner.info',
|
||||
url='http://www.dittberner.info/projects/pyalchemybiz/',
|
||||
packages=['pyalchemybiz'],
|
||||
install_requires=['sqlalchemy >= 0.3.10'],
|
||||
license='GPL'
|
||||
)
|
||||
url='http://www.dittberner.info/projects/pyalchemybiz',
|
||||
install_requires=["Pylons>=0.9.6.2", "SQLAlchemy>=0.4"],
|
||||
packages=find_packages(exclude=['ez_setup']),
|
||||
include_package_data=True,
|
||||
test_suite='nose.collector',
|
||||
package_data={'pyalchemybiz': ['i18n/*/LC_MESSAGES/*.mo']},
|
||||
#message_extractors = {'pyalchemybiz': [
|
||||
# ('**.py', 'python', None),
|
||||
# ('templates/**.mako', 'mako', None),
|
||||
# ('public/**', 'ignore', None)]},
|
||||
entry_points="""
|
||||
[paste.app_factory]
|
||||
main = pyalchemybiz.config.middleware:make_app
|
||||
|
||||
[paste.app_install]
|
||||
main = pylons.util:PylonsInstaller
|
||||
""",
|
||||
)
|
||||
|
|
21
test.ini
Normal file
21
test.ini
Normal file
|
@ -0,0 +1,21 @@
|
|||
#
|
||||
# pyalchemybiz - Pylons testing environment configuration
|
||||
#
|
||||
# The %(here)s variable will be replaced with the parent directory of this file
|
||||
#
|
||||
[DEFAULT]
|
||||
debug = true
|
||||
# Uncomment and replace with the address which should receive any error reports
|
||||
#email_to = you@yourdomain.com
|
||||
smtp_server = localhost
|
||||
error_email_from = paste@localhost
|
||||
|
||||
[server:main]
|
||||
use = egg:Paste#http
|
||||
host = 0.0.0.0
|
||||
port = 5000
|
||||
|
||||
[app:main]
|
||||
use = config:development.ini
|
||||
|
||||
# Add additional test specific configuration options as necessary.
|
Loading…
Reference in a new issue