From 554276ed23079886f25ae5f226757db027e00683 Mon Sep 17 00:00:00 2001
From: Jan Dittberner
Date: Sun, 5 Oct 2008 15:23:54 +0000
Subject: [PATCH] initial Pylons code (fixes #3)
git-svn-id: file:///var/www/wwwusers/usr01/svn/pyalchemybiz/trunk@5 389c73d4-bf09-4d3d-a15e-f94a37d0667a
---
MANIFEST.in | 2 +
README.txt | 19 +++
data/templates/base.mako.py | 45 ++++++++
data/templates/customer.mako.py | 50 ++++++++
development.ini | 70 ++++++++++++
docs/index.txt | 12 ++
pyalchemybiz.egg-info/PKG-INFO | 10 ++
pyalchemybiz.egg-info/SOURCES.txt | 29 +++++
pyalchemybiz.egg-info/dependency_links.txt | 1 +
pyalchemybiz.egg-info/entry_points.txt | 7 ++
.../paste_deploy_config.ini_tmpl | 64 +++++++++++
pyalchemybiz.egg-info/paster_plugins.txt | 2 +
pyalchemybiz.egg-info/requires.txt | 1 +
pyalchemybiz.egg-info/top_level.txt | 1 +
pyalchemybiz/__init__.py | 8 --
pyalchemybiz/config/__init__.py | 0
pyalchemybiz/config/environment.py | 38 ++++++
pyalchemybiz/config/middleware.py | 57 +++++++++
pyalchemybiz/config/routing.py | 24 ++++
pyalchemybiz/controllers/__init__.py | 0
pyalchemybiz/controllers/customer.py | 20 ++++
pyalchemybiz/controllers/error.py | 41 +++++++
pyalchemybiz/controllers/template.py | 27 +++++
pyalchemybiz/lib/__init__.py | 0
pyalchemybiz/lib/app_globals.py | 14 +++
pyalchemybiz/lib/base.py | 36 ++++++
pyalchemybiz/lib/helpers.py | 7 ++
pyalchemybiz/model/__init__.py | 17 +++
pyalchemybiz/model/customer.py | 5 +
pyalchemybiz/model/meta.py | 14 +++
pyalchemybiz/productdb.py | 20 ----
pyalchemybiz/public/index.html | 108 ++++++++++++++++++
pyalchemybiz/templates/base.mako | 20 ++++
pyalchemybiz/templates/customer.mako | 9 ++
pyalchemybiz/tests/__init__.py | 40 +++++++
pyalchemybiz/tests/functional/__init__.py | 0
.../tests/functional/test_customer.py | 7 ++
pyalchemybiz/tests/test_models.py | 0
pyalchemybiz/websetup.py | 22 ++++
setup.cfg | 59 ++++++++++
setup.py | 50 +++++---
test.ini | 21 ++++
42 files changed, 930 insertions(+), 47 deletions(-)
create mode 100644 MANIFEST.in
create mode 100644 README.txt
create mode 100644 data/templates/base.mako.py
create mode 100644 data/templates/customer.mako.py
create mode 100644 development.ini
create mode 100644 docs/index.txt
create mode 100644 pyalchemybiz.egg-info/PKG-INFO
create mode 100644 pyalchemybiz.egg-info/SOURCES.txt
create mode 100644 pyalchemybiz.egg-info/dependency_links.txt
create mode 100644 pyalchemybiz.egg-info/entry_points.txt
create mode 100644 pyalchemybiz.egg-info/paste_deploy_config.ini_tmpl
create mode 100644 pyalchemybiz.egg-info/paster_plugins.txt
create mode 100644 pyalchemybiz.egg-info/requires.txt
create mode 100644 pyalchemybiz.egg-info/top_level.txt
create mode 100644 pyalchemybiz/config/__init__.py
create mode 100644 pyalchemybiz/config/environment.py
create mode 100644 pyalchemybiz/config/middleware.py
create mode 100644 pyalchemybiz/config/routing.py
create mode 100644 pyalchemybiz/controllers/__init__.py
create mode 100644 pyalchemybiz/controllers/customer.py
create mode 100644 pyalchemybiz/controllers/error.py
create mode 100644 pyalchemybiz/controllers/template.py
create mode 100644 pyalchemybiz/lib/__init__.py
create mode 100644 pyalchemybiz/lib/app_globals.py
create mode 100644 pyalchemybiz/lib/base.py
create mode 100644 pyalchemybiz/lib/helpers.py
create mode 100644 pyalchemybiz/model/__init__.py
create mode 100644 pyalchemybiz/model/customer.py
create mode 100644 pyalchemybiz/model/meta.py
delete mode 100644 pyalchemybiz/productdb.py
create mode 100644 pyalchemybiz/public/index.html
create mode 100644 pyalchemybiz/templates/base.mako
create mode 100644 pyalchemybiz/templates/customer.mako
create mode 100644 pyalchemybiz/tests/__init__.py
create mode 100644 pyalchemybiz/tests/functional/__init__.py
create mode 100644 pyalchemybiz/tests/functional/test_customer.py
create mode 100644 pyalchemybiz/tests/test_models.py
create mode 100644 pyalchemybiz/websetup.py
create mode 100644 setup.cfg
create mode 100644 test.ini
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..5b63bda
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,2 @@
+recursive-include pyalchemybiz/public *
+recursive-include pyalchemybiz/templates *
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..6718930
--- /dev/null
+++ b/README.txt
@@ -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.
diff --git a/data/templates/base.mako.py b/data/templates/base.mako.py
new file mode 100644
index 0000000..0349a7a
--- /dev/null
+++ b/data/templates/base.mako.py
@@ -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'\n\n \n PyAlchemyBiz\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 \n \n \n ')
+ # SOURCE LINE 12
+ __M_writer(unicode(next.body()))
+ __M_writer(u'')
+ # SOURCE LINE 13
+ __M_writer(u' \n
\n \n\n')
+ return ''
+ finally:
+ context.caller_stack._pop_frame()
+
+
diff --git a/data/templates/customer.mako.py b/data/templates/customer.mako.py
new file mode 100644
index 0000000..a7cc270
--- /dev/null
+++ b/data/templates/customer.mako.py
@@ -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\nHallo
\n\n\n')
+ # SOURCE LINE 6
+ for customer in c.customers:
+ # SOURCE LINE 7
+ __M_writer(u' - ')
+ __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']
\n')
+ # SOURCE LINE 9
+ __M_writer(u'
\n')
+ return ''
+ finally:
+ context.caller_stack._pop_frame()
+
+
diff --git a/development.ini b/development.ini
new file mode 100644
index 0000000..4e8ce6a
--- /dev/null
+++ b/development.ini
@@ -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
diff --git a/docs/index.txt b/docs/index.txt
new file mode 100644
index 0000000..b1e5533
--- /dev/null
+++ b/docs/index.txt
@@ -0,0 +1,12 @@
+pyalchemybiz
+++++++++++++
+
+This is the main index page of your documentation. It should be written in
+`reStructuredText format `_.
+
+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``.
diff --git a/pyalchemybiz.egg-info/PKG-INFO b/pyalchemybiz.egg-info/PKG-INFO
new file mode 100644
index 0000000..ad177e1
--- /dev/null
+++ b/pyalchemybiz.egg-info/PKG-INFO
@@ -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
diff --git a/pyalchemybiz.egg-info/SOURCES.txt b/pyalchemybiz.egg-info/SOURCES.txt
new file mode 100644
index 0000000..6be95e1
--- /dev/null
+++ b/pyalchemybiz.egg-info/SOURCES.txt
@@ -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
\ No newline at end of file
diff --git a/pyalchemybiz.egg-info/dependency_links.txt b/pyalchemybiz.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/pyalchemybiz.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/pyalchemybiz.egg-info/entry_points.txt b/pyalchemybiz.egg-info/entry_points.txt
new file mode 100644
index 0000000..416807a
--- /dev/null
+++ b/pyalchemybiz.egg-info/entry_points.txt
@@ -0,0 +1,7 @@
+
+ [paste.app_factory]
+ main = pyalchemybiz.config.middleware:make_app
+
+ [paste.app_install]
+ main = pylons.util:PylonsInstaller
+
\ No newline at end of file
diff --git a/pyalchemybiz.egg-info/paste_deploy_config.ini_tmpl b/pyalchemybiz.egg-info/paste_deploy_config.ini_tmpl
new file mode 100644
index 0000000..e5458c4
--- /dev/null
+++ b/pyalchemybiz.egg-info/paste_deploy_config.ini_tmpl
@@ -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
diff --git a/pyalchemybiz.egg-info/paster_plugins.txt b/pyalchemybiz.egg-info/paster_plugins.txt
new file mode 100644
index 0000000..435fb65
--- /dev/null
+++ b/pyalchemybiz.egg-info/paster_plugins.txt
@@ -0,0 +1,2 @@
+Pylons
+WebHelpers
diff --git a/pyalchemybiz.egg-info/requires.txt b/pyalchemybiz.egg-info/requires.txt
new file mode 100644
index 0000000..fe9f093
--- /dev/null
+++ b/pyalchemybiz.egg-info/requires.txt
@@ -0,0 +1 @@
+Pylons>=0.9.6.2
\ No newline at end of file
diff --git a/pyalchemybiz.egg-info/top_level.txt b/pyalchemybiz.egg-info/top_level.txt
new file mode 100644
index 0000000..2bc407b
--- /dev/null
+++ b/pyalchemybiz.egg-info/top_level.txt
@@ -0,0 +1 @@
+pyalchemybiz
diff --git a/pyalchemybiz/__init__.py b/pyalchemybiz/__init__.py
index 8918ae1..e69de29 100644
--- a/pyalchemybiz/__init__.py
+++ b/pyalchemybiz/__init__.py
@@ -1,8 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Package pyalchemybiz
-#
-# Author: Jan Dittberner
-# Version: $Id$
-#
-# This file is part of pyalchemybiz
diff --git a/pyalchemybiz/config/__init__.py b/pyalchemybiz/config/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pyalchemybiz/config/environment.py b/pyalchemybiz/config/environment.py
new file mode 100644
index 0000000..9658bd6
--- /dev/null
+++ b/pyalchemybiz/config/environment.py
@@ -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)
diff --git a/pyalchemybiz/config/middleware.py b/pyalchemybiz/config/middleware.py
new file mode 100644
index 0000000..84ed761
--- /dev/null
+++ b/pyalchemybiz/config/middleware.py
@@ -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:] section of the Paste ini file (where
+ 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
diff --git a/pyalchemybiz/config/routing.py b/pyalchemybiz/config/routing.py
new file mode 100644
index 0000000..af711a9
--- /dev/null
+++ b/pyalchemybiz/config/routing.py
@@ -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
diff --git a/pyalchemybiz/controllers/__init__.py b/pyalchemybiz/controllers/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pyalchemybiz/controllers/customer.py b/pyalchemybiz/controllers/customer.py
new file mode 100644
index 0000000..25550f7
--- /dev/null
+++ b/pyalchemybiz/controllers/customer.py
@@ -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
diff --git a/pyalchemybiz/controllers/error.py b/pyalchemybiz/controllers/error.py
new file mode 100644
index 0000000..665ac31
--- /dev/null
+++ b/pyalchemybiz/controllers/error.py
@@ -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)
diff --git a/pyalchemybiz/controllers/template.py b/pyalchemybiz/controllers/template.py
new file mode 100644
index 0000000..740491b
--- /dev/null
+++ b/pyalchemybiz/controllers/template.py
@@ -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)
diff --git a/pyalchemybiz/lib/__init__.py b/pyalchemybiz/lib/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pyalchemybiz/lib/app_globals.py b/pyalchemybiz/lib/app_globals.py
new file mode 100644
index 0000000..7f7585f
--- /dev/null
+++ b/pyalchemybiz/lib/app_globals.py
@@ -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
diff --git a/pyalchemybiz/lib/base.py b/pyalchemybiz/lib/base.py
new file mode 100644
index 0000000..1b923c0
--- /dev/null
+++ b/pyalchemybiz/lib/base.py
@@ -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 == '_']
diff --git a/pyalchemybiz/lib/helpers.py b/pyalchemybiz/lib/helpers.py
new file mode 100644
index 0000000..25a63d1
--- /dev/null
+++ b/pyalchemybiz/lib/helpers.py
@@ -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
diff --git a/pyalchemybiz/model/__init__.py b/pyalchemybiz/model/__init__.py
new file mode 100644
index 0000000..b4c8fe7
--- /dev/null
+++ b/pyalchemybiz/model/__init__.py
@@ -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)
diff --git a/pyalchemybiz/model/customer.py b/pyalchemybiz/model/customer.py
new file mode 100644
index 0000000..5fe8321
--- /dev/null
+++ b/pyalchemybiz/model/customer.py
@@ -0,0 +1,5 @@
+t_customer = None
+
+class Customer(object):
+ def __str__(self):
+ return "%s %s" % (self.firstname, self.lastname)
diff --git a/pyalchemybiz/model/meta.py b/pyalchemybiz/model/meta.py
new file mode 100644
index 0000000..578584a
--- /dev/null
+++ b/pyalchemybiz/model/meta.py
@@ -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()
diff --git a/pyalchemybiz/productdb.py b/pyalchemybiz/productdb.py
deleted file mode 100644
index 50d5016..0000000
--- a/pyalchemybiz/productdb.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Package pyalchemybiz
-#
-# Author: Jan Dittberner
-# 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()
diff --git a/pyalchemybiz/public/index.html b/pyalchemybiz/public/index.html
new file mode 100644
index 0000000..98183c1
--- /dev/null
+++ b/pyalchemybiz/public/index.html
@@ -0,0 +1,108 @@
+
+
+
+ Pylons Default Page
+
+
+
+
+Welcome to your Pylons Web Application
+
+Weren't expecting to see this page?
+
+The pyalchemybiz/public/ directory is searched for static files
+ before your controllers are run. Remove this file (pyalchemybiz/public/index.html)
+ and edit the routes in pyalchemybiz/config/routing.py to point the
+ root path to a 'hello' controller we'll create below:
+
map.connect('', controller='hello', action='index')
+
+
+Getting Started
+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:
+
+pyalchemybiz$ paster controller hello
+
+
+ This generates the following the following code in pyalchemybiz/controllers/hello.py:
+
+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'
+
+
+This controller simply prints out 'Hello World' to the browser. Pylons' default routes
+ automatically set up this controller to respond at the /hello URL.
+ With the additional route described above, this controller will also respond at the
+ root path.
+
+
+Using a template
+To call a template and do something a little more complex, this following example
+ shows how to print out some request information from a
+ Mako template.
+
+Create a serverinfo.mako file in your project's pyalchemybiz/templates/
+ directory with the following contents:
+
+
+<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>
+
+
+Then add the following to your 'hello' controller class:
+
+ 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')
+
+
+You can now view the page at: /hello/serverinfo
+
+
+
diff --git a/pyalchemybiz/templates/base.mako b/pyalchemybiz/templates/base.mako
new file mode 100644
index 0000000..ed0c538
--- /dev/null
+++ b/pyalchemybiz/templates/base.mako
@@ -0,0 +1,20 @@
+
+
+
+ PyAlchemyBiz
+ ${h.stylesheet_link_tag('/pyalchemybiz.css')}
+ ${h.javascript_include_tag(
+ '/javascripts/pyalchemybiz.js', builtins=True)}
+
+
+
+ ${next.body()}\
+
+
+
+
diff --git a/pyalchemybiz/templates/customer.mako b/pyalchemybiz/templates/customer.mako
new file mode 100644
index 0000000..8aefd56
--- /dev/null
+++ b/pyalchemybiz/templates/customer.mako
@@ -0,0 +1,9 @@
+<%inherit file="base.mako" />
+
+Hallo
+
+
+% for customer in c.customers:
+ - ${customer.firstname} ${customer.lastname} [${h.link_to('edit', h.url_for(id=customer.id, action="edit"))}]
+% endfor
+
diff --git a/pyalchemybiz/tests/__init__.py b/pyalchemybiz/tests/__init__.py
new file mode 100644
index 0000000..91ff2e7
--- /dev/null
+++ b/pyalchemybiz/tests/__init__.py
@@ -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)
diff --git a/pyalchemybiz/tests/functional/__init__.py b/pyalchemybiz/tests/functional/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pyalchemybiz/tests/functional/test_customer.py b/pyalchemybiz/tests/functional/test_customer.py
new file mode 100644
index 0000000..5a96361
--- /dev/null
+++ b/pyalchemybiz/tests/functional/test_customer.py
@@ -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...
diff --git a/pyalchemybiz/tests/test_models.py b/pyalchemybiz/tests/test_models.py
new file mode 100644
index 0000000..e69de29
diff --git a/pyalchemybiz/websetup.py b/pyalchemybiz/websetup.py
new file mode 100644
index 0000000..5504807
--- /dev/null
+++ b/pyalchemybiz/websetup.py
@@ -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.")
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..60ab224
--- /dev/null
+++ b/setup.cfg
@@ -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
diff --git a/setup.py b/setup.py
index 57f6141..c6d0429 100755
--- a/setup.py
+++ b/setup.py
@@ -1,19 +1,31 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Author: Jan Dittberner
-# Version: $Id$
-#
-# This file is part of pyalchemybiz
-#
-from setuptools import setup
-setup(name='pyalchemybiz',
- description='Python SQLAlchemy Business',
- version='0.1dev',
- 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'
- )
+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',
+ 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
+ """,
+)
diff --git a/test.ini b/test.ini
new file mode 100644
index 0000000..9d3ed61
--- /dev/null
+++ b/test.ini
@@ -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.