summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Gr?nholm <alex.gronholm@nextday.fi>2011-05-22 05:03:21 +0300
committerAlex Gr?nholm <alex.gronholm@nextday.fi>2011-05-22 05:03:21 +0300
commit1df1c78299e06fecde664d4ddb5ec549097daf88 (patch)
tree39202cc5b606804ae6c5d012cb7b97acfa55eb0c
parentaf0125821babc057b451f659b816216569ce8f26 (diff)
downloadpastedeploy-1df1c78299e06fecde664d4ddb5ec549097daf88.tar.gz
Refactored the code to be compatible with Python 3.1 and above
-rw-r--r--paste/deploy/compat.py30
-rw-r--r--paste/deploy/converters.py11
-rw-r--r--paste/deploy/loadwsgi.py73
-rw-r--r--paste/deploy/paster_templates.py10
-rw-r--r--paste/deploy/util.py4
-rw-r--r--tests/__init__.py1
-rw-r--r--tests/fixture.py3
-rw-r--r--tests/sample_configs/test_config.ini2
-rw-r--r--tests/sample_configs/test_error.ini8
-rw-r--r--tests/test_basic_app.py12
-rw-r--r--tests/test_config.py117
-rw-r--r--tests/test_config_middleware.py16
-rw-r--r--tests/test_filter.py11
-rw-r--r--tests/test_load_package.py14
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'))