Real World template project — summer 0.7.2 documentation

# 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

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

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