summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt3
-rw-r--r--HACKING.txt42
-rw-r--r--TODO.txt3
m---------docs/_themes0
-rw-r--r--hacking-tox.ini25
-rw-r--r--pyramid/i18n.py17
-rw-r--r--pyramid/request.py8
-rw-r--r--pyramid/scaffolds/copydir.py8
-rw-r--r--pyramid/tests/test_config/test_init.py11
-rw-r--r--pyramid/tests/test_i18n.py54
-rw-r--r--pyramid/tests/test_integration.py10
-rw-r--r--pyramid/tests/test_scaffolds/test_copydir.py47
-rw-r--r--pyramid/tests/test_scripts/test_pdistreport.py1
-rw-r--r--pyramid/tests/test_url.py2
-rw-r--r--setup.py1
15 files changed, 169 insertions, 63 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 48efad6d4..b805a12a0 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -4,6 +4,9 @@ Next Release
Features
--------
+- Add ``localizer`` property (reified) to the request.
+ See https://github.com/Pylons/pyramid/issues/508.
+
- Add ``pdistreport`` script, which prints the Python version in use, the
Pyramid version in use, and the version number and location of all Python
distributions currently installed.
diff --git a/HACKING.txt b/HACKING.txt
index 5b5dcc458..abfed6dab 100644
--- a/HACKING.txt
+++ b/HACKING.txt
@@ -16,13 +16,32 @@ checkout.
- Check out a read-only copy of the Pyramid source::
- $ git clone git://github.com/Pylons/pyramid.git
+ $ git clone git://github.com/Pylons/pyramid.git .
(alternately, create a writeable fork on GitHub and check that out).
+Since pyramid is a framework and not an application, it can be
+convenient to work against a sample application, preferably in its
+own virtualenv. A quick way to achieve this is to (ab-)use ``tox``
+(http://codespeak.net/~hpk/tox/) with a custom configuration file that's part of
+the checkout::
+
+ tox -c hacking-tox.ini
+
+This will create a python-2.7 based virtualenv named ``env27`` (pyramid's
+``.gitconfig` ignores all top-level folders that start with ``env`` specifically
+for this use case) and inside that a simple pyramid application named
+``hacking`` that you can then fire up like so::
+
+ cd env27/hacking
+ ../bin/pserve development.ini
+
+Alternatively, if you don't want to install ``tox`` at this point,
+you an achieve the same manually by following these steps:
+
- Create a virtualenv in which to install Pyramid::
- $ virtualenv2.6 --no-site-packages env
+ $ virtualenv env
- Install ``setuptools-git`` into the virtualenv (for good measure, as we're
using git to do version control)::
@@ -93,9 +112,13 @@ Coding Style
Running Tests
--------------
-- To run tests for Pyramid on a single Python version, run ``python setup.py
- test`` against the Python interpreter from virtualenv into which
- you've ``setup.py develop``-ed Pyramid.
+- To run all tests for Pyramid on a single Python version, run ``nosetests`` from
+ your development virtualenv (See *Using a Development Checkout* above).
+
+- To run individual tests (i.e. during development) you can use a regular
+ expression with the ``-t`` parameter courtesy of the `nose-selecttests
+ <https://pypi.python.org/pypi/nose-selecttests/>`_ plugin that's been installed (along with nose itself) via ``python setup.py dev``. The easiest usage is to
+ simply provide the verbatim name of the test you're working on.
- To run the full set of Pyramid tests on all platforms, install ``tox``
(http://codespeak.net/~hpk/tox/) into a system Python. The ``tox`` console
@@ -107,9 +130,16 @@ Running Tests
example::
$ /usr/bin/easy_install tox
- $ cd ~/hack-on-pyramid/pyramid
+ $ cd ~/hack-on-pyramid/
$ /usr/bin/tox
+- The tests can also be run usign ``pytest`` (http://pytest.org/). This is
+ intended as a convenience for people who are more used or fond of ``pytest``.
+ Run the tests like so::
+
+ $ $VENV/bin/easy_install pytest
+ $ py.test --strict pyramid/
+
Test Coverage
-------------
diff --git a/TODO.txt b/TODO.txt
index 7a3561494..46eb33b82 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -56,9 +56,6 @@ Nice-to-Have
app1" and "domain app1.localhost = app1"), ProxyPreserveHost and the nginx
equivalent, preserving HTTPS URLs.
-- Make "localizer" a property of request (instead of requiring
- "get_localizer(request)"?
-
- Alias the stupid long default session factory name.
- Debug option to print view matching decision (e.g. debug_viewlookup or so).
diff --git a/docs/_themes b/docs/_themes
-Subproject 8673c4a14f192c15f1949dc9862821e60f31604
+Subproject a181b85d4ca08fa109ee2786d4f1b5b17e9b458
diff --git a/hacking-tox.ini b/hacking-tox.ini
new file mode 100644
index 000000000..9520b7aef
--- /dev/null
+++ b/hacking-tox.ini
@@ -0,0 +1,25 @@
+[tox]
+envlist =
+ env27,ttw27-create,ttw27-install
+
+[testenv:env27]
+envdir = env27
+basepython = python2.7
+usedevelop = True
+deps = setuptools-git
+commands =
+ python setup.py dev
+
+[testenv:ttw27-create]
+envdir = env27
+usedevelop = True
+changedir = env27
+commands =
+ pcreate -s starter hacking
+
+[testenv:ttw27-install]
+envdir = env27
+usedevelop = True
+changedir = env27/hacking
+commands =
+ python setup.py develop
diff --git a/pyramid/i18n.py b/pyramid/i18n.py
index b4bc0eaa7..dc2c25f18 100644
--- a/pyramid/i18n.py
+++ b/pyramid/i18n.py
@@ -197,17 +197,15 @@ def make_localizer(current_locale_name, translation_directories):
def get_localizer(request):
""" Retrieve a :class:`pyramid.i18n.Localizer` object
corresponding to the current request's locale name. """
- localizer = getattr(request, 'localizer', None)
- if localizer is None:
- # no locale object cached on request
- try:
- registry = request.registry
- except AttributeError:
- registry = get_current_registry()
+ # no locale object cached on request
+ try:
+ registry = request.registry
+ except AttributeError:
+ registry = get_current_registry()
- current_locale_name = get_locale_name(request)
- localizer = registry.queryUtility(ILocalizer, name=current_locale_name)
+ current_locale_name = get_locale_name(request)
+ localizer = registry.queryUtility(ILocalizer, name=current_locale_name)
if localizer is None:
# no localizer utility registered yet
@@ -216,7 +214,6 @@ def get_localizer(request):
registry.registerUtility(localizer, ILocalizer,
name=current_locale_name)
- request.localizer = localizer
return localizer
diff --git a/pyramid/request.py b/pyramid/request.py
index 5bca5b1f0..5dedee4f1 100644
--- a/pyramid/request.py
+++ b/pyramid/request.py
@@ -24,6 +24,7 @@ from pyramid.compat import (
)
from pyramid.decorator import reify
+from pyramid.i18n import get_localizer
from pyramid.response import Response
from pyramid.url import URLMethodsMixin
from pyramid.util import InstancePropertyMixin
@@ -383,6 +384,13 @@ class Request(BaseRequest, DeprecatedRequestMethodsMixin, URLMethodsMixin,
def json_body(self):
return json.loads(text_(self.body, self.charset))
+ @reify
+ def localizer(self):
+ """ Convenience property to return a localizer by calling
+ :func:`pyramid.i18n.get_localizer`. """
+ return get_localizer(self)
+
+
def route_request_iface(name, bases=()):
# zope.interface treats the __name__ as the __doc__ and changes __name__
# to None for interfaces that contain spaces if you do not pass a
diff --git a/pyramid/scaffolds/copydir.py b/pyramid/scaffolds/copydir.py
index ba0988523..7864dd1a1 100644
--- a/pyramid/scaffolds/copydir.py
+++ b/pyramid/scaffolds/copydir.py
@@ -90,16 +90,16 @@ def copy_dir(source, dest, vars, verbosity, simulate, indent=0,
if verbosity:
out('%sRecursing into %s' % (pad, os.path.basename(full)))
copy_dir((source[0], full), dest_full, vars, verbosity, simulate,
- indent=indent+1,
- sub_vars=sub_vars, interactive=interactive,
+ indent=indent+1, sub_vars=sub_vars,
+ interactive=interactive, overwrite=overwrite,
template_renderer=template_renderer, out_=out_)
continue
elif not use_pkg_resources and os.path.isdir(full):
if verbosity:
out('%sRecursing into %s' % (pad, os.path.basename(full)))
copy_dir(full, dest_full, vars, verbosity, simulate,
- indent=indent+1,
- sub_vars=sub_vars, interactive=interactive,
+ indent=indent+1, sub_vars=sub_vars,
+ interactive=interactive, overwrite=overwrite,
template_renderer=template_renderer, out_=out_)
continue
elif use_pkg_resources:
diff --git a/pyramid/tests/test_config/test_init.py b/pyramid/tests/test_config/test_init.py
index 7c2880a18..b8cbbd676 100644
--- a/pyramid/tests/test_config/test_init.py
+++ b/pyramid/tests/test_config/test_init.py
@@ -1955,12 +1955,6 @@ class DummyRequest:
self.params = {}
self.cookies = {}
-class DummyResponse:
- status = '200 OK'
- headerlist = ()
- app_iter = ()
- body = ''
-
class DummyThreadLocalManager(object):
pushed = None
popped = False
@@ -1992,11 +1986,6 @@ class DummyRegistry(object):
def queryUtility(self, *arg, **kw):
return self.util
-from pyramid.interfaces import IResponse
-@implementer(IResponse)
-class DummyResponse(object):
- pass
-
from zope.interface import Interface
class IOther(Interface):
pass
diff --git a/pyramid/tests/test_i18n.py b/pyramid/tests/test_i18n.py
index bd4998b10..336e51b6a 100644
--- a/pyramid/tests/test_i18n.py
+++ b/pyramid/tests/test_i18n.py
@@ -230,39 +230,36 @@ class Test_get_localizer(unittest.TestCase):
from pyramid.i18n import get_localizer
return get_localizer(request)
- def test_no_registry_on_request(self):
+ def test_default_localizer(self):
+ # `get_localizer` returns a default localizer for `en`
+ from pyramid.i18n import Localizer
request = DummyRequest()
- request.localizer = '123'
result = self._callFUT(request)
- self.assertEqual(result, '123')
+ self.assertEqual(result.__class__, Localizer)
+ self.assertEqual(result.locale_name, 'en')
- def test_with_registry_on_request(self):
+ def test_custom_localizer_for_default_locale(self):
from pyramid.threadlocal import get_current_registry
+ from pyramid.interfaces import ILocalizer
registry = get_current_registry()
+ dummy = object()
+ registry.registerUtility(dummy, ILocalizer, name='en')
request = DummyRequest()
- request.localizer = '123'
- request.registry = registry
- result = self._callFUT(request)
- self.assertEqual(result, '123')
-
- def test_locale_on_request(self):
- request = DummyRequest()
- request.localizer = 'abc'
result = self._callFUT(request)
- self.assertEqual(result, 'abc')
+ self.assertEqual(result, dummy)
- def test_locale_from_registry(self):
+ def test_custom_localizer_for_custom_locale(self):
from pyramid.threadlocal import get_current_registry
from pyramid.interfaces import ILocalizer
registry = get_current_registry()
- locale = 'abc'
- registry.registerUtility(locale, ILocalizer, name='en')
+ dummy = object()
+ registry.registerUtility(dummy, ILocalizer, name='ie')
request = DummyRequest()
- request.locale_name = 'en'
+ request.locale_name = 'ie'
result = self._callFUT(request)
- self.assertEqual(result, 'abc')
+ self.assertEqual(result, dummy)
- def test_locale_from_mo(self):
+ def test_localizer_from_mo(self):
from pyramid.threadlocal import get_current_registry
from pyramid.interfaces import ITranslationDirectories
from pyramid.i18n import Localizer
@@ -278,7 +275,7 @@ class Test_get_localizer(unittest.TestCase):
self.assertEqual(result.translate('Approve'), 'Approve')
self.assertTrue(hasattr(result, 'pluralize'))
- def test_locale_from_mo_bad_mo(self):
+ def test_localizer_from_mo_bad_mo(self):
from pyramid.threadlocal import get_current_registry
from pyramid.interfaces import ITranslationDirectories
from pyramid.i18n import Localizer
@@ -292,6 +289,23 @@ class Test_get_localizer(unittest.TestCase):
self.assertEqual(result.translate('Approve', 'deformsite'),
'Approve')
+ def test_request_has_localizer(self):
+ from pyramid.threadlocal import get_current_registry
+ from pyramid.interfaces import ILocalizer
+ from pyramid.request import Request
+ # register mock localizer
+ dummy = object()
+ registry = get_current_registry()
+ registry.registerUtility(dummy, ILocalizer, name='en')
+ request = Request(environ={})
+ self.assertEqual(request.localizer, dummy)
+ # `get_localizer` is only called once...
+ other = object()
+ registry.registerUtility(other, ILocalizer, name='en')
+ self.assertNotEqual(request.localizer, other)
+ self.assertEqual(request.localizer, dummy)
+
+
class Test_default_locale_negotiator(unittest.TestCase):
def setUp(self):
cleanUp()
diff --git a/pyramid/tests/test_integration.py b/pyramid/tests/test_integration.py
index 66205e618..eda4ae9f3 100644
--- a/pyramid/tests/test_integration.py
+++ b/pyramid/tests/test_integration.py
@@ -72,7 +72,7 @@ class IntegrationBase(object):
here = os.path.dirname(__file__)
-class TestStaticAppBase(IntegrationBase):
+class StaticAppBase(IntegrationBase):
def test_basic(self):
res = self.testapp.get('/minimal.pt', status=200)
_assertBody(res.body, os.path.join(here, 'fixtures/minimal.pt'))
@@ -198,10 +198,10 @@ class TestEventOnlySubscribers(IntegrationBase, unittest.TestCase):
self.assertEqual(sorted(res.body.split()),
[b'foobar', b'foobar2', b'foobaryup', b'foobaryup2'])
-class TestStaticAppUsingAbsPath(TestStaticAppBase, unittest.TestCase):
+class TestStaticAppUsingAbsPath(StaticAppBase, unittest.TestCase):
package = 'pyramid.tests.pkgs.static_abspath'
-class TestStaticAppUsingAssetSpec(TestStaticAppBase, unittest.TestCase):
+class TestStaticAppUsingAssetSpec(StaticAppBase, unittest.TestCase):
package = 'pyramid.tests.pkgs.static_assetspec'
class TestStaticAppNoSubpath(unittest.TestCase):
@@ -649,6 +649,10 @@ class AcceptContentTypeTest(unittest.TestCase):
from webtest import TestApp
self.testapp = TestApp(app)
+ def tearDown(self):
+ import pyramid.config
+ pyramid.config.global_registries.empty()
+
def test_ordering(self):
res = self.testapp.get('/hello', headers={'Accept': 'application/json; q=1.0, text/plain; q=0.9'}, status=200)
self.assertEqual(res.content_type, 'application/json')
diff --git a/pyramid/tests/test_scaffolds/test_copydir.py b/pyramid/tests/test_scaffolds/test_copydir.py
index d757b837c..1e92b3c36 100644
--- a/pyramid/tests/test_scaffolds/test_copydir.py
+++ b/pyramid/tests/test_scaffolds/test_copydir.py
@@ -103,16 +103,57 @@ class Test_copy_dir(unittest.TestCase):
1, False,
overwrite=False,
template_renderer=dummy_template_renderer)
- target = os.path.join(self.dirname, 'mypackage', '__init__.py')
- with open(target, 'w') as f:
- f.write('These are not the words you are looking for.')
+ # toplevel file
+ toplevel = os.path.join(self.dirname, 'mypackage', '__init__.py')
+ with open(toplevel, 'w') as f:
+ f.write('These are the words you are looking for.')
+ # sub directory file
+ sub = os.path.join(self.dirname, 'mypackage', 'templates', 'mytemplate.pt')
+ with open(sub, 'w') as f:
+ f.write('These are the words you are looking for.')
self._callFUT(source,
self.dirname,
vars,
1, False,
overwrite=False,
template_renderer=dummy_template_renderer)
+ with open(toplevel, 'r') as f:
+ tcontent = f.read()
+ self.assertEqual('These are the words you are looking for.', tcontent)
+ with open(sub, 'r') as f:
+ tcontent = f.read()
+ self.assertEqual('These are the words you are looking for.', tcontent)
+ def test_overwrite_true(self):
+ vars = {'package':'mypackage'}
+ source = pkg_resources.resource_filename(*self.fixturetuple)
+ self._callFUT(source,
+ self.dirname,
+ vars,
+ 1, False,
+ overwrite=True,
+ template_renderer=dummy_template_renderer)
+ # toplevel file
+ toplevel = os.path.join(self.dirname, 'mypackage', '__init__.py')
+ with open(toplevel, 'w') as f:
+ f.write('These are not the words you are looking for.')
+ # sub directory file
+ sub = os.path.join(self.dirname, 'mypackage', 'templates', 'mytemplate.pt')
+ with open(sub, 'w') as f:
+ f.write('These are not the words you are looking for.')
+ self._callFUT(source,
+ self.dirname,
+ vars,
+ 1, False,
+ overwrite=True,
+ template_renderer=dummy_template_renderer)
+ with open(toplevel, 'r') as f:
+ tcontent = f.read()
+ self.assertNotEqual('These are not the words you are looking for.', tcontent)
+ with open(sub, 'r') as f:
+ tcontent = f.read()
+ self.assertNotEqual('These are not the words you are looking for.', tcontent)
+
def test_detect_SkipTemplate(self):
vars = {'package':'mypackage'}
source = pkg_resources.resource_filename(*self.fixturetuple)
diff --git a/pyramid/tests/test_scripts/test_pdistreport.py b/pyramid/tests/test_scripts/test_pdistreport.py
index a8316c0e5..e229667c5 100644
--- a/pyramid/tests/test_scripts/test_pdistreport.py
+++ b/pyramid/tests/test_scripts/test_pdistreport.py
@@ -1,5 +1,4 @@
import unittest
-from pyramid.tests.test_scripts import dummy
class TestPDistReportCommand(unittest.TestCase):
def _callFUT(self, **kw):
diff --git a/pyramid/tests/test_url.py b/pyramid/tests/test_url.py
index 9841c143e..bf1c514c5 100644
--- a/pyramid/tests/test_url.py
+++ b/pyramid/tests/test_url.py
@@ -611,7 +611,6 @@ class TestURLMethodsMixin(unittest.TestCase):
('pyramid.tests:static/foo.css', request, {}) )
def test_static_url_abspath_integration_with_staticurlinfo(self):
- import os
from pyramid.interfaces import IStaticURLInfo
from pyramid.config.views import StaticURLInfo
info = StaticURLInfo()
@@ -626,7 +625,6 @@ class TestURLMethodsMixin(unittest.TestCase):
'http://example.com:5432/absstatic/test_url.py')
def test_static_url_noscheme_uses_scheme_from_request(self):
- import os
from pyramid.interfaces import IStaticURLInfo
from pyramid.config.views import StaticURLInfo
info = StaticURLInfo()
diff --git a/setup.py b/setup.py
index 60b20b069..64e63956e 100644
--- a/setup.py
+++ b/setup.py
@@ -65,6 +65,7 @@ docs_extras = [
testing_extras = tests_require + [
'nose',
+ 'nose-selecttests',
'coverage',
'virtualenv', # for scaffolding tests
]