Michael Merickel
2017-03-28 14be695bd7d187e162145a28ac07fe341dae3208
rewrite low-level pyramid config functions to use plaster
6 files modified
315 ■■■■■ changed files
docs/api/paster.rst 6 ●●●● patch | view | raw | blame | history
pyramid/paster.py 59 ●●●●● patch | view | raw | blame | history
pyramid/scripts/common.py 27 ●●●● patch | view | raw | blame | history
pyramid/tests/test_paster.py 180 ●●●●● patch | view | raw | blame | history
pyramid/tests/test_scripts/dummy.py 41 ●●●●● patch | view | raw | blame | history
setup.py 2 ●●●●● patch | view | raw | blame | history
docs/api/paster.rst
@@ -7,8 +7,8 @@
    .. autofunction:: bootstrap
    .. autofunction:: get_app(config_uri, name=None, options=None)
    .. autofunction:: get_app
    .. autofunction:: get_appsettings(config_uri, name=None, options=None)
    .. autofunction:: get_appsettings
    .. autofunction:: setup_logging(config_uri, global_conf=None)
    .. autofunction:: setup_logging
pyramid/paster.py
@@ -1,14 +1,17 @@
import os
from paste.deploy import (
    loadapp,
    appconfig,
    )
from pyramid.scripting import prepare
from pyramid.scripts.common import setup_logging  # noqa, api
from pyramid.scripts.common import get_config_loader
def get_app(config_uri, name=None, options=None, loadapp=loadapp):
def setup_logging(config_uri, global_conf=None):
    """
    Set up Python logging with the filename specified via ``config_uri``
    (a string in the form ``filename#sectionname``).
    Extra defaults can optionally be specified as a dict in ``global_conf``.
    """
    loader = get_config_loader(config_uri)
    loader.setup_logging(global_conf)
def get_app(config_uri, name=None, options=None):
    """ Return the WSGI application named ``name`` in the PasteDeploy
    config file specified by ``config_uri``.
@@ -18,20 +21,13 @@
    If the ``name`` is None, this will attempt to parse the name from
    the ``config_uri`` string expecting the format ``inifile#name``.
    If no name is found, the name will default to "main"."""
    path, section = _getpathsec(config_uri, name)
    config_name = 'config:%s' % path
    here_dir = os.getcwd()
    If no name is found, the name will default to "main".
    app = loadapp(
        config_name,
        name=section,
        relative_to=here_dir,
        global_conf=options)
    """
    loader = get_config_loader(config_uri)
    return loader.get_wsgi_app(name, options)
    return app
def get_appsettings(config_uri, name=None, options=None, appconfig=appconfig):
def get_appsettings(config_uri, name=None, options=None):
    """ Return a dictionary representing the key/value pairs in an ``app``
    section within the file represented by ``config_uri``.
@@ -41,24 +37,11 @@
    If the ``name`` is None, this will attempt to parse the name from
    the ``config_uri`` string expecting the format ``inifile#name``.
    If no name is found, the name will default to "main"."""
    path, section = _getpathsec(config_uri, name)
    config_name = 'config:%s' % path
    here_dir = os.getcwd()
    return appconfig(
        config_name,
        name=section,
        relative_to=here_dir,
        global_conf=options)
    If no name is found, the name will default to "main".
def _getpathsec(config_uri, name):
    if '#' in config_uri:
        path, section = config_uri.split('#', 1)
    else:
        path, section = config_uri, 'main'
    if name:
        section = name
    return path, section
    """
    loader = get_config_loader(config_uri)
    return loader.get_wsgi_app_settings(name, options)
def bootstrap(config_uri, request=None, options=None):
    """ Load a WSGI application from the PasteDeploy config file specified
pyramid/scripts/common.py
@@ -1,6 +1,4 @@
import os
from pyramid.compat import configparser
from logging.config import fileConfig
import plaster
def parse_vars(args):
    """
@@ -17,26 +15,9 @@
        result[name] = value
    return result
def setup_logging(config_uri, global_conf=None,
                  fileConfig=fileConfig,
                  configparser=configparser):
def get_config_loader(config_uri):
    """
    Set up logging via :func:`logging.config.fileConfig` with the filename
    specified via ``config_uri`` (a string in the form
    ``filename#sectionname``).
    Find a ``plaster.ILoader`` object supporting the "wsgi" protocol.
    ConfigParser defaults are specified for the special ``__file__``
    and ``here`` variables, similar to PasteDeploy config loading.
    Extra defaults can optionally be specified as a dict in ``global_conf``.
    """
    path = config_uri.split('#', 1)[0]
    parser = configparser.ConfigParser()
    parser.read([path])
    if parser.has_section('loggers'):
        config_file = os.path.abspath(path)
        full_global_conf = dict(
            __file__=config_file,
            here=os.path.dirname(config_file))
        if global_conf:
            full_global_conf.update(global_conf)
        return fileConfig(config_file, full_global_conf)
    return plaster.get_loader(config_uri, protocols=['wsgi'])
pyramid/tests/test_paster.py
@@ -1,58 +1,32 @@
import os
import unittest
from pyramid.tests.test_scripts.dummy import DummyLoader
here = os.path.dirname(__file__)
class Test_get_app(unittest.TestCase):
    def _callFUT(self, config_file, section_name, **kw):
        from pyramid.paster import get_app
        return get_app(config_file, section_name, **kw)
    def _callFUT(self, config_file, section_name, options=None, _loader=None):
        import pyramid.paster
        old_loader = pyramid.paster.get_config_loader
        try:
            if _loader is not None:
                pyramid.paster.get_config_loader = _loader
            return pyramid.paster.get_app(config_file, section_name,
                                          options=options)
        finally:
            pyramid.paster.get_config_loader = old_loader
    def test_it(self):
        app = DummyApp()
        loadapp = DummyLoadWSGI(app)
        result = self._callFUT('/foo/bar/myapp.ini', 'myapp', loadapp=loadapp)
        self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini')
        self.assertEqual(loadapp.section_name, 'myapp')
        self.assertEqual(loadapp.relative_to, os.getcwd())
        self.assertEqual(result, app)
    def test_it_with_hash(self):
        app = DummyApp()
        loadapp = DummyLoadWSGI(app)
        loader = DummyLoader(app=app)
        result = self._callFUT(
            '/foo/bar/myapp.ini#myapp', None, loadapp=loadapp
            )
        self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini')
        self.assertEqual(loadapp.section_name, 'myapp')
        self.assertEqual(loadapp.relative_to, os.getcwd())
        self.assertEqual(result, app)
    def test_it_with_hash_and_name_override(self):
        app = DummyApp()
        loadapp = DummyLoadWSGI(app)
        result = self._callFUT(
            '/foo/bar/myapp.ini#myapp', 'yourapp', loadapp=loadapp
            )
        self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini')
        self.assertEqual(loadapp.section_name, 'yourapp')
        self.assertEqual(loadapp.relative_to, os.getcwd())
        self.assertEqual(result, app)
    def test_it_with_options(self):
        app = DummyApp()
        loadapp = DummyLoadWSGI(app)
        options = {'a':1}
        result = self._callFUT(
            '/foo/bar/myapp.ini#myapp',
            'yourapp',
            loadapp=loadapp,
            options=options,
            )
        self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini')
        self.assertEqual(loadapp.section_name, 'yourapp')
        self.assertEqual(loadapp.relative_to, os.getcwd())
        self.assertEqual(loadapp.kw, {'global_conf':options})
            '/foo/bar/myapp.ini', 'myapp', options={'a': 'b'},
            _loader=loader)
        self.assertEqual(loader.uri, '/foo/bar/myapp.ini')
        self.assertEqual(len(loader.calls), 1)
        self.assertEqual(loader.calls[0]['op'], 'app')
        self.assertEqual(loader.calls[0]['name'], 'myapp')
        self.assertEqual(loader.calls[0]['defaults'], {'a': 'b'})
        self.assertEqual(result, app)
    def test_it_with_dummyapp_requiring_options(self):
@@ -63,38 +37,28 @@
        self.assertEqual(app.settings['foo'], 'baz')
class Test_get_appsettings(unittest.TestCase):
    def _callFUT(self, config_file, section_name, **kw):
        from pyramid.paster import get_appsettings
        return get_appsettings(config_file, section_name, **kw)
    def _callFUT(self, config_file, section_name, options=None, _loader=None):
        import pyramid.paster
        old_loader = pyramid.paster.get_config_loader
        try:
            if _loader is not None:
                pyramid.paster.get_config_loader = _loader
            return pyramid.paster.get_appsettings(config_file, section_name,
                                                  options=options)
        finally:
            pyramid.paster.get_config_loader = old_loader
    def test_it(self):
        values = {'a':1}
        appconfig = DummyLoadWSGI(values)
        result = self._callFUT('/foo/bar/myapp.ini', 'myapp',
                               appconfig=appconfig)
        self.assertEqual(appconfig.config_name, 'config:/foo/bar/myapp.ini')
        self.assertEqual(appconfig.section_name, 'myapp')
        self.assertEqual(appconfig.relative_to, os.getcwd())
        self.assertEqual(result, values)
    def test_it_with_hash(self):
        values = {'a':1}
        appconfig = DummyLoadWSGI(values)
        result = self._callFUT('/foo/bar/myapp.ini#myapp', None,
                               appconfig=appconfig)
        self.assertEqual(appconfig.config_name, 'config:/foo/bar/myapp.ini')
        self.assertEqual(appconfig.section_name, 'myapp')
        self.assertEqual(appconfig.relative_to, os.getcwd())
        self.assertEqual(result, values)
    def test_it_with_hash_and_name_override(self):
        values = {'a':1}
        appconfig = DummyLoadWSGI(values)
        result = self._callFUT('/foo/bar/myapp.ini#myapp', 'yourapp',
                               appconfig=appconfig)
        self.assertEqual(appconfig.config_name, 'config:/foo/bar/myapp.ini')
        self.assertEqual(appconfig.section_name, 'yourapp')
        self.assertEqual(appconfig.relative_to, os.getcwd())
        values = {'a': 1}
        loader = DummyLoader(app_settings=values)
        result = self._callFUT(
            '/foo/bar/myapp.ini', 'myapp', options={'a': 'b'},
            _loader=loader)
        self.assertEqual(loader.uri, '/foo/bar/myapp.ini')
        self.assertEqual(len(loader.calls), 1)
        self.assertEqual(loader.calls[0]['op'], 'app_settings')
        self.assertEqual(loader.calls[0]['name'], 'myapp')
        self.assertEqual(loader.calls[0]['defaults'], {'a': 'b'})
        self.assertEqual(result, values)
    def test_it_with_dummyapp_requiring_options(self):
@@ -105,40 +69,39 @@
        self.assertEqual(result['foo'], 'baz')
class Test_setup_logging(unittest.TestCase):
    def _callFUT(self, config_file, global_conf=None):
        from pyramid.paster import setup_logging
        dummy_cp = DummyConfigParserModule
        return setup_logging(
            config_uri=config_file,
            global_conf=global_conf,
            fileConfig=self.fileConfig,
            configparser=dummy_cp,
            )
    def _callFUT(self, config_file, global_conf=None, _loader=None):
        import pyramid.paster
        old_loader = pyramid.paster.get_config_loader
        try:
            if _loader is not None:
                pyramid.paster.get_config_loader = _loader
            return pyramid.paster.setup_logging(config_file, global_conf)
        finally:
            pyramid.paster.get_config_loader = old_loader
    def test_it_no_global_conf(self):
        config_file, dict = self._callFUT('/abc')
        # os.path.abspath is a sop to Windows
        self.assertEqual(config_file, os.path.abspath('/abc'))
        self.assertEqual(dict['__file__'], os.path.abspath('/abc'))
        self.assertEqual(dict['here'], os.path.abspath('/'))
        loader = DummyLoader()
        self._callFUT('/abc', _loader=loader)
        self.assertEqual(loader.uri, '/abc')
        self.assertEqual(len(loader.calls), 1)
        self.assertEqual(loader.calls[0]['op'], 'logging')
        self.assertEqual(loader.calls[0]['defaults'], None)
    def test_it_global_conf_empty(self):
        config_file, dict = self._callFUT('/abc', global_conf={})
        # os.path.abspath is a sop to Windows
        self.assertEqual(config_file, os.path.abspath('/abc'))
        self.assertEqual(dict['__file__'], os.path.abspath('/abc'))
        self.assertEqual(dict['here'], os.path.abspath('/'))
        loader = DummyLoader()
        self._callFUT('/abc', global_conf={}, _loader=loader)
        self.assertEqual(loader.uri, '/abc')
        self.assertEqual(len(loader.calls), 1)
        self.assertEqual(loader.calls[0]['op'], 'logging')
        self.assertEqual(loader.calls[0]['defaults'], {})
    def test_it_global_conf_not_empty(self):
        config_file, dict = self._callFUT('/abc', global_conf={'key': 'val'})
        # os.path.abspath is a sop to Windows
        self.assertEqual(config_file, os.path.abspath('/abc'))
        self.assertEqual(dict['__file__'], os.path.abspath('/abc'))
        self.assertEqual(dict['here'], os.path.abspath('/'))
        self.assertEqual(dict['key'], 'val')
    def fileConfig(self, config_file, dict):
        return config_file, dict
        loader = DummyLoader()
        self._callFUT('/abc', global_conf={'key': 'val'}, _loader=loader)
        self.assertEqual(loader.uri, '/abc')
        self.assertEqual(len(loader.calls), 1)
        self.assertEqual(loader.calls[0]['op'], 'logging')
        self.assertEqual(loader.calls[0]['defaults'], {'key': 'val'})
class Test_bootstrap(unittest.TestCase):
    def _callFUT(self, config_uri, request=None):
@@ -186,17 +149,6 @@
    settings = {}
dummy_registry = DummyRegistry()
class DummyLoadWSGI:
    def __init__(self, result):
        self.result = result
    def __call__(self, config_name, name=None, relative_to=None, **kw):
        self.config_name = config_name
        self.section_name = name
        self.relative_to = relative_to
        self.kw = kw
        return self.result
class DummyApp:
    def __init__(self):
pyramid/tests/test_scripts/dummy.py
@@ -162,3 +162,44 @@
    def iter_entry_points(self, name):
        return self.entry_points
class dummy_setup_logging(object):
    def __call__(self, config_uri, global_conf):
        self.config_uri = config_uri
        self.global_conf = global_conf
class DummyLoader(object):
    def __init__(self, settings=None, app_settings=None, app=None):
        if not settings:
            settings = {}
        if not app_settings:
            app_settings = {}
        self.settings = settings
        self.app_settings = app_settings
        self.app = app
        self.calls = []
    def __call__(self, uri):
        self.uri = uri
        return self
    def add_call(self, op, name, defaults):
        self.calls.append({'op': op, 'name': name, 'defaults': defaults})
    def get_settings(self, name=None, defaults=None):
        self.add_call('settings', name, defaults)
        return self.result
    def get_wsgi_app(self, name=None, defaults=None):
        self.add_call('app', name, defaults)
        return self.app
    def get_wsgi_app_settings(self, name=None, defaults=None):
        self.add_call('app_settings', name, defaults)
        return self.app_settings
    def setup_logging(self, defaults):
        self.add_call('logging', None, defaults)
        self.defaults = defaults
setup.py
@@ -34,10 +34,12 @@
    'venusian >= 1.0a3', # ``ignore``
    'translationstring >= 0.4', # py3 compat
    'PasteDeploy >= 1.5.0', # py3 compat
    'plaster',
    'hupper',
    ]
tests_require = [
    'plaster_pastedeploy',
    'WebTest >= 1.3.1', # py3 compat
    'zope.component >= 4.0', # py3 compat
    ]