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-2016 Martin Slouf <martin.slouf@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-2016 Martin Slouf <martin.slouf@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-2016 Martin Slouf <martin.slouf@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

# 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)

    # 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-2016 Martin Slouf <martin.slouf@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


class ApplicationContext(summer.Context):

    def __init__(self):
        session_provider = summer.DefaultSessionProvider(conf.sqlalchemy_uri, conf.sqlalchemy_autocommit)
        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()