Real World template project¶
Presents a template of a real Python project and shows features of the summer framework.
Requirements:
SQLite – uses in memory db available with no special config.
LDAP – uses simple ldap db holding user accounts.
SQL database is simple and uses just two entities with m:n relationship between Category <–> Item.
LDAP support can be turned off, if not, you will need to set up your own
ldap server, see ldap/sample.local.sh
for details.
As well as with Basic Application Context, there are some obvious configuration files:
standard Python logging config
logging.cfg
summer framework config
conf.py
Project is organized with one single package, so please look at:
tmplprojecttest.py
tmplproject/main.py
tmplproject/appcontext.py
conf.py¶
# Copyright (C) 2009-2019 Martin Slouf <martinslouf@users.sourceforge.net>
#
# This file is a part of Summer.
#
# Summer is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 3 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import os.path
import summer
# create ConfigValue instance
config_value = summer.ConfigValue()
project_name = "tmplproject"
project_topdir = os.path.abspath(os.path.join(__file__, "..", ".."))
# allow override by setting SQLALCHEMY_URI environment variable (depends on your OS)
sqlalchemy_uri = config_value("SQLALCHEMY_URI", "sqlite:///:memory:")
sqlalchemy_autocommit = config_value("SQLALCHEMY_AUTOCOMMIT", False)
l10n_domain = project_name
l10n_dir = "%s/l10n" % (project_topdir,)
l10n_languages = ("cs", "en")
ldap_host = config_value("LDAP_HOST", "localhost")
ldap_port = config_value("LDAP_PORT", 389)
ldap_base = "dc=sample,dc=local"
ldap_login = config_value("LDAP_LOGIN", "cn=admin,dc=sample,dc=local")
ldap_password = config_value("LDAP_PASSWORD", "secret")
tmplprojecttest.py¶
# Copyright (C) 2009-2019 Martin Slouf <martinslouf@users.sourceforge.net>
#
# This file is a part of Summer.
#
# Summer is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 3 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Relatively advanced standalone example.
Check the sample config files in this directory. Look at the single
:py:module:`tmplproject` module.
"""
import logging.config
import os.path
import sys
import unittest
# configure logging as soon as possible
LOGGING_CFG = os.path.join(os.path.dirname(__file__), "logging.cfg")
logging.config.fileConfig(LOGGING_CFG)
logger = logging.getLogger(__name__)
logger.info("logging config = %s", LOGGING_CFG)
from summer.tests.examples.tmplproject.tmplproject import main
class TmplProjectTest(unittest.TestCase):
"""Demonstrates various summer features in *real-world* project."""
def setUp(self):
pass
def tearDown(self):
pass
def test_tmplproject(self):
logger.info("#### TEST STARTS HERE ####")
main.main(sys.argv[1:])
logger.info("#### TEST ENDS HERE ####")
if __name__ == "__main__":
unittest.main()
tmplproject/main.py¶
# Copyright (C) 2009-2019 Martin Slouf <martinslouf@users.sourceforge.net>
#
# This file is a part of Summer.
#
# Summer is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 3 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Main entry point to the program."""
# usual imports
import logging
import summer
# import ApplicationContext
from .appcontext import ctx
# import for demo purposes
from .model import Category, DeclarativeFooEntity
# configure logging as soon as possible
logger = logging.getLogger(__name__)
def main(args):
"""Entry point to our program."""
logger.info("sample started")
# create the sample database
ctx.session_factory.create_schema()
# run demonstration
do_demonstration()
logger.info("sample finished")
def do_demonstration():
mark = "PROGRAM OUTPUT>"
# l10n
logger.info("%s test localization -- %s", mark, _("localized message"))
# db
logger.info("let's create some objects and persist them")
category_dao = ctx.category_dao
for i in range(1, 16):
cat = Category()
cat.order = i
cat.code = "code_%02d" % (cat.order,)
category_dao.save(cat)
# we go through result set using paging
logger.info(
"let's iterate using db paging through what we have just persisted")
cat_filter = summer.Filter(1, 5)
for page in range(1, 4):
cat_filter.page = page
logger.info("%s page %d", mark, cat_filter.page)
for cat in category_dao.find(cat_filter):
logger.info("%s %s", mark, cat)
# db declarative entity
numbers = range(1, 5)
s = ctx.session_factory.sqlalchemy_session
for i in numbers:
s.add(DeclarativeFooEntity(name="name_%d" % (i,)))
s.commit()
col = s.query(DeclarativeFooEntity).all()
s.commit()
assert len(numbers) == len(col)
# ldap
logger.info("let's use LDAP demo query for arbitrary objects (not all of them, just those with ou=users)")
user_manager = ctx.user_manager
for user in user_manager.find():
logger.info("%s %s", mark, user)
tmplproject/appcontext.py¶
# Copyright (C) 2009-2019 Martin Slouf <martinslouf@users.sourceforge.net>
#
# This file is a part of Summer.
#
# Summer is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 3 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
Application context definition.
"""
import summer
# do all the necessary imports, all that is imported bellow is deployed
# into the context, just as an example -- you can deploy anything you want
# of course
from .orm.tables import TableDefinitions
from .orm.mappings import ClassMappings
from .manager import (
CategoryDao, CategoryManager,
ItemDao, ItemManager,
UserDao, UserManager,
)
from . import conf
# we mix traditional and declarative approach in SQLAlchemy entities -- we must share metadata and engine
from . import sessionprovider
class ApplicationContext(summer.Context):
def __init__(self):
session_provider = sessionprovider.session_provider
ldap_connection_provider = summer.DefaultLdapConnectionProvider(
conf.ldap_host,
conf.ldap_port,
conf.ldap_login,
conf.ldap_password,
conf.ldap_base)
l10n = summer.Localization(conf.l10n_domain, conf.l10n_dir, conf.l10n_languages)
summer.Context.__init__(self, session_provider, ldap_connection_provider, l10n)
def orm_init(self):
# you can do whatever setup you want, here you can see so-called
# "classical" mapping, see *SqlAlchemy* for details
# first let's complete database initialization with custom table
# definitions and mappings
self.session_factory.table_definitions = TableDefinitions()
# class mappings must be defined _after_ table definitions
self.session_factory.class_mappings = ClassMappings()
def context_init(self):
# deploy our dao objects
self.category_dao = CategoryDao(self.session_factory)
self.item_dao = ItemDao(self.session_factory)
# let's deploy LDAP DAO's; treat them as analogy to SQL DAO's,
# though the LDAP has no sense of SQL transaction
self.user_dao = UserDao(self.ldap_session_factory)
# let's define some higher level business level objects (managers)
self.category_manager = CategoryManager(self.category_dao)
self.item_manager = ItemManager(self.item_dao)
self.user_manager = UserManager(self.user_dao)
# module level reference to (singleton) ApplicationContext
ctx = ApplicationContext()