diff options
author | Alex Gr?nholm <alex.gronholm@nextday.fi> | 2011-05-22 05:03:21 +0300 |
---|---|---|
committer | Alex Gr?nholm <alex.gronholm@nextday.fi> | 2011-05-22 05:03:21 +0300 |
commit | 1df1c78299e06fecde664d4ddb5ec549097daf88 (patch) | |
tree | 39202cc5b606804ae6c5d012cb7b97acfa55eb0c | |
parent | af0125821babc057b451f659b816216569ce8f26 (diff) | |
download | pastedeploy-1df1c78299e06fecde664d4ddb5ec549097daf88.tar.gz |
Refactored the code to be compatible with Python 3.1 and above
-rw-r--r-- | paste/deploy/compat.py | 30 | ||||
-rw-r--r-- | paste/deploy/converters.py | 11 | ||||
-rw-r--r-- | paste/deploy/loadwsgi.py | 73 | ||||
-rw-r--r-- | paste/deploy/paster_templates.py | 10 | ||||
-rw-r--r-- | paste/deploy/util.py | 4 | ||||
-rw-r--r-- | tests/__init__.py | 1 | ||||
-rw-r--r-- | tests/fixture.py | 3 | ||||
-rw-r--r-- | tests/sample_configs/test_config.ini | 2 | ||||
-rw-r--r-- | tests/sample_configs/test_error.ini | 8 | ||||
-rw-r--r-- | tests/test_basic_app.py | 12 | ||||
-rw-r--r-- | tests/test_config.py | 117 | ||||
-rw-r--r-- | tests/test_config_middleware.py | 16 | ||||
-rw-r--r-- | tests/test_filter.py | 11 | ||||
-rw-r--r-- | tests/test_load_package.py | 14 |
14 files changed, 211 insertions, 101 deletions
diff --git a/paste/deploy/compat.py b/paste/deploy/compat.py new file mode 100644 index 0000000..f7b93f5 --- /dev/null +++ b/paste/deploy/compat.py @@ -0,0 +1,30 @@ +# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org) +# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php +"""Python 2<->3 compatibility module""" +import sys + + +def print_(template, *args, **kwargs): + template = str(template) + if args: + template = template % args + elif kwargs: + template = template % kwargs + sys.stdout.writelines(template) + +if sys.version_info < (3, 0): + basestring = basestring + from ConfigParser import ConfigParser + from urllib import unquote + iteritems = lambda d: d.iteritems() + + def reraise(t, e, tb): + exec('raise t, e, tb', dict(t=t, e=e, tb=tb)) +else: + basestring = str + from configparser import ConfigParser + from urllib.parse import unquote + iteritems = lambda d: d.items() + + def reraise(t, e, tb): + exec('raise e from tb', dict(e=e, tb=tb)) diff --git a/paste/deploy/converters.py b/paste/deploy/converters.py index f852e6c..f37d267 100644 --- a/paste/deploy/converters.py +++ b/paste/deploy/converters.py @@ -1,17 +1,17 @@ # (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org) # Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php +from paste.deploy.compat import basestring def asbool(obj): - if isinstance(obj, (str, unicode)): + if isinstance(obj, basestring): obj = obj.strip().lower() if obj in ['true', 'yes', 'on', 'y', 't', '1']: return True elif obj in ['false', 'no', 'off', 'n', 'f', '0']: return False else: - raise ValueError( - "String is not true/false: %r" % obj) + raise ValueError("String is not true/false: %r" % obj) return bool(obj) @@ -19,12 +19,11 @@ def asint(obj): try: return int(obj) except (TypeError, ValueError): - raise ValueError( - "Bad integer value: %r" % obj) + raise ValueError("Bad integer value: %r" % obj) def aslist(obj, sep=None, strip=True): - if isinstance(obj, (str, unicode)): + if isinstance(obj, basestring): lst = obj.split(sep) if strip: lst = [v.strip() for v in lst] diff --git a/paste/deploy/loadwsgi.py b/paste/deploy/loadwsgi.py index a4a8b4b..2da8213 100644 --- a/paste/deploy/loadwsgi.py +++ b/paste/deploy/loadwsgi.py @@ -1,12 +1,13 @@ # (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org) # Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php -from ConfigParser import ConfigParser +from __future__ import with_statement import os +import sys import re -import urllib import pkg_resources +from paste.deploy.compat import ConfigParser, unquote, iteritems from paste.deploy.util import fix_call __all__ = ['loadapp', 'loadserver', 'loadfilter', 'appconfig'] @@ -51,6 +52,10 @@ class NicerConfigParser(ConfigParser): def __init__(self, filename, *args, **kw): ConfigParser.__init__(self, *args, **kw) self.filename = filename + if hasattr(self, '_interpolation'): + self._interpolation = self.InterpolateWrapper(self._interpolation) + + read_file = getattr(ConfigParser, 'read_file', ConfigParser.readfp) def defaults(self): """Return the defaults, with their values interpolated (with the @@ -59,21 +64,45 @@ class NicerConfigParser(ConfigParser): Mainly to support defaults using values such as %(here)s """ defaults = ConfigParser.defaults(self).copy() - for key, val in defaults.iteritems(): - defaults[key] = self._interpolate('DEFAULT', key, val, defaults) + for key, val in iteritems(defaults): + defaults[key] = self.get('DEFAULT', key) or val return defaults def _interpolate(self, section, option, rawval, vars): + # Python < 3.2 try: return ConfigParser._interpolate( self, section, option, rawval, vars) - except Exception, e: + except Exception: + e = sys.exc_info()[1] args = list(e.args) args[0] = 'Error in file %s, [%s] %s=%r: %s' % ( self.filename, section, option, rawval, e) e.args = tuple(args) + e.message = args[0] raise + class InterpolateWrapper(object): + # Python >= 3.2 + def __init__(self, original): + self._original = original + + def __getattr__(self, name): + return getattr(self._original, name) + + def before_get(self, parser, section, option, value, defaults): + try: + return self._original.before_get(parser, section, option, + value, defaults) + except Exception: + e = sys.exc_info()[1] + args = list(e.args) + args[0] = 'Error in file %s, [%s] %s=%r: %s' % ( + parser.filename, section, option, value, e) + e.args = tuple(args) + e.message = args[0] + raise + ############################################################ ## Object types @@ -88,8 +117,8 @@ class _ObjectType(object): def __init__(self): # Normalize these variables: - self.egg_protocols = map(_aslist, _aslist(self.egg_protocols)) - self.config_prefixes = map(_aslist, _aslist(self.config_prefixes)) + self.egg_protocols = [_aslist(p) for p in _aslist(self.egg_protocols)] + self.config_prefixes = [_aslist(p) for p in _aslist(self.config_prefixes)] def __repr__(self): return '<%s protocols=%r prefixes=%r>' % ( @@ -286,7 +315,7 @@ def _loadconfig(object_type, uri, path, name, relative_to, path = relative_to + '/' + path if path.startswith('///'): path = path[2:] - path = urllib.unquote(path) + path = unquote(path) loader = ConfigLoader(path) if global_conf: loader.update_defaults(global_conf, overwrite=False) @@ -349,27 +378,17 @@ class ConfigLoader(_Loader): def __init__(self, filename): self.filename = filename = filename.strip() - self.parser = NicerConfigParser(self.filename) - # Don't lower-case keys: - self.parser.optionxform = str - # Stupid ConfigParser ignores files that aren't found, so - # we have to add an extra check: - if not os.path.exists(filename): - if filename.strip() != filename: - raise IOError( - "File %r not found; trailing whitespace: " - "did you try to use a # on the same line as a filename? " - "(comments must be on their own line)" % filename) - raise IOError( - "File %r not found" % filename) - self.parser.read(filename) - self.parser._defaults.setdefault( - 'here', os.path.dirname(os.path.abspath(filename))) - self.parser._defaults.setdefault( - '__file__', os.path.abspath(filename)) + defaults = { + 'here': os.path.dirname(os.path.abspath(filename)), + '__file__': os.path.abspath(filename) + } + self.parser = NicerConfigParser(filename, defaults=defaults) + self.parser.optionxform = str # Don't lower-case keys + with open(filename) as f: + self.parser.read_file(f) def update_defaults(self, new_defaults, overwrite=True): - for key, value in new_defaults.items(): + for key, value in iteritems(new_defaults): if not overwrite and key in self.parser._defaults: continue self.parser._defaults[key] = value diff --git a/paste/deploy/paster_templates.py b/paste/deploy/paster_templates.py index 25be21b..9c5f942 100644 --- a/paste/deploy/paster_templates.py +++ b/paste/deploy/paster_templates.py @@ -4,6 +4,8 @@ import os from paste.script.templates import Template +from paste.deploy.compat import print_ + class PasteDeploy(Template): @@ -28,7 +30,7 @@ class PasteDeploy(Template): ' main = %(package)s.wsgiapp:make_app\n') % vars, indent=False) if command.verbose: - print '*' * 72 - print '* Run "paster serve docs/devel_config.ini" to run the sample application' - print '* on http://localhost:8080' - print '*' * 72 + print_('*' * 72) + print_('* Run "paster serve docs/devel_config.ini" to run the sample application') + print_('* on http://localhost:8080') + print_('*' * 72) diff --git a/paste/deploy/util.py b/paste/deploy/util.py index 41f8dbd..c5056b2 100644 --- a/paste/deploy/util.py +++ b/paste/deploy/util.py @@ -3,6 +3,8 @@ import inspect import sys +from paste.deploy.compat import reraise + def fix_type_error(exc_info, callable, varargs, kwargs): """ @@ -54,5 +56,5 @@ def fix_call(callable, *args, **kw): val = callable(*args, **kw) except TypeError: exc_info = fix_type_error(None, callable, args, kw) - raise exc_info[0], exc_info[1], exc_info[2] + reraise(*exc_info) return val diff --git a/tests/__init__.py b/tests/__init__.py index 0ba8f8a..cffe526 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -11,4 +11,3 @@ import pkg_resources # Make absolutely sure we're testing *this* package, not # some other installed package pkg_resources.require('PasteDeploy') - diff --git a/tests/fixture.py b/tests/fixture.py index 6c3e99f..751659d 100644 --- a/tests/fixture.py +++ b/tests/fixture.py @@ -12,10 +12,9 @@ if not os.path.exists(egg_info_dir): os.symlink(info_dir, egg_info_dir) except: shutil.copytree(info_dir, egg_info_dir) - + sys.path.append(os.path.dirname(egg_info_dir)) from pkg_resources import * working_set.add_entry(os.path.dirname(egg_info_dir)) require('FakeApp') - diff --git a/tests/sample_configs/test_config.ini b/tests/sample_configs/test_config.ini index 69bae5a..d614829 100644 --- a/tests/sample_configs/test_config.ini +++ b/tests/sample_configs/test_config.ini @@ -1,11 +1,13 @@ [DEFAULT] def1 = a def2 = b +basepath = %(here)s [app:test1] use = egg:FakeApp#configed setting1 = foo setting2 = bar +apppath = %(basepath)s/app [app:test2] use = egg:FakeApp#configed diff --git a/tests/sample_configs/test_error.ini b/tests/sample_configs/test_error.ini new file mode 100644 index 0000000..b6ad5b2 --- /dev/null +++ b/tests/sample_configs/test_error.ini @@ -0,0 +1,8 @@ +[DEFAULT] +def1 = a +def2 = b + +[app:main] +use = egg:FakeApp#configed +setting1 = foo +setting2 = %(does_not_exist)s/bar diff --git a/tests/test_basic_app.py b/tests/test_basic_app.py index 11d1f40..1ddb52b 100644 --- a/tests/test_basic_app.py +++ b/tests/test_basic_app.py @@ -1,9 +1,12 @@ -from paste.deploy import loadapp, loadfilter, appconfig -from fixture import * +from paste.deploy import loadapp + +from tests.fixture import * import fakeapp.apps + here = os.path.dirname(__file__) + def test_main(): app = loadapp('config:sample_configs/basic_app.ini', relative_to=here) @@ -18,11 +21,12 @@ def test_main(): relative_to=here, name='main') assert app is fakeapp.apps.basic_app + def test_other(): app = loadapp('config:sample_configs/basic_app.ini#other', relative_to=here) assert app is fakeapp.apps.basic_app2 - + def test_composit(): app = loadapp('config:sample_configs/basic_app.ini#remote_addr', @@ -30,5 +34,3 @@ def test_composit(): assert isinstance(app, fakeapp.apps.RemoteAddrDispatch) assert app.map['127.0.0.1'] is fakeapp.apps.basic_app assert app.map['0.0.0.0'] is fakeapp.apps.basic_app2 - - diff --git a/tests/test_config.py b/tests/test_config.py index 26ba482..b6cd158 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,116 +1,145 @@ -import os -from paste.deploy import loadapp, loadfilter, appconfig -from fixture import * +from nose.tools import eq_ + +from paste.deploy import loadapp, appconfig +from tests.fixture import * import fakeapp.configapps as fc -from pprint import pprint + ini_file = 'config:sample_configs/test_config.ini' here = os.path.dirname(__file__) config_path = os.path.join(here, 'sample_configs') config_filename = os.path.join(config_path, 'test_config.ini') + def test_config_egg(): app = loadapp('egg:FakeApp#configed') assert isinstance(app, fc.SimpleApp) - + + def test_config1(): app = loadapp(ini_file, relative_to=here, name='test1') - assert app.local_conf == { - 'setting1': 'foo', 'setting2': 'bar'} - assert app.global_conf == { - 'def1': 'a', 'def2': 'b', + eq_(app.local_conf, { + 'setting1': 'foo', + 'setting2': 'bar', + 'apppath': os.path.join(config_path, 'app')}) + eq_(app.global_conf, { + 'def1': 'a', + 'def2': 'b', + 'basepath': config_path, 'here': config_path, - '__file__': config_filename} + '__file__': config_filename}) + def test_config2(): app = loadapp(ini_file, relative_to=here, name='test2') - assert app.local_conf == { - 'local conf': 'something'} - assert app.global_conf == { + eq_(app.local_conf, { + 'local conf': 'something'}) + eq_(app.global_conf, { 'def1': 'test2', 'def2': 'b', + 'basepath': config_path, 'another': 'TEST', 'here': config_path, - '__file__': config_filename} + '__file__': config_filename}) # Run this to make sure the global-conf-modified test2 # didn't mess up the general global conf test_config1() + def test_config3(): app = loadapp(ini_file, relative_to=here, name='test3') assert isinstance(app, fc.SimpleApp) - assert app.local_conf == { + eq_(app.local_conf, { 'local conf': 'something', - 'another': 'something more\nacross several\nlines'} - assert app.global_conf == { + 'another': 'something more\nacross several\nlines'}) + eq_(app.global_conf, { 'def1': 'test3', 'def2': 'b', + 'basepath': config_path, 'another': 'TEST', 'here': config_path, - '__file__': config_filename} + '__file__': config_filename}) test_config2() - + + def test_foreign_config(): app = loadapp(ini_file, relative_to=here, name='test_foreign_config') assert isinstance(app, fc.SimpleApp) - assert app.local_conf == { + eq_(app.local_conf, { 'another': 'FOO', - 'bob': 'your uncle'} - pprint(app.global_conf) - assert app.global_conf == { + 'bob': 'your uncle'}) + eq_(app.global_conf, { 'def1': 'a', 'def2': 'from include', 'def3': 'c', + 'basepath': config_path, 'glob': 'override', 'here': config_path, - '__file__': os.path.join(config_path, 'test_config.ini')} - + '__file__': os.path.join(config_path, 'test_config.ini')}) + + def test_config_get(): app = loadapp(ini_file, relative_to=here, name='test_get') assert isinstance(app, fc.SimpleApp) - assert app.local_conf == { + eq_(app.local_conf, { 'def1': 'a', - 'foo': 'TEST'} - assert app.global_conf == { + 'foo': 'TEST'}) + eq_(app.global_conf, { 'def1': 'a', 'def2': 'TEST', + 'basepath': os.path.join(here, 'sample_configs'), 'here': config_path, - '__file__': config_filename} + '__file__': config_filename}) + def test_appconfig(): conf = appconfig(ini_file, relative_to=here, name='test_get') - assert conf == { + eq_(conf, { 'def1': 'a', 'def2': 'TEST', + 'basepath': os.path.join(here, 'sample_configs'), 'here': config_path, '__file__': config_filename, - 'foo': 'TEST'} - assert conf.local_conf == { + 'foo': 'TEST'}) + eq_(conf.local_conf, { 'def1': 'a', - 'foo': 'TEST'} - assert conf.global_conf == { + 'foo': 'TEST'}) + eq_(conf.global_conf, { 'def1': 'a', 'def2': 'TEST', + 'basepath': os.path.join(here, 'sample_configs'), 'here': config_path, - '__file__': config_filename,} + '__file__': config_filename}) + def test_appconfig_filter_with(): conf = appconfig('config:test_filter_with.ini', relative_to=config_path) - assert conf['example'] == 'test' + eq_(conf['example'], 'test') + def test_global_conf(): - conf = appconfig(ini_file, relative_to=here, name='test_global_conf', global_conf={'def2': 'TEST DEF 2', 'inherit': 'bazbar'}) - pprint(conf) - assert conf == { + conf = appconfig(ini_file, relative_to=here, name='test_global_conf', + global_conf={'def2': 'TEST DEF 2', 'inherit': 'bazbar'}) + eq_(conf, { 'def1': 'a', # Note that this gets overwritten: 'def2': 'b', + 'basepath': os.path.join(here, 'sample_configs'), 'here': config_path, 'inherit': 'bazbar', '__file__': config_filename, 'test_interp': 'this:bazbar', - } - assert conf.local_conf == { - 'test_interp': 'this:bazbar', - } - + }) + eq_(conf.local_conf, { + 'test_interp': 'this:bazbar'}) + + +def test_interpolate_exception(): + try: + appconfig('config:test_error.ini', relative_to=config_path) + except Exception: + e = sys.exc_info()[1] + expected = "Error in file %s" % os.path.join(config_path, 'test_error.ini') + eq_(str(e).split(',')[0], expected) + else: + assert False, 'Should have raised an exception' diff --git a/tests/test_config_middleware.py b/tests/test_config_middleware.py index 868e75f..cc315e3 100644 --- a/tests/test_config_middleware.py +++ b/tests/test_config_middleware.py @@ -1,8 +1,12 @@ from nose.tools import assert_raises +from nose.plugins.skip import SkipTest + from paste.deploy.config import ConfigMiddleware -from paste.fixture import TestApp -class Bug(Exception): pass + +class Bug(Exception): + pass + def app_with_exception(environ, start_response): def cont(): @@ -11,8 +15,14 @@ def app_with_exception(environ, start_response): start_response('200 OK', [('Content-type', 'text/html')]) return cont() + def test_error(): + # This import is conditional due to Paste not yet working on py3k + try: + from paste.fixture import TestApp + except ImportError: + raise SkipTest + wrapped = ConfigMiddleware(app_with_exception, {'test': 1}) test_app = TestApp(wrapped) assert_raises(Bug, test_app.get, '/') - diff --git a/tests/test_filter.py b/tests/test_filter.py index 77ee2ee..a76af7c 100644 --- a/tests/test_filter.py +++ b/tests/test_filter.py @@ -1,9 +1,11 @@ -from paste.deploy import loadapp, loadfilter -from fixture import * +from paste.deploy import loadapp +from tests.fixture import * import fakeapp.apps + here = os.path.dirname(__file__) + def test_filter_app(): app = loadapp('config:sample_configs/test_filter.ini#filt', relative_to=here) @@ -11,6 +13,7 @@ def test_filter_app(): assert app.app is fakeapp.apps.basic_app assert app.method_to_call == 'lower' + def test_pipeline(): app = loadapp('config:sample_configs/test_filter.ini#piped', relative_to=here) @@ -18,6 +21,7 @@ def test_pipeline(): assert app.app is fakeapp.apps.basic_app assert app.method_to_call == 'upper' + def test_filter_app2(): app = loadapp('config:sample_configs/test_filter.ini#filt2', relative_to=here) @@ -25,6 +29,7 @@ def test_filter_app2(): assert app.app is fakeapp.apps.basic_app assert app.method_to_call == 'lower' + def test_pipeline2(): app = loadapp('config:sample_configs/test_filter.ini#piped2', relative_to=here) @@ -32,12 +37,14 @@ def test_pipeline2(): assert app.app is fakeapp.apps.basic_app assert app.method_to_call == 'upper' + def test_filter_app_inverted(): app = loadapp('config:sample_configs/test_filter.ini#inv', relative_to=here) assert isinstance(app, fakeapp.apps.CapFilter) assert app.app is fakeapp.apps.basic_app + def test_filter_with_filter_with(): app = loadapp('config:sample_configs/test_filter_with.ini', relative_to=here) diff --git a/tests/test_load_package.py b/tests/test_load_package.py index a66b7d0..b3fea55 100644 --- a/tests/test_load_package.py +++ b/tests/test_load_package.py @@ -1,10 +1,12 @@ -import sys, os -import pkg_resources -import site from pprint import pprint +import sys + +import pkg_resources + +from paste.deploy.compat import print_ + def test_load_package(): - print 'Path:' + print_('Path:') pprint(sys.path) - print pkg_resources.require('FakeApp') - + print_(pkg_resources.require('FakeApp')) |