summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Merickel <github@m.merickel.org>2018-10-15 09:56:42 -0500
committerGitHub <noreply@github.com>2018-10-15 09:56:42 -0500
commitbda1306749c62ef4f11cfe567ed7d56c8ad94240 (patch)
tree304c696c105ca15bbe0f13d96c79524974de768b /src
parent81576ee51564c49d5ff3c1c07f214f22a8438231 (diff)
parenta54bc1ccac17625991e26eb5d4577f893803c683 (diff)
downloadpyramid-bda1306749c62ef4f11cfe567ed7d56c8ad94240.tar.gz
pyramid-bda1306749c62ef4f11cfe567ed7d56c8ad94240.tar.bz2
pyramid-bda1306749c62ef4f11cfe567ed7d56c8ad94240.zip
Merge pull request #3388 from mmerickel/black
format source using black
Diffstat (limited to 'src')
-rw-r--r--src/pyramid/asset.py19
-rw-r--r--src/pyramid/authentication.py354
-rw-r--r--src/pyramid/authorization.py42
-rw-r--r--src/pyramid/compat.py65
-rw-r--r--src/pyramid/config/__init__.py308
-rw-r--r--src/pyramid/config/adapters.py77
-rw-r--r--src/pyramid/config/assets.py67
-rw-r--r--src/pyramid/config/factories.py95
-rw-r--r--src/pyramid/config/i18n.py31
-rw-r--r--src/pyramid/config/predicates.py1
-rw-r--r--src/pyramid/config/rendering.py31
-rw-r--r--src/pyramid/config/routes.py148
-rw-r--r--src/pyramid/config/security.py110
-rw-r--r--src/pyramid/config/settings.py4
-rw-r--r--src/pyramid/config/testing.py58
-rw-r--r--src/pyramid/config/tweens.py47
-rw-r--r--src/pyramid/config/util.py41
-rw-r--r--src/pyramid/config/views.py574
-rw-r--r--src/pyramid/config/zca.py4
-rw-r--r--src/pyramid/csrf.py68
-rw-r--r--src/pyramid/decorator.py2
-rw-r--r--src/pyramid/encode.py7
-rw-r--r--src/pyramid/events.py37
-rw-r--r--src/pyramid/exceptions.py22
-rw-r--r--src/pyramid/httpexceptions.py336
-rw-r--r--src/pyramid/i18n.py77
-rw-r--r--src/pyramid/interfaces.py374
-rw-r--r--src/pyramid/location.py5
-rw-r--r--src/pyramid/paster.py7
-rw-r--r--src/pyramid/path.py41
-rw-r--r--src/pyramid/predicates.py55
-rw-r--r--src/pyramid/registry.py70
-rw-r--r--src/pyramid/renderers.py109
-rw-r--r--src/pyramid/request.py53
-rw-r--r--src/pyramid/resource.py9
-rw-r--r--src/pyramid/response.py46
-rw-r--r--src/pyramid/router.py63
-rw-r--r--src/pyramid/scaffolds/__init__.py17
-rw-r--r--src/pyramid/scaffolds/copydir.py169
-rw-r--r--src/pyramid/scaffolds/template.py51
-rw-r--r--src/pyramid/scaffolds/tests.py28
-rw-r--r--src/pyramid/scripting.py26
-rw-r--r--src/pyramid/scripts/common.py6
-rw-r--r--src/pyramid/scripts/pcreate.py188
-rw-r--r--src/pyramid/scripts/pdistreport.py31
-rw-r--r--src/pyramid/scripts/prequest.py71
-rw-r--r--src/pyramid/scripts/proutes.py134
-rw-r--r--src/pyramid/scripts/pserve.py107
-rw-r--r--src/pyramid/scripts/pshell.py78
-rw-r--r--src/pyramid/scripts/ptweens.py42
-rw-r--r--src/pyramid/scripts/pviews.py76
-rw-r--r--src/pyramid/security.py108
-rw-r--r--src/pyramid/session.py99
-rw-r--r--src/pyramid/settings.py3
-rw-r--r--src/pyramid/static.py89
-rw-r--r--src/pyramid/testing.py145
-rw-r--r--src/pyramid/threadlocal.py12
-rw-r--r--src/pyramid/traversal.py158
-rw-r--r--src/pyramid/tweens.py3
-rw-r--r--src/pyramid/url.py93
-rw-r--r--src/pyramid/urldispatch.py78
-rw-r--r--src/pyramid/util.py69
-rw-r--r--src/pyramid/view.py109
-rw-r--r--src/pyramid/viewderivers.py171
-rw-r--r--src/pyramid/wsgi.py2
65 files changed, 3415 insertions, 2205 deletions
diff --git a/src/pyramid/asset.py b/src/pyramid/asset.py
index 9d7a3ee63..0d7575a85 100644
--- a/src/pyramid/asset.py
+++ b/src/pyramid/asset.py
@@ -3,14 +3,12 @@ import pkg_resources
from pyramid.compat import string_types
-from pyramid.path import (
- package_path,
- package_name,
- )
+from pyramid.path import package_path, package_name
+
def resolve_asset_spec(spec, pname='__main__'):
if pname and not isinstance(pname, string_types):
- pname = pname.__name__ # as package
+ pname = pname.__name__ # as package
if os.path.isabs(spec):
return None, spec
filename = spec
@@ -20,6 +18,7 @@ def resolve_asset_spec(spec, pname='__main__'):
pname, filename = None, spec
return pname, filename
+
def asset_spec_from_abspath(abspath, package):
""" Try to convert an absolute path to a resource in a package to
a resource specification if possible; otherwise return the
@@ -28,11 +27,14 @@ def asset_spec_from_abspath(abspath, package):
return abspath
pp = package_path(package) + os.path.sep
if abspath.startswith(pp):
- relpath = abspath[len(pp):]
- return '%s:%s' % (package_name(package),
- relpath.replace(os.path.sep, '/'))
+ relpath = abspath[len(pp) :]
+ return '%s:%s' % (
+ package_name(package),
+ relpath.replace(os.path.sep, '/'),
+ )
return abspath
+
# bw compat only; use pyramid.path.AssetResolver().resolve(spec).abspath()
def abspath_from_asset_spec(spec, pname='__main__'):
if pname is None:
@@ -41,4 +43,3 @@ def abspath_from_asset_spec(spec, pname='__main__'):
if pname is None:
return filename
return pkg_resources.resource_filename(pname, filename)
-
diff --git a/src/pyramid/authentication.py b/src/pyramid/authentication.py
index a9604e336..7cb6b6811 100644
--- a/src/pyramid/authentication.py
+++ b/src/pyramid/authentication.py
@@ -21,17 +21,11 @@ from pyramid.compat import (
bytes_,
ascii_native_,
native_,
- )
+)
-from pyramid.interfaces import (
- IAuthenticationPolicy,
- IDebugLogger,
- )
+from pyramid.interfaces import IAuthenticationPolicy, IDebugLogger
-from pyramid.security import (
- Authenticated,
- Everyone,
- )
+from pyramid.security import Authenticated, Everyone
from pyramid.util import strings_differ
from pyramid.util import SimpleSerializer
@@ -74,36 +68,41 @@ class CallbackAuthenticationPolicy(object):
debug and self._log(
'call to unauthenticated_userid returned None; returning None',
'authenticated_userid',
- request)
+ request,
+ )
return None
if self._clean_principal(userid) is None:
debug and self._log(
- ('use of userid %r is disallowed by any built-in Pyramid '
- 'security policy, returning None' % userid),
+ (
+ 'use of userid %r is disallowed by any built-in Pyramid '
+ 'security policy, returning None' % userid
+ ),
'authenticated_userid',
- request)
+ request,
+ )
return None
if self.callback is None:
debug and self._log(
'there was no groupfinder callback; returning %r' % (userid,),
'authenticated_userid',
- request)
+ request,
+ )
return userid
callback_ok = self.callback(userid, request)
- if callback_ok is not None: # is not None!
+ if callback_ok is not None: # is not None!
debug and self._log(
- 'groupfinder callback returned %r; returning %r' % (
- callback_ok, userid),
+ 'groupfinder callback returned %r; returning %r'
+ % (callback_ok, userid),
'authenticated_userid',
- request
- )
+ request,
+ )
return userid
debug and self._log(
'groupfinder callback returned None; returning None',
'authenticated_userid',
- request
- )
+ request,
+ )
def effective_principals(self, request):
""" A list of effective principals derived from request.
@@ -134,42 +133,45 @@ class CallbackAuthenticationPolicy(object):
if userid is None:
debug and self._log(
- 'unauthenticated_userid returned %r; returning %r' % (
- userid, effective_principals),
+ 'unauthenticated_userid returned %r; returning %r'
+ % (userid, effective_principals),
'effective_principals',
- request
- )
+ request,
+ )
return effective_principals
if self._clean_principal(userid) is None:
debug and self._log(
- ('unauthenticated_userid returned disallowed %r; returning %r '
- 'as if it was None' % (userid, effective_principals)),
+ (
+ 'unauthenticated_userid returned disallowed %r; returning '
+ '%r as if it was None' % (userid, effective_principals)
+ ),
'effective_principals',
- request
- )
+ request,
+ )
return effective_principals
if self.callback is None:
debug and self._log(
'groupfinder callback is None, so groups is []',
'effective_principals',
- request)
+ request,
+ )
groups = []
else:
groups = self.callback(userid, request)
debug and self._log(
'groupfinder callback returned %r as groups' % (groups,),
'effective_principals',
- request)
+ request,
+ )
- if groups is None: # is None!
+ if groups is None: # is None!
debug and self._log(
- 'returning effective principals: %r' % (
- effective_principals,),
+ 'returning effective principals: %r' % (effective_principals,),
'effective_principals',
- request
- )
+ request,
+ )
return effective_principals
effective_principals.append(Authenticated)
@@ -177,10 +179,9 @@ class CallbackAuthenticationPolicy(object):
effective_principals.extend(groups)
debug and self._log(
- 'returning effective principals: %r' % (
- effective_principals,),
+ 'returning effective principals: %r' % (effective_principals,),
'effective_principals',
- request
+ request,
)
return effective_principals
@@ -241,7 +242,8 @@ class RepozeWho1AuthenticationPolicy(CallbackAuthenticationPolicy):
self.debug and self._log(
'repoze.who identity is None, returning None',
'authenticated_userid',
- request)
+ request,
+ )
return None
userid = identity['repoze.who.userid']
@@ -250,21 +252,25 @@ class RepozeWho1AuthenticationPolicy(CallbackAuthenticationPolicy):
self.debug and self._log(
'repoze.who.userid is None, returning None' % userid,
'authenticated_userid',
- request)
+ request,
+ )
return None
if self._clean_principal(userid) is None:
self.debug and self._log(
- ('use of userid %r is disallowed by any built-in Pyramid '
- 'security policy, returning None' % userid),
+ (
+ 'use of userid %r is disallowed by any built-in Pyramid '
+ 'security policy, returning None' % userid
+ ),
'authenticated_userid',
- request)
+ request,
+ )
return None
if self.callback is None:
return userid
- if self.callback(identity, request) is not None: # is not None!
+ if self.callback(identity, request) is not None: # is not None!
return userid
def unauthenticated_userid(self, request):
@@ -292,11 +298,13 @@ class RepozeWho1AuthenticationPolicy(CallbackAuthenticationPolicy):
if identity is None:
self.debug and self._log(
- ('repoze.who identity was None; returning %r' %
- effective_principals),
+ (
+ 'repoze.who identity was None; returning %r'
+ % effective_principals
+ ),
'effective_principals',
- request
- )
+ request,
+ )
return effective_principals
if self.callback is None:
@@ -304,33 +312,39 @@ class RepozeWho1AuthenticationPolicy(CallbackAuthenticationPolicy):
else:
groups = self.callback(identity, request)
- if groups is None: # is None!
+ if groups is None: # is None!
self.debug and self._log(
- ('security policy groups callback returned None; returning %r' %
- effective_principals),
+ (
+ 'security policy groups callback returned None; returning '
+ '%r' % effective_principals
+ ),
'effective_principals',
- request
- )
+ request,
+ )
return effective_principals
userid = identity['repoze.who.userid']
if userid is None:
self.debug and self._log(
- ('repoze.who.userid was None; returning %r' %
- effective_principals),
+ (
+ 'repoze.who.userid was None; returning %r'
+ % effective_principals
+ ),
'effective_principals',
- request
- )
+ request,
+ )
return effective_principals
if self._clean_principal(userid) is None:
self.debug and self._log(
- ('unauthenticated_userid returned disallowed %r; returning %r '
- 'as if it was None' % (userid, effective_principals)),
+ (
+ 'unauthenticated_userid returned disallowed %r; returning '
+ '%r as if it was None' % (userid, effective_principals)
+ ),
'effective_principals',
- request
- )
+ request,
+ )
return effective_principals
effective_principals.append(Authenticated)
@@ -367,6 +381,7 @@ class RepozeWho1AuthenticationPolicy(CallbackAuthenticationPolicy):
identity = self._get_identity(request)
return identifier.forget(request.environ, identity)
+
@implementer(IAuthenticationPolicy)
class RemoteUserAuthenticationPolicy(CallbackAuthenticationPolicy):
""" A :app:`Pyramid` :term:`authentication policy` which
@@ -419,6 +434,7 @@ class RemoteUserAuthenticationPolicy(CallbackAuthenticationPolicy):
be done somewhere else or in a subclass."""
return []
+
@implementer(IAuthenticationPolicy)
class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy):
"""A :app:`Pyramid` :term:`authentication policy` which
@@ -580,30 +596,31 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy):
.. versionchanged:: 1.10
Added the ``samesite`` option and made the default ``'Lax'``.
-
+
Objects of this class implement the interface described by
:class:`pyramid.interfaces.IAuthenticationPolicy`.
"""
- def __init__(self,
- secret,
- callback=None,
- cookie_name='auth_tkt',
- secure=False,
- include_ip=False,
- timeout=None,
- reissue_time=None,
- max_age=None,
- path="/",
- http_only=False,
- wild_domain=True,
- debug=False,
- hashalg='sha512',
- parent_domain=False,
- domain=None,
- samesite='Lax',
- ):
+ def __init__(
+ self,
+ secret,
+ callback=None,
+ cookie_name='auth_tkt',
+ secure=False,
+ include_ip=False,
+ timeout=None,
+ reissue_time=None,
+ max_age=None,
+ path="/",
+ http_only=False,
+ wild_domain=True,
+ debug=False,
+ hashalg='sha512',
+ parent_domain=False,
+ domain=None,
+ samesite='Lax',
+ ):
self.cookie = AuthTktCookieHelper(
secret,
cookie_name=cookie_name,
@@ -619,7 +636,7 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy):
parent_domain=parent_domain,
domain=domain,
samesite=samesite,
- )
+ )
self.callback = callback
self.debug = debug
@@ -643,12 +660,15 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy):
""" A list of headers which will delete appropriate cookies."""
return self.cookie.forget(request)
+
def b64encode(v):
return base64.b64encode(bytes_(v)).strip().replace(b'\n', b'')
+
def b64decode(v):
return base64.b64decode(bytes_(v))
+
# this class licensed under the MIT license (stolen from Paste)
class AuthTicket(object):
"""
@@ -670,9 +690,18 @@ class AuthTicket(object):
"""
- def __init__(self, secret, userid, ip, tokens=(), user_data='',
- time=None, cookie_name='auth_tkt', secure=False,
- hashalg='md5'):
+ def __init__(
+ self,
+ secret,
+ userid,
+ ip,
+ tokens=(),
+ user_data='',
+ time=None,
+ cookie_name='auth_tkt',
+ secure=False,
+ hashalg='md5',
+ ):
self.secret = secret
self.userid = userid
self.ip = ip
@@ -688,17 +717,27 @@ class AuthTicket(object):
def digest(self):
return calculate_digest(
- self.ip, self.time, self.secret, self.userid, self.tokens,
- self.user_data, self.hashalg)
+ self.ip,
+ self.time,
+ self.secret,
+ self.userid,
+ self.tokens,
+ self.user_data,
+ self.hashalg,
+ )
def cookie_value(self):
- v = '%s%08x%s!' % (self.digest(), int(self.time),
- url_quote(self.userid))
+ v = '%s%08x%s!' % (
+ self.digest(),
+ int(self.time),
+ url_quote(self.userid),
+ )
if self.tokens:
v += self.tokens + '!'
v += self.user_data
return v
+
# this class licensed under the MIT license (stolen from Paste)
class BadTicket(Exception):
"""
@@ -706,10 +745,12 @@ class BadTicket(Exception):
determine what the expected digest should have been, expected is set.
This should not be shown by default, but can be useful for debugging.
"""
+
def __init__(self, msg, expected=None):
self.expected = expected
Exception.__init__(self, msg)
+
# this function licensed under the MIT license (stolen from Paste)
def parse_ticket(secret, ticket, ip, hashalg='md5'):
"""
@@ -722,37 +763,41 @@ def parse_ticket(secret, ticket, ip, hashalg='md5'):
digest_size = hashlib.new(hashalg).digest_size * 2
digest = ticket[:digest_size]
try:
- timestamp = int(ticket[digest_size:digest_size + 8], 16)
+ timestamp = int(ticket[digest_size : digest_size + 8], 16)
except ValueError as e:
raise BadTicket('Timestamp is not a hex integer: %s' % e)
try:
- userid, data = ticket[digest_size + 8:].split('!', 1)
+ userid, data = ticket[digest_size + 8 :].split('!', 1)
except ValueError:
raise BadTicket('userid is not followed by !')
userid = url_unquote(userid)
if '!' in data:
tokens, user_data = data.split('!', 1)
- else: # pragma: no cover (never generated)
+ else: # pragma: no cover (never generated)
# @@: Is this the right order?
tokens = ''
user_data = data
- expected = calculate_digest(ip, timestamp, secret,
- userid, tokens, user_data, hashalg)
+ expected = calculate_digest(
+ ip, timestamp, secret, userid, tokens, user_data, hashalg
+ )
# Avoid timing attacks (see
# http://seb.dbzteam.org/crypto/python-oauth-timing-hmac.pdf)
if strings_differ(expected, digest):
- raise BadTicket('Digest signature is not correct',
- expected=(expected, digest))
+ raise BadTicket(
+ 'Digest signature is not correct', expected=(expected, digest)
+ )
tokens = tokens.split(',')
return (timestamp, userid, tokens, user_data)
+
# this function licensed under the MIT license (stolen from Paste)
-def calculate_digest(ip, timestamp, secret, userid, tokens, user_data,
- hashalg='md5'):
+def calculate_digest(
+ ip, timestamp, secret, userid, tokens, user_data, hashalg='md5'
+):
secret = bytes_(secret, 'utf-8')
userid = bytes_(userid, 'utf-8')
tokens = bytes_(tokens, 'utf-8')
@@ -767,24 +812,29 @@ def calculate_digest(ip, timestamp, secret, userid, tokens, user_data,
# encode_ip_timestamp not required, left in for backwards compatibility
ip_timestamp = encode_ip_timestamp(ip, timestamp)
- hash_obj.update(ip_timestamp + secret + userid + b'\0' +
- tokens + b'\0' + user_data)
+ hash_obj.update(
+ ip_timestamp + secret + userid + b'\0' + tokens + b'\0' + user_data
+ )
digest = hash_obj.hexdigest()
hash_obj2 = hashlib.new(hashalg)
hash_obj2.update(bytes_(digest) + secret)
return hash_obj2.hexdigest()
+
# this function licensed under the MIT license (stolen from Paste)
def encode_ip_timestamp(ip, timestamp):
ip_chars = ''.join(map(chr, map(int, ip.split('.'))))
t = int(timestamp)
- ts = ((t & 0xff000000) >> 24,
- (t & 0xff0000) >> 16,
- (t & 0xff00) >> 8,
- t & 0xff)
+ ts = (
+ (t & 0xFF000000) >> 24,
+ (t & 0xFF0000) >> 16,
+ (t & 0xFF00) >> 8,
+ t & 0xFF,
+ )
ts_chars = ''.join(map(chr, ts))
return bytes_(ip_chars + ts_chars)
+
class AuthTktCookieHelper(object):
"""
A helper class for use in third-party authentication policy
@@ -792,41 +842,43 @@ class AuthTktCookieHelper(object):
:class:`pyramid.authentication.AuthTktAuthenticationPolicy` for the
meanings of the constructor arguments.
"""
- parse_ticket = staticmethod(parse_ticket) # for tests
- AuthTicket = AuthTicket # for tests
- BadTicket = BadTicket # for tests
- now = None # for tests
+
+ parse_ticket = staticmethod(parse_ticket) # for tests
+ AuthTicket = AuthTicket # for tests
+ BadTicket = BadTicket # for tests
+ now = None # for tests
userid_type_decoders = {
- 'int':int,
- 'unicode':lambda x: utf_8_decode(x)[0], # bw compat for old cookies
+ 'int': int,
+ 'unicode': lambda x: utf_8_decode(x)[0], # bw compat for old cookies
'b64unicode': lambda x: utf_8_decode(b64decode(x))[0],
'b64str': lambda x: b64decode(x),
- }
+ }
userid_type_encoders = {
int: ('int', str),
long: ('int', str),
text_type: ('b64unicode', lambda x: b64encode(utf_8_encode(x)[0])),
binary_type: ('b64str', lambda x: b64encode(x)),
- }
-
- def __init__(self,
- secret,
- cookie_name='auth_tkt',
- secure=False,
- include_ip=False,
- timeout=None,
- reissue_time=None,
- max_age=None,
- http_only=False,
- path="/",
- wild_domain=True,
- hashalg='md5',
- parent_domain=False,
- domain=None,
- samesite='Lax',
- ):
+ }
+
+ def __init__(
+ self,
+ secret,
+ cookie_name='auth_tkt',
+ secure=False,
+ include_ip=False,
+ timeout=None,
+ reissue_time=None,
+ max_age=None,
+ http_only=False,
+ path="/",
+ wild_domain=True,
+ hashalg='md5',
+ parent_domain=False,
+ domain=None,
+ samesite='Lax',
+ ):
serializer = SimpleSerializer()
@@ -845,7 +897,9 @@ class AuthTktCookieHelper(object):
self.secure = secure
self.include_ip = include_ip
self.timeout = timeout if timeout is None else int(timeout)
- self.reissue_time = reissue_time if reissue_time is None else int(reissue_time)
+ self.reissue_time = (
+ reissue_time if reissue_time is None else int(reissue_time)
+ )
self.max_age = max_age if max_age is None else int(max_age)
self.wild_domain = wild_domain
self.parent_domain = parent_domain
@@ -893,16 +947,17 @@ class AuthTktCookieHelper(object):
try:
timestamp, userid, tokens, user_data = self.parse_ticket(
- self.secret, cookie, remote_addr, self.hashalg)
+ self.secret, cookie, remote_addr, self.hashalg
+ )
except self.BadTicket:
return None
- now = self.now # service tests
+ now = self.now # service tests
if now is None:
now = time_mod.time()
- if self.timeout and ( (timestamp + self.timeout) < now ):
+ if self.timeout and ((timestamp + self.timeout) < now):
# the auth_tkt data has expired
return None
@@ -910,7 +965,7 @@ class AuthTktCookieHelper(object):
user_data_info = user_data.split('|')
for datum in filter(None, user_data_info):
if datum.startswith(userid_typename):
- userid_type = datum[len(userid_typename):]
+ userid_type = datum[len(userid_typename) :]
decoder = self.userid_type_decoders.get(userid_type)
if decoder:
userid = decoder(userid)
@@ -918,15 +973,18 @@ class AuthTktCookieHelper(object):
reissue = self.reissue_time is not None
if reissue and not hasattr(request, '_authtkt_reissued'):
- if ( (now - timestamp) > self.reissue_time ):
+ if (now - timestamp) > self.reissue_time:
# See https://github.com/Pylons/pyramid/issues#issue/108
tokens = list(filter(None, tokens))
- headers = self.remember(request, userid, max_age=self.max_age,
- tokens=tokens)
+ headers = self.remember(
+ request, userid, max_age=self.max_age, tokens=tokens
+ )
+
def reissue_authtkt(request, response):
if not hasattr(request, '_authtkt_reissue_revoked'):
for k, v in headers:
response.headerlist.append((k, v))
+
request.add_response_callback(reissue_authtkt)
request._authtkt_reissued = True
@@ -986,8 +1044,9 @@ class AuthTktCookieHelper(object):
"userid is of type {}, and is not supported by the "
"AuthTktAuthenticationPolicy. Explicitly converting to string "
"and storing as base64. Subsequent requests will receive a "
- "string as the userid, it will not be decoded back to the type "
- "provided.".format(type(userid)), RuntimeWarning
+ "string as the userid, it will not be decoded back to the "
+ "type provided.".format(type(userid)),
+ RuntimeWarning,
)
encoding, encoder = self.userid_type_encoders.get(text_type)
userid = str(userid)
@@ -1018,12 +1077,13 @@ class AuthTktCookieHelper(object):
user_data=user_data,
cookie_name=self.cookie_name,
secure=self.secure,
- hashalg=self.hashalg
- )
+ hashalg=self.hashalg,
+ )
cookie_value = ticket.cookie_value()
return self._get_cookies(request, cookie_value, max_age)
+
@implementer(IAuthenticationPolicy)
class SessionAuthenticationPolicy(CallbackAuthenticationPolicy):
""" A :app:`Pyramid` authentication policy which gets its data from the
@@ -1094,8 +1154,8 @@ class BasicAuthAuthenticationPolicy(CallbackAuthenticationPolicy):
``realm``
- Default: ``"Realm"``. The Basic Auth Realm string. Usually displayed to
- the user by the browser in the login dialog.
+ Default: ``"Realm"``. The Basic Auth Realm string. Usually displayed
+ to the user by the browser in the login dialog.
``debug``
@@ -1123,6 +1183,7 @@ class BasicAuthAuthenticationPolicy(CallbackAuthenticationPolicy):
return response
return HTTPForbidden()
"""
+
def __init__(self, check, realm='Realm', debug=False):
self.check = check
self.realm = realm
@@ -1158,7 +1219,8 @@ class BasicAuthAuthenticationPolicy(CallbackAuthenticationPolicy):
HTTPBasicCredentials = namedtuple(
- 'HTTPBasicCredentials', ['username', 'password'])
+ 'HTTPBasicCredentials', ['username', 'password']
+)
def extract_http_basic_credentials(request):
@@ -1183,7 +1245,7 @@ def extract_http_basic_credentials(request):
try:
authbytes = b64decode(auth.strip())
- except (TypeError, binascii.Error): # can't decode
+ except (TypeError, binascii.Error): # can't decode
return None
# try utf-8 first, then latin-1; see discussion in
@@ -1195,7 +1257,7 @@ def extract_http_basic_credentials(request):
try:
username, password = auth.split(':', 1)
- except ValueError: # not enough values to unpack
+ except ValueError: # not enough values to unpack
return None
return HTTPBasicCredentials(username, password)
diff --git a/src/pyramid/authorization.py b/src/pyramid/authorization.py
index 4845762ef..974748765 100644
--- a/src/pyramid/authorization.py
+++ b/src/pyramid/authorization.py
@@ -6,13 +6,8 @@ from pyramid.location import lineage
from pyramid.compat import is_nonstr_iter
-from pyramid.security import (
- ACLAllowed,
- ACLDenied,
- Allow,
- Deny,
- Everyone,
- )
+from pyramid.security import ACLAllowed, ACLDenied, Allow, Deny, Everyone
+
@implementer(IAuthorizationPolicy)
class ACLAuthorizationPolicy(object):
@@ -90,20 +85,19 @@ class ACLAuthorizationPolicy(object):
ace_permissions = [ace_permissions]
if permission in ace_permissions:
if ace_action == Allow:
- return ACLAllowed(ace, acl, permission,
- principals, location)
+ return ACLAllowed(
+ ace, acl, permission, principals, location
+ )
else:
- return ACLDenied(ace, acl, permission,
- principals, location)
+ return ACLDenied(
+ ace, acl, permission, principals, location
+ )
# default deny (if no ACL in lineage at all, or if none of the
# principals were mentioned in any ACE we found)
return ACLDenied(
- '<default deny>',
- acl,
- permission,
- principals,
- context)
+ '<default deny>', acl, permission, principals, context
+ )
def principals_allowed_by_permission(self, context, permission):
""" Return the set of principals explicitly granted the
@@ -132,14 +126,14 @@ class ACLAuthorizationPolicy(object):
if ace_principal not in denied_here:
allowed_here.add(ace_principal)
if (ace_action == Deny) and (permission in ace_permissions):
- denied_here.add(ace_principal)
- if ace_principal == Everyone:
- # clear the entire allowed set, as we've hit a
- # deny of Everyone ala (Deny, Everyone, ALL)
- allowed = set()
- break
- elif ace_principal in allowed:
- allowed.remove(ace_principal)
+ denied_here.add(ace_principal)
+ if ace_principal == Everyone:
+ # clear the entire allowed set, as we've hit a
+ # deny of Everyone ala (Deny, Everyone, ALL)
+ allowed = set()
+ break
+ elif ace_principal in allowed:
+ allowed.remove(ace_principal)
allowed.update(allowed_here)
diff --git a/src/pyramid/compat.py b/src/pyramid/compat.py
index a7f9c1287..31832c874 100644
--- a/src/pyramid/compat.py
+++ b/src/pyramid/compat.py
@@ -7,8 +7,9 @@ WIN = platform.system() == 'Windows'
try: # pragma: no cover
import __pypy__
+
PYPY = True
-except: # pragma: no cover
+except BaseException: # pragma: no cover
__pypy__ = None
PYPY = False
@@ -27,20 +28,21 @@ PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3
if PY2:
- string_types = basestring,
+ string_types = (basestring,)
integer_types = (int, long)
class_types = (type, types.ClassType)
text_type = unicode
binary_type = str
long = long
else:
- string_types = str,
- integer_types = int,
- class_types = type,
+ string_types = (str,)
+ integer_types = (int,)
+ class_types = (type,)
text_type = str
binary_type = bytes
long = int
+
def text_(s, encoding='latin-1', errors='strict'):
""" If ``s`` is an instance of ``binary_type``, return
``s.decode(encoding, errors)``, otherwise return ``s``"""
@@ -48,6 +50,7 @@ def text_(s, encoding='latin-1', errors='strict'):
return s.decode(encoding, errors)
return s
+
def bytes_(s, encoding='latin-1', errors='strict'):
""" If ``s`` is an instance of ``text_type``, return
``s.encode(encoding, errors)``, otherwise return ``s``"""
@@ -55,17 +58,23 @@ def bytes_(s, encoding='latin-1', errors='strict'):
return s.encode(encoding, errors)
return s
+
if PY2:
+
def ascii_native_(s):
if isinstance(s, text_type):
s = s.encode('ascii')
return str(s)
+
+
else:
+
def ascii_native_(s):
if isinstance(s, text_type):
s = s.encode('ascii')
return str(s, 'ascii', 'strict')
+
ascii_native_.__doc__ = """
Python 3: If ``s`` is an instance of ``text_type``, return
``s.encode('ascii')``, otherwise return ``str(s, 'ascii', 'strict')``
@@ -76,13 +85,17 @@ Python 2: If ``s`` is an instance of ``text_type``, return
if PY2:
+
def native_(s, encoding='latin-1', errors='strict'):
""" If ``s`` is an instance of ``text_type``, return
``s.encode(encoding, errors)``, otherwise return ``str(s)``"""
if isinstance(s, text_type):
return s.encode(encoding, errors)
return str(s)
+
+
else:
+
def native_(s, encoding='latin-1', errors='strict'):
""" If ``s`` is an instance of ``text_type``, return
``s``, otherwise return ``str(s, encoding, errors)``"""
@@ -90,6 +103,7 @@ else:
return s
return str(s, encoding, errors)
+
native_.__doc__ = """
Python 3: If ``s`` is an instance of ``text_type``, return ``s``, otherwise
return ``str(s, encoding, errors)``
@@ -106,25 +120,34 @@ if PY2:
from urllib import urlencode as url_encode
from urllib2 import urlopen as url_open
- def url_unquote_text(v, encoding='utf-8', errors='replace'): # pragma: no cover
+ def url_unquote_text(
+ v, encoding='utf-8', errors='replace'
+ ): # pragma: no cover
v = url_unquote(v)
return v.decode(encoding, errors)
- def url_unquote_native(v, encoding='utf-8', errors='replace'): # pragma: no cover
+ def url_unquote_native(
+ v, encoding='utf-8', errors='replace'
+ ): # pragma: no cover
return native_(url_unquote_text(v, encoding, errors))
+
+
else:
from urllib import parse
+
urlparse = parse
from urllib.parse import quote as url_quote
from urllib.parse import quote_plus as url_quote_plus
from urllib.parse import unquote as url_unquote
from urllib.parse import urlencode as url_encode
from urllib.request import urlopen as url_open
+
url_unquote_text = url_unquote
url_unquote_native = url_unquote
if PY2: # pragma: no cover
+
def exec_(code, globs=None, locs=None):
"""Execute code in a namespace."""
if globs is None:
@@ -137,12 +160,15 @@ if PY2: # pragma: no cover
locs = globs
exec("""exec code in globs, locs""")
- exec_("""def reraise(tp, value, tb=None):
+ exec_(
+ """def reraise(tp, value, tb=None):
raise tp, value, tb
-""")
+"""
+ )
else: # pragma: no cover
import builtins
+
exec_ = getattr(builtins, "exec")
def reraise(tp, value, tb=None):
@@ -156,6 +182,7 @@ else: # pragma: no cover
if PY2: # pragma: no cover
+
def iteritems_(d):
return d.iteritems()
@@ -164,7 +191,10 @@ if PY2: # pragma: no cover
def iterkeys_(d):
return d.iterkeys()
+
+
else: # pragma: no cover
+
def iteritems_(d):
return d.items()
@@ -178,18 +208,25 @@ else: # pragma: no cover
if PY2:
map_ = map
else:
+
def map_(*arg):
return list(map(*arg))
+
if PY2:
+
def is_nonstr_iter(v):
return hasattr(v, '__iter__')
+
+
else:
+
def is_nonstr_iter(v):
if isinstance(v, str):
return False
return hasattr(v, '__iter__')
+
if PY2:
im_func = 'im_func'
im_self = 'im_self'
@@ -227,21 +264,27 @@ else:
import json
if PY2:
+
def decode_path_info(path):
return path.decode('utf-8')
+
+
else:
# see PEP 3333 for why we encode WSGI PATH_INFO to latin-1 before
# decoding it to utf-8
def decode_path_info(path):
return path.encode('latin-1').decode('utf-8')
+
if PY2:
from urlparse import unquote as unquote_to_bytes
def unquote_bytes_to_wsgi(bytestring):
return unquote_to_bytes(bytestring)
+
+
else:
- # see PEP 3333 for why we decode the path to latin-1
+ # see PEP 3333 for why we decode the path to latin-1
from urllib.parse import unquote_to_bytes
def unquote_bytes_to_wsgi(bytestring):
@@ -251,6 +294,7 @@ else:
def is_bound_method(ob):
return inspect.ismethod(ob) and getattr(ob, im_self, None) is not None
+
# support annotations and keyword-only arguments in PY3
if PY2:
from inspect import getargspec
@@ -262,6 +306,7 @@ if PY2:
else:
from itertools import zip_longest
+
def is_unbound_method(fn):
"""
This consistently verifies that the callable is bound to a
diff --git a/src/pyramid/config/__init__.py b/src/pyramid/config/__init__.py
index 2f4e133f0..f5790352e 100644
--- a/src/pyramid/config/__init__.py
+++ b/src/pyramid/config/__init__.py
@@ -17,17 +17,13 @@ from pyramid.interfaces import (
PHASE1_CONFIG,
PHASE2_CONFIG,
PHASE3_CONFIG,
- )
+)
from pyramid.asset import resolve_asset_spec
from pyramid.authorization import ACLAuthorizationPolicy
-from pyramid.compat import (
- text_,
- reraise,
- string_types,
- )
+from pyramid.compat import text_, reraise, string_types
from pyramid.events import ApplicationCreated
@@ -35,21 +31,13 @@ from pyramid.exceptions import (
ConfigurationConflictError,
ConfigurationError,
ConfigurationExecutionError,
- )
+)
from pyramid.httpexceptions import default_exceptionresponse_view
-from pyramid.path import (
- caller_package,
- package_of,
- )
+from pyramid.path import caller_package, package_of
-from pyramid.registry import (
- Introspectable,
- Introspector,
- Registry,
- undefer,
- )
+from pyramid.registry import Introspectable, Introspector, Registry, undefer
from pyramid.router import Router
@@ -57,17 +45,9 @@ from pyramid.settings import aslist
from pyramid.threadlocal import manager
-from pyramid.util import (
- WeakOrderedSet,
- object_description,
- )
+from pyramid.util import WeakOrderedSet, object_description
-from pyramid.config.util import (
- ActionInfo,
- PredicateList,
- action_method,
- not_,
-)
+from pyramid.config.util import ActionInfo, PredicateList, action_method, not_
from pyramid.config.adapters import AdaptersConfiguratorMixin
from pyramid.config.assets import AssetsConfiguratorMixin
@@ -94,6 +74,7 @@ PHASE1_CONFIG = PHASE1_CONFIG # api
PHASE2_CONFIG = PHASE2_CONFIG # api
PHASE3_CONFIG = PHASE3_CONFIG # api
+
class Configurator(
TestingConfiguratorMixin,
TweensConfiguratorMixin,
@@ -107,7 +88,7 @@ class Configurator(
SettingsConfiguratorMixin,
FactoriesConfiguratorMixin,
AdaptersConfiguratorMixin,
- ):
+):
"""
A Configurator is used to configure a :app:`Pyramid`
:term:`application registry`.
@@ -284,8 +265,9 @@ class Configurator(
``with``-statement to make threadlocal configuration available for
further configuration with an implicit commit.
"""
- manager = manager # for testing injection
- venusian = venusian # for testing injection
+
+ manager = manager # for testing injection
+ venusian = venusian # for testing injection
_ainfo = None
basepath = None
includepath = ()
@@ -294,27 +276,28 @@ class Configurator(
introspectable = Introspectable
inspect = inspect
- def __init__(self,
- registry=None,
- package=None,
- settings=None,
- root_factory=None,
- authentication_policy=None,
- authorization_policy=None,
- renderers=None,
- debug_logger=None,
- locale_negotiator=None,
- request_factory=None,
- response_factory=None,
- default_permission=None,
- session_factory=None,
- default_view_mapper=None,
- autocommit=False,
- exceptionresponse_view=default_exceptionresponse_view,
- route_prefix=None,
- introspection=True,
- root_package=None,
- ):
+ def __init__(
+ self,
+ registry=None,
+ package=None,
+ settings=None,
+ root_factory=None,
+ authentication_policy=None,
+ authorization_policy=None,
+ renderers=None,
+ debug_logger=None,
+ locale_negotiator=None,
+ request_factory=None,
+ response_factory=None,
+ default_permission=None,
+ session_factory=None,
+ default_view_mapper=None,
+ autocommit=False,
+ exceptionresponse_view=default_exceptionresponse_view,
+ route_prefix=None,
+ introspection=True,
+ root_package=None,
+ ):
if package is None:
package = caller_package()
if root_package is None:
@@ -345,23 +328,24 @@ class Configurator(
session_factory=session_factory,
default_view_mapper=default_view_mapper,
exceptionresponse_view=exceptionresponse_view,
- )
+ )
- def setup_registry(self,
- settings=None,
- root_factory=None,
- authentication_policy=None,
- authorization_policy=None,
- renderers=None,
- debug_logger=None,
- locale_negotiator=None,
- request_factory=None,
- response_factory=None,
- default_permission=None,
- session_factory=None,
- default_view_mapper=None,
- exceptionresponse_view=default_exceptionresponse_view,
- ):
+ def setup_registry(
+ self,
+ settings=None,
+ root_factory=None,
+ authentication_policy=None,
+ authorization_policy=None,
+ renderers=None,
+ debug_logger=None,
+ locale_negotiator=None,
+ request_factory=None,
+ response_factory=None,
+ default_permission=None,
+ session_factory=None,
+ default_view_mapper=None,
+ exceptionresponse_view=default_exceptionresponse_view,
+ ):
""" When you pass a non-``None`` ``registry`` argument to the
:term:`Configurator` constructor, no initial setup is performed
against the registry. This is because the registry you pass in may
@@ -404,12 +388,15 @@ class Configurator(
if exceptionresponse_view is not None:
exceptionresponse_view = self.maybe_dotted(exceptionresponse_view)
self.add_view(exceptionresponse_view, context=IExceptionResponse)
- self.add_view(exceptionresponse_view,context=WebobWSGIHTTPException)
+ self.add_view(
+ exceptionresponse_view, context=WebobWSGIHTTPException
+ )
# commit below because:
#
# - the default exceptionresponse_view requires the superdefault view
- # mapper, so we need to configure it before adding default_view_mapper
+ # mapper, so we need to configure it before adding
+ # default_view_mapper
#
# - superdefault renderers should be overrideable without requiring
# the user to commit before calling config.add_renderer
@@ -424,7 +411,7 @@ class Configurator(
# automatic conflict resolution.
if authentication_policy and not authorization_policy:
- authorization_policy = ACLAuthorizationPolicy() # default
+ authorization_policy = ACLAuthorizationPolicy() # default
if authorization_policy:
self.set_authorization_policy(authorization_policy)
@@ -468,7 +455,7 @@ class Configurator(
def _make_spec(self, path_or_spec):
package, filename = resolve_asset_spec(path_or_spec, self.package_name)
if package is None:
- return filename # absolute filename
+ return filename # absolute filename
return '%s:%s' % (package, filename)
def _fix_registry(self):
@@ -480,38 +467,55 @@ class Configurator(
_registry = self.registry
if not hasattr(_registry, 'notify'):
+
def notify(*events):
- [ _ for _ in _registry.subscribers(events, None) ]
+ [_ for _ in _registry.subscribers(events, None)]
+
_registry.notify = notify
if not hasattr(_registry, 'has_listeners'):
_registry.has_listeners = True
if not hasattr(_registry, 'queryAdapterOrSelf'):
+
def queryAdapterOrSelf(object, interface, default=None):
if not interface.providedBy(object):
- return _registry.queryAdapter(object, interface,
- default=default)
+ return _registry.queryAdapter(
+ object, interface, default=default
+ )
return object
+
_registry.queryAdapterOrSelf = queryAdapterOrSelf
if not hasattr(_registry, 'registerSelfAdapter'):
- def registerSelfAdapter(required=None, provided=None,
- name=empty, info=empty, event=True):
- return _registry.registerAdapter(lambda x: x,
- required=required,
- provided=provided, name=name,
- info=info, event=event)
+
+ def registerSelfAdapter(
+ required=None,
+ provided=None,
+ name=empty,
+ info=empty,
+ event=True,
+ ):
+ return _registry.registerAdapter(
+ lambda x: x,
+ required=required,
+ provided=provided,
+ name=name,
+ info=info,
+ event=event,
+ )
+
_registry.registerSelfAdapter = registerSelfAdapter
if not hasattr(_registry, '_lock'):
_registry._lock = threading.Lock()
if not hasattr(_registry, '_clear_view_lookup_cache'):
+
def _clear_view_lookup_cache():
_registry._view_lookup_cache = {}
- _registry._clear_view_lookup_cache = _clear_view_lookup_cache
+ _registry._clear_view_lookup_cache = _clear_view_lookup_cache
# API
@@ -530,7 +534,7 @@ class Configurator(
introspector = property(
_get_introspector, _set_introspector, _del_introspector
- )
+ )
def get_predlist(self, name):
predlist = self.registry.queryUtility(IPredicateList, name=name)
@@ -539,30 +543,41 @@ class Configurator(
self.registry.registerUtility(predlist, IPredicateList, name=name)
return predlist
-
- def _add_predicate(self, type, name, factory, weighs_more_than=None,
- weighs_less_than=None):
+ def _add_predicate(
+ self, type, name, factory, weighs_more_than=None, weighs_less_than=None
+ ):
factory = self.maybe_dotted(factory)
discriminator = ('%s option' % type, name)
intr = self.introspectable(
'%s predicates' % type,
discriminator,
'%s predicate named %s' % (type, name),
- '%s predicate' % type)
+ '%s predicate' % type,
+ )
intr['name'] = name
intr['factory'] = factory
intr['weighs_more_than'] = weighs_more_than
intr['weighs_less_than'] = weighs_less_than
+
def register():
predlist = self.get_predlist(type)
- predlist.add(name, factory, weighs_more_than=weighs_more_than,
- weighs_less_than=weighs_less_than)
- self.action(discriminator, register, introspectables=(intr,),
- order=PHASE1_CONFIG) # must be registered early
+ predlist.add(
+ name,
+ factory,
+ weighs_more_than=weighs_more_than,
+ weighs_less_than=weighs_less_than,
+ )
+
+ self.action(
+ discriminator,
+ register,
+ introspectables=(intr,),
+ order=PHASE1_CONFIG,
+ ) # must be registered early
@property
def action_info(self):
- info = self.info # usually a ZCML action (ParserInfo) if self.info
+ info = self.info # usually a ZCML action (ParserInfo) if self.info
if not info:
# Try to provide more accurate info for conflict reports
if self._ainfo:
@@ -571,8 +586,16 @@ class Configurator(
info = ActionInfo(None, 0, '', '')
return info
- def action(self, discriminator, callable=None, args=(), kw=None, order=0,
- introspectables=(), **extra):
+ def action(
+ self,
+ discriminator,
+ callable=None,
+ args=(),
+ kw=None,
+ order=0,
+ introspectables=(),
+ **extra
+ ):
""" Register an action which will be executed when
:meth:`pyramid.config.Configurator.commit` is called (or executed
immediately if ``autocommit`` is ``True``).
@@ -607,7 +630,7 @@ class Configurator(
"""
# catch nonhashable discriminators here; most unit tests use
# autocommit=False, which won't catch unhashable discriminators
- assert hash(discriminator)
+ assert hash(discriminator)
if kw is None:
kw = {}
@@ -645,8 +668,8 @@ class Configurator(
info=action_info,
includepath=self.includepath,
introspectables=introspectables,
- )
)
+ )
self.action_state.action(**action)
def _get_action_state(self):
@@ -663,7 +686,7 @@ class Configurator(
action_state = property(_get_action_state, _set_action_state)
- _ctx = action_state # bw compat
+ _ctx = action_state # bw compat
def commit(self):
"""
@@ -687,7 +710,7 @@ class Configurator(
self.action_state.execute_actions(introspector=self.introspector)
finally:
self.end()
- self.action_state = ActionState() # old actions have been processed
+ self.action_state = ActionState() # old actions have been processed
def include(self, callable, route_prefix=None):
"""Include a configuration callable, to support imperative
@@ -800,17 +823,18 @@ class Configurator(
c = getattr(module, 'includeme')
except AttributeError:
raise ConfigurationError(
- "module %r has no attribute 'includeme'" % (module.__name__)
- )
-
+ "module %r has no attribute 'includeme'"
+ % (module.__name__)
+ )
+
spec = module.__name__ + ':' + c.__name__
sourcefile = self.inspect.getsourcefile(c)
if sourcefile is None:
raise ConfigurationError(
'No source file for module %r (.py file must exist, '
- 'refusing to use orphan .pyc or .pyo file).' % module.__name__)
-
+ 'refusing to use orphan .pyc or .pyo file).' % module.__name__
+ )
if action_state.processSpec(spec):
with self.route_prefix_context(route_prefix):
@@ -820,7 +844,7 @@ class Configurator(
root_package=self.root_package,
autocommit=self.autocommit,
route_prefix=self.route_prefix,
- )
+ )
configurator.basepath = os.path.dirname(sourcefile)
configurator.includepath = self.includepath + (spec,)
@@ -886,7 +910,7 @@ class Configurator(
autocommit=self.autocommit,
route_prefix=self.route_prefix,
introspection=self.introspection,
- )
+ )
configurator.basepath = self.basepath
configurator.includepath = self.includepath
configurator.info = self.info
@@ -914,7 +938,7 @@ class Configurator(
return relative_spec
return self._make_spec(relative_spec)
- absolute_resource_spec = absolute_asset_spec # b/w compat forever
+ absolute_resource_spec = absolute_asset_spec # b/w compat forever
def begin(self, request=_marker):
""" Indicate that application or test configuration has begun.
@@ -940,7 +964,7 @@ class Configurator(
request = current['request']
else:
request = None
- self.manager.push({'registry':self.registry, 'request':request})
+ self.manager.push({'registry': self.registry, 'request': request})
def end(self):
""" Indicate that application or test configuration has ended.
@@ -961,8 +985,9 @@ class Configurator(
self.commit()
# this is *not* an action method (uses caller_package)
- def scan(self, package=None, categories=None, onerror=None, ignore=None,
- **kw):
+ def scan(
+ self, package=None, categories=None, onerror=None, ignore=None, **kw
+ ):
"""Scan a Python package and any of its subpackages for objects
marked with :term:`configuration decoration` such as
:class:`pyramid.view.view_config`. Any decorated object found will
@@ -1021,7 +1046,7 @@ class Configurator(
"""
package = self.maybe_dotted(package)
- if package is None: # pragma: no cover
+ if package is None: # pragma: no cover
package = caller_package()
ctorkw = {'config': self}
@@ -1029,8 +1054,9 @@ class Configurator(
scanner = self.venusian.Scanner(**ctorkw)
- scanner.scan(package, categories=categories, onerror=onerror,
- ignore=ignore)
+ scanner.scan(
+ package, categories=categories, onerror=onerror, ignore=ignore
+ )
def make_wsgi_app(self):
""" Commits any pending configuration statements, sends a
@@ -1079,8 +1105,18 @@ class ActionState(object):
self._seen_files.add(spec)
return True
- def action(self, discriminator, callable=None, args=(), kw=None, order=0,
- includepath=(), info=None, introspectables=(), **extra):
+ def action(
+ self,
+ discriminator,
+ callable=None,
+ args=(),
+ kw=None,
+ order=0,
+ includepath=(),
+ info=None,
+ introspectables=(),
+ **extra
+ ):
"""Add an action with the given discriminator, callable and arguments
"""
if kw is None:
@@ -1096,8 +1132,8 @@ class ActionState(object):
info=info,
order=order,
introspectables=introspectables,
- )
)
+ )
self.actions.append(action)
def execute_actions(self, clear=True, introspector=None):
@@ -1179,8 +1215,7 @@ class ActionState(object):
if self.actions:
all_actions.extend(self.actions)
action_iter = resolveConflicts(
- self.actions,
- state=conflict_state,
+ self.actions, state=conflict_state
)
self.actions = []
@@ -1203,9 +1238,11 @@ class ActionState(object):
except Exception:
t, v, tb = sys.exc_info()
try:
- reraise(ConfigurationExecutionError,
- ConfigurationExecutionError(t, v, info),
- tb)
+ reraise(
+ ConfigurationExecutionError,
+ ConfigurationExecutionError(t, v, info),
+ tb,
+ )
finally:
del t, v, tb
@@ -1290,9 +1327,12 @@ def resolveConflicts(actions, state=None):
# error out if we went backward in order
if state.min_order is not None and order < state.min_order:
- r = ['Actions were added to order={0} after execution had moved '
- 'on to order={1}. Conflicting actions: '
- .format(order, state.min_order)]
+ r = [
+ 'Actions were added to order={0} after execution had moved '
+ 'on to order={1}. Conflicting actions: '.format(
+ order, state.min_order
+ )
+ ]
for i, action in actiongroup:
for line in str(action['info']).rstrip().split('\n'):
r.append(" " + line)
@@ -1348,8 +1388,10 @@ def resolveConflicts(actions, state=None):
# if the new action conflicts with the resolved action then
# note the conflict, otherwise drop the action as it's
# effectively overriden by the previous action
- if (includepath[:len(basepath)] != basepath or
- includepath == basepath):
+ if (
+ includepath[: len(basepath)] != basepath
+ or includepath == basepath
+ ):
L = conflicts.setdefault(discriminator, [baseinfo])
L.append(action['info'])
@@ -1360,8 +1402,10 @@ def resolveConflicts(actions, state=None):
for _, action in rest:
includepath = action['includepath']
# Test whether path is a prefix of opath
- if (includepath[:len(basepath)] != basepath or # not a prefix
- includepath == basepath):
+ if (
+ includepath[: len(basepath)] != basepath
+ or includepath == basepath # not a prefix
+ ):
L = conflicts.setdefault(discriminator, [baseinfo])
L.append(action['info'])
@@ -1389,8 +1433,14 @@ def normalize_actions(actions):
def expand_action_tuple(
- discriminator, callable=None, args=(), kw=None, includepath=(),
- info=None, order=0, introspectables=(),
+ discriminator,
+ callable=None,
+ args=(),
+ kw=None,
+ includepath=(),
+ info=None,
+ order=0,
+ introspectables=(),
):
if kw is None:
kw = {}
@@ -1403,7 +1453,7 @@ def expand_action_tuple(
info=info,
order=order,
introspectables=introspectables,
- )
+ )
global_registries = WeakOrderedSet()
diff --git a/src/pyramid/config/adapters.py b/src/pyramid/config/adapters.py
index 945faa3c6..e5668c40e 100644
--- a/src/pyramid/config/adapters.py
+++ b/src/pyramid/config/adapters.py
@@ -4,11 +4,7 @@ from functools import update_wrapper
from zope.interface import Interface
-from pyramid.interfaces import (
- IResponse,
- ITraverser,
- IResourceURL,
- )
+from pyramid.interfaces import IResponse, ITraverser, IResourceURL
from pyramid.util import takes_one_arg
@@ -53,33 +49,33 @@ class AdaptersConfiguratorMixin(object):
predlist = self.get_predlist('subscriber')
order, preds, phash = predlist.make(self, **predicates)
- derived_predicates = [ self._derive_predicate(p) for p in preds ]
+ derived_predicates = [self._derive_predicate(p) for p in preds]
derived_subscriber = self._derive_subscriber(
- subscriber,
- derived_predicates,
- )
+ subscriber, derived_predicates
+ )
intr.update(
- {'phash':phash,
- 'order':order,
- 'predicates':preds,
- 'derived_predicates':derived_predicates,
- 'derived_subscriber':derived_subscriber,
- }
- )
+ {
+ 'phash': phash,
+ 'order': order,
+ 'predicates': preds,
+ 'derived_predicates': derived_predicates,
+ 'derived_subscriber': derived_subscriber,
+ }
+ )
self.registry.registerHandler(derived_subscriber, iface)
-
+
intr = self.introspectable(
'subscribers',
id(subscriber),
self.object_description(subscriber),
- 'subscriber'
- )
-
+ 'subscriber',
+ )
+
intr['subscriber'] = subscriber
intr['interfaces'] = iface
-
+
self.action(None, register, introspectables=(intr,))
return subscriber
@@ -87,8 +83,10 @@ class AdaptersConfiguratorMixin(object):
derived_predicate = predicate
if eventonly(predicate):
+
def derived_predicate(*arg):
return predicate(arg[0])
+
# seems pointless to try to fix __doc__, __module__, etc as
# predicate will invariably be an instance
@@ -98,8 +96,10 @@ class AdaptersConfiguratorMixin(object):
derived_subscriber = subscriber
if eventonly(subscriber):
+
def derived_subscriber(*arg):
return subscriber(arg[0])
+
if hasattr(subscriber, '__name__'):
update_wrapper(derived_subscriber, subscriber)
@@ -132,10 +132,11 @@ class AdaptersConfiguratorMixin(object):
update_wrapper(subscriber_wrapper, subscriber)
return subscriber_wrapper
-
+
@action_method
- def add_subscriber_predicate(self, name, factory, weighs_more_than=None,
- weighs_less_than=None):
+ def add_subscriber_predicate(
+ self, name, factory, weighs_more_than=None, weighs_less_than=None
+ ):
"""
.. versionadded:: 1.4
@@ -159,8 +160,8 @@ class AdaptersConfiguratorMixin(object):
name,
factory,
weighs_more_than=weighs_more_than,
- weighs_less_than=weighs_less_than
- )
+ weighs_less_than=weighs_less_than,
+ )
@action_method
def add_response_adapter(self, adapter, type_or_iface):
@@ -178,18 +179,21 @@ class AdaptersConfiguratorMixin(object):
See :ref:`using_iresponse` for more information."""
adapter = self.maybe_dotted(adapter)
type_or_iface = self.maybe_dotted(type_or_iface)
+
def register():
reg = self.registry
if adapter is None:
reg.registerSelfAdapter((type_or_iface,), IResponse)
else:
reg.registerAdapter(adapter, (type_or_iface,), IResponse)
+
discriminator = (IResponse, type_or_iface)
intr = self.introspectable(
'response adapters',
discriminator,
self.object_description(adapter),
- 'response adapter')
+ 'response adapter',
+ )
intr['adapter'] = adapter
intr['type'] = type_or_iface
self.action(discriminator, register, introspectables=(intr,))
@@ -255,17 +259,19 @@ class AdaptersConfiguratorMixin(object):
"""
iface = self.maybe_dotted(iface)
adapter = self.maybe_dotted(adapter)
+
def register(iface=iface):
if iface is None:
iface = Interface
self.registry.registerAdapter(adapter, (iface,), ITraverser)
+
discriminator = ('traverser', iface)
intr = self.introspectable(
- 'traversers',
+ 'traversers',
discriminator,
'traverser for %r' % iface,
'traverser',
- )
+ )
intr['adapter'] = adapter
intr['iface'] = iface
self.action(discriminator, register, introspectables=(intr,))
@@ -303,24 +309,25 @@ class AdaptersConfiguratorMixin(object):
"""
adapter = self.maybe_dotted(adapter)
resource_iface = self.maybe_dotted(resource_iface)
+
def register(resource_iface=resource_iface):
if resource_iface is None:
resource_iface = Interface
self.registry.registerAdapter(
- adapter,
- (resource_iface, Interface),
- IResourceURL,
- )
+ adapter, (resource_iface, Interface), IResourceURL
+ )
+
discriminator = ('resource url adapter', resource_iface)
intr = self.introspectable(
- 'resource url adapters',
+ 'resource url adapters',
discriminator,
'resource url adapter for resource iface %r' % resource_iface,
'resource url adapter',
- )
+ )
intr['adapter'] = adapter
intr['resource_iface'] = resource_iface
self.action(discriminator, register, introspectables=(intr,))
+
def eventonly(callee):
return takes_one_arg(callee, argname='event')
diff --git a/src/pyramid/config/assets.py b/src/pyramid/config/assets.py
index b9536df42..fd8b2ee49 100644
--- a/src/pyramid/config/assets.py
+++ b/src/pyramid/config/assets.py
@@ -4,16 +4,14 @@ import sys
from zope.interface import implementer
-from pyramid.interfaces import (
- IPackageOverrides,
- PHASE1_CONFIG,
-)
+from pyramid.interfaces import IPackageOverrides, PHASE1_CONFIG
from pyramid.exceptions import ConfigurationError
from pyramid.threadlocal import get_current_registry
from pyramid.config.util import action_method
+
class OverrideProvider(pkg_resources.DefaultProvider):
def __init__(self, module):
pkg_resources.DefaultProvider.__init__(self, module)
@@ -35,7 +33,8 @@ class OverrideProvider(pkg_resources.DefaultProvider):
if filename is not None:
return filename
return pkg_resources.DefaultProvider.get_resource_filename(
- self, manager, resource_name)
+ self, manager, resource_name
+ )
def get_resource_stream(self, manager, resource_name):
""" Return a readable file-like object for resource_name."""
@@ -45,7 +44,8 @@ class OverrideProvider(pkg_resources.DefaultProvider):
if stream is not None:
return stream
return pkg_resources.DefaultProvider.get_resource_stream(
- self, manager, resource_name)
+ self, manager, resource_name
+ )
def get_resource_string(self, manager, resource_name):
""" Return a string containing the contents of resource_name."""
@@ -55,7 +55,8 @@ class OverrideProvider(pkg_resources.DefaultProvider):
if string is not None:
return string
return pkg_resources.DefaultProvider.get_resource_string(
- self, manager, resource_name)
+ self, manager, resource_name
+ )
def has_resource(self, resource_name):
overrides = self._get_overrides()
@@ -63,8 +64,7 @@ class OverrideProvider(pkg_resources.DefaultProvider):
result = overrides.has_resource(resource_name)
if result is not None:
return result
- return pkg_resources.DefaultProvider.has_resource(
- self, resource_name)
+ return pkg_resources.DefaultProvider.has_resource(self, resource_name)
def resource_isdir(self, resource_name):
overrides = self._get_overrides()
@@ -73,7 +73,8 @@ class OverrideProvider(pkg_resources.DefaultProvider):
if result is not None:
return result
return pkg_resources.DefaultProvider.resource_isdir(
- self, resource_name)
+ self, resource_name
+ )
def resource_listdir(self, resource_name):
overrides = self._get_overrides()
@@ -82,7 +83,8 @@ class OverrideProvider(pkg_resources.DefaultProvider):
if result is not None:
return result
return pkg_resources.DefaultProvider.resource_listdir(
- self, resource_name)
+ self, resource_name
+ )
@implementer(IPackageOverrides)
@@ -193,9 +195,10 @@ class DirectoryOverride:
def __call__(self, resource_name):
if resource_name.startswith(self.path):
- new_path = resource_name[self.pathlen:]
+ new_path = resource_name[self.pathlen :]
return self.source, new_path
+
class FileOverride:
def __init__(self, path, source):
self.path = path
@@ -215,6 +218,7 @@ class PackageAssetSource(object):
the empty string, as returned by the ``FileOverride``.
"""
+
def __init__(self, package, prefix):
self.package = package
if hasattr(package, '__name__'):
@@ -262,6 +266,7 @@ class FSAssetSource(object):
An asset source relative to a path in the filesystem.
"""
+
def __init__(self, prefix):
self.prefix = prefix
@@ -305,14 +310,16 @@ class FSAssetSource(object):
class AssetsConfiguratorMixin(object):
- def _override(self, package, path, override_source,
- PackageOverrides=PackageOverrides):
+ def _override(
+ self, package, path, override_source, PackageOverrides=PackageOverrides
+ ):
pkg_name = package.__name__
override = self.registry.queryUtility(IPackageOverrides, name=pkg_name)
if override is None:
override = PackageOverrides(package)
- self.registry.registerUtility(override, IPackageOverrides,
- name=pkg_name)
+ self.registry.registerUtility(
+ override, IPackageOverrides, name=pkg_name
+ )
override.insert(path, override_source)
@action_method
@@ -331,7 +338,8 @@ class AssetsConfiguratorMixin(object):
information about asset overrides."""
if to_override == override_with:
raise ConfigurationError(
- 'You cannot override an asset with itself')
+ 'You cannot override an asset with itself'
+ )
package = to_override
path = ''
@@ -346,7 +354,8 @@ class AssetsConfiguratorMixin(object):
if not os.path.exists(override_with):
raise ConfigurationError(
'Cannot override asset with an absolute path that does '
- 'not exist')
+ 'not exist'
+ )
override_isdir = os.path.isdir(override_with)
override_package = None
override_prefix = override_with
@@ -360,22 +369,23 @@ class AssetsConfiguratorMixin(object):
to_package = sys.modules[override_package]
override_source = PackageAssetSource(to_package, override_prefix)
- override_isdir = (
- override_prefix == '' or
- override_with.endswith('/')
+ override_isdir = override_prefix == '' or override_with.endswith(
+ '/'
)
if overridden_isdir and (not override_isdir):
raise ConfigurationError(
'A directory cannot be overridden with a file (put a '
- 'slash at the end of override_with if necessary)')
+ 'slash at the end of override_with if necessary)'
+ )
if (not overridden_isdir) and override_isdir:
raise ConfigurationError(
'A file cannot be overridden with a directory (put a '
- 'slash at the end of to_override if necessary)')
+ 'slash at the end of to_override if necessary)'
+ )
- override = _override or self._override # test jig
+ override = _override or self._override # test jig
def register():
__import__(package)
@@ -387,10 +397,11 @@ class AssetsConfiguratorMixin(object):
(package, override_package, path, override_prefix),
'%s -> %s' % (to_override, override_with),
'asset override',
- )
+ )
intr['to_override'] = to_override
intr['override_with'] = override_with
- self.action(None, register, introspectables=(intr,),
- order=PHASE1_CONFIG)
+ self.action(
+ None, register, introspectables=(intr,), order=PHASE1_CONFIG
+ )
- override_resource = override_asset # bw compat
+ override_resource = override_asset # bw compat
diff --git a/src/pyramid/config/factories.py b/src/pyramid/config/factories.py
index 52248269d..2ec1558a6 100644
--- a/src/pyramid/config/factories.py
+++ b/src/pyramid/config/factories.py
@@ -8,18 +8,16 @@ from pyramid.interfaces import (
IRequestExtensions,
IRootFactory,
ISessionFactory,
- )
+)
from pyramid.router import default_execution_policy
from pyramid.traversal import DefaultRootFactory
-from pyramid.util import (
- get_callable_name,
- InstancePropertyHelper,
- )
+from pyramid.util import get_callable_name, InstancePropertyHelper
from pyramid.config.util import action_method
+
class FactoriesConfiguratorMixin(object):
@action_method
def set_root_factory(self, factory):
@@ -41,10 +39,12 @@ class FactoriesConfiguratorMixin(object):
self.registry.registerUtility(factory, IRootFactory)
self.registry.registerUtility(factory, IDefaultRootFactory) # b/c
- intr = self.introspectable('root factories',
- None,
- self.object_description(factory),
- 'root factory')
+ intr = self.introspectable(
+ 'root factories',
+ None,
+ self.object_description(factory),
+ 'root factory',
+ )
intr['factory'] = factory
self.action(IRootFactory, register, introspectables=(intr,))
@@ -67,9 +67,13 @@ class FactoriesConfiguratorMixin(object):
def register():
self.registry.registerUtility(factory, ISessionFactory)
- intr = self.introspectable('session factory', None,
- self.object_description(factory),
- 'session factory')
+
+ intr = self.introspectable(
+ 'session factory',
+ None,
+ self.object_description(factory),
+ 'session factory',
+ )
intr['factory'] = factory
self.action(ISessionFactory, register, introspectables=(intr,))
@@ -97,9 +101,13 @@ class FactoriesConfiguratorMixin(object):
def register():
self.registry.registerUtility(factory, IRequestFactory)
- intr = self.introspectable('request factory', None,
- self.object_description(factory),
- 'request factory')
+
+ intr = self.introspectable(
+ 'request factory',
+ None,
+ self.object_description(factory),
+ 'request factory',
+ )
intr['factory'] = factory
self.action(IRequestFactory, register, introspectables=(intr,))
@@ -122,18 +130,19 @@ class FactoriesConfiguratorMixin(object):
def register():
self.registry.registerUtility(factory, IResponseFactory)
- intr = self.introspectable('response factory', None,
- self.object_description(factory),
- 'response factory')
+ intr = self.introspectable(
+ 'response factory',
+ None,
+ self.object_description(factory),
+ 'response factory',
+ )
intr['factory'] = factory
self.action(IResponseFactory, register, introspectables=(intr,))
@action_method
- def add_request_method(self,
- callable=None,
- name=None,
- property=False,
- reify=False):
+ def add_request_method(
+ self, callable=None, name=None, property=False, reify=False
+ ):
""" Add a property or method to the request object.
When adding a method to the request, ``callable`` may be any
@@ -177,7 +186,8 @@ class FactoriesConfiguratorMixin(object):
property = property or reify
if property:
name, callable = InstancePropertyHelper.make_property(
- callable, name=name, reify=reify)
+ callable, name=name, reify=reify
+ )
elif name is None:
name = callable.__name__
else:
@@ -196,23 +206,31 @@ class FactoriesConfiguratorMixin(object):
if callable is None:
self.action(('request extensions', name), None)
elif property:
- intr = self.introspectable('request extensions', name,
- self.object_description(callable),
- 'request property')
+ intr = self.introspectable(
+ 'request extensions',
+ name,
+ self.object_description(callable),
+ 'request property',
+ )
intr['callable'] = callable
intr['property'] = True
intr['reify'] = reify
- self.action(('request extensions', name), register,
- introspectables=(intr,))
+ self.action(
+ ('request extensions', name), register, introspectables=(intr,)
+ )
else:
- intr = self.introspectable('request extensions', name,
- self.object_description(callable),
- 'request method')
+ intr = self.introspectable(
+ 'request extensions',
+ name,
+ self.object_description(callable),
+ 'request method',
+ )
intr['callable'] = callable
intr['property'] = False
intr['reify'] = False
- self.action(('request extensions', name), register,
- introspectables=(intr,))
+ self.action(
+ ('request extensions', name), register, introspectables=(intr,)
+ )
@action_method
def set_execution_policy(self, policy):
@@ -231,9 +249,12 @@ class FactoriesConfiguratorMixin(object):
def register():
self.registry.registerUtility(policy, IExecutionPolicy)
- intr = self.introspectable('execution policy', None,
- self.object_description(policy),
- 'execution policy')
+ intr = self.introspectable(
+ 'execution policy',
+ None,
+ self.object_description(policy),
+ 'execution policy',
+ )
intr['policy'] = policy
self.action(IExecutionPolicy, register, introspectables=(intr,))
diff --git a/src/pyramid/config/i18n.py b/src/pyramid/config/i18n.py
index 5dabe2845..6e7334448 100644
--- a/src/pyramid/config/i18n.py
+++ b/src/pyramid/config/i18n.py
@@ -1,13 +1,11 @@
-from pyramid.interfaces import (
- ILocaleNegotiator,
- ITranslationDirectories,
- )
+from pyramid.interfaces import ILocaleNegotiator, ITranslationDirectories
from pyramid.exceptions import ConfigurationError
from pyramid.path import AssetResolver
from pyramid.config.util import action_method
+
class I18NConfiguratorMixin(object):
@action_method
def set_locale_negotiator(self, negotiator):
@@ -30,11 +28,16 @@ class I18NConfiguratorMixin(object):
:class:`pyramid.config.Configurator` constructor can be used to
achieve the same purpose.
"""
+
def register():
self._set_locale_negotiator(negotiator)
- intr = self.introspectable('locale negotiator', None,
- self.object_description(negotiator),
- 'locale negotiator')
+
+ intr = self.introspectable(
+ 'locale negotiator',
+ None,
+ self.object_description(negotiator),
+ 'locale negotiator',
+ )
intr['negotiator'] = negotiator
self.action(ILocaleNegotiator, register, introspectables=(intr,))
@@ -97,10 +100,15 @@ class I18NConfiguratorMixin(object):
asset = resolver.resolve(spec)
directory = asset.abspath()
if not asset.isdir():
- raise ConfigurationError('"%s" is not a directory' %
- directory)
- intr = self.introspectable('translation directories', directory,
- spec, 'translation directory')
+ raise ConfigurationError(
+ '"%s" is not a directory' % directory
+ )
+ intr = self.introspectable(
+ 'translation directories',
+ directory,
+ spec,
+ 'translation directory',
+ )
intr['directory'] = directory
intr['spec'] = spec
introspectables.append(intr)
@@ -117,4 +125,3 @@ class I18NConfiguratorMixin(object):
tdirs.insert(0, directory)
self.action(None, register, introspectables=introspectables)
-
diff --git a/src/pyramid/config/predicates.py b/src/pyramid/config/predicates.py
index bda763161..cdbf68ca4 100644
--- a/src/pyramid/config/predicates.py
+++ b/src/pyramid/config/predicates.py
@@ -1,2 +1,3 @@
import zope.deprecation
+
zope.deprecation.moved('pyramid.predicates', 'Pyramid 1.10')
diff --git a/src/pyramid/config/rendering.py b/src/pyramid/config/rendering.py
index 0d55c41e8..948199636 100644
--- a/src/pyramid/config/rendering.py
+++ b/src/pyramid/config/rendering.py
@@ -1,7 +1,4 @@
-from pyramid.interfaces import (
- IRendererFactory,
- PHASE1_CONFIG,
- )
+from pyramid.interfaces import IRendererFactory, PHASE1_CONFIG
from pyramid import renderers
from pyramid.config.util import action_method
@@ -9,13 +6,14 @@ from pyramid.config.util import action_method
DEFAULT_RENDERERS = (
('json', renderers.json_renderer_factory),
('string', renderers.string_renderer_factory),
- )
+)
+
class RenderingConfiguratorMixin(object):
def add_default_renderers(self):
for name, renderer in DEFAULT_RENDERERS:
self.add_renderer(name, renderer)
-
+
@action_method
def add_renderer(self, name, factory):
"""
@@ -36,16 +34,23 @@ class RenderingConfiguratorMixin(object):
# as a name
if not name:
name = ''
+
def register():
self.registry.registerUtility(factory, IRendererFactory, name=name)
- intr = self.introspectable('renderer factories',
- name,
- self.object_description(factory),
- 'renderer factory')
+
+ intr = self.introspectable(
+ 'renderer factories',
+ name,
+ self.object_description(factory),
+ 'renderer factory',
+ )
intr['factory'] = factory
intr['name'] = name
# we need to register renderers early (in phase 1) because they are
# used during view configuration (which happens in phase 3)
- self.action((IRendererFactory, name), register, order=PHASE1_CONFIG,
- introspectables=(intr,))
-
+ self.action(
+ (IRendererFactory, name),
+ register,
+ order=PHASE1_CONFIG,
+ introspectables=(intr,),
+ )
diff --git a/src/pyramid/config/routes.py b/src/pyramid/config/routes.py
index 5d05429a7..4e1cb0762 100644
--- a/src/pyramid/config/routes.py
+++ b/src/pyramid/config/routes.py
@@ -7,16 +7,13 @@ from pyramid.interfaces import (
IRouteRequest,
IRoutesMapper,
PHASE2_CONFIG,
- )
+)
from pyramid.exceptions import ConfigurationError
from pyramid.request import route_request_iface
from pyramid.urldispatch import RoutesMapper
-from pyramid.util import (
- as_sorted_tuple,
- is_nonstr_iter,
-)
+from pyramid.util import as_sorted_tuple, is_nonstr_iter
import pyramid.predicates
@@ -26,26 +23,29 @@ from pyramid.config.util import (
predvalseq,
)
+
class RoutesConfiguratorMixin(object):
@action_method
- def add_route(self,
- name,
- pattern=None,
- factory=None,
- for_=None,
- header=None,
- xhr=None,
- accept=None,
- path_info=None,
- request_method=None,
- request_param=None,
- traverse=None,
- custom_predicates=(),
- use_global_views=False,
- path=None,
- pregenerator=None,
- static=False,
- **predicates):
+ def add_route(
+ self,
+ name,
+ pattern=None,
+ factory=None,
+ for_=None,
+ header=None,
+ xhr=None,
+ accept=None,
+ path_info=None,
+ request_method=None,
+ request_param=None,
+ traverse=None,
+ custom_predicates=(),
+ use_global_views=False,
+ path=None,
+ pregenerator=None,
+ static=False,
+ **predicates
+ ):
""" Add a :term:`route configuration` to the current
configuration state, as well as possibly a :term:`view
configuration` to be used to specify a :term:`view callable`
@@ -158,8 +158,8 @@ class RoutesConfiguratorMixin(object):
For backwards compatibility purposes (as of :app:`Pyramid` 1.0), a
``path`` keyword argument passed to this function will be used to
represent the pattern value if the ``pattern`` argument is
- ``None``. If both ``path`` and ``pattern`` are passed, ``pattern``
- wins.
+ ``None``. If both ``path`` and ``pattern`` are passed,
+ ``pattern`` wins.
xhr
@@ -297,27 +297,31 @@ class RoutesConfiguratorMixin(object):
"""
if custom_predicates:
warnings.warn(
- ('The "custom_predicates" argument to Configurator.add_route '
- 'is deprecated as of Pyramid 1.5. Use '
- '"config.add_route_predicate" and use the registered '
- 'route predicate as a predicate argument to add_route '
- 'instead. See "Adding A Third Party View, Route, or '
- 'Subscriber Predicate" in the "Hooks" chapter of the '
- 'documentation for more information.'),
+ (
+ 'The "custom_predicates" argument to '
+ 'Configurator.add_route is deprecated as of Pyramid 1.5. '
+ 'Use "config.add_route_predicate" and use the registered '
+ 'route predicate as a predicate argument to add_route '
+ 'instead. See "Adding A Third Party View, Route, or '
+ 'Subscriber Predicate" in the "Hooks" chapter of the '
+ 'documentation for more information.'
+ ),
DeprecationWarning,
- stacklevel=3
- )
+ stacklevel=3,
+ )
if accept is not None:
if not is_nonstr_iter(accept):
if '*' in accept:
warnings.warn(
- ('Passing a media range to the "accept" argument of '
- 'Configurator.add_route is deprecated as of Pyramid '
- '1.10. Use a list of explicit media types.'),
+ (
+ 'Passing a media range to the "accept" argument '
+ 'of Configurator.add_route is deprecated as of '
+ 'Pyramid 1.10. Use a list of explicit media types.'
+ ),
DeprecationWarning,
stacklevel=3,
- )
+ )
# XXX switch this to False when range support is dropped
accept = [normalize_accept_offer(accept, allow_range=True)]
@@ -347,15 +351,16 @@ class RoutesConfiguratorMixin(object):
pattern = parsed.path
original_pregenerator = pregenerator
+
def external_url_pregenerator(request, elements, kw):
if '_app_url' in kw:
raise ValueError(
'You cannot generate a path to an external route '
'pattern via request.route_path nor pass an _app_url '
'to request.route_url when generating a URL for an '
- 'external route pattern (pattern was "%s") ' %
- (pattern,)
- )
+ 'external route pattern (pattern was "%s") '
+ % (pattern,)
+ )
if '_scheme' in kw:
scheme = kw['_scheme']
elif parsed.scheme:
@@ -365,8 +370,7 @@ class RoutesConfiguratorMixin(object):
kw['_app_url'] = '{0}://{1}'.format(scheme, parsed.netloc)
if original_pregenerator:
- elements, kw = original_pregenerator(
- request, elements, kw)
+ elements, kw = original_pregenerator(request, elements, kw)
return elements, kw
pregenerator = external_url_pregenerator
@@ -379,10 +383,9 @@ class RoutesConfiguratorMixin(object):
introspectables = []
- intr = self.introspectable('routes',
- name,
- '%s (pattern: %r)' % (name, pattern),
- 'route')
+ intr = self.introspectable(
+ 'routes', name, '%s (pattern: %r)' % (name, pattern), 'route'
+ )
intr['name'] = name
intr['pattern'] = pattern
intr['factory'] = factory
@@ -404,17 +407,21 @@ class RoutesConfiguratorMixin(object):
introspectables.append(intr)
if factory:
- factory_intr = self.introspectable('root factories',
- name,
- self.object_description(factory),
- 'root factory')
+ factory_intr = self.introspectable(
+ 'root factories',
+ name,
+ self.object_description(factory),
+ 'root factory',
+ )
factory_intr['factory'] = factory
factory_intr['route_name'] = name
factory_intr.relate('routes', name)
introspectables.append(factory_intr)
def register_route_request_iface():
- request_iface = self.registry.queryUtility(IRouteRequest, name=name)
+ request_iface = self.registry.queryUtility(
+ IRouteRequest, name=name
+ )
if request_iface is None:
if use_global_views:
bases = (IRequest,)
@@ -422,7 +429,8 @@ class RoutesConfiguratorMixin(object):
bases = ()
request_iface = route_request_iface(name, bases)
self.registry.registerUtility(
- request_iface, IRouteRequest, name=name)
+ request_iface, IRouteRequest, name=name
+ )
def register_connect():
pvals = predicates.copy()
@@ -436,15 +444,19 @@ class RoutesConfiguratorMixin(object):
accept=accept,
traverse=traverse,
custom=predvalseq(custom_predicates),
- )
)
+ )
predlist = self.get_predlist('route')
_, preds, _ = predlist.make(self, **pvals)
route = mapper.connect(
- name, pattern, factory, predicates=preds,
- pregenerator=pregenerator, static=static
- )
+ name,
+ pattern,
+ factory,
+ predicates=preds,
+ pregenerator=pregenerator,
+ static=static,
+ )
intr['object'] = route
return route
@@ -455,12 +467,17 @@ class RoutesConfiguratorMixin(object):
# But IRouteRequest interfaces must be registered before we begin to
# process view registrations (in phase 3)
- self.action(('route', name), register_route_request_iface,
- order=PHASE2_CONFIG, introspectables=introspectables)
+ self.action(
+ ('route', name),
+ register_route_request_iface,
+ order=PHASE2_CONFIG,
+ introspectables=introspectables,
+ )
@action_method
- def add_route_predicate(self, name, factory, weighs_more_than=None,
- weighs_less_than=None):
+ def add_route_predicate(
+ self, name, factory, weighs_more_than=None, weighs_less_than=None
+ ):
""" Adds a route predicate factory. The view predicate can later be
named as a keyword argument to
:meth:`pyramid.config.Configurator.add_route`.
@@ -481,8 +498,8 @@ class RoutesConfiguratorMixin(object):
name,
factory,
weighs_more_than=weighs_more_than,
- weighs_less_than=weighs_less_than
- )
+ weighs_less_than=weighs_less_than,
+ )
def add_default_route_predicates(self):
p = pyramid.predicates
@@ -496,7 +513,7 @@ class RoutesConfiguratorMixin(object):
('effective_principals', p.EffectivePrincipalsPredicate),
('custom', p.CustomPredicate),
('traverse', p.TraversePredicate),
- ):
+ ):
self.add_route_predicate(name, factory)
def get_routes_mapper(self):
@@ -541,8 +558,7 @@ class RoutesConfiguratorMixin(object):
old_route_prefix = ''
route_prefix = '{}/{}'.format(
- old_route_prefix.rstrip('/'),
- route_prefix.lstrip('/'),
+ old_route_prefix.rstrip('/'), route_prefix.lstrip('/')
)
route_prefix = route_prefix.strip('/')
diff --git a/src/pyramid/config/security.py b/src/pyramid/config/security.py
index c7afbcf4e..3b55c41d7 100644
--- a/src/pyramid/config/security.py
+++ b/src/pyramid/config/security.py
@@ -8,7 +8,7 @@ from pyramid.interfaces import (
IDefaultPermission,
PHASE1_CONFIG,
PHASE2_CONFIG,
- )
+)
from pyramid.csrf import LegacySessionCSRFStoragePolicy
from pyramid.exceptions import ConfigurationError
@@ -16,8 +16,8 @@ from pyramid.util import as_sorted_tuple
from pyramid.config.util import action_method
-class SecurityConfiguratorMixin(object):
+class SecurityConfiguratorMixin(object):
def add_default_security(self):
self.set_csrf_storage_policy(LegacySessionCSRFStoragePolicy())
@@ -35,20 +35,30 @@ class SecurityConfiguratorMixin(object):
achieve the same purpose.
"""
+
def register():
self._set_authentication_policy(policy)
if self.registry.queryUtility(IAuthorizationPolicy) is None:
raise ConfigurationError(
'Cannot configure an authentication policy without '
'also configuring an authorization policy '
- '(use the set_authorization_policy method)')
- intr = self.introspectable('authentication policy', None,
- self.object_description(policy),
- 'authentication policy')
+ '(use the set_authorization_policy method)'
+ )
+
+ intr = self.introspectable(
+ 'authentication policy',
+ None,
+ self.object_description(policy),
+ 'authentication policy',
+ )
intr['policy'] = policy
# authentication policy used by view config (phase 3)
- self.action(IAuthenticationPolicy, register, order=PHASE2_CONFIG,
- introspectables=(intr,))
+ self.action(
+ IAuthenticationPolicy,
+ register,
+ order=PHASE2_CONFIG,
+ introspectables=(intr,),
+ )
def _set_authentication_policy(self, policy):
policy = self.maybe_dotted(policy)
@@ -67,8 +77,10 @@ class SecurityConfiguratorMixin(object):
:class:`pyramid.config.Configurator` constructor can be used to
achieve the same purpose.
"""
+
def register():
self._set_authorization_policy(policy)
+
def ensure():
if self.autocommit:
return
@@ -76,16 +88,24 @@ class SecurityConfiguratorMixin(object):
raise ConfigurationError(
'Cannot configure an authorization policy without '
'also configuring an authentication policy '
- '(use the set_authorization_policy method)')
+ '(use the set_authorization_policy method)'
+ )
- intr = self.introspectable('authorization policy', None,
- self.object_description(policy),
- 'authorization policy')
+ intr = self.introspectable(
+ 'authorization policy',
+ None,
+ self.object_description(policy),
+ 'authorization policy',
+ )
intr['policy'] = policy
# authorization policy used by view config (phase 3) and
# authentication policy (phase 2)
- self.action(IAuthorizationPolicy, register, order=PHASE1_CONFIG,
- introspectables=(intr,))
+ self.action(
+ IAuthorizationPolicy,
+ register,
+ order=PHASE1_CONFIG,
+ introspectables=(intr,),
+ )
self.action(None, ensure)
def _set_authorization_policy(self, policy):
@@ -133,21 +153,25 @@ class SecurityConfiguratorMixin(object):
:class:`pyramid.config.Configurator` constructor can be used to
achieve the same purpose.
"""
+
def register():
self.registry.registerUtility(permission, IDefaultPermission)
- intr = self.introspectable('default permission',
- None,
- permission,
- 'default permission')
+
+ intr = self.introspectable(
+ 'default permission', None, permission, 'default permission'
+ )
intr['value'] = permission
- perm_intr = self.introspectable('permissions',
- permission,
- permission,
- 'permission')
+ perm_intr = self.introspectable(
+ 'permissions', permission, permission, 'permission'
+ )
perm_intr['value'] = permission
# default permission used during view registration (phase 3)
- self.action(IDefaultPermission, register, order=PHASE1_CONFIG,
- introspectables=(intr, perm_intr,))
+ self.action(
+ IDefaultPermission,
+ register,
+ order=PHASE1_CONFIG,
+ introspectables=(intr, perm_intr),
+ )
def add_permission(self, permission_name):
"""
@@ -161,11 +185,8 @@ class SecurityConfiguratorMixin(object):
config.add_permission('view')
"""
intr = self.introspectable(
- 'permissions',
- permission_name,
- permission_name,
- 'permission'
- )
+ 'permissions', permission_name, permission_name, 'permission'
+ )
intr['value'] = permission_name
self.action(None, introspectables=(intr,))
@@ -217,22 +238,30 @@ class SecurityConfiguratorMixin(object):
"""
options = DefaultCSRFOptions(
- require_csrf, token, header, safe_methods, callback,
+ require_csrf, token, header, safe_methods, callback
)
+
def register():
self.registry.registerUtility(options, IDefaultCSRFOptions)
- intr = self.introspectable('default csrf view options',
- None,
- options,
- 'default csrf view options')
+
+ intr = self.introspectable(
+ 'default csrf view options',
+ None,
+ options,
+ 'default csrf view options',
+ )
intr['require_csrf'] = require_csrf
intr['token'] = token
intr['header'] = header
intr['safe_methods'] = as_sorted_tuple(safe_methods)
intr['callback'] = callback
- self.action(IDefaultCSRFOptions, register, order=PHASE1_CONFIG,
- introspectables=(intr,))
+ self.action(
+ IDefaultCSRFOptions,
+ register,
+ order=PHASE1_CONFIG,
+ introspectables=(intr,),
+ )
@action_method
def set_csrf_storage_policy(self, policy):
@@ -245,12 +274,13 @@ class SecurityConfiguratorMixin(object):
how to generate and persist CSRF tokens.
"""
+
def register():
self.registry.registerUtility(policy, ICSRFStoragePolicy)
- intr = self.introspectable('csrf storage policy',
- None,
- policy,
- 'csrf storage policy')
+
+ intr = self.introspectable(
+ 'csrf storage policy', None, policy, 'csrf storage policy'
+ )
intr['policy'] = policy
self.action(ICSRFStoragePolicy, register, introspectables=(intr,))
diff --git a/src/pyramid/config/settings.py b/src/pyramid/config/settings.py
index 11a1f7d8c..07b469c29 100644
--- a/src/pyramid/config/settings.py
+++ b/src/pyramid/config/settings.py
@@ -2,6 +2,7 @@ import os
from pyramid.settings import asbool, aslist
+
class SettingsConfiguratorMixin(object):
def _set_settings(self, mapping):
if mapping is None:
@@ -60,11 +61,13 @@ def Settings(d=None, _environ_=os.environ, **kw):
d.update(**kw)
eget = _environ_.get
+
def expand_key(key):
keys = [key]
if not key.startswith('pyramid.'):
keys.append('pyramid.' + key)
return keys
+
def S(settings_key, env_key=None, type_=str, default=False):
value = default
keys = expand_key(settings_key)
@@ -74,6 +77,7 @@ def Settings(d=None, _environ_=os.environ, **kw):
value = eget(env_key, value)
value = type_(value)
d.update({k: value for k in keys})
+
def O(settings_key, override_key): # noqa: E743
for key in expand_key(settings_key):
d[key] = d[key] or d[override_key]
diff --git a/src/pyramid/config/testing.py b/src/pyramid/config/testing.py
index 1daf5cdeb..1655df52c 100644
--- a/src/pyramid/config/testing.py
+++ b/src/pyramid/config/testing.py
@@ -5,22 +5,25 @@ from pyramid.interfaces import (
IAuthorizationPolicy,
IAuthenticationPolicy,
IRendererFactory,
- )
+)
from pyramid.renderers import RendererHelper
-from pyramid.traversal import (
- decode_path_info,
- split_path_info,
- )
+from pyramid.traversal import decode_path_info, split_path_info
from pyramid.config.util import action_method
+
class TestingConfiguratorMixin(object):
# testing API
- def testing_securitypolicy(self, userid=None, groupids=(),
- permissive=True, remember_result=None,
- forget_result=None):
+ def testing_securitypolicy(
+ self,
+ userid=None,
+ groupids=(),
+ permissive=True,
+ remember_result=None,
+ forget_result=None,
+ ):
"""Unit/integration testing helper: Registers a pair of faux
:app:`Pyramid` security policies: a :term:`authentication
policy` and a :term:`authorization policy`.
@@ -64,9 +67,10 @@ class TestingConfiguratorMixin(object):
The ``forget_result`` argument.
"""
from pyramid.testing import DummySecurityPolicy
+
policy = DummySecurityPolicy(
userid, groupids, permissive, remember_result, forget_result
- )
+ )
self.registry.registerUtility(policy, IAuthorizationPolicy)
self.registry.registerUtility(policy, IAuthenticationPolicy)
return policy
@@ -85,6 +89,7 @@ class TestingConfiguratorMixin(object):
:func:`pyramid.traversal.find_resource` is called with an
equivalent path string or tuple.
"""
+
class DummyTraverserFactory:
def __init__(self, context):
self.context = context
@@ -93,14 +98,22 @@ class TestingConfiguratorMixin(object):
path = decode_path_info(request.environ['PATH_INFO'])
ob = resources[path]
traversed = split_path_info(path)
- return {'context':ob, 'view_name':'','subpath':(),
- 'traversed':traversed, 'virtual_root':ob,
- 'virtual_root_path':(), 'root':ob}
- self.registry.registerAdapter(DummyTraverserFactory, (Interface,),
- ITraverser)
+ return {
+ 'context': ob,
+ 'view_name': '',
+ 'subpath': (),
+ 'traversed': traversed,
+ 'virtual_root': ob,
+ 'virtual_root_path': (),
+ 'root': ob,
+ }
+
+ self.registry.registerAdapter(
+ DummyTraverserFactory, (Interface,), ITraverser
+ )
return resources
- testing_models = testing_resources # b/w compat
+ testing_models = testing_resources # b/w compat
@action_method
def testing_add_subscriber(self, event_iface=None):
@@ -122,8 +135,10 @@ class TestingConfiguratorMixin(object):
"""
event_iface = self.maybe_dotted(event_iface)
L = []
+
def subscriber(*event):
L.extend(event)
+
self.add_subscriber(subscriber, event_iface)
return L
@@ -149,19 +164,22 @@ class TestingConfiguratorMixin(object):
"""
from pyramid.testing import DummyRendererFactory
+
helper = RendererHelper(name=path, registry=self.registry)
- factory = self.registry.queryUtility(IRendererFactory, name=helper.type)
+ factory = self.registry.queryUtility(
+ IRendererFactory, name=helper.type
+ )
if not isinstance(factory, DummyRendererFactory):
factory = DummyRendererFactory(helper.type, factory)
- self.registry.registerUtility(factory, IRendererFactory,
- name=helper.type)
+ self.registry.registerUtility(
+ factory, IRendererFactory, name=helper.type
+ )
from pyramid.testing import DummyTemplateRenderer
+
if renderer is None:
renderer = DummyTemplateRenderer()
factory.add(path, renderer)
return renderer
testing_add_template = testing_add_renderer
-
-
diff --git a/src/pyramid/config/tweens.py b/src/pyramid/config/tweens.py
index 8bf21cf71..b74a57adf 100644
--- a/src/pyramid/config/tweens.py
+++ b/src/pyramid/config/tweens.py
@@ -2,26 +2,17 @@ from zope.interface import implementer
from pyramid.interfaces import ITweens
-from pyramid.compat import (
- string_types,
- is_nonstr_iter,
- )
+from pyramid.compat import string_types, is_nonstr_iter
from pyramid.exceptions import ConfigurationError
-from pyramid.tweens import (
- MAIN,
- INGRESS,
- EXCVIEW,
- )
+from pyramid.tweens import MAIN, INGRESS, EXCVIEW
-from pyramid.util import (
- is_string_or_iterable,
- TopologicalSorter,
- )
+from pyramid.util import is_string_or_iterable, TopologicalSorter
from pyramid.config.util import action_method
+
class TweensConfiguratorMixin(object):
def add_tween(self, tween_factory, under=None, over=None):
"""
@@ -65,7 +56,7 @@ class TweensConfiguratorMixin(object):
- An iterable of any combination of the above. This allows the user
to specify fallbacks if the desired tween is not included, as well
as compatibility with multiple other tweens.
-
+
``under`` means 'closer to the main Pyramid application than',
``over`` means 'closer to the request ingress than'.
@@ -104,8 +95,9 @@ class TweensConfiguratorMixin(object):
For more information, see :ref:`registering_tweens`.
"""
- return self._add_tween(tween_factory, under=under, over=over,
- explicit=False)
+ return self._add_tween(
+ tween_factory, under=under, over=over, explicit=False
+ )
def add_default_tweens(self):
self.add_tween(EXCVIEW)
@@ -116,8 +108,9 @@ class TweensConfiguratorMixin(object):
if not isinstance(tween_factory, string_types):
raise ConfigurationError(
'The "tween_factory" argument to add_tween must be a '
- 'dotted name to a globally importable object, not %r' %
- tween_factory)
+ 'dotted name to a globally importable object, not %r'
+ % tween_factory
+ )
name = tween_factory
@@ -130,7 +123,8 @@ class TweensConfiguratorMixin(object):
if p is not None:
if not is_string_or_iterable(p):
raise ConfigurationError(
- '"%s" must be a string or iterable, not %s' % (t, p))
+ '"%s" must be a string or iterable, not %s' % (t, p)
+ )
if over is INGRESS or is_nonstr_iter(over) and INGRESS in over:
raise ConfigurationError('%s cannot be over INGRESS' % name)
@@ -150,15 +144,16 @@ class TweensConfiguratorMixin(object):
if explicit:
tweens.add_explicit(name, tween_factory)
else:
- tweens.add_implicit(name, tween_factory, under=under, over=over)
+ tweens.add_implicit(
+ name, tween_factory, under=under, over=over
+ )
discriminator = ('tween', name, explicit)
tween_type = explicit and 'explicit' or 'implicit'
- intr = self.introspectable('tweens',
- discriminator,
- name,
- '%s tween' % tween_type)
+ intr = self.introspectable(
+ 'tweens', discriminator, name, '%s tween' % tween_type
+ )
intr['name'] = name
intr['factory'] = tween_factory
intr['type'] = tween_type
@@ -167,6 +162,7 @@ class TweensConfiguratorMixin(object):
introspectables.append(intr)
self.action(discriminator, register, introspectables=introspectables)
+
@implementer(ITweens)
class Tweens(object):
def __init__(self):
@@ -174,7 +170,8 @@ class Tweens(object):
default_before=None,
default_after=INGRESS,
first=INGRESS,
- last=MAIN)
+ last=MAIN,
+ )
self.explicit = []
def add_explicit(self, name, factory):
diff --git a/src/pyramid/config/util.py b/src/pyramid/config/util.py
index 05d810f6f..8723b7721 100644
--- a/src/pyramid/config/util.py
+++ b/src/pyramid/config/util.py
@@ -4,23 +4,18 @@ import traceback
from webob.acceptparse import Accept
from zope.interface import implementer
-from pyramid.compat import (
- bytes_,
- is_nonstr_iter
-)
+from pyramid.compat import bytes_, is_nonstr_iter
from pyramid.interfaces import IActionInfo
from pyramid.exceptions import ConfigurationError
from pyramid.predicates import Notted
from pyramid.registry import predvalseq
-from pyramid.util import (
- TopologicalSorter,
- takes_one_arg,
-)
+from pyramid.util import TopologicalSorter, takes_one_arg
TopologicalSorter = TopologicalSorter # support bw-compat imports
takes_one_arg = takes_one_arg # support bw-compat imports
+
@implementer(IActionInfo)
class ActionInfo(object):
def __init__(self, file, line, function, src):
@@ -34,10 +29,12 @@ class ActionInfo(object):
src = '\n'.join(' %s' % x for x in srclines)
return 'Line %s of file %s:\n%s' % (self.line, self.file, src)
+
def action_method(wrapped):
""" Wrapper to provide the right conflict info report data when a method
that calls Configurator.action calls another that does the same. Not a
documented API but used by some external systems."""
+
def wrapper(self, *arg, **kw):
if self._ainfo is None:
self._ainfo = []
@@ -55,10 +52,10 @@ def action_method(wrapped):
# extra stack frame. This should no longer be necessary in
# Python 3.5.1
last_frame = ActionInfo(*f[-1])
- if last_frame.function == 'extract_stack': # pragma: no cover
+ if last_frame.function == 'extract_stack': # pragma: no cover
f.pop()
info = ActionInfo(*f[-backframes])
- except Exception: # pragma: no cover
+ except Exception: # pragma: no cover
info = ActionInfo(None, 0, '', '')
self._ainfo.append(info)
try:
@@ -112,6 +109,7 @@ class not_(object):
.. versionadded:: 1.5
"""
+
def __init__(self, value):
self.value = value
@@ -119,8 +117,8 @@ class not_(object):
# under = after
# over = before
-class PredicateList(object):
+class PredicateList(object):
def __init__(self):
self.sorter = TopologicalSorter()
self.last_added = None
@@ -128,16 +126,13 @@ class PredicateList(object):
def add(self, name, factory, weighs_more_than=None, weighs_less_than=None):
# Predicates should be added to a predicate list in (presumed)
# computation expense order.
- ## if weighs_more_than is None and weighs_less_than is None:
- ## weighs_more_than = self.last_added or FIRST
- ## weighs_less_than = LAST
+ # if weighs_more_than is None and weighs_less_than is None:
+ # weighs_more_than = self.last_added or FIRST
+ # weighs_less_than = LAST
self.last_added = name
self.sorter.add(
- name,
- factory,
- after=weighs_more_than,
- before=weighs_less_than,
- )
+ name, factory, after=weighs_more_than, before=weighs_less_than
+ )
def names(self):
# Return the list of valid predicate names.
@@ -161,7 +156,7 @@ class PredicateList(object):
preds = []
for n, (name, predicate_factory) in enumerate(ordered):
vals = kw.pop(name, None)
- if vals is None: # XXX should this be a sentinel other than None?
+ if vals is None: # XXX should this be a sentinel other than None?
continue
if not isinstance(vals, predvalseq):
vals = (vals,)
@@ -183,8 +178,9 @@ class PredicateList(object):
preds.append(pred)
if kw:
from difflib import get_close_matches
+
closest = []
- names = [ name for name, _ in ordered ]
+ names = [name for name, _ in ordered]
for name in kw:
closest.extend(get_close_matches(name, names, 3))
@@ -266,8 +262,7 @@ def sort_accept_offers(offers, order=None):
parsed = Accept.parse_offer(value)
type_w = find_order_index(
- parsed.type + '/' + parsed.subtype,
- max_weight,
+ parsed.type + '/' + parsed.subtype, max_weight
)
if parsed.params:
diff --git a/src/pyramid/config/views.py b/src/pyramid/config/views.py
index e6baa7c17..cc5b48ecb 100644
--- a/src/pyramid/config/views.py
+++ b/src/pyramid/config/views.py
@@ -6,11 +6,7 @@ import os
import warnings
from webob.acceptparse import Accept
-from zope.interface import (
- Interface,
- implementedBy,
- implementer,
- )
+from zope.interface import Interface, implementedBy, implementer
from zope.interface.interfaces import IInterface
from pyramid.interfaces import (
@@ -31,7 +27,7 @@ from pyramid.interfaces import (
IViewDeriverInfo,
IViewMapperFactory,
PHASE1_CONFIG,
- )
+)
from pyramid import renderers
@@ -42,20 +38,17 @@ from pyramid.compat import (
url_quote,
WIN,
is_nonstr_iter,
- )
+)
from pyramid.decorator import reify
-from pyramid.exceptions import (
- ConfigurationError,
- PredicateMismatch,
- )
+from pyramid.exceptions import ConfigurationError, PredicateMismatch
from pyramid.httpexceptions import (
HTTPForbidden,
HTTPNotFound,
default_exceptionresponse_view,
- )
+)
from pyramid.registry import Deferred
@@ -66,10 +59,7 @@ from pyramid.url import parse_url_overrides
from pyramid.view import AppendSlashNotFoundViewFactory
-from pyramid.util import (
- as_sorted_tuple,
- TopologicalSorter,
- )
+from pyramid.util import as_sorted_tuple, TopologicalSorter
import pyramid.predicates
import pyramid.viewderivers
@@ -91,19 +81,19 @@ from pyramid.config.util import (
normalize_accept_offer,
predvalseq,
sort_accept_offers,
- )
+)
urljoin = urlparse.urljoin
url_parse = urlparse.urlparse
-DefaultViewMapper = DefaultViewMapper # bw-compat
-preserve_view_attrs = preserve_view_attrs # bw-compat
-requestonly = requestonly # bw-compat
-view_description = view_description # bw-compat
+DefaultViewMapper = DefaultViewMapper # bw-compat
+preserve_view_attrs = preserve_view_attrs # bw-compat
+requestonly = requestonly # bw-compat
+view_description = view_description # bw-compat
+
@implementer(IMultiView)
class MultiView(object):
-
def __init__(self, name):
self.name = name
self.media_views = {}
@@ -181,21 +171,22 @@ class MultiView(object):
continue
raise PredicateMismatch(self.name)
+
def attr_wrapped_view(view, info):
- accept, order, phash = (info.options.get('accept', None),
- getattr(info, 'order', MAX_ORDER),
- getattr(info, 'phash', DEFAULT_PHASH))
+ accept, order, phash = (
+ info.options.get('accept', None),
+ getattr(info, 'order', MAX_ORDER),
+ getattr(info, 'phash', DEFAULT_PHASH),
+ )
# this is a little silly but we don't want to decorate the original
# function with attributes that indicate accept, order, and phash,
# so we use a wrapper
- if (
- (accept is None) and
- (order == MAX_ORDER) and
- (phash == DEFAULT_PHASH)
- ):
- return view # defaults
+ if (accept is None) and (order == MAX_ORDER) and (phash == DEFAULT_PHASH):
+ return view # defaults
+
def attr_view(context, request):
return view(context, request)
+
attr_view.__accept__ = accept
attr_view.__order__ = order
attr_view.__phash__ = phash
@@ -203,31 +194,38 @@ def attr_wrapped_view(view, info):
attr_view.__permission__ = info.options.get('permission')
return attr_view
+
attr_wrapped_view.options = ('accept', 'attr', 'permission')
+
def predicated_view(view, info):
preds = info.predicates
if not preds:
return view
+
def predicate_wrapper(context, request):
for predicate in preds:
if not predicate(context, request):
view_name = getattr(view, '__name__', view)
raise PredicateMismatch(
- 'predicate mismatch for view %s (%s)' % (
- view_name, predicate.text()))
+ 'predicate mismatch for view %s (%s)'
+ % (view_name, predicate.text())
+ )
return view(context, request)
+
def checker(context, request):
- return all((predicate(context, request) for predicate in
- preds))
+ return all((predicate(context, request) for predicate in preds))
+
predicate_wrapper.__predicated__ = checker
predicate_wrapper.__predicates__ = preds
return predicate_wrapper
+
def viewdefaults(wrapped):
""" Decorator for add_view-like methods which takes into account
__view_defaults__ attached to view it is passed. Not a documented API but
used by some external systems."""
+
def wrapper(self, *arg, **kw):
defaults = {}
if arg:
@@ -238,19 +236,23 @@ def viewdefaults(wrapped):
if inspect.isclass(view):
defaults = getattr(view, '__view_defaults__', {}).copy()
if '_backframes' not in kw:
- kw['_backframes'] = 1 # for action_method
+ kw['_backframes'] = 1 # for action_method
defaults.update(kw)
return wrapped(self, *arg, **defaults)
+
return functools.wraps(wrapped)(wrapper)
+
def combine_decorators(*decorators):
def decorated(view_callable):
# reversed() allows a more natural ordering in the api
for decorator in reversed(decorators):
view_callable = decorator(view_callable)
return view_callable
+
return decorated
+
class ViewsConfiguratorMixin(object):
@viewdefaults
@action_method
@@ -281,7 +283,8 @@ class ViewsConfiguratorMixin(object):
check_csrf=None,
require_csrf=None,
exception_only=False,
- **view_options):
+ **view_options
+ ):
""" Add a :term:`view configuration` to the current
configuration state. Arguments to ``add_view`` are broken
down below into *predicate* arguments and *non-predicate*
@@ -725,8 +728,8 @@ class ViewsConfiguratorMixin(object):
If CSRF checking is performed, the checked value will be the value of
``request.params[check_name]``. This value will be compared against
the value of ``policy.get_csrf_token()`` (where ``policy`` is an
- implementation of :meth:`pyramid.interfaces.ICSRFStoragePolicy`), and the
- check will pass if these two values are the same. If the check
+ implementation of :meth:`pyramid.interfaces.ICSRFStoragePolicy`), and
+ the check will pass if these two values are the same. If the check
passes, the associated view will be permitted to execute. If the
check fails, the associated view will not be permitted to execute.
@@ -804,42 +807,49 @@ class ViewsConfiguratorMixin(object):
"""
if custom_predicates:
warnings.warn(
- ('The "custom_predicates" argument to Configurator.add_view '
- 'is deprecated as of Pyramid 1.5. Use '
- '"config.add_view_predicate" and use the registered '
- 'view predicate as a predicate argument to add_view instead. '
- 'See "Adding A Third Party View, Route, or Subscriber '
- 'Predicate" in the "Hooks" chapter of the documentation '
- 'for more information.'),
+ (
+ 'The "custom_predicates" argument to '
+ 'Configurator.add_view is deprecated as of Pyramid 1.5. '
+ 'Use "config.add_view_predicate" and use the registered '
+ 'view predicate as a predicate argument to add_view '
+ 'instead. See "Adding A Third Party View, Route, or '
+ 'Subscriber Predicate" in the "Hooks" chapter of the '
+ 'documentation for more information.'
+ ),
DeprecationWarning,
stacklevel=4,
- )
+ )
if check_csrf is not None:
warnings.warn(
- ('The "check_csrf" argument to Configurator.add_view is '
- 'deprecated as of Pyramid 1.7. Use the "require_csrf" option '
- 'instead or see "Checking CSRF Tokens Automatically" in the '
- '"Sessions" chapter of the documentation for more '
- 'information.'),
+ (
+ 'The "check_csrf" argument to Configurator.add_view is '
+ 'deprecated as of Pyramid 1.7. Use the "require_csrf" '
+ 'option instead or see "Checking CSRF Tokens '
+ 'Automatically" in the "Sessions" chapter of the '
+ 'documentation for more information.'
+ ),
DeprecationWarning,
stacklevel=4,
- )
+ )
if accept is not None:
if is_nonstr_iter(accept):
raise ConfigurationError(
- 'A list is not supported in the "accept" view predicate.',
+ 'A list is not supported in the "accept" view predicate.'
)
if '*' in accept:
warnings.warn(
- ('Passing a media range to the "accept" argument of '
- 'Configurator.add_view is deprecated as of Pyramid 1.10. '
- 'Use explicit media types to avoid ambiguities in '
- 'content negotiation that may impact your users.'),
+ (
+ 'Passing a media range to the "accept" argument of '
+ 'Configurator.add_view is deprecated as of '
+ 'Pyramid 1.10. Use explicit media types to avoid '
+ 'ambiguities in content negotiation that may impact '
+ 'your users.'
+ ),
DeprecationWarning,
stacklevel=4,
- )
+ )
# XXX when media ranges are gone, switch allow_range=False
accept = normalize_accept_offer(accept, allow_range=True)
@@ -856,17 +866,21 @@ class ViewsConfiguratorMixin(object):
if not view:
if renderer:
+
def view(context, request):
return {}
+
else:
- raise ConfigurationError('"view" was not specified and '
- 'no "renderer" specified')
+ raise ConfigurationError(
+ '"view" was not specified and ' 'no "renderer" specified'
+ )
if request_type is not None:
request_type = self.maybe_dotted(request_type)
if not IInterface.providedBy(request_type):
raise ConfigurationError(
- 'request_type must be an interface, not %s' % request_type)
+ 'request_type must be an interface, not %s' % request_type
+ )
if context is None:
context = for_
@@ -875,7 +889,8 @@ class ViewsConfiguratorMixin(object):
if exception_only and not isexc:
raise ConfigurationError(
'view "context" must be an exception type when '
- '"exception_only" is True')
+ '"exception_only" is True'
+ )
r_context = context
if r_context is None:
@@ -885,24 +900,26 @@ class ViewsConfiguratorMixin(object):
if isinstance(renderer, string_types):
renderer = renderers.RendererHelper(
- name=renderer, package=self.package,
- registry=self.registry)
+ name=renderer, package=self.package, registry=self.registry
+ )
introspectables = []
ovals = view_options.copy()
- ovals.update(dict(
- xhr=xhr,
- request_method=request_method,
- path_info=path_info,
- request_param=request_param,
- header=header,
- accept=accept,
- containment=containment,
- request_type=request_type,
- match_param=match_param,
- check_csrf=check_csrf,
- custom=predvalseq(custom_predicates),
- ))
+ ovals.update(
+ dict(
+ xhr=xhr,
+ request_method=request_method,
+ path_info=path_info,
+ request_param=request_param,
+ header=header,
+ accept=accept,
+ containment=containment,
+ request_type=request_type,
+ match_param=match_param,
+ check_csrf=check_csrf,
+ custom=predvalseq(custom_predicates),
+ )
+ )
def discrim_func():
# We need to defer the discriminator until we know what the phash
@@ -924,80 +941,82 @@ class ViewsConfiguratorMixin(object):
order, preds, phash = predlist.make(self, **pvals)
- view_intr.update({
- 'phash': phash,
- 'order': order,
- 'predicates': preds,
- })
+ view_intr.update(
+ {'phash': phash, 'order': order, 'predicates': preds}
+ )
return ('view', context, name, route_name, phash)
discriminator = Deferred(discrim_func)
if inspect.isclass(view) and attr:
view_desc = 'method %r of %s' % (
- attr, self.object_description(view))
+ attr,
+ self.object_description(view),
+ )
else:
view_desc = self.object_description(view)
tmpl_intr = None
- view_intr = self.introspectable('views',
- discriminator,
- view_desc,
- 'view')
- view_intr.update(dict(
- name=name,
- context=context,
- exception_only=exception_only,
- containment=containment,
- request_param=request_param,
- request_methods=request_method,
- route_name=route_name,
- attr=attr,
- xhr=xhr,
- accept=accept,
- header=header,
- path_info=path_info,
- match_param=match_param,
- check_csrf=check_csrf,
- http_cache=http_cache,
- require_csrf=require_csrf,
- callable=view,
- mapper=mapper,
- decorator=decorator,
- ))
+ view_intr = self.introspectable(
+ 'views', discriminator, view_desc, 'view'
+ )
+ view_intr.update(
+ dict(
+ name=name,
+ context=context,
+ exception_only=exception_only,
+ containment=containment,
+ request_param=request_param,
+ request_methods=request_method,
+ route_name=route_name,
+ attr=attr,
+ xhr=xhr,
+ accept=accept,
+ header=header,
+ path_info=path_info,
+ match_param=match_param,
+ check_csrf=check_csrf,
+ http_cache=http_cache,
+ require_csrf=require_csrf,
+ callable=view,
+ mapper=mapper,
+ decorator=decorator,
+ )
+ )
view_intr.update(view_options)
introspectables.append(view_intr)
def register(permission=permission, renderer=renderer):
request_iface = IRequest
if route_name is not None:
- request_iface = self.registry.queryUtility(IRouteRequest,
- name=route_name)
+ request_iface = self.registry.queryUtility(
+ IRouteRequest, name=route_name
+ )
if request_iface is None:
# route configuration should have already happened in
# phase 2
raise ConfigurationError(
- 'No route named %s found for view registration' %
- route_name)
+ 'No route named %s found for view registration'
+ % route_name
+ )
if renderer is None:
# use default renderer if one exists (reg'd in phase 1)
if self.registry.queryUtility(IRendererFactory) is not None:
renderer = renderers.RendererHelper(
- name=None,
- package=self.package,
- registry=self.registry
- )
+ name=None, package=self.package, registry=self.registry
+ )
renderer_type = getattr(renderer, 'type', None)
intrspc = self.introspector
if (
- renderer_type is not None and
- tmpl_intr is not None and
- intrspc is not None and
- intrspc.get('renderer factories', renderer_type) is not None
- ):
+ renderer_type is not None
+ and tmpl_intr is not None
+ and intrspc is not None
+ and intrspc.get('renderer factories', renderer_type)
+ is not None
+ ):
# allow failure of registered template factories to be deferred
# until view execution, like other bad renderer factories; if
# we tried to relate this to an existing renderer factory
@@ -1013,8 +1032,9 @@ class ViewsConfiguratorMixin(object):
register_view(IViewClassifier, request_iface, derived_view)
if isexc:
derived_exc_view = derive_view(True, renderer)
- register_view(IExceptionViewClassifier, request_iface,
- derived_exc_view)
+ register_view(
+ IExceptionViewClassifier, request_iface, derived_exc_view
+ )
if exception_only:
derived_view = derived_exc_view
@@ -1085,8 +1105,8 @@ class ViewsConfiguratorMixin(object):
for view_type in (IView, ISecuredView, IMultiView):
old_view = registered(
- (classifier, request_iface, r_context),
- view_type, name)
+ (classifier, request_iface, r_context), view_type, name
+ )
if old_view is not None:
break
@@ -1109,8 +1129,8 @@ class ViewsConfiguratorMixin(object):
derived_view,
(classifier, request_iface, context),
view_iface,
- name
- )
+ name,
+ )
else:
# - A view or multiview was already registered for this
@@ -1136,32 +1156,33 @@ class ViewsConfiguratorMixin(object):
# unregister any existing views
self.registry.adapters.unregister(
(classifier, request_iface, r_context),
- view_type, name=name)
+ view_type,
+ name=name,
+ )
self.registry.registerAdapter(
multiview,
(classifier, request_iface, context),
- IMultiView, name=name)
+ IMultiView,
+ name=name,
+ )
if mapper:
mapper_intr = self.introspectable(
'view mappers',
discriminator,
'view mapper for %s' % view_desc,
- 'view mapper'
- )
+ 'view mapper',
+ )
mapper_intr['mapper'] = mapper
mapper_intr.relate('views', discriminator)
introspectables.append(mapper_intr)
if route_name:
- view_intr.relate('routes', route_name) # see add_route
+ view_intr.relate('routes', route_name) # see add_route
if renderer is not None and renderer.name and '.' in renderer.name:
# the renderer is a template
tmpl_intr = self.introspectable(
- 'templates',
- discriminator,
- renderer.name,
- 'template'
- )
+ 'templates', discriminator, renderer.name, 'template'
+ )
tmpl_intr.relate('views', discriminator)
tmpl_intr['name'] = renderer.name
tmpl_intr['type'] = renderer.type
@@ -1170,11 +1191,8 @@ class ViewsConfiguratorMixin(object):
if permission is not None:
# if a permission exists, register a permission introspectable
perm_intr = self.introspectable(
- 'permissions',
- permission,
- permission,
- 'permission'
- )
+ 'permissions', permission, permission, 'permission'
+ )
perm_intr['value'] = permission
perm_intr.relate('views', discriminator)
introspectables.append(perm_intr)
@@ -1192,8 +1210,10 @@ class ViewsConfiguratorMixin(object):
def _apply_view_derivers(self, info):
# These derivers are not really derivers and so have fixed order
- outer_derivers = [('attr_wrapped_view', attr_wrapped_view),
- ('predicated_view', predicated_view)]
+ outer_derivers = [
+ ('attr_wrapped_view', attr_wrapped_view),
+ ('predicated_view', predicated_view),
+ ]
view = info.original_view
derivers = self.registry.getUtility(IViewDerivers)
@@ -1202,8 +1222,9 @@ class ViewsConfiguratorMixin(object):
return view
@action_method
- def add_view_predicate(self, name, factory, weighs_more_than=None,
- weighs_less_than=None):
+ def add_view_predicate(
+ self, name, factory, weighs_more_than=None, weighs_less_than=None
+ ):
"""
.. versionadded:: 1.4
@@ -1226,8 +1247,8 @@ class ViewsConfiguratorMixin(object):
name,
factory,
weighs_more_than=weighs_more_than,
- weighs_less_than=weighs_less_than
- )
+ weighs_less_than=weighs_less_than,
+ )
def add_default_view_predicates(self):
p = pyramid.predicates
@@ -1245,7 +1266,7 @@ class ViewsConfiguratorMixin(object):
('physical_path', p.PhysicalPathPredicate),
('effective_principals', p.EffectivePrincipalsPredicate),
('custom', p.CustomPredicate),
- ):
+ ):
self.add_view_predicate(name, factory)
def add_default_accept_view_order(self):
@@ -1261,10 +1282,7 @@ class ViewsConfiguratorMixin(object):
@action_method
def add_accept_view_order(
- self,
- value,
- weighs_more_than=None,
- weighs_less_than=None,
+ self, value, weighs_more_than=None, weighs_less_than=None
):
"""
Specify an ordering preference for the ``accept`` view option used
@@ -1293,19 +1311,22 @@ class ViewsConfiguratorMixin(object):
.. versionadded:: 1.10
"""
+
def check_type(than):
than_type, than_subtype, than_params = Accept.parse_offer(than)
# text/plain vs text/html;charset=utf8
if bool(offer_params) ^ bool(than_params):
raise ConfigurationError(
'cannot compare a media type with params to one without '
- 'params')
+ 'params'
+ )
# text/plain;charset=utf8 vs text/html;charset=utf8
if offer_params and (
offer_subtype != than_subtype or offer_type != than_type
):
raise ConfigurationError(
- 'cannot compare params across different media types')
+ 'cannot compare params across different media types'
+ )
def normalize_types(thans):
thans = [normalize_accept_offer(than) for than in thans]
@@ -1328,25 +1349,27 @@ class ViewsConfiguratorMixin(object):
discriminator = ('accept view order', value)
intr = self.introspectable(
- 'accept view order',
- value,
- value,
- 'accept view order')
+ 'accept view order', value, value, 'accept view order'
+ )
intr['value'] = value
intr['weighs_more_than'] = weighs_more_than
intr['weighs_less_than'] = weighs_less_than
+
def register():
sorter = self.registry.queryUtility(IAcceptOrder)
if sorter is None:
sorter = TopologicalSorter()
self.registry.registerUtility(sorter, IAcceptOrder)
sorter.add(
- value, value,
- before=weighs_more_than,
- after=weighs_less_than,
+ value, value, before=weighs_more_than, after=weighs_less_than
)
- self.action(discriminator, register, introspectables=(intr,),
- order=PHASE1_CONFIG) # must be registered before add_view
+
+ self.action(
+ discriminator,
+ register,
+ introspectables=(intr,),
+ order=PHASE1_CONFIG,
+ ) # must be registered before add_view
@action_method
def add_view_deriver(self, deriver, name=None, under=None, over=None):
@@ -1390,8 +1413,9 @@ class ViewsConfiguratorMixin(object):
name = deriver.__name__
if name in (INGRESS, VIEW):
- raise ConfigurationError('%s is a reserved view deriver name'
- % name)
+ raise ConfigurationError(
+ '%s is a reserved view deriver name' % name
+ )
if under is None:
under = 'decorated_view'
@@ -1415,15 +1439,12 @@ class ViewsConfiguratorMixin(object):
raise ConfigurationError('%s cannot be under "mapped_view"' % name)
discriminator = ('view deriver', name)
- intr = self.introspectable(
- 'view derivers',
- name,
- name,
- 'view deriver')
+ intr = self.introspectable('view derivers', name, name, 'view deriver')
intr['name'] = name
intr['deriver'] = deriver
intr['under'] = under
intr['over'] = over
+
def register():
derivers = self.registry.queryUtility(IViewDerivers)
if derivers is None:
@@ -1435,8 +1456,13 @@ class ViewsConfiguratorMixin(object):
)
self.registry.registerUtility(derivers, IViewDerivers)
derivers.add(name, deriver, before=over, after=under)
- self.action(discriminator, register, introspectables=(intr,),
- order=PHASE1_CONFIG) # must be registered before add_view
+
+ self.action(
+ discriminator,
+ register,
+ introspectables=(intr,),
+ order=PHASE1_CONFIG,
+ ) # must be registered before add_view
def add_default_view_derivers(self):
d = pyramid.viewderivers
@@ -1450,12 +1476,7 @@ class ViewsConfiguratorMixin(object):
]
last = INGRESS
for name, deriver in derivers:
- self.add_view_deriver(
- deriver,
- name=name,
- under=last,
- over=VIEW,
- )
+ self.add_view_deriver(deriver, name=name, under=last, over=VIEW)
last = name
# leave the csrf_view loosely coupled to the rest of the pipeline
@@ -1547,26 +1568,39 @@ class ViewsConfiguratorMixin(object):
return self._derive_view(view, attr=attr, renderer=renderer)
# b/w compat
- def _derive_view(self, view, permission=None, predicates=(),
- attr=None, renderer=None, wrapper_viewname=None,
- viewname=None, accept=None, order=MAX_ORDER,
- phash=DEFAULT_PHASH, decorator=None, route_name=None,
- mapper=None, http_cache=None, context=None,
- require_csrf=None, exception_only=False,
- extra_options=None):
+ def _derive_view(
+ self,
+ view,
+ permission=None,
+ predicates=(),
+ attr=None,
+ renderer=None,
+ wrapper_viewname=None,
+ viewname=None,
+ accept=None,
+ order=MAX_ORDER,
+ phash=DEFAULT_PHASH,
+ decorator=None,
+ route_name=None,
+ mapper=None,
+ http_cache=None,
+ context=None,
+ require_csrf=None,
+ exception_only=False,
+ extra_options=None,
+ ):
view = self.maybe_dotted(view)
mapper = self.maybe_dotted(mapper)
if isinstance(renderer, string_types):
renderer = renderers.RendererHelper(
- name=renderer, package=self.package,
- registry=self.registry)
+ name=renderer, package=self.package, registry=self.registry
+ )
if renderer is None:
# use default renderer if one exists
if self.registry.queryUtility(IRendererFactory) is not None:
renderer = renderers.RendererHelper(
- name=None,
- package=self.package,
- registry=self.registry)
+ name=None, package=self.package, registry=self.registry
+ )
options = dict(
view=view,
@@ -1581,7 +1615,7 @@ class ViewsConfiguratorMixin(object):
decorator=decorator,
http_cache=http_cache,
require_csrf=require_csrf,
- route_name=route_name
+ route_name=route_name,
)
if extra_options:
options.update(extra_options)
@@ -1624,7 +1658,7 @@ class ViewsConfiguratorMixin(object):
mapper=None,
match_param=None,
**view_options
- ):
+ ):
""" Add a forbidden view to the current configuration state. The
view will be called when Pyramid or application code raises a
:exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of
@@ -1658,13 +1692,18 @@ class ViewsConfiguratorMixin(object):
The view is created using ``exception_only=True``.
"""
for arg in (
- 'name', 'permission', 'context', 'for_', 'require_csrf',
+ 'name',
+ 'permission',
+ 'context',
+ 'for_',
+ 'require_csrf',
'exception_only',
):
if arg in view_options:
raise ConfigurationError(
'%s may not be used as an argument to add_forbidden_view'
- % (arg,))
+ % (arg,)
+ )
if view is None:
view = default_exceptionresponse_view
@@ -1691,11 +1730,11 @@ class ViewsConfiguratorMixin(object):
require_csrf=False,
attr=attr,
renderer=renderer,
- )
+ )
settings.update(view_options)
return self.add_view(**settings)
- set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias
+ set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias
@viewdefaults
@action_method
@@ -1720,7 +1759,7 @@ class ViewsConfiguratorMixin(object):
match_param=None,
append_slash=False,
**view_options
- ):
+ ):
""" Add a default :term:`Not Found View` to the current configuration
state. The view will be called when Pyramid or application code raises
an :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g., when a
@@ -1766,7 +1805,8 @@ class ViewsConfiguratorMixin(object):
config.add_notfound_view(append_slash=HTTPMovedPermanently)
The above means that a redirect to a slash-appended route will be
- attempted, but instead of :class:`~pyramid.httpexceptions.HTTPTemporaryRedirect`
+ attempted, but instead of
+ :class:`~pyramid.httpexceptions.HTTPTemporaryRedirect`
being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will
be used` for the redirect response if a slash-appended route is found.
@@ -1789,18 +1829,24 @@ class ViewsConfiguratorMixin(object):
.. versionchanged: 1.10
- Default response was changed from :class:`~pyramid.httpexceptions.HTTPFound`
+ Default response was changed from
+ :class:`~pyramid.httpexceptions.HTTPFound`
to :class:`~pyramid.httpexceptions.HTTPTemporaryRedirect`.
"""
for arg in (
- 'name', 'permission', 'context', 'for_', 'require_csrf',
+ 'name',
+ 'permission',
+ 'context',
+ 'for_',
+ 'require_csrf',
'exception_only',
):
if arg in view_options:
raise ConfigurationError(
'%s may not be used as an argument to add_notfound_view'
- % (arg,))
+ % (arg,)
+ )
if view is None:
view = default_exceptionresponse_view
@@ -1825,13 +1871,13 @@ class ViewsConfiguratorMixin(object):
route_name=route_name,
permission=NO_PERMISSION_REQUIRED,
require_csrf=False,
- )
+ )
settings.update(view_options)
if append_slash:
view = self._derive_view(view, attr=attr, renderer=renderer)
if IResponse.implementedBy(append_slash):
view = AppendSlashNotFoundViewFactory(
- view, redirect_class=append_slash,
+ view, redirect_class=append_slash
)
else:
view = AppendSlashNotFoundViewFactory(view)
@@ -1841,7 +1887,7 @@ class ViewsConfiguratorMixin(object):
settings['renderer'] = renderer
return self.add_view(**settings)
- set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias
+ set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias
@viewdefaults
@action_method
@@ -1851,7 +1897,7 @@ class ViewsConfiguratorMixin(object):
context=None,
# force all other arguments to be specified as key=value
**view_options
- ):
+ ):
""" Add an :term:`exception view` for the specified ``exception`` to
the current configuration state. The view will be called when Pyramid
or application code raises the given exception.
@@ -1867,21 +1913,28 @@ class ViewsConfiguratorMixin(object):
.. versionadded:: 1.8
"""
for arg in (
- 'name', 'for_', 'exception_only', 'require_csrf', 'permission',
+ 'name',
+ 'for_',
+ 'exception_only',
+ 'require_csrf',
+ 'permission',
):
if arg in view_options:
raise ConfigurationError(
'%s may not be used as an argument to add_exception_view'
- % (arg,))
+ % (arg,)
+ )
if context is None:
context = Exception
- view_options.update(dict(
- view=view,
- context=context,
- exception_only=True,
- permission=NO_PERMISSION_REQUIRED,
- require_csrf=False,
- ))
+ view_options.update(
+ dict(
+ view=view,
+ context=context,
+ exception_only=True,
+ permission=NO_PERMISSION_REQUIRED,
+ require_csrf=False,
+ )
+ )
return self.add_view(**view_options)
@action_method
@@ -1909,17 +1962,25 @@ class ViewsConfiguratorMixin(object):
can be used to achieve the same purpose.
"""
mapper = self.maybe_dotted(mapper)
+
def register():
self.registry.registerUtility(mapper, IViewMapperFactory)
+
# IViewMapperFactory is looked up as the result of view config
# in phase 3
- intr = self.introspectable('view mappers',
- IViewMapperFactory,
- self.object_description(mapper),
- 'default view mapper')
+ intr = self.introspectable(
+ 'view mappers',
+ IViewMapperFactory,
+ self.object_description(mapper),
+ 'default view mapper',
+ )
intr['mapper'] = mapper
- self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,
- introspectables=(intr,))
+ self.action(
+ IViewMapperFactory,
+ register,
+ order=PHASE1_CONFIG,
+ introspectables=(intr,),
+ )
@action_method
def add_static_view(self, name, path, **kw):
@@ -2054,14 +2115,15 @@ class ViewsConfiguratorMixin(object):
self.registry.registerUtility(info, IStaticURLInfo)
return info
+
def isexception(o):
if IInterface.providedBy(o):
if IException.isEqualOrExtendedBy(o):
return True
- return (
- isinstance(o, Exception) or
- (inspect.isclass(o) and (issubclass(o, Exception)))
- )
+ return isinstance(o, Exception) or (
+ inspect.isclass(o) and (issubclass(o, Exception))
+ )
+
def runtime_exc_view(view, excview):
# create a view callable which can pretend to be both a normal view
@@ -2094,6 +2156,7 @@ def runtime_exc_view(view, excview):
fn = getattr(selected_view, attr, None)
if fn is not None:
return fn(context, request)
+
return wrapper
# these methods are dynamic per-request and should dispatch to their
@@ -2104,16 +2167,12 @@ def runtime_exc_view(view, excview):
wrapper_view.__predicates__ = wrap_fn('__predicates__')
return wrapper_view
+
@implementer(IViewDeriverInfo)
class ViewDeriverInfo(object):
- def __init__(self,
- view,
- registry,
- package,
- predicates,
- exception_only,
- options,
- ):
+ def __init__(
+ self, view, registry, package, predicates, exception_only, options
+ ):
self.original_view = view
self.registry = registry
self.package = package
@@ -2125,6 +2184,7 @@ class ViewDeriverInfo(object):
def settings(self):
return self.registry.settings
+
@implementer(IStaticURLInfo)
class StaticURLInfo(object):
def __init__(self):
@@ -2134,12 +2194,13 @@ class StaticURLInfo(object):
def generate(self, path, request, **kw):
for (url, spec, route_name) in self.registrations:
if path.startswith(spec):
- subpath = path[len(spec):]
- if WIN: # pragma: no cover
- subpath = subpath.replace('\\', '/') # windows
+ subpath = path[len(spec) :]
+ if WIN: # pragma: no cover
+ subpath = subpath.replace('\\', '/') # windows
if self.cache_busters:
subpath, kw = self._bust_asset_path(
- request, spec, subpath, kw)
+ request, spec, subpath, kw
+ )
if url is None:
kw['subpath'] = subpath
return request.route_url(route_name, **kw)
@@ -2147,8 +2208,11 @@ class StaticURLInfo(object):
app_url, qs, anchor = parse_url_overrides(request, kw)
parsed = url_parse(url)
if not parsed.scheme:
- url = urlparse.urlunparse(parsed._replace(
- scheme=request.environ['wsgi.url_scheme']))
+ url = urlparse.urlunparse(
+ parsed._replace(
+ scheme=request.environ['wsgi.url_scheme']
+ )
+ )
subpath = url_quote(subpath)
result = urljoin(url, subpath)
return result + qs + anchor
@@ -2161,7 +2225,7 @@ class StaticURLInfo(object):
# appending a slash here if the spec doesn't have one is
# required for proper prefix matching done in ``generate``
# (``subpath = path[len(spec):]``).
- if os.path.isabs(spec): # FBO windows
+ if os.path.isabs(spec): # FBO windows
sep = os.sep
else:
sep = '/'
@@ -2189,8 +2253,9 @@ class StaticURLInfo(object):
cache_max_age = extra.pop('cache_max_age', None)
# create a view
- view = static_view(spec, cache_max_age=cache_max_age,
- use_subpath=True)
+ view = static_view(
+ spec, cache_max_age=cache_max_age, use_subpath=True
+ )
# Mutate extra to allow factory, etc to be passed through here.
# Treat permission specially because we'd like to default to
@@ -2207,7 +2272,7 @@ class StaticURLInfo(object):
# register a route using the computed view, permission, and
# pattern, plus any extras passed to us via add_static_view
- pattern = "%s*subpath" % name # name already ends with slash
+ pattern = "%s*subpath" % name # name already ends with slash
if config.route_prefix:
route_name = '__%s/%s' % (config.route_prefix, name)
else:
@@ -2233,10 +2298,9 @@ class StaticURLInfo(object):
# url, spec, route_name
registrations.append((url, spec, route_name))
- intr = config.introspectable('static views',
- name,
- 'static view for %r' % name,
- 'static view')
+ intr = config.introspectable(
+ 'static views', name, 'static view for %r' % name, 'static view'
+ )
intr['name'] = name
intr['spec'] = spec
@@ -2245,7 +2309,7 @@ class StaticURLInfo(object):
def add_cache_buster(self, config, spec, cachebust, explicit=False):
# ensure the spec always has a trailing slash as we only support
# adding cache busters to folders, not files
- if os.path.isabs(spec): # FBO windows
+ if os.path.isabs(spec): # FBO windows
sep = os.sep
else:
sep = '/'
@@ -2282,10 +2346,9 @@ class StaticURLInfo(object):
cache_busters.insert(new_idx, (spec, cachebust, explicit))
- intr = config.introspectable('cache busters',
- spec,
- 'cache buster for %r' % spec,
- 'cache buster')
+ intr = config.introspectable(
+ 'cache busters', spec, 'cache buster for %r' % spec, 'cache buster'
+ )
intr['cachebust'] = cachebust
intr['path'] = spec
intr['explicit'] = explicit
@@ -2318,9 +2381,8 @@ class StaticURLInfo(object):
kw['pathspec'] = pathspec
kw['rawspec'] = rawspec
for spec_, cachebust, explicit in reversed(self.cache_busters):
- if (
- (explicit and rawspec.startswith(spec_)) or
- (not explicit and pathspec.startswith(spec_))
+ if (explicit and rawspec.startswith(spec_)) or (
+ not explicit and pathspec.startswith(spec_)
):
subpath, kw = cachebust(request, subpath, kw)
break
diff --git a/src/pyramid/config/zca.py b/src/pyramid/config/zca.py
index bcd5c31e3..7bf637632 100644
--- a/src/pyramid/config/zca.py
+++ b/src/pyramid/config/zca.py
@@ -1,5 +1,6 @@
from pyramid.threadlocal import get_current_registry
+
class ZCAConfiguratorMixin(object):
def hook_zca(self):
""" Call :func:`zope.component.getSiteManager.sethook` with the
@@ -10,11 +11,12 @@ class ZCAConfiguratorMixin(object):
:app:`Pyramid` :term:`application registry` rather than the Zope
'global' registry."""
from zope.component import getSiteManager
+
getSiteManager.sethook(get_current_registry)
def unhook_zca(self):
""" Call :func:`zope.component.getSiteManager.reset` to undo the
action of :meth:`pyramid.config.Configurator.hook_zca`."""
from zope.component import getSiteManager
- getSiteManager.reset()
+ getSiteManager.reset()
diff --git a/src/pyramid/csrf.py b/src/pyramid/csrf.py
index da171d9af..fba5d9baa 100644
--- a/src/pyramid/csrf.py
+++ b/src/pyramid/csrf.py
@@ -4,22 +4,11 @@ from webob.cookies import CookieProfile
from zope.interface import implementer
-from pyramid.compat import (
- bytes_,
- urlparse,
- text_,
-)
-from pyramid.exceptions import (
- BadCSRFOrigin,
- BadCSRFToken,
-)
+from pyramid.compat import bytes_, urlparse, text_
+from pyramid.exceptions import BadCSRFOrigin, BadCSRFToken
from pyramid.interfaces import ICSRFStoragePolicy
from pyramid.settings import aslist
-from pyramid.util import (
- SimpleSerializer,
- is_same_domain,
- strings_differ
-)
+from pyramid.util import SimpleSerializer, is_same_domain, strings_differ
@implementer(ICSRFStoragePolicy)
@@ -37,6 +26,7 @@ class LegacySessionCSRFStoragePolicy(object):
.. versionadded:: 1.9
"""
+
def new_csrf_token(self, request):
""" Sets a new CSRF token into the session and returns it. """
return request.session.new_csrf_token()
@@ -50,7 +40,8 @@ class LegacySessionCSRFStoragePolicy(object):
""" Returns ``True`` if the ``supplied_token`` is valid."""
expected_token = self.get_csrf_token(request)
return not strings_differ(
- bytes_(expected_token), bytes_(supplied_token))
+ bytes_(expected_token), bytes_(supplied_token)
+ )
@implementer(ICSRFStoragePolicy)
@@ -68,6 +59,7 @@ class SessionCSRFStoragePolicy(object):
.. versionadded:: 1.9
"""
+
_token_factory = staticmethod(lambda: text_(uuid.uuid4().hex))
def __init__(self, key='_csrft_'):
@@ -91,7 +83,8 @@ class SessionCSRFStoragePolicy(object):
""" Returns ``True`` if the ``supplied_token`` is valid."""
expected_token = self.get_csrf_token(request)
return not strings_differ(
- bytes_(expected_token), bytes_(supplied_token))
+ bytes_(expected_token), bytes_(supplied_token)
+ )
@implementer(ICSRFStoragePolicy)
@@ -111,10 +104,19 @@ class CookieCSRFStoragePolicy(object):
Added the ``samesite`` option and made the default ``'Lax'``.
"""
+
_token_factory = staticmethod(lambda: text_(uuid.uuid4().hex))
- def __init__(self, cookie_name='csrf_token', secure=False, httponly=False,
- domain=None, max_age=None, path='/', samesite='Lax'):
+ def __init__(
+ self,
+ cookie_name='csrf_token',
+ secure=False,
+ httponly=False,
+ domain=None,
+ max_age=None,
+ path='/',
+ samesite='Lax',
+ ):
serializer = SimpleSerializer()
self.cookie_profile = CookieProfile(
cookie_name=cookie_name,
@@ -132,11 +134,10 @@ class CookieCSRFStoragePolicy(object):
""" Sets a new CSRF token into the request and returns it. """
token = self._token_factory()
request.cookies[self.cookie_name] = token
+
def set_cookie(request, response):
- self.cookie_profile.set_cookies(
- response,
- token,
- )
+ self.cookie_profile.set_cookies(response, token)
+
request.add_response_callback(set_cookie)
return token
@@ -153,7 +154,8 @@ class CookieCSRFStoragePolicy(object):
""" Returns ``True`` if the ``supplied_token`` is valid."""
expected_token = self.get_csrf_token(request)
return not strings_differ(
- bytes_(expected_token), bytes_(supplied_token))
+ bytes_(expected_token), bytes_(supplied_token)
+ )
def get_csrf_token(request):
@@ -182,10 +184,9 @@ def new_csrf_token(request):
return csrf.new_csrf_token(request)
-def check_csrf_token(request,
- token='csrf_token',
- header='X-CSRF-Token',
- raises=True):
+def check_csrf_token(
+ request, token='csrf_token', header='X-CSRF-Token', raises=True
+):
""" Check the CSRF token returned by the
:class:`pyramid.interfaces.ICSRFStoragePolicy` implementation against the
value in ``request.POST.get(token)`` (if a POST request) or
@@ -246,8 +247,8 @@ def check_csrf_origin(request, trusted_origins=None, raises=True):
Check the ``Origin`` of the request to see if it is a cross site request or
not.
- If the value supplied by the ``Origin`` or ``Referer`` header isn't one of the
- trusted origins and ``raises`` is ``True``, this function will raise a
+ If the value supplied by the ``Origin`` or ``Referer`` header isn't one of
+ the trusted origins and ``raises`` is ``True``, this function will raise a
:exc:`pyramid.exceptions.BadCSRFOrigin` exception, but if ``raises`` is
``False``, this function will return ``False`` instead. If the CSRF origin
checks are successful this function will return ``True`` unconditionally.
@@ -267,6 +268,7 @@ def check_csrf_origin(request, trusted_origins=None, raises=True):
Moved from :mod:`pyramid.session` to :mod:`pyramid.csrf`
"""
+
def _fail(reason):
if raises:
raise BadCSRFOrigin(reason)
@@ -315,7 +317,8 @@ def check_csrf_origin(request, trusted_origins=None, raises=True):
if trusted_origins is None:
trusted_origins = aslist(
request.registry.settings.get(
- "pyramid.csrf_trusted_origins", [])
+ "pyramid.csrf_trusted_origins", []
+ )
)
if request.host_port not in set(["80", "443"]):
@@ -325,8 +328,9 @@ def check_csrf_origin(request, trusted_origins=None, raises=True):
# Actually check to see if the request's origin matches any of our
# trusted origins.
- if not any(is_same_domain(originp.netloc, host)
- for host in trusted_origins):
+ if not any(
+ is_same_domain(originp.netloc, host) for host in trusted_origins
+ ):
reason = (
"Referer checking failed - {0} does not match any trusted "
"origins."
diff --git a/src/pyramid/decorator.py b/src/pyramid/decorator.py
index 065a3feed..89cbb0f6e 100644
--- a/src/pyramid/decorator.py
+++ b/src/pyramid/decorator.py
@@ -32,6 +32,7 @@ class reify(object):
>>> f.jammy
2
"""
+
def __init__(self, wrapped):
self.wrapped = wrapped
update_wrapper(self, wrapped)
@@ -42,4 +43,3 @@ class reify(object):
val = self.wrapped(inst)
setattr(inst, self.wrapped.__name__, val)
return val
-
diff --git a/src/pyramid/encode.py b/src/pyramid/encode.py
index 73ff14e62..2cf2247da 100644
--- a/src/pyramid/encode.py
+++ b/src/pyramid/encode.py
@@ -4,9 +4,10 @@ from pyramid.compat import (
is_nonstr_iter,
url_quote as _url_quote,
url_quote_plus as _quote_plus,
- )
+)
-def url_quote(val, safe=''): # bw compat api
+
+def url_quote(val, safe=''): # bw compat api
cls = val.__class__
if cls is text_type:
val = val.encode('utf-8')
@@ -14,6 +15,7 @@ def url_quote(val, safe=''): # bw compat api
val = str(val).encode('utf-8')
return _url_quote(val, safe=safe)
+
# bw compat api (dnr)
def quote_plus(val, safe=''):
cls = val.__class__
@@ -23,6 +25,7 @@ def quote_plus(val, safe=''):
val = str(val).encode('utf-8')
return _quote_plus(val, safe=safe)
+
def urlencode(query, doseq=True, quote_via=quote_plus):
"""
An alternate implementation of Python's stdlib
diff --git a/src/pyramid/events.py b/src/pyramid/events.py
index 93fc127a1..fb3730f63 100644
--- a/src/pyramid/events.py
+++ b/src/pyramid/events.py
@@ -1,9 +1,6 @@
import venusian
-from zope.interface import (
- implementer,
- Interface
- )
+from zope.interface import implementer, Interface
from pyramid.interfaces import (
IContextFound,
@@ -12,7 +9,8 @@ from pyramid.interfaces import (
IApplicationCreated,
IBeforeRender,
IBeforeTraversal,
- )
+)
+
class subscriber(object):
""" Decorator activated via a :term:`scan` which treats the function
@@ -89,7 +87,8 @@ class subscriber(object):
Added the ``_depth`` and ``_category`` arguments.
"""
- venusian = venusian # for unit testing
+
+ venusian = venusian # for unit testing
def __init__(self, *ifaces, **predicates):
self.ifaces = ifaces
@@ -103,10 +102,15 @@ class subscriber(object):
config.add_subscriber(wrapped, iface, **self.predicates)
def __call__(self, wrapped):
- self.venusian.attach(wrapped, self.register, category=self.category,
- depth=self.depth + 1)
+ self.venusian.attach(
+ wrapped,
+ self.register,
+ category=self.category,
+ depth=self.depth + 1,
+ )
return wrapped
+
@implementer(INewRequest)
class NewRequest(object):
""" An instance of this class is emitted as an :term:`event`
@@ -114,9 +118,11 @@ class NewRequest(object):
event instance has an attribute, ``request``, which is a
:term:`request` object. This event class implements the
:class:`pyramid.interfaces.INewRequest` interface."""
+
def __init__(self, request):
self.request = request
+
@implementer(INewResponse)
class NewResponse(object):
""" An instance of this class is emitted as an :term:`event`
@@ -149,10 +155,12 @@ class NewResponse(object):
almost purely for symmetry with the
:class:`pyramid.interfaces.INewRequest` event.
"""
+
def __init__(self, request, response):
self.request = request
self.response = response
+
@implementer(IBeforeTraversal)
class BeforeTraversal(object):
"""
@@ -173,6 +181,7 @@ class BeforeTraversal(object):
def __init__(self, request):
self.request = request
+
@implementer(IContextFound)
class ContextFound(object):
""" An instance of this class is emitted as an :term:`event` after
@@ -194,10 +203,13 @@ class ContextFound(object):
As of :app:`Pyramid` 1.0, for backwards compatibility purposes, this
event may also be imported as :class:`pyramid.events.AfterTraversal`.
"""
+
def __init__(self, request):
self.request = request
-AfterTraversal = ContextFound # b/c as of 1.0
+
+AfterTraversal = ContextFound # b/c as of 1.0
+
@implementer(IApplicationCreated)
class ApplicationCreated(object):
@@ -214,11 +226,14 @@ class ApplicationCreated(object):
:class:`pyramid.events.WSGIApplicationCreatedEvent`. This was the name
of the event class before :app:`Pyramid` 1.0.
"""
+
def __init__(self, app):
self.app = app
self.object = app
-WSGIApplicationCreatedEvent = ApplicationCreated # b/c (as of 1.0)
+
+WSGIApplicationCreatedEvent = ApplicationCreated # b/c (as of 1.0)
+
@implementer(IBeforeRender)
class BeforeRender(dict):
@@ -283,7 +298,7 @@ class BeforeRender(dict):
See also :class:`pyramid.interfaces.IBeforeRender`.
"""
+
def __init__(self, system, rendering_val=None):
dict.__init__(self, system)
self.rendering_val = rendering_val
-
diff --git a/src/pyramid/exceptions.py b/src/pyramid/exceptions.py
index c95922eb0..9a7054731 100644
--- a/src/pyramid/exceptions.py
+++ b/src/pyramid/exceptions.py
@@ -1,11 +1,7 @@
-from pyramid.httpexceptions import (
- HTTPBadRequest,
- HTTPNotFound,
- HTTPForbidden,
- )
+from pyramid.httpexceptions import HTTPBadRequest, HTTPNotFound, HTTPForbidden
-NotFound = HTTPNotFound # bw compat
-Forbidden = HTTPForbidden # bw compat
+NotFound = HTTPNotFound # bw compat
+Forbidden = HTTPForbidden # bw compat
CR = '\n'
@@ -15,6 +11,7 @@ class BadCSRFOrigin(HTTPBadRequest):
This exception indicates the request has failed cross-site request forgery
origin validation.
"""
+
title = "Bad CSRF Origin"
explanation = (
"Access is denied. This server can not verify that the origin or "
@@ -29,6 +26,7 @@ class BadCSRFToken(HTTPBadRequest):
This exception indicates the request has failed cross-site request
forgery token validation.
"""
+
title = 'Bad CSRF Token'
explanation = (
'Access is denied. This server can not verify that your cross-site '
@@ -36,7 +34,9 @@ class BadCSRFToken(HTTPBadRequest):
'supplied the wrong cross-site request forgery token or your session '
'no longer exists. This may be due to session timeout or because '
'browser is not supplying the credentials required, as can happen '
- 'when the browser has cookies turned off.')
+ 'when the browser has cookies turned off.'
+ )
+
class PredicateMismatch(HTTPNotFound):
"""
@@ -65,6 +65,7 @@ class PredicateMismatch(HTTPNotFound):
exception view.
"""
+
class URLDecodeError(UnicodeDecodeError):
"""
This exception is raised when :app:`Pyramid` cannot
@@ -76,10 +77,12 @@ class URLDecodeError(UnicodeDecodeError):
decoded.
"""
+
class ConfigurationError(Exception):
""" Raised when inappropriate input values are supplied to an API
method of a :term:`Configurator`"""
+
class ConfigurationConflictError(ConfigurationError):
""" Raised when a configuration conflict is detected during action
processing"""
@@ -91,7 +94,7 @@ class ConfigurationConflictError(ConfigurationError):
r = ["Conflicting configuration actions"]
items = sorted(self._conflicts.items())
for discriminator, infos in items:
- r.append(" For: %s" % (discriminator, ))
+ r.append(" For: %s" % (discriminator,))
for info in infos:
for line in str(info).rstrip().split(CR):
r.append(" " + line)
@@ -113,6 +116,7 @@ class ConfigurationExecutionError(ConfigurationError):
class CyclicDependencyError(Exception):
""" The exception raised when the Pyramid topological sorter detects a
cyclic dependency."""
+
def __init__(self, cycles):
self.cycles = cycles
diff --git a/src/pyramid/httpexceptions.py b/src/pyramid/httpexceptions.py
index bef8420b1..959a45f37 100644
--- a/src/pyramid/httpexceptions.py
+++ b/src/pyramid/httpexceptions.py
@@ -137,16 +137,12 @@ from zope.interface import implementer
from webob import html_escape as _html_escape
from webob.acceptparse import create_accept_header
-from pyramid.compat import (
- class_types,
- text_type,
- binary_type,
- text_,
- )
+from pyramid.compat import class_types, text_type, binary_type, text_
from pyramid.interfaces import IExceptionResponse
from pyramid.response import Response
+
def _no_escape(value):
if value is None:
return ''
@@ -159,10 +155,10 @@ def _no_escape(value):
value = text_type(value)
return value
+
@implementer(IExceptionResponse)
class HTTPException(Response, Exception):
-
- ## You should set in subclasses:
+ # You should set in subclasses:
# code = 200
# title = 'OK'
# explanation = 'why this happens'
@@ -190,23 +186,29 @@ class HTTPException(Response, Exception):
# implies that this class' ``exception`` property always returns
# ``self`` (it exists only for bw compat at this point).
#
- # - documentation improvements (Pyramid-specific docstrings where necessary)
+ # - documentation improvements (Pyramid-specific docstrings where
+ # necessary)
#
code = 520
title = 'Unknown Error'
explanation = ''
- body_template_obj = Template('''\
+ body_template_obj = Template(
+ '''\
${explanation}${br}${br}
${detail}
${html_comment}
-''')
+'''
+ )
- plain_template_obj = Template('''\
+ plain_template_obj = Template(
+ '''\
${status}
-${body}''')
+${body}'''
+ )
- html_template_obj = Template('''\
+ html_template_obj = Template(
+ '''\
<html>
<head>
<title>${status}</title>
@@ -215,13 +217,21 @@ ${body}''')
<h1>${status}</h1>
${body}
</body>
-</html>''')
+</html>'''
+ )
- ## Set this to True for responses that should have no request body
+ # Set this to True for responses that should have no request body
empty_body = False
- def __init__(self, detail=None, headers=None, comment=None,
- body_template=None, json_formatter=None, **kw):
+ def __init__(
+ self,
+ detail=None,
+ headers=None,
+ comment=None,
+ body_template=None,
+ json_formatter=None,
+ **kw
+ ):
status = '%s %s' % (self.code, self.title)
Response.__init__(self, status=status, **kw)
Exception.__init__(self, detail)
@@ -243,9 +253,7 @@ ${body}''')
return str(self.detail) if self.detail else self.explanation
def _json_formatter(self, status, body, title, environ):
- return {'message': body,
- 'code': status,
- 'title': self.title}
+ return {'message': body, 'code': status, 'title': self.title}
def prepare(self, environ):
if not self.has_body and not self.empty_body:
@@ -255,7 +263,9 @@ ${body}''')
accept = create_accept_header(accept_value)
# Attempt to match text/html or application/json, if those don't
# match, we will fall through to defaulting to text/plain
- acceptable = accept.acceptable_offers(['text/html', 'application/json'])
+ acceptable = accept.acceptable_offers(
+ ['text/html', 'application/json']
+ )
acceptable = [offer[0] for offer in acceptable] + ['text/plain']
match = acceptable[0]
@@ -281,8 +291,10 @@ ${body}''')
def substitute(self, status, body):
jsonbody = self.excobj._json_formatter(
status=status,
- body=body, title=self.excobj.title,
- environ=environ)
+ body=body,
+ title=self.excobj.title,
+ environ=environ,
+ )
return json.dumps(jsonbody)
page_template = JsonPageTemplate(self)
@@ -299,7 +311,7 @@ ${body}''')
'detail': escape(self.detail or ''),
'comment': escape(comment),
'html_comment': html_comment,
- }
+ }
body_tmpl = self.body_template_obj
if HTTPException.body_template_obj is not body_tmpl:
# Custom template; add headers to args
@@ -324,7 +336,7 @@ ${body}''')
# bw compat only
return self
- exception = wsgi_response # bw compat only
+ exception = wsgi_response # bw compat only
def __call__(self, environ, start_response):
# differences from webob.exc.WSGIHTTPException
@@ -337,7 +349,9 @@ ${body}''')
self.prepare(environ)
return Response.__call__(self, environ, start_response)
-WSGIHTTPException = HTTPException # b/c post 1.5
+
+WSGIHTTPException = HTTPException # b/c post 1.5
+
class HTTPError(HTTPException):
"""
@@ -347,6 +361,7 @@ class HTTPError(HTTPException):
and that any work in progress should not be committed.
"""
+
class HTTPRedirection(HTTPException):
"""
base class for exceptions with status codes in the 300s (redirections)
@@ -357,16 +372,19 @@ class HTTPRedirection(HTTPException):
condition.
"""
+
class HTTPSuccessful(HTTPException):
"""
Base class for exceptions with status codes in the 200s (successful
responses)
"""
+
############################################################
-## 2xx success
+# 2xx success
############################################################
+
class HTTPOk(HTTPSuccessful):
"""
subclass of :class:`~HTTPSuccessful`
@@ -375,9 +393,11 @@ class HTTPOk(HTTPSuccessful):
code: 200, title: OK
"""
+
code = 200
title = 'OK'
+
class HTTPCreated(HTTPSuccessful):
"""
subclass of :class:`~HTTPSuccessful`
@@ -387,9 +407,11 @@ class HTTPCreated(HTTPSuccessful):
code: 201, title: Created
"""
+
code = 201
title = 'Created'
+
class HTTPAccepted(HTTPSuccessful):
"""
subclass of :class:`~HTTPSuccessful`
@@ -399,10 +421,12 @@ class HTTPAccepted(HTTPSuccessful):
code: 202, title: Accepted
"""
+
code = 202
title = 'Accepted'
explanation = 'The request is accepted for processing.'
+
class HTTPNonAuthoritativeInformation(HTTPSuccessful):
"""
subclass of :class:`~HTTPSuccessful`
@@ -413,9 +437,11 @@ class HTTPNonAuthoritativeInformation(HTTPSuccessful):
code: 203, title: Non-Authoritative Information
"""
+
code = 203
title = 'Non-Authoritative Information'
+
class HTTPNoContent(HTTPSuccessful):
"""
subclass of :class:`~HTTPSuccessful`
@@ -426,10 +452,12 @@ class HTTPNoContent(HTTPSuccessful):
code: 204, title: No Content
"""
+
code = 204
title = 'No Content'
empty_body = True
+
class HTTPResetContent(HTTPSuccessful):
"""
subclass of :class:`~HTTPSuccessful`
@@ -440,10 +468,12 @@ class HTTPResetContent(HTTPSuccessful):
code: 205, title: Reset Content
"""
+
code = 205
title = 'Reset Content'
empty_body = True
+
class HTTPPartialContent(HTTPSuccessful):
"""
subclass of :class:`~HTTPSuccessful`
@@ -453,15 +483,18 @@ class HTTPPartialContent(HTTPSuccessful):
code: 206, title: Partial Content
"""
+
code = 206
title = 'Partial Content'
-## FIXME: add 207 Multi-Status (but it's complicated)
+
+# FIXME: add 207 Multi-Status (but it's complicated)
############################################################
-## 3xx redirection
+# 3xx redirection
############################################################
+
class _HTTPMove(HTTPRedirection):
"""
redirections which require a Location field
@@ -472,6 +505,7 @@ class _HTTPMove(HTTPRedirection):
You must provide a ``location`` keyword argument.
"""
+
# differences from webob.exc._HTTPMove:
#
# - ${location} isn't wrapped in an <a> tag in body
@@ -486,18 +520,33 @@ class _HTTPMove(HTTPRedirection):
# - ``add_slash`` argument is no longer accepted: code that passes
# add_slash argument to the constructor will receive an exception.
explanation = 'The resource has been moved to'
- body_template_obj = Template('''\
+ body_template_obj = Template(
+ '''\
${explanation} ${location}; you should be redirected automatically.
${detail}
-${html_comment}''')
+${html_comment}'''
+ )
- def __init__(self, location='', detail=None, headers=None, comment=None,
- body_template=None, **kw):
+ def __init__(
+ self,
+ location='',
+ detail=None,
+ headers=None,
+ comment=None,
+ body_template=None,
+ **kw
+ ):
if location is None:
raise ValueError("HTTP redirects need a location to redirect to.")
super(_HTTPMove, self).__init__(
- detail=detail, headers=headers, comment=comment,
- body_template=body_template, location=location, **kw)
+ detail=detail,
+ headers=headers,
+ comment=comment,
+ body_template=body_template,
+ location=location,
+ **kw
+ )
+
class HTTPMultipleChoices(_HTTPMove):
"""
@@ -511,9 +560,11 @@ class HTTPMultipleChoices(_HTTPMove):
code: 300, title: Multiple Choices
"""
+
code = 300
title = 'Multiple Choices'
+
class HTTPMovedPermanently(_HTTPMove):
"""
subclass of :class:`~_HTTPMove`
@@ -524,9 +575,11 @@ class HTTPMovedPermanently(_HTTPMove):
code: 301, title: Moved Permanently
"""
+
code = 301
title = 'Moved Permanently'
+
class HTTPFound(_HTTPMove):
"""
subclass of :class:`~_HTTPMove`
@@ -536,10 +589,12 @@ class HTTPFound(_HTTPMove):
code: 302, title: Found
"""
+
code = 302
title = 'Found'
explanation = 'The resource was found at'
+
# This one is safe after a POST (the redirected location will be
# retrieved with GET):
class HTTPSeeOther(_HTTPMove):
@@ -552,9 +607,11 @@ class HTTPSeeOther(_HTTPMove):
code: 303, title: See Other
"""
+
code = 303
title = 'See Other'
+
class HTTPNotModified(HTTPRedirection):
"""
subclass of :class:`~HTTPRedirection`
@@ -565,11 +622,13 @@ class HTTPNotModified(HTTPRedirection):
code: 304, title: Not Modified
"""
+
# FIXME: this should include a date or etag header
code = 304
title = 'Not Modified'
empty_body = True
+
class HTTPUseProxy(_HTTPMove):
"""
subclass of :class:`~_HTTPMove`
@@ -579,11 +638,12 @@ class HTTPUseProxy(_HTTPMove):
code: 305, title: Use Proxy
"""
+
# Not a move, but looks a little like one
code = 305
title = 'Use Proxy'
- explanation = (
- 'The resource must be accessed through a proxy located at')
+ explanation = 'The resource must be accessed through a proxy located at'
+
class HTTPTemporaryRedirect(_HTTPMove):
"""
@@ -594,9 +654,11 @@ class HTTPTemporaryRedirect(_HTTPMove):
code: 307, title: Temporary Redirect
"""
+
code = 307
title = 'Temporary Redirect'
+
class HTTPPermanentRedirect(_HTTPMove):
"""
subclass of :class:`~_HTTPMove`
@@ -607,13 +669,16 @@ class HTTPPermanentRedirect(_HTTPMove):
code: 308, title: Permanent Redirect
"""
+
code = 308
title = 'Permanent Redirect'
+
############################################################
-## 4xx client error
+# 4xx client error
############################################################
+
class HTTPClientError(HTTPError):
"""
base class for the 400s, where the client is in error
@@ -623,9 +688,11 @@ class HTTPClientError(HTTPError):
a bug. A server-side traceback is not warranted. Unless specialized,
this is a '400 Bad Request'
"""
+
code = 400
title = 'Bad Request'
+
class HTTPBadRequest(HTTPClientError):
"""
subclass of :class:`~HTTPClientError`
@@ -635,8 +702,12 @@ class HTTPBadRequest(HTTPClientError):
code: 400, title: Bad Request
"""
- explanation = ('The server could not comply with the request since '
- 'it is either malformed or otherwise incorrect.')
+
+ explanation = (
+ 'The server could not comply with the request since '
+ 'it is either malformed or otherwise incorrect.'
+ )
+
class HTTPUnauthorized(HTTPClientError):
"""
@@ -646,13 +717,16 @@ class HTTPUnauthorized(HTTPClientError):
code: 401, title: Unauthorized
"""
+
code = 401
title = 'Unauthorized'
explanation = (
'This server could not verify that you are authorized to '
'access the document you requested. Either you supplied the '
'wrong credentials (e.g., bad password), or your browser '
- 'does not understand how to supply the credentials required.')
+ 'does not understand how to supply the credentials required.'
+ )
+
class HTTPPaymentRequired(HTTPClientError):
"""
@@ -660,9 +734,11 @@ class HTTPPaymentRequired(HTTPClientError):
code: 402, title: Payment Required
"""
+
code = 402
title = 'Payment Required'
- explanation = ('Access was denied for financial reasons.')
+ explanation = 'Access was denied for financial reasons.'
+
class HTTPForbidden(HTTPClientError):
"""
@@ -693,6 +769,7 @@ class HTTPForbidden(HTTPClientError):
exception as necessary to provide extended information in an error
report shown to a user.
"""
+
# differences from webob.exc.HTTPForbidden:
#
# - accepts a ``result`` keyword argument
@@ -705,14 +782,28 @@ class HTTPForbidden(HTTPClientError):
#
code = 403
title = 'Forbidden'
- explanation = ('Access was denied to this resource.')
- def __init__(self, detail=None, headers=None, comment=None,
- body_template=None, result=None, **kw):
- HTTPClientError.__init__(self, detail=detail, headers=headers,
- comment=comment, body_template=body_template,
- **kw)
+ explanation = 'Access was denied to this resource.'
+
+ def __init__(
+ self,
+ detail=None,
+ headers=None,
+ comment=None,
+ body_template=None,
+ result=None,
+ **kw
+ ):
+ HTTPClientError.__init__(
+ self,
+ detail=detail,
+ headers=headers,
+ comment=comment,
+ body_template=body_template,
+ **kw
+ )
self.result = result
+
class HTTPNotFound(HTTPClientError):
"""
subclass of :class:`~HTTPClientError`
@@ -732,9 +823,11 @@ class HTTPNotFound(HTTPClientError):
string will be available as the ``message`` attribute of this exception,
for availability to the :term:`Not Found View`.
"""
+
code = 404
title = 'Not Found'
- explanation = ('The resource could not be found.')
+ explanation = 'The resource could not be found.'
+
class HTTPMethodNotAllowed(HTTPClientError):
"""
@@ -745,14 +838,18 @@ class HTTPMethodNotAllowed(HTTPClientError):
code: 405, title: Method Not Allowed
"""
+
# differences from webob.exc.HTTPMethodNotAllowed:
#
# - body_template_obj uses ${br} instead of <br />
code = 405
title = 'Method Not Allowed'
- body_template_obj = Template('''\
+ body_template_obj = Template(
+ '''\
The method ${REQUEST_METHOD} is not allowed for this resource. ${br}${br}
-${detail}''')
+${detail}'''
+ )
+
class HTTPNotAcceptable(HTTPClientError):
"""
@@ -765,12 +862,14 @@ class HTTPNotAcceptable(HTTPClientError):
code: 406, title: Not Acceptable
"""
+
# differences from webob.exc.HTTPNotAcceptable:
#
# - "template" attribute left off (useless, bug in webob?)
code = 406
title = 'Not Acceptable'
+
class HTTPProxyAuthenticationRequired(HTTPClientError):
"""
subclass of :class:`~HTTPClientError`
@@ -780,9 +879,11 @@ class HTTPProxyAuthenticationRequired(HTTPClientError):
code: 407, title: Proxy Authentication Required
"""
+
code = 407
title = 'Proxy Authentication Required'
- explanation = ('Authentication with a local proxy is needed.')
+ explanation = 'Authentication with a local proxy is needed.'
+
class HTTPRequestTimeout(HTTPClientError):
"""
@@ -793,10 +894,14 @@ class HTTPRequestTimeout(HTTPClientError):
code: 408, title: Request Timeout
"""
+
code = 408
title = 'Request Timeout'
- explanation = ('The server has waited too long for the request to '
- 'be sent by the client.')
+ explanation = (
+ 'The server has waited too long for the request to '
+ 'be sent by the client.'
+ )
+
class HTTPConflict(HTTPClientError):
"""
@@ -807,10 +912,13 @@ class HTTPConflict(HTTPClientError):
code: 409, title: Conflict
"""
+
code = 409
title = 'Conflict'
- explanation = ('There was a conflict when trying to complete '
- 'your request.')
+ explanation = (
+ 'There was a conflict when trying to complete ' 'your request.'
+ )
+
class HTTPGone(HTTPClientError):
"""
@@ -821,10 +929,14 @@ class HTTPGone(HTTPClientError):
code: 410, title: Gone
"""
+
code = 410
title = 'Gone'
- explanation = ('This resource is no longer available. No forwarding '
- 'address is given.')
+ explanation = (
+ 'This resource is no longer available. No forwarding '
+ 'address is given.'
+ )
+
class HTTPLengthRequired(HTTPClientError):
"""
@@ -835,9 +947,11 @@ class HTTPLengthRequired(HTTPClientError):
code: 411, title: Length Required
"""
+
code = 411
title = 'Length Required'
- explanation = ('Content-Length header required.')
+ explanation = 'Content-Length header required.'
+
class HTTPPreconditionFailed(HTTPClientError):
"""
@@ -849,9 +963,11 @@ class HTTPPreconditionFailed(HTTPClientError):
code: 412, title: Precondition Failed
"""
+
code = 412
title = 'Precondition Failed'
- explanation = ('Request precondition failed.')
+ explanation = 'Request precondition failed.'
+
class HTTPRequestEntityTooLarge(HTTPClientError):
"""
@@ -863,9 +979,11 @@ class HTTPRequestEntityTooLarge(HTTPClientError):
code: 413, title: Request Entity Too Large
"""
+
code = 413
title = 'Request Entity Too Large'
- explanation = ('The body of your request was too large for this server.')
+ explanation = 'The body of your request was too large for this server.'
+
class HTTPRequestURITooLong(HTTPClientError):
"""
@@ -877,9 +995,11 @@ class HTTPRequestURITooLong(HTTPClientError):
code: 414, title: Request-URI Too Long
"""
+
code = 414
title = 'Request-URI Too Long'
- explanation = ('The request URI was too long for this server.')
+ explanation = 'The request URI was too long for this server.'
+
class HTTPUnsupportedMediaType(HTTPClientError):
"""
@@ -891,12 +1011,14 @@ class HTTPUnsupportedMediaType(HTTPClientError):
code: 415, title: Unsupported Media Type
"""
+
# differences from webob.exc.HTTPUnsupportedMediaType:
#
# - "template_obj" attribute left off (useless, bug in webob?)
code = 415
title = 'Unsupported Media Type'
+
class HTTPRequestRangeNotSatisfiable(HTTPClientError):
"""
subclass of :class:`~HTTPClientError`
@@ -909,9 +1031,11 @@ class HTTPRequestRangeNotSatisfiable(HTTPClientError):
code: 416, title: Request Range Not Satisfiable
"""
+
code = 416
title = 'Request Range Not Satisfiable'
- explanation = ('The Range requested is not available.')
+ explanation = 'The Range requested is not available.'
+
class HTTPExpectationFailed(HTTPClientError):
"""
@@ -922,9 +1046,11 @@ class HTTPExpectationFailed(HTTPClientError):
code: 417, title: Expectation Failed
"""
+
code = 417
title = 'Expectation Failed'
- explanation = ('Expectation failed.')
+ explanation = 'Expectation failed.'
+
class HTTPUnprocessableEntity(HTTPClientError):
"""
@@ -940,11 +1066,13 @@ class HTTPUnprocessableEntity(HTTPClientError):
code: 422, title: Unprocessable Entity
"""
- ## Note: from WebDAV
+
+ # Note: from WebDAV
code = 422
title = 'Unprocessable Entity'
explanation = 'Unable to process the contained instructions'
+
class HTTPLocked(HTTPClientError):
"""
subclass of :class:`~HTTPClientError`
@@ -953,10 +1081,12 @@ class HTTPLocked(HTTPClientError):
code: 423, title: Locked
"""
- ## Note: from WebDAV
+
+ # Note: from WebDAV
code = 423
title = 'Locked'
- explanation = ('The resource is locked')
+ explanation = 'The resource is locked'
+
class HTTPFailedDependency(HTTPClientError):
"""
@@ -967,12 +1097,15 @@ class HTTPFailedDependency(HTTPClientError):
code: 424, title: Failed Dependency
"""
- ## Note: from WebDAV
+
+ # Note: from WebDAV
code = 424
title = 'Failed Dependency'
explanation = (
'The method could not be performed because the requested '
- 'action dependended on another action and that action failed')
+ 'action dependended on another action and that action failed'
+ )
+
class HTTPPreconditionRequired(HTTPClientError):
"""
@@ -991,10 +1124,11 @@ class HTTPPreconditionRequired(HTTPClientError):
code: 428, title: Precondition Required
"""
+
code = 428
title = 'Precondition Required'
- explanation = (
- 'The origin server requires the request to be conditional.')
+ explanation = 'The origin server requires the request to be conditional.'
+
class HTTPTooManyRequests(HTTPClientError):
"""
@@ -1007,11 +1141,14 @@ class HTTPTooManyRequests(HTTPClientError):
code: 429, title: Too Many Requests
"""
+
code = 429
title = 'Too Many Requests'
explanation = (
'The action could not be performed because there were too '
- 'many requests by the client.')
+ 'many requests by the client.'
+ )
+
class HTTPRequestHeaderFieldsTooLarge(HTTPClientError):
"""
@@ -1025,13 +1162,14 @@ class HTTPRequestHeaderFieldsTooLarge(HTTPClientError):
code: 431, title: Request Header Fields Too Large
"""
+
code = 431
title = 'Request Header Fields Too Large'
- explanation = (
- 'The requests header fields were too large.')
+ explanation = 'The requests header fields were too large.'
+
############################################################
-## 5xx Server Error
+# 5xx Server Error
############################################################
# Response status codes beginning with the digit "5" indicate cases in
# which the server is aware that it has erred or is incapable of
@@ -1041,6 +1179,7 @@ class HTTPRequestHeaderFieldsTooLarge(HTTPClientError):
# agents SHOULD display any included entity to the user. These response
# codes are applicable to any request method.
+
class HTTPServerError(HTTPError):
"""
base class for the 500s, where the server is in-error
@@ -1048,9 +1187,11 @@ class HTTPServerError(HTTPError):
This is an error condition in which the server is presumed to be
in-error. Unless specialized, this is a '500 Internal Server Error'.
"""
+
code = 500
title = 'Internal Server Error'
+
class HTTPInternalServerError(HTTPServerError):
"""
subclass of :class:`~HTTPServerError`
@@ -1060,9 +1201,12 @@ class HTTPInternalServerError(HTTPServerError):
code: 500, title: Internal Server Error
"""
+
explanation = (
'The server has either erred or is incapable of performing '
- 'the requested operation.')
+ 'the requested operation.'
+ )
+
class HTTPNotImplemented(HTTPServerError):
"""
@@ -1073,12 +1217,14 @@ class HTTPNotImplemented(HTTPServerError):
code: 501, title: Not Implemented
"""
+
# differences from webob.exc.HTTPNotAcceptable:
#
# - "template" attr left off (useless, bug in webob?)
code = 501
title = 'Not Implemented'
+
class HTTPBadGateway(HTTPServerError):
"""
subclass of :class:`~HTTPServerError`
@@ -1089,9 +1235,11 @@ class HTTPBadGateway(HTTPServerError):
code: 502, title: Bad Gateway
"""
+
code = 502
title = 'Bad Gateway'
- explanation = ('Bad gateway.')
+ explanation = 'Bad gateway.'
+
class HTTPServiceUnavailable(HTTPServerError):
"""
@@ -1102,10 +1250,14 @@ class HTTPServiceUnavailable(HTTPServerError):
code: 503, title: Service Unavailable
"""
+
code = 503
title = 'Service Unavailable'
- explanation = ('The server is currently unavailable. '
- 'Please try again at a later time.')
+ explanation = (
+ 'The server is currently unavailable. '
+ 'Please try again at a later time.'
+ )
+
class HTTPGatewayTimeout(HTTPServerError):
"""
@@ -1118,9 +1270,11 @@ class HTTPGatewayTimeout(HTTPServerError):
code: 504, title: Gateway Timeout
"""
+
code = 504
title = 'Gateway Timeout'
- explanation = ('The gateway has timed out.')
+ explanation = 'The gateway has timed out.'
+
class HTTPVersionNotSupported(HTTPServerError):
"""
@@ -1132,9 +1286,11 @@ class HTTPVersionNotSupported(HTTPServerError):
code: 505, title: HTTP Version Not Supported
"""
+
code = 505
title = 'HTTP Version Not Supported'
- explanation = ('The HTTP version is not supported.')
+ explanation = 'The HTTP version is not supported.'
+
class HTTPInsufficientStorage(HTTPServerError):
"""
@@ -1145,9 +1301,11 @@ class HTTPInsufficientStorage(HTTPServerError):
code: 507, title: Insufficient Storage
"""
+
code = 507
title = 'Insufficient Storage'
- explanation = ('There was not enough space to save the resource')
+ explanation = 'There was not enough space to save the resource'
+
def exception_response(status_code, **kw):
"""Creates an HTTP exception based on a status code. Example::
@@ -1159,22 +1317,24 @@ def exception_response(status_code, **kw):
exc = status_map[status_code](**kw)
return exc
+
def default_exceptionresponse_view(context, request):
if not isinstance(context, Exception):
# backwards compat for an exception response view registered via
# config.set_notfound_view or config.set_forbidden_view
# instead of as a proper exception view
context = request.exception or context
- return context # assumed to be an IResponse
+ return context # assumed to be an IResponse
+
status_map = {}
code = None
for name, value in list(globals().items()):
if (
- isinstance(value, class_types) and
- issubclass(value, HTTPException) and
- value not in {HTTPClientError, HTTPServerError} and
- not name.startswith('_')
+ isinstance(value, class_types)
+ and issubclass(value, HTTPException)
+ and value not in {HTTPClientError, HTTPServerError}
+ and not name.startswith('_')
):
code = getattr(value, 'code', None)
if code:
diff --git a/src/pyramid/i18n.py b/src/pyramid/i18n.py
index 1d11adfe3..e99a29aab 100644
--- a/src/pyramid/i18n.py
+++ b/src/pyramid/i18n.py
@@ -4,9 +4,9 @@ import os
from translationstring import (
Translator,
Pluralizer,
- TranslationString, # API
- TranslationStringFactory, # API
- )
+ TranslationString, # API
+ TranslationStringFactory, # API
+)
from pyramid.compat import PY2
from pyramid.decorator import reify
@@ -15,7 +15,7 @@ from pyramid.interfaces import (
ILocalizer,
ITranslationDirectories,
ILocaleNegotiator,
- )
+)
from pyramid.threadlocal import get_current_registry
@@ -24,6 +24,7 @@ TranslationStringFactory = TranslationStringFactory # PyFlakes
DEFAULT_PLURAL = lambda n: int(n != 1)
+
class Localizer(object):
"""
An object providing translation and pluralizations related to
@@ -31,6 +32,7 @@ class Localizer(object):
:class:`pyramid.i18n.Localizer` object is created using the
:func:`pyramid.i18n.get_localizer` function.
"""
+
def __init__(self, locale_name, translations):
self.locale_name = locale_name
self.translations = translations
@@ -80,13 +82,13 @@ class Localizer(object):
and ``plural`` objects should be unicode strings. There is no
reason to use translation string objects as arguments as all
metadata is ignored.
-
+
``n`` represents the number of elements. ``domain`` is the
translation domain to use to do the pluralization, and ``mapping``
is the interpolation mapping that should be used on the result. If
the ``domain`` is not supplied, a default domain is used (usually
``messages``).
-
+
Example::
num = 1
@@ -108,12 +110,13 @@ class Localizer(object):
num,
mapping={'num':num})
-
+
"""
if self.pluralizer is None:
self.pluralizer = Pluralizer(self.translations)
- return self.pluralizer(singular, plural, n, domain=domain,
- mapping=mapping)
+ return self.pluralizer(
+ singular, plural, n, domain=domain, mapping=mapping
+ )
def default_locale_negotiator(request):
@@ -124,7 +127,7 @@ def default_locale_negotiator(request):
the request object (possibly set by a view or a listener for an
:term:`event`). If the attribute exists and it is not ``None``,
its value will be used.
-
+
- Then it looks for the ``request.params['_LOCALE_']`` value.
- Then it looks for the ``request.cookies['_LOCALE_']`` value.
@@ -142,6 +145,7 @@ def default_locale_negotiator(request):
locale_name = request.cookies.get(name)
return locale_name
+
def negotiate_locale_name(request):
""" Negotiate and return the :term:`locale name` associated with
the current request."""
@@ -149,8 +153,9 @@ def negotiate_locale_name(request):
registry = request.registry
except AttributeError:
registry = get_current_registry()
- negotiator = registry.queryUtility(ILocaleNegotiator,
- default=default_locale_negotiator)
+ negotiator = registry.queryUtility(
+ ILocaleNegotiator, default=default_locale_negotiator
+ )
locale_name = negotiator(request)
if locale_name is None:
@@ -159,6 +164,7 @@ def negotiate_locale_name(request):
return locale_name
+
def get_locale_name(request):
"""
.. deprecated:: 1.5
@@ -167,9 +173,10 @@ def get_locale_name(request):
"""
return request.locale_name
+
def make_localizer(current_locale_name, translation_directories):
""" Create a :class:`pyramid.i18n.Localizer` object
- corresponding to the provided locale name from the
+ corresponding to the provided locale name from the
translations found in the list of translation directories."""
translations = Translations()
translations._catalog = {}
@@ -199,16 +206,17 @@ def make_localizer(current_locale_name, translation_directories):
if not os.path.isdir(os.path.realpath(messages_dir)):
continue
for mofile in os.listdir(messages_dir):
- mopath = os.path.realpath(os.path.join(messages_dir,
- mofile))
+ mopath = os.path.realpath(os.path.join(messages_dir, mofile))
if mofile.endswith('.mo') and os.path.isfile(mopath):
with open(mopath, 'rb') as mofp:
domain = mofile[:-3]
dtrans = Translations(mofp, domain)
translations.add(dtrans)
- return Localizer(locale_name=current_locale_name,
- translations=translations)
+ return Localizer(
+ locale_name=current_locale_name, translations=translations
+ )
+
def get_localizer(request):
"""
@@ -219,6 +227,7 @@ def get_localizer(request):
"""
return request.localizer
+
class Translations(gettext.GNUTranslations, object):
"""An extended translation catalog class (ripped off from Babel) """
@@ -272,8 +281,10 @@ class Translations(gettext.GNUTranslations, object):
return cls(fileobj=fp, domain=domain)
def __repr__(self):
- return '<%s: "%s">' % (type(self).__name__,
- self._info.get('project-id-version'))
+ return '<%s: "%s">' % (
+ type(self).__name__,
+ self._info.get('project-id-version'),
+ )
def add(self, translations, merge=True):
"""Add the given translations to the catalog.
@@ -331,13 +342,13 @@ class Translations(gettext.GNUTranslations, object):
domain.
"""
return self._domains.get(domain, self).gettext(message)
-
+
def ldgettext(self, domain, message):
- """Like ``lgettext()``, but look the message up in the specified
+ """Like ``lgettext()``, but look the message up in the specified
domain.
- """
+ """
return self._domains.get(domain, self).lgettext(message)
-
+
def dugettext(self, domain, message):
"""Like ``ugettext()``, but look the message up in the specified
domain.
@@ -346,29 +357,32 @@ class Translations(gettext.GNUTranslations, object):
return self._domains.get(domain, self).ugettext(message)
else:
return self._domains.get(domain, self).gettext(message)
-
+
def dngettext(self, domain, singular, plural, num):
"""Like ``ngettext()``, but look the message up in the specified
domain.
"""
return self._domains.get(domain, self).ngettext(singular, plural, num)
-
+
def ldngettext(self, domain, singular, plural, num):
"""Like ``lngettext()``, but look the message up in the specified
domain.
"""
return self._domains.get(domain, self).lngettext(singular, plural, num)
-
+
def dungettext(self, domain, singular, plural, num):
"""Like ``ungettext()`` but look the message up in the specified
domain.
"""
if PY2:
return self._domains.get(domain, self).ungettext(
- singular, plural, num)
+ singular, plural, num
+ )
else:
return self._domains.get(domain, self).ngettext(
- singular, plural, num)
+ singular, plural, num
+ )
+
class LocalizerRequestMixin(object):
@reify
@@ -384,8 +398,9 @@ class LocalizerRequestMixin(object):
tdirs = registry.queryUtility(ITranslationDirectories, default=[])
localizer = make_localizer(current_locale_name, tdirs)
- registry.registerUtility(localizer, ILocalizer,
- name=current_locale_name)
+ registry.registerUtility(
+ localizer, ILocalizer, name=current_locale_name
+ )
return localizer
@@ -393,5 +408,3 @@ class LocalizerRequestMixin(object):
def locale_name(self):
locale_name = negotiate_locale_name(self)
return locale_name
-
-
diff --git a/src/pyramid/interfaces.py b/src/pyramid/interfaces.py
index 4df5593f8..e2e211b67 100644
--- a/src/pyramid/interfaces.py
+++ b/src/pyramid/interfaces.py
@@ -1,14 +1,12 @@
from zope.deprecation import deprecated
-from zope.interface import (
- Attribute,
- Interface,
- )
+from zope.interface import Attribute, Interface
from pyramid.compat import PY2
# public API interfaces
+
class IContextFound(Interface):
""" An event type that is emitted after :app:`Pyramid` finds a
:term:`context` object but before it calls any view code. See the
@@ -21,32 +19,41 @@ class IContextFound(Interface):
:app:`Pyramid` before 1.0, this event interface can also be
imported as :class:`pyramid.interfaces.IAfterTraversal`.
"""
+
request = Attribute('The request object')
+
IAfterTraversal = IContextFound
+
class IBeforeTraversal(Interface):
"""
An event type that is emitted after :app:`Pyramid` attempted to find a
route but before it calls any traversal or view code. See the documentation
attached to :class:`pyramid.events.Routefound` for more information.
"""
+
request = Attribute('The request object')
+
class INewRequest(Interface):
""" An event type that is emitted whenever :app:`Pyramid`
begins to process a new request. See the documentation attached
to :class:`pyramid.events.NewRequest` for more information."""
+
request = Attribute('The request object')
+
class INewResponse(Interface):
""" An event type that is emitted whenever any :app:`Pyramid`
view returns a response. See the
documentation attached to :class:`pyramid.events.NewResponse`
for more information."""
+
request = Attribute('The request object')
response = Attribute('The response object')
+
class IApplicationCreated(Interface):
""" Event issued when the
:meth:`pyramid.config.Configurator.make_wsgi_app` method
@@ -60,9 +67,12 @@ class IApplicationCreated(Interface):
versions before 1.0, this interface can also be imported as
:class:`pyramid.interfaces.IWSGIApplicationCreatedEvent`.
"""
+
app = Attribute("Created application")
-IWSGIApplicationCreatedEvent = IApplicationCreated # b /c
+
+IWSGIApplicationCreatedEvent = IApplicationCreated # b /c
+
class IResponse(Interface):
""" Represents a WSGI response using the WebOb response interface.
@@ -74,7 +84,8 @@ class IResponse(Interface):
:mod:`pyramid.httpexceptions`."""
RequestClass = Attribute(
- """ Alias for :class:`pyramid.request.Request` """)
+ """ Alias for :class:`pyramid.request.Request` """
+ )
def __call__(environ, start_response):
""" :term:`WSGI` call interface, should call the start_response
@@ -82,21 +93,25 @@ class IResponse(Interface):
accept_ranges = Attribute(
"""Gets and sets and deletes the Accept-Ranges header. For more
- information on Accept-Ranges see RFC 2616, section 14.5""")
+ information on Accept-Ranges see RFC 2616, section 14.5"""
+ )
age = Attribute(
"""Gets and sets and deletes the Age header. Converts using int.
- For more information on Age see RFC 2616, section 14.6.""")
+ For more information on Age see RFC 2616, section 14.6."""
+ )
allow = Attribute(
"""Gets and sets and deletes the Allow header. Converts using
- list. For more information on Allow see RFC 2616, Section 14.7.""")
+ list. For more information on Allow see RFC 2616, Section 14.7."""
+ )
app_iter = Attribute(
"""Returns the app_iter of the response.
If body was set, this will create an app_iter from that body
- (a single-item list)""")
+ (a single-item list)"""
+ )
def app_iter_range(start, stop):
""" Return a new app_iter built from the response app_iter that
@@ -104,21 +119,24 @@ class IResponse(Interface):
body = Attribute(
"""The body of the response, as a str. This will read in the entire
- app_iter if necessary.""")
+ app_iter if necessary."""
+ )
body_file = Attribute(
"""A file-like object that can be used to write to the body. If you
- passed in a list app_iter, that app_iter will be modified by writes.""")
+ passed in a list app_iter, that app_iter will be modified by writes."""
+ )
cache_control = Attribute(
- """Get/set/modify the Cache-Control header (RFC 2616 section 14.9)""")
+ """Get/set/modify the Cache-Control header (RFC 2616 section 14.9)"""
+ )
cache_expires = Attribute(
""" Get/set the Cache-Control and Expires headers. This sets the
- response to expire in the number of seconds passed when set. """)
+ response to expire in the number of seconds passed when set. """
+ )
- charset = Attribute(
- """Get/set the charset (in the Content-Type)""")
+ charset = Attribute("""Get/set the charset (in the Content-Type)""")
def conditional_response_app(environ, start_response):
""" Like the normal __call__ interface, but checks conditional
@@ -133,52 +151,62 @@ class IResponse(Interface):
content_disposition = Attribute(
"""Gets and sets and deletes the Content-Disposition header.
For more information on Content-Disposition see RFC 2616 section
- 19.5.1.""")
+ 19.5.1."""
+ )
content_encoding = Attribute(
"""Gets and sets and deletes the Content-Encoding header. For more
- information about Content-Encoding see RFC 2616 section 14.11.""")
+ information about Content-Encoding see RFC 2616 section 14.11."""
+ )
content_language = Attribute(
"""Gets and sets and deletes the Content-Language header. Converts
using list. For more information about Content-Language see RFC 2616
- section 14.12.""")
+ section 14.12."""
+ )
content_length = Attribute(
"""Gets and sets and deletes the Content-Length header. For more
information on Content-Length see RFC 2616 section 14.17.
- Converts using int. """)
+ Converts using int. """
+ )
content_location = Attribute(
"""Gets and sets and deletes the Content-Location header. For more
- information on Content-Location see RFC 2616 section 14.14.""")
+ information on Content-Location see RFC 2616 section 14.14."""
+ )
content_md5 = Attribute(
"""Gets and sets and deletes the Content-MD5 header. For more
- information on Content-MD5 see RFC 2616 section 14.14.""")
+ information on Content-MD5 see RFC 2616 section 14.14."""
+ )
content_range = Attribute(
"""Gets and sets and deletes the Content-Range header. For more
information on Content-Range see section 14.16. Converts using
- ContentRange object.""")
+ ContentRange object."""
+ )
content_type = Attribute(
"""Get/set the Content-Type header (or None), without the charset
or any parameters. If you include parameters (or ; at all) when
setting the content_type, any existing parameters will be deleted;
- otherwise they will be preserved.""")
+ otherwise they will be preserved."""
+ )
content_type_params = Attribute(
"""A dictionary of all the parameters in the content type. This is
not a view, set to change, modifications of the dict would not
- be applied otherwise.""")
+ be applied otherwise."""
+ )
def copy():
""" Makes a copy of the response and returns the copy. """
date = Attribute(
"""Gets and sets and deletes the Date header. For more information on
- Date see RFC 2616 section 14.18. Converts using HTTP date.""")
+ Date see RFC 2616 section 14.18. Converts using HTTP date."""
+ )
def delete_cookie(name, path='/', domain=None):
""" Delete a cookie from the client. Note that path and domain must
@@ -191,31 +219,34 @@ class IResponse(Interface):
environ = Attribute(
"""Get/set the request environ associated with this response,
- if any.""")
+ if any."""
+ )
etag = Attribute(
""" Gets and sets and deletes the ETag header. For more information
- on ETag see RFC 2616 section 14.19. Converts using Entity tag.""")
+ on ETag see RFC 2616 section 14.19. Converts using Entity tag."""
+ )
expires = Attribute(
""" Gets and sets and deletes the Expires header. For more
information on Expires see RFC 2616 section 14.21. Converts using
- HTTP date.""")
+ HTTP date."""
+ )
- headerlist = Attribute(
- """ The list of response headers. """)
+ headerlist = Attribute(""" The list of response headers. """)
- headers = Attribute(
- """ The headers in a dictionary-like object """)
+ headers = Attribute(""" The headers in a dictionary-like object """)
last_modified = Attribute(
""" Gets and sets and deletes the Last-Modified header. For more
information on Last-Modified see RFC 2616 section 14.29. Converts
- using HTTP date.""")
+ using HTTP date."""
+ )
location = Attribute(
""" Gets and sets and deletes the Location header. For more
- information on Location see RFC 2616 section 14.30.""")
+ information on Location see RFC 2616 section 14.30."""
+ )
def md5_etag(body=None, set_content_md5=False):
""" Generate an etag for the response object using an MD5 hash of the
@@ -230,34 +261,46 @@ class IResponse(Interface):
pragma = Attribute(
""" Gets and sets and deletes the Pragma header. For more information
- on Pragma see RFC 2616 section 14.32. """)
+ on Pragma see RFC 2616 section 14.32. """
+ )
request = Attribute(
- """ Return the request associated with this response if any. """)
+ """ Return the request associated with this response if any. """
+ )
retry_after = Attribute(
""" Gets and sets and deletes the Retry-After header. For more
information on Retry-After see RFC 2616 section 14.37. Converts
- using HTTP date or delta seconds.""")
+ using HTTP date or delta seconds."""
+ )
server = Attribute(
""" Gets and sets and deletes the Server header. For more information
- on Server see RFC216 section 14.38. """)
+ on Server see RFC216 section 14.38. """
+ )
- def set_cookie(name, value='', max_age=None, path='/', domain=None,
- secure=False, httponly=False, comment=None, expires=None,
- overwrite=False):
+ def set_cookie(
+ name,
+ value='',
+ max_age=None,
+ path='/',
+ domain=None,
+ secure=False,
+ httponly=False,
+ comment=None,
+ expires=None,
+ overwrite=False,
+ ):
""" Set (add) a cookie for the response """
- status = Attribute(
- """ The status string. """)
+ status = Attribute(""" The status string. """)
- status_int = Attribute(
- """ The status as an integer """)
+ status_int = Attribute(""" The status as an integer """)
unicode_body = Attribute(
""" Get/set the unicode value of the body (using the charset of
- the Content-Type)""")
+ the Content-Type)"""
+ )
def unset_cookie(name, strict=True):
""" Unset a cookie with the given name (remove it from the
@@ -265,16 +308,20 @@ class IResponse(Interface):
vary = Attribute(
"""Gets and sets and deletes the Vary header. For more information
- on Vary see section 14.44. Converts using list.""")
+ on Vary see section 14.44. Converts using list."""
+ )
www_authenticate = Attribute(
""" Gets and sets and deletes the WWW-Authenticate header. For more
information on WWW-Authenticate see RFC 2616 section 14.47. Converts
- using 'parse_auth' and 'serialize_auth'. """)
+ using 'parse_auth' and 'serialize_auth'. """
+ )
-class IException(Interface): # not an API
+
+class IException(Interface): # not an API
""" An interface representing a generic exception """
+
class IExceptionResponse(IException, IResponse):
""" An interface representing a WSGI response which is also an exception
object. Register an exception view using this interface as a ``context``
@@ -283,9 +330,11 @@ class IExceptionResponse(IException, IResponse):
:class:`pyramid.response.Response`, including
:class:`pyramid.httpexceptions.HTTPNotFound` and
:class:`pyramid.httpexceptions.HTTPForbidden`)."""
+
def prepare(environ):
""" Prepares the response for being called as a WSGI application """
+
class IDict(Interface):
# Documentation-only interface
@@ -354,6 +403,7 @@ class IDict(Interface):
def clear():
""" Clear all values from the dictionary """
+
class IBeforeRender(IDict):
"""
Subscribers to this event may introspect and modify the set of
@@ -373,26 +423,37 @@ class IBeforeRender(IDict):
See also :ref:`beforerender_event`.
"""
- rendering_val = Attribute('The value returned by a view or passed to a '
- '``render`` method for this rendering. '
- 'This feature is new in Pyramid 1.2.')
+
+ rendering_val = Attribute(
+ 'The value returned by a view or passed to a '
+ '``render`` method for this rendering. '
+ 'This feature is new in Pyramid 1.2.'
+ )
+
class IRendererInfo(Interface):
""" An object implementing this interface is passed to every
:term:`renderer factory` constructor as its only argument (conventionally
named ``info``)"""
+
name = Attribute('The value passed by the user as the renderer name')
- package = Attribute('The "current package" when the renderer '
- 'configuration statement was found')
+ package = Attribute(
+ 'The "current package" when the renderer '
+ 'configuration statement was found'
+ )
type = Attribute('The renderer type name')
- registry = Attribute('The "current" application registry when the '
- 'renderer was created')
- settings = Attribute('The deployment settings dictionary related '
- 'to the current application')
+ registry = Attribute(
+ 'The "current" application registry when the ' 'renderer was created'
+ )
+ settings = Attribute(
+ 'The deployment settings dictionary related '
+ 'to the current application'
+ )
def clone():
""" Return a shallow copy that does not share any mutable state."""
+
class IRendererFactory(Interface):
def __call__(info):
""" Return an object that implements
@@ -400,6 +461,7 @@ class IRendererFactory(Interface):
object that implements :class:`pyramid.interfaces.IRendererInfo`.
"""
+
class IRenderer(Interface):
def __call__(value, system):
""" Call the renderer with the result of the
@@ -413,6 +475,7 @@ class IRenderer(Interface):
view), and ``request`` (the request object passed to the
view)."""
+
class ITemplateRenderer(IRenderer):
def implementation():
""" Return the object that the underlying templating system
@@ -420,12 +483,14 @@ class ITemplateRenderer(IRenderer):
accepts arbitrary keyword arguments and returns a string or
unicode object """
+
deprecated(
'ITemplateRenderer',
'As of Pyramid 1.5 the, "pyramid.interfaces.ITemplateRenderer" interface '
'is scheduled to be removed. It was used by the Mako and Chameleon '
- 'renderers which have been split into their own packages.'
- )
+ 'renderers which have been split into their own packages.',
+)
+
class IViewMapper(Interface):
def __call__(self, object):
@@ -435,6 +500,7 @@ class IViewMapper(Interface):
object. An IViewMapper is returned by
:class:`pyramid.interfaces.IViewMapperFactory`."""
+
class IViewMapperFactory(Interface):
def __call__(self, **kw):
"""
@@ -448,6 +514,7 @@ class IViewMapperFactory(Interface):
invocation signatures and response values.
"""
+
class IAuthenticationPolicy(Interface):
""" An object representing a Pyramid authentication policy. """
@@ -500,8 +567,10 @@ class IAuthenticationPolicy(Interface):
"""
+
class IAuthorizationPolicy(Interface):
""" An object representing a Pyramid authorization policy. """
+
def permits(context, principals, permission):
""" Return an instance of :class:`pyramid.security.Allowed` if any
of the ``principals`` is allowed the ``permission`` in the current
@@ -518,7 +587,8 @@ class IAuthorizationPolicy(Interface):
``pyramid.security.principals_allowed_by_permission`` API is
used."""
-class IMultiDict(IDict): # docs-only interface
+
+class IMultiDict(IDict): # docs-only interface
"""
An ordered dictionary that can have multiple values for each key. A
multidict adds the methods ``getall``, ``getone``, ``mixed``, ``extend``,
@@ -556,36 +626,46 @@ class IMultiDict(IDict): # docs-only interface
dictionary. This is similar to the kind of dictionary often used to
represent the variables in a web request. """
+
# internal interfaces
+
class IRequest(Interface):
""" Request type interface attached to all request objects """
+
class ITweens(Interface):
""" Marker interface for utility registration representing the ordered
set of a configuration's tween factories"""
+
class IRequestHandler(Interface):
""" """
+
def __call__(self, request):
""" Must return a tuple of IReqest, IResponse or raise an exception.
The ``request`` argument will be an instance of an object that
provides IRequest."""
-IRequest.combined = IRequest # for exception view lookups
+
+IRequest.combined = IRequest # for exception view lookups
+
class IRequestExtensions(Interface):
""" Marker interface for storing request extensions (properties and
methods) which will be added to the request object."""
+
descriptors = Attribute(
- """A list of descriptors that will be added to each request.""")
- methods = Attribute(
- """A list of methods to be added to each request.""")
+ """A list of descriptors that will be added to each request."""
+ )
+ methods = Attribute("""A list of methods to be added to each request.""")
+
class IRouteRequest(Interface):
""" *internal only* interface used as in a utility lookup to find
route-specific interfaces. Not an API."""
+
class IAcceptOrder(Interface):
"""
Marker interface for a list of accept headers with the most important
@@ -593,8 +673,10 @@ class IAcceptOrder(Interface):
"""
+
class IStaticURLInfo(Interface):
""" A policy for generating URLs to static assets """
+
def add(config, name, spec, **extra):
""" Add a new static info registration """
@@ -604,15 +686,19 @@ class IStaticURLInfo(Interface):
def add_cache_buster(config, spec, cache_buster):
""" Add a new cache buster to a particular set of assets """
+
class IResponseFactory(Interface):
""" A utility which generates a response """
+
def __call__(request):
""" Return a response object implementing IResponse,
e.g. :class:`pyramid.response.Response`). It should handle the
case when ``request`` is ``None``."""
+
class IRequestFactory(Interface):
""" A utility which generates a request """
+
def __call__(environ):
""" Return an instance of ``pyramid.request.Request``"""
@@ -620,18 +706,23 @@ class IRequestFactory(Interface):
""" Return an empty request object (see
:meth:`pyramid.request.Request.blank`)"""
+
class IViewClassifier(Interface):
""" *Internal only* marker interface for views."""
+
class IExceptionViewClassifier(Interface):
""" *Internal only* marker interface for exception views."""
+
class IView(Interface):
def __call__(context, request):
""" Must return an object that implements IResponse. """
+
class ISecuredView(IView):
""" *Internal only* interface. Not an API. """
+
def __call_permissive__(context, request):
""" Guaranteed-permissive version of __call__ """
@@ -639,21 +730,26 @@ class ISecuredView(IView):
""" Return True if view execution will be permitted using the
context and request, False otherwise"""
+
class IMultiView(ISecuredView):
""" *internal only*. A multiview is a secured view that is a
collection of other views. Each of the views is associated with
zero or more predicates. Not an API."""
+
def add(view, predicates, order, accept=None, phash=None):
""" Add a view to the multiview. """
+
class IRootFactory(Interface):
def __call__(request):
""" Return a root object based on the request """
+
class IDefaultRootFactory(Interface):
def __call__(request):
""" Return the *default* root object for an application """
+
class ITraverser(Interface):
def __call__(request):
""" Return a dictionary with (at least) the keys ``root``,
@@ -678,21 +774,26 @@ class ITraverser(Interface):
as attributes of the ``request`` object by the :term:`router`.
"""
-ITraverserFactory = ITraverser # b / c for 1.0 code
+
+ITraverserFactory = ITraverser # b / c for 1.0 code
+
class IViewPermission(Interface):
def __call__(context, request):
""" Return True if the permission allows, return False if it denies.
"""
+
class IRouter(Interface):
"""
WSGI application which routes requests to 'view' code based on
a view registry.
"""
+
registry = Attribute(
- """Component architecture registry local to this application.""")
+ """Component architecture registry local to this application."""
+ )
def request_context(environ):
"""
@@ -734,6 +835,7 @@ class IRouter(Interface):
"""
+
class IExecutionPolicy(Interface):
def __call__(environ, router):
"""
@@ -762,22 +864,28 @@ class IExecutionPolicy(Interface):
return request.invoke_exception_view(reraise=True)
"""
+
class ISettings(IDict):
""" Runtime settings utility for pyramid; represents the
deployment settings for the application. Implements a mapping
interface."""
+
# this interface, even if it becomes unused within Pyramid, is
# imported by other packages (such as traversalwrapper)
class ILocation(Interface):
"""Objects that have a structural location"""
+
__parent__ = Attribute("The parent in the location hierarchy")
__name__ = Attribute("The name within the parent")
+
class IDebugLogger(Interface):
""" Interface representing a PEP 282 logger """
-ILogger = IDebugLogger # b/c
+
+ILogger = IDebugLogger # b/c
+
class IRoutePregenerator(Interface):
def __call__(request, elements, kw):
@@ -804,21 +912,27 @@ class IRoutePregenerator(Interface):
"""
+
class IRoute(Interface):
""" Interface representing the type of object returned from
``IRoutesMapper.get_route``"""
+
name = Attribute('The route name')
pattern = Attribute('The route pattern')
factory = Attribute(
'The :term:`root factory` used by the :app:`Pyramid` router '
- 'when this route matches (or ``None``)')
+ 'when this route matches (or ``None``)'
+ )
predicates = Attribute(
'A sequence of :term:`route predicate` objects used to '
'determine if a request matches this route or not after '
- 'basic pattern matching has been completed.')
- pregenerator = Attribute('This attribute should either be ``None`` or '
- 'a callable object implementing the '
- '``IRoutePregenerator`` interface')
+ 'basic pattern matching has been completed.'
+ )
+ pregenerator = Attribute(
+ 'This attribute should either be ``None`` or '
+ 'a callable object implementing the '
+ '``IRoutePregenerator`` interface'
+ )
def match(path):
"""
@@ -831,14 +945,17 @@ class IRoute(Interface):
If the ``path`` passed to this function cannot be matched by
the ``pattern`` of this route, return ``None``.
"""
+
def generate(kw):
"""
Generate a URL based on filling in the dynamic segment markers
in the pattern using the ``kw`` dictionary provided.
"""
+
class IRoutesMapper(Interface):
""" Interface representing a Routes ``Mapper`` object """
+
def get_routes():
""" Return a sequence of Route objects registered in the mapper.
Static routes will not be returned in this sequence."""
@@ -850,8 +967,14 @@ class IRoutesMapper(Interface):
""" Returns an ``IRoute`` object if a route with the name ``name``
was registered, otherwise return ``None``."""
- def connect(name, pattern, factory=None, predicates=(), pregenerator=None,
- static=True):
+ def connect(
+ name,
+ pattern,
+ factory=None,
+ predicates=(),
+ pregenerator=None,
+ static=True,
+ ):
""" Add a new route. """
def generate(name, kw):
@@ -865,23 +988,26 @@ class IRoutesMapper(Interface):
``match`` key will be the matchdict or ``None`` if no route
matched. Static routes will not be considered for matching. """
+
class IResourceURL(Interface):
virtual_path = Attribute(
'The virtual url path of the resource as a string.'
- )
+ )
physical_path = Attribute(
'The physical url path of the resource as a string.'
- )
+ )
virtual_path_tuple = Attribute(
'The virtual url path of the resource as a tuple. (New in 1.5)'
- )
+ )
physical_path_tuple = Attribute(
'The physical url path of the resource as a tuple. (New in 1.5)'
- )
+ )
+
class IPEP302Loader(Interface):
""" See http://www.python.org/dev/peps/pep-0302/#id30.
"""
+
def get_data(path):
""" Retrieve data for and arbitrary "files" from storage backend.
@@ -924,43 +1050,54 @@ class IPEP302Loader(Interface):
class IPackageOverrides(IPEP302Loader):
""" Utility for pkg_resources overrides """
+
# VH_ROOT_KEY is an interface; its imported from other packages (e.g.
# traversalwrapper)
VH_ROOT_KEY = 'HTTP_X_VHM_ROOT'
+
class ILocalizer(Interface):
""" Localizer for a specific language """
+
class ILocaleNegotiator(Interface):
def __call__(request):
""" Return a locale name """
+
class ITranslationDirectories(Interface):
""" A list object representing all known translation directories
for an application"""
+
class IDefaultPermission(Interface):
""" A string object representing the default permission to be used
for all view configurations which do not explicitly declare their
own."""
+
class IDefaultCSRFOptions(Interface):
""" An object representing the default CSRF settings to be used for
all view configurations which do not explicitly declare their own."""
+
require_csrf = Attribute(
'Boolean attribute. If ``True``, then CSRF checks will be enabled by '
- 'default for the view unless overridden.')
+ 'default for the view unless overridden.'
+ )
token = Attribute('The key to be matched in the body of the request.')
header = Attribute('The header to be matched with the CSRF token.')
safe_methods = Attribute('A set of safe methods that skip CSRF checks.')
callback = Attribute('A callback to disable CSRF checks per-request.')
+
class ISessionFactory(Interface):
""" An interface representing a factory which accepts a request object and
returns an ISession object """
+
def __call__(request):
""" Return an ISession object """
+
class ISession(IDict):
""" An interface representing a session (a web session object,
usually accessed via ``request.session``.
@@ -1158,16 +1295,21 @@ class IIntrospectable(Interface):
title = Attribute('Text title describing this introspectable')
type_name = Attribute('Text type name describing this introspectable')
- order = Attribute('integer order in which registered with introspector '
- '(managed by introspector, usually)')
+ order = Attribute(
+ 'integer order in which registered with introspector '
+ '(managed by introspector, usually)'
+ )
category_name = Attribute('introspection category name')
- discriminator = Attribute('introspectable discriminator (within category) '
- '(must be hashable)')
+ discriminator = Attribute(
+ 'introspectable discriminator (within category) ' '(must be hashable)'
+ )
discriminator_hash = Attribute('an integer hash of the discriminator')
- action_info = Attribute('An IActionInfo object representing the caller '
- 'that invoked the creation of this introspectable '
- '(usually a sentinel until updated during '
- 'self.register)')
+ action_info = Attribute(
+ 'An IActionInfo object representing the caller '
+ 'that invoked the creation of this introspectable '
+ '(usually a sentinel until updated during '
+ 'self.register)'
+ )
def relate(category_name, discriminator):
""" Indicate an intent to relate this IIntrospectable with another
@@ -1199,7 +1341,7 @@ class IIntrospectable(Interface):
method = getattr(introspector, methodname)
method((i.category_name, i.discriminator),
(category_name, discriminator))
- """
+ """ # noqa: E501
def __hash__():
@@ -1209,19 +1351,23 @@ class IIntrospectable(Interface):
return hash((self.category_name,) + (self.discriminator,))
"""
+
class IActionInfo(Interface):
""" Class which provides code introspection capability associated with an
- action. The ParserInfo class used by ZCML implements the same interface."""
- file = Attribute(
- 'Filename of action-invoking code as a string')
+ action. The ParserInfo class used by ZCML implements the same interface.
+ """
+
+ file = Attribute('Filename of action-invoking code as a string')
line = Attribute(
'Starting line number in file (as an integer) of action-invoking code.'
- 'This will be ``None`` if the value could not be determined.')
+ 'This will be ``None`` if the value could not be determined.'
+ )
def __str__():
""" Return a representation of the action information (including
source code from file, if possible) """
+
class IAssetDescriptor(Interface):
"""
Describes an :term:`asset`.
@@ -1260,19 +1406,24 @@ class IAssetDescriptor(Interface):
Returns True if asset exists, otherwise returns False.
"""
+
class IJSONAdapter(Interface):
"""
Marker interface for objects that can convert an arbitrary object
into a JSON-serializable primitive.
"""
+
class IPredicateList(Interface):
""" Interface representing a predicate list """
+
class IViewDeriver(Interface):
- options = Attribute('A list of supported options to be passed to '
- ':meth:`pyramid.config.Configurator.add_view`. '
- 'This attribute is optional.')
+ options = Attribute(
+ 'A list of supported options to be passed to '
+ ':meth:`pyramid.config.Configurator.add_view`. '
+ 'This attribute is optional.'
+ )
def __call__(view, info):
"""
@@ -1285,24 +1436,35 @@ class IViewDeriver(Interface):
"""
+
class IViewDeriverInfo(Interface):
""" An object implementing this interface is passed to every
:term:`view deriver` during configuration."""
- registry = Attribute('The "current" application registry where the '
- 'view was created')
- package = Attribute('The "current package" where the view '
- 'configuration statement was found')
- settings = Attribute('The deployment settings dictionary related '
- 'to the current application')
- options = Attribute('The view options passed to the view, including any '
- 'default values that were not overriden')
+
+ registry = Attribute(
+ 'The "current" application registry where the ' 'view was created'
+ )
+ package = Attribute(
+ 'The "current package" where the view '
+ 'configuration statement was found'
+ )
+ settings = Attribute(
+ 'The deployment settings dictionary related '
+ 'to the current application'
+ )
+ options = Attribute(
+ 'The view options passed to the view, including any '
+ 'default values that were not overriden'
+ )
predicates = Attribute('The list of predicates active on the view')
original_view = Attribute('The original view object being wrapped')
exception_only = Attribute('The view will only be invoked for exceptions')
+
class IViewDerivers(Interface):
""" Interface for view derivers list """
+
class ICacheBuster(Interface):
"""
A cache buster modifies the URL generation machinery for
@@ -1310,6 +1472,7 @@ class ICacheBuster(Interface):
.. versionadded:: 1.6
"""
+
def __call__(request, subpath, kw):
"""
Modifies a subpath and/or keyword arguments from which a static asset
@@ -1344,6 +1507,7 @@ class ICacheBuster(Interface):
``config.override_asset('myapp:static/foo.png', 'themepkg:bar.png')``.
"""
+
# configuration phases: a lower phase number means the actions associated
# with this phase will be executed earlier than those with later phase
# numbers. The default phase number is 0, FTR.
diff --git a/src/pyramid/location.py b/src/pyramid/location.py
index 4124895a5..d90aed0d1 100644
--- a/src/pyramid/location.py
+++ b/src/pyramid/location.py
@@ -12,6 +12,7 @@
#
##############################################################################
+
def inside(resource1, resource2):
"""Is ``resource1`` 'inside' ``resource2``? Return ``True`` if so, else
``False``.
@@ -28,6 +29,7 @@ def inside(resource1, resource2):
return False
+
def lineage(resource):
"""
Return a generator representing the :term:`lineage` of the
@@ -46,7 +48,7 @@ def lineage(resource):
Calling ``lineage(thing2)`` will return a generator. When we turn
it into a list, we will get::
-
+
list(lineage(thing2))
[ <Thing object at thing2>, <Thing object at thing1> ]
"""
@@ -63,4 +65,3 @@ def lineage(resource):
resource = resource.__parent__
except AttributeError:
resource = None
-
diff --git a/src/pyramid/paster.py b/src/pyramid/paster.py
index f7544f0c5..22c09e41a 100644
--- a/src/pyramid/paster.py
+++ b/src/pyramid/paster.py
@@ -1,6 +1,7 @@
from pyramid.scripting import prepare
from pyramid.scripts.common import get_config_loader
+
def setup_logging(config_uri, global_conf=None):
"""
Set up Python logging with the filename specified via ``config_uri``
@@ -11,6 +12,7 @@ def setup_logging(config_uri, global_conf=None):
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``.
@@ -27,6 +29,7 @@ def get_app(config_uri, name=None, options=None):
loader = get_config_loader(config_uri)
return loader.get_wsgi_app(name, options)
+
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``.
@@ -43,6 +46,7 @@ def get_appsettings(config_uri, name=None, options=None):
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
by ``config_uri``. The environment will be configured as if it is
@@ -83,7 +87,7 @@ def bootstrap(config_uri, request=None, options=None):
for you if none is provided. You can mutate the request's ``environ``
later to setup a specific host/port/scheme/etc.
- ``options`` Is passed to get_app for use as variable assignments like
+ ``options`` Is passed to get_app for use as variable assignments like
{'http_port': 8080} and then use %(http_port)s in the
config file.
@@ -108,4 +112,3 @@ def bootstrap(config_uri, request=None, options=None):
env = prepare(request)
env['app'] = app
return env
-
diff --git a/src/pyramid/path.py b/src/pyramid/path.py
index 3fac7e940..c70be99db 100644
--- a/src/pyramid/path.py
+++ b/src/pyramid/path.py
@@ -9,9 +9,13 @@ from pyramid.interfaces import IAssetDescriptor
from pyramid.compat import string_types
-ignore_types = [ imp.C_EXTENSION, imp.C_BUILTIN ]
-init_names = [ '__init__%s' % x[0] for x in imp.get_suffixes() if
- x[0] and x[2] not in ignore_types ]
+ignore_types = [imp.C_EXTENSION, imp.C_BUILTIN]
+init_names = [
+ '__init__%s' % x[0]
+ for x in imp.get_suffixes()
+ if x[0] and x[2] not in ignore_types
+]
+
def caller_path(path, level=2):
if not os.path.isabs(path):
@@ -20,12 +24,14 @@ def caller_path(path, level=2):
path = os.path.join(prefix, path)
return path
+
def caller_module(level=2, sys=sys):
module_globals = sys._getframe(level).f_globals
module_name = module_globals.get('__name__') or '__main__'
module = sys.modules[module_name]
return module
+
def package_name(pkg_or_module):
""" If this function is passed a module, return the dotted Python
package name of the package in which the module lives. If this
@@ -45,23 +51,26 @@ def package_name(pkg_or_module):
return pkg_name
return pkg_name.rsplit('.', 1)[0]
+
def package_of(pkg_or_module):
""" Return the package of a module or return the package itself """
pkg_name = package_name(pkg_or_module)
__import__(pkg_name)
return sys.modules[pkg_name]
+
def caller_package(level=2, caller_module=caller_module):
# caller_module in arglist for tests
module = caller_module(level + 1)
f = getattr(module, '__file__', '')
- if (('__init__.py' in f) or ('__init__$py' in f)): # empty at >>>
+ if ('__init__.py' in f) or ('__init__$py' in f): # empty at >>>
# Module is a package
return module
# Go up one level to get package
package_name = module.__name__.rsplit('.', 1)[0]
return sys.modules[package_name]
+
def package_path(package):
# computing the abspath is actually kinda expensive so we memoize
# the result
@@ -78,12 +87,15 @@ def package_path(package):
pass
return prefix
+
class _CALLER_PACKAGE(object):
- def __repr__(self): # pragma: no cover (for docs)
+ def __repr__(self): # pragma: no cover (for docs)
return 'pyramid.path.CALLER_PACKAGE'
+
CALLER_PACKAGE = _CALLER_PACKAGE()
+
class Resolver(object):
def __init__(self, package=CALLER_PACKAGE):
if package in (None, CALLER_PACKAGE):
@@ -95,7 +107,7 @@ class Resolver(object):
except ImportError:
raise ValueError(
'The dotted name %r cannot be imported' % (package,)
- )
+ )
package = sys.modules[package]
self.package = package_of(package)
@@ -164,6 +176,7 @@ class AssetResolver(Resolver):
to the :meth:`~pyramid.path.AssetResolver.resolve` method, the resulting
absolute asset spec would be ``xml.minidom:template.pt``.
"""
+
def resolve(self, spec):
"""
Resolve the asset spec named as ``spec`` to an object that has the
@@ -208,6 +221,7 @@ class AssetResolver(Resolver):
)
return PkgResourcesAssetDescriptor(package_name, path)
+
class DottedNameResolver(Resolver):
""" A class used to resolve a :term:`dotted Python name` to a package or
module object.
@@ -258,6 +272,7 @@ class DottedNameResolver(Resolver):
:meth:`~pyramid.path.DottedNameResolver.resolve` method, the resulting
import would be for ``xml.minidom``.
"""
+
def resolve(self, dotted):
"""
This method resolves a dotted name reference to a global Python
@@ -332,7 +347,7 @@ class DottedNameResolver(Resolver):
if not package:
raise ValueError(
'relative name %r irresolveable without package' % (value,)
- )
+ )
if value in ['.', ':']:
value = package.__name__
else:
@@ -348,7 +363,7 @@ class DottedNameResolver(Resolver):
def _zope_dottedname_style(self, value, package):
""" package.module.attr style """
- module = getattr(package, '__name__', None) # package may be None
+ module = getattr(package, '__name__', None) # package may be None
if not module:
module = None
if value == '.':
@@ -364,7 +379,7 @@ class DottedNameResolver(Resolver):
raise ValueError(
'relative name %r irresolveable without '
'package' % (value,)
- )
+ )
module = module.split('.')
name.pop(0)
while not name[0]:
@@ -380,10 +395,11 @@ class DottedNameResolver(Resolver):
found = getattr(found, n)
except AttributeError:
__import__(used)
- found = getattr(found, n) # pragma: no cover
+ found = getattr(found, n) # pragma: no cover
return found
+
@implementer(IAssetDescriptor)
class PkgResourcesAssetDescriptor(object):
pkg_resources = pkg_resources
@@ -397,7 +413,8 @@ class PkgResourcesAssetDescriptor(object):
def abspath(self):
return os.path.abspath(
- self.pkg_resources.resource_filename(self.pkg_name, self.path))
+ self.pkg_resources.resource_filename(self.pkg_name, self.path)
+ )
def stream(self):
return self.pkg_resources.resource_stream(self.pkg_name, self.path)
@@ -411,9 +428,9 @@ class PkgResourcesAssetDescriptor(object):
def exists(self):
return self.pkg_resources.resource_exists(self.pkg_name, self.path)
+
@implementer(IAssetDescriptor)
class FSAssetDescriptor(object):
-
def __init__(self, path):
self.path = os.path.abspath(path)
diff --git a/src/pyramid/predicates.py b/src/pyramid/predicates.py
index 97edae8a0..b95dfd9be 100644
--- a/src/pyramid/predicates.py
+++ b/src/pyramid/predicates.py
@@ -8,17 +8,15 @@ from pyramid.csrf import check_csrf_token
from pyramid.traversal import (
find_interface,
traversal_path,
- resource_path_tuple
- )
+ resource_path_tuple,
+)
from pyramid.urldispatch import _compile_route
-from pyramid.util import (
- as_sorted_tuple,
- object_description,
-)
+from pyramid.util import as_sorted_tuple, object_description
_marker = object()
+
class XHRPredicate(object):
def __init__(self, val, config):
self.val = bool(val)
@@ -31,6 +29,7 @@ class XHRPredicate(object):
def __call__(self, context, request):
return bool(request.is_xhr) is self.val
+
class RequestMethodPredicate(object):
def __init__(self, val, config):
request_method = as_sorted_tuple(val)
@@ -47,6 +46,7 @@ class RequestMethodPredicate(object):
def __call__(self, context, request):
return request.method in self.val
+
class PathInfoPredicate(object):
def __init__(self, val, config):
self.orig = val
@@ -63,7 +63,8 @@ class PathInfoPredicate(object):
def __call__(self, context, request):
return self.val.match(request.upath_info) is not None
-
+
+
class RequestParamPredicate(object):
def __init__(self, val, config):
val = as_sorted_tuple(val)
@@ -85,7 +86,7 @@ class RequestParamPredicate(object):
def text(self):
return 'request_param %s' % ','.join(
- ['%s=%s' % (x,y) if y else x for x, y in self.reqs]
+ ['%s=%s' % (x, y) if y else x for x, y in self.reqs]
)
phash = text
@@ -99,6 +100,7 @@ class RequestParamPredicate(object):
return False
return True
+
class HeaderPredicate(object):
def __init__(self, val, config):
name = val
@@ -129,6 +131,7 @@ class HeaderPredicate(object):
return False
return self.val.match(val) is not None
+
class AcceptPredicate(object):
_is_using_deprecated_ranges = False
@@ -151,6 +154,7 @@ class AcceptPredicate(object):
return self.values[0] in request.accept
return bool(request.accept.acceptable_offers(self.values))
+
class ContainmentPredicate(object):
def __init__(self, val, config):
self.val = config.maybe_dotted(val)
@@ -163,7 +167,8 @@ class ContainmentPredicate(object):
def __call__(self, context, request):
ctx = getattr(request, 'context', context)
return find_interface(ctx, self.val) is not None
-
+
+
class RequestTypePredicate(object):
def __init__(self, val, config):
self.val = val
@@ -175,18 +180,19 @@ class RequestTypePredicate(object):
def __call__(self, context, request):
return self.val.providedBy(request)
-
+
+
class MatchParamPredicate(object):
def __init__(self, val, config):
val = as_sorted_tuple(val)
self.val = val
- reqs = [ p.split('=', 1) for p in val ]
- self.reqs = [ (x.strip(), y.strip()) for x, y in reqs ]
+ reqs = [p.split('=', 1) for p in val]
+ self.reqs = [(x.strip(), y.strip()) for x, y in reqs]
def text(self):
return 'match_param %s' % ','.join(
- ['%s=%s' % (x,y) for x, y in self.reqs]
- )
+ ['%s=%s' % (x, y) for x, y in self.reqs]
+ )
phash = text
@@ -198,7 +204,8 @@ class MatchParamPredicate(object):
if request.matchdict.get(k) != v:
return False
return True
-
+
+
class CustomPredicate(object):
def __init__(self, func, config):
self.func = func
@@ -207,8 +214,8 @@ class CustomPredicate(object):
return getattr(
self.func,
'__text__',
- 'custom predicate: %s' % object_description(self.func)
- )
+ 'custom predicate: %s' % object_description(self.func),
+ )
def phash(self):
# using hash() here rather than id() is intentional: we
@@ -221,8 +228,8 @@ class CustomPredicate(object):
def __call__(self, context, request):
return self.func(context, request)
-
-
+
+
class TraversePredicate(object):
# Can only be used as a *route* "predicate"; it adds 'traverse' to the
# matchdict if it's specified in the routing args. This causes the
@@ -231,7 +238,7 @@ class TraversePredicate(object):
def __init__(self, val, config):
_, self.tgenerate = _compile_route(val)
self.val = val
-
+
def text(self):
return 'traverse matchdict pseudo-predicate'
@@ -252,10 +259,11 @@ class TraversePredicate(object):
# return True.
return True
+
class CheckCSRFTokenPredicate(object):
- check_csrf_token = staticmethod(check_csrf_token) # testing
-
+ check_csrf_token = staticmethod(check_csrf_token) # testing
+
def __init__(self, val, config):
self.val = val
@@ -272,6 +280,7 @@ class CheckCSRFTokenPredicate(object):
return self.check_csrf_token(request, val, raises=False)
return True
+
class PhysicalPathPredicate(object):
def __init__(self, val, config):
if is_nonstr_iter(val):
@@ -290,6 +299,7 @@ class PhysicalPathPredicate(object):
return resource_path_tuple(context) == self.val
return False
+
class EffectivePrincipalsPredicate(object):
def __init__(self, val, config):
if is_nonstr_iter(val):
@@ -310,6 +320,7 @@ class EffectivePrincipalsPredicate(object):
return True
return False
+
class Notted(object):
def __init__(self, predicate):
self.predicate = predicate
diff --git a/src/pyramid/registry.py b/src/pyramid/registry.py
index a741c495e..c24125830 100644
--- a/src/pyramid/registry.py
+++ b/src/pyramid/registry.py
@@ -7,19 +7,13 @@ from zope.interface.registry import Components
from pyramid.compat import text_
from pyramid.decorator import reify
-from pyramid.interfaces import (
- IIntrospector,
- IIntrospectable,
- ISettings,
-)
+from pyramid.interfaces import IIntrospector, IIntrospectable, ISettings
-from pyramid.path import (
- CALLER_PACKAGE,
- caller_package,
-)
+from pyramid.path import CALLER_PACKAGE, caller_package
empty = text_('')
+
class Registry(Components, dict):
""" A registry object is an :term:`application registry`.
@@ -82,13 +76,19 @@ class Registry(Components, dict):
self.has_listeners = True
return result
- def registerSelfAdapter(self, required=None, provided=None, name=empty,
- info=empty, event=True):
+ def registerSelfAdapter(
+ self, required=None, provided=None, name=empty, info=empty, event=True
+ ):
# registerAdapter analogue which always returns the object itself
# when required is matched
- return self.registerAdapter(lambda x: x, required=required,
- provided=provided, name=name,
- info=info, event=event)
+ return self.registerAdapter(
+ lambda x: x,
+ required=required,
+ provided=provided,
+ name=name,
+ info=info,
+ event=event,
+ )
def queryAdapterOrSelf(self, object, interface, default=None):
# queryAdapter analogue which returns the object if it implements
@@ -106,7 +106,7 @@ class Registry(Components, dict):
def notify(self, *events):
if self.has_listeners:
# iterating over subscribers assures they get executed
- [ _ for _ in self.subscribers(events, None) ]
+ [_ for _ in self.subscribers(events, None)]
# backwards compatibility for code that wants to look up a settings
# object via ``registry.getUtility(ISettings)``
@@ -119,6 +119,7 @@ class Registry(Components, dict):
settings = property(_get_settings, _set_settings)
+
@implementer(IIntrospector)
class Introspector(object):
def __init__(self):
@@ -147,16 +148,19 @@ class Introspector(object):
values = category.values()
values = sorted(set(values), key=sort_key)
return [
- {'introspectable': intr,
- 'related': self.related(intr)}
+ {'introspectable': intr, 'related': self.related(intr)}
for intr in values
]
def categorized(self, sort_key=None):
L = []
for category_name in self.categories():
- L.append((category_name, self.get_category(category_name,
- sort_key=sort_key)))
+ L.append(
+ (
+ category_name,
+ self.get_category(category_name, sort_key=sort_key),
+ )
+ )
return L
def categories(self):
@@ -186,7 +190,7 @@ class Introspector(object):
def relate(self, *pairs):
introspectables = self._get_intrs_by_pairs(pairs)
- relatable = ((x,y) for x in introspectables for y in introspectables)
+ relatable = ((x, y) for x in introspectables for y in introspectables)
for x, y in relatable:
L = self._refs.setdefault(x, [])
if x is not y and y not in L:
@@ -194,7 +198,7 @@ class Introspector(object):
def unrelate(self, *pairs):
introspectables = self._get_intrs_by_pairs(pairs)
- relatable = ((x,y) for x in introspectables for y in introspectables)
+ relatable = ((x, y) for x in introspectables for y in introspectables)
for x, y in relatable:
L = self._refs.get(x, [])
if y in L:
@@ -207,11 +211,12 @@ class Introspector(object):
raise KeyError((category_name, discriminator))
return self._refs.get(intr, [])
+
@implementer(IIntrospectable)
class Introspectable(dict):
- order = 0 # mutated by introspector.add
- action_info = None # mutated by self.register
+ order = 0 # mutated by introspector.add
+ action_info = None # mutated by self.register
def __init__(self, category_name, discriminator, title, type_name):
self.category_name = category_name
@@ -240,14 +245,16 @@ class Introspectable(dict):
def __repr__(self):
self._assert_resolved()
- return '<%s category %r, discriminator %r>' % (self.__class__.__name__,
- self.category_name,
- self.discriminator)
+ return '<%s category %r, discriminator %r>' % (
+ self.__class__.__name__,
+ self.category_name,
+ self.discriminator,
+ )
def __nonzero__(self):
return True
- __bool__ = __nonzero__ # py3
+ __bool__ = __nonzero__ # py3
def register(self, introspector, action_info):
self.discriminator = undefer(self.discriminator)
@@ -261,8 +268,9 @@ class Introspectable(dict):
method = introspector.unrelate
method(
(self.category_name, self.discriminator),
- (category_name, discriminator)
- )
+ (category_name, discriminator),
+ )
+
class Deferred(object):
""" Can be used by a third-party configuration extender to wrap a
@@ -270,6 +278,7 @@ class Deferred(object):
discriminator cannot be computed because it relies on unresolved values.
The function should accept no arguments and should return a hashable
discriminator."""
+
def __init__(self, func):
self.func = func
@@ -282,6 +291,7 @@ class Deferred(object):
def resolve(self):
return self.value
+
def undefer(v):
""" Function which accepts an object and returns it unless it is a
:class:`pyramid.registry.Deferred` instance. If it is an instance of
@@ -291,7 +301,9 @@ def undefer(v):
v = v.resolve()
return v
+
class predvalseq(tuple):
""" A subtype of tuple used to represent a sequence of predicate values """
+
global_registry = Registry('global')
diff --git a/src/pyramid/renderers.py b/src/pyramid/renderers.py
index d1c85b371..a8e3ec16f 100644
--- a/src/pyramid/renderers.py
+++ b/src/pyramid/renderers.py
@@ -3,22 +3,12 @@ import json
import os
import re
-from zope.interface import (
- implementer,
- providedBy,
- )
+from zope.interface import implementer, providedBy
from zope.interface.registry import Components
-from pyramid.interfaces import (
- IJSONAdapter,
- IRendererFactory,
- IRendererInfo,
- )
+from pyramid.interfaces import IJSONAdapter, IRendererFactory, IRendererInfo
-from pyramid.compat import (
- string_types,
- text_type,
- )
+from pyramid.compat import string_types, text_type
from pyramid.csrf import get_csrf_token
from pyramid.decorator import reify
@@ -35,6 +25,7 @@ from pyramid.util import hide_attrs
# API
+
def render(renderer_name, value, request=None, package=None):
""" Using the renderer ``renderer_name`` (a template
or a static renderer), render the value (or set of values) present
@@ -76,19 +67,19 @@ def render(renderer_name, value, request=None, package=None):
registry = None
if package is None:
package = caller_package()
- helper = RendererHelper(name=renderer_name, package=package,
- registry=registry)
+ helper = RendererHelper(
+ name=renderer_name, package=package, registry=registry
+ )
with hide_attrs(request, 'response'):
result = helper.render(value, None, request=request)
return result
-def render_to_response(renderer_name,
- value,
- request=None,
- package=None,
- response=None):
+
+def render_to_response(
+ renderer_name, value, request=None, package=None, response=None
+):
""" Using the renderer ``renderer_name`` (a template
or a static renderer), render the value (or set of values) using
the result of the renderer's ``__call__`` method (usually a string
@@ -137,8 +128,9 @@ def render_to_response(renderer_name,
registry = None
if package is None:
package = caller_package()
- helper = RendererHelper(name=renderer_name, package=package,
- registry=registry)
+ helper = RendererHelper(
+ name=renderer_name, package=package, registry=registry
+ )
with hide_attrs(request, 'response'):
if response is not None:
@@ -147,6 +139,7 @@ def render_to_response(renderer_name,
return result
+
def get_renderer(renderer_name, package=None, registry=None):
""" Return the renderer object for the renderer ``renderer_name``.
@@ -165,12 +158,15 @@ def get_renderer(renderer_name, package=None, registry=None):
"""
if package is None:
package = caller_package()
- helper = RendererHelper(name=renderer_name, package=package,
- registry=registry)
+ helper = RendererHelper(
+ name=renderer_name, package=package, registry=registry
+ )
return helper.renderer
+
# concrete renderer factory implementations (also API)
+
def string_renderer_factory(info):
def _render(value, system):
if not isinstance(value, string_types):
@@ -182,10 +178,13 @@ def string_renderer_factory(info):
if ct == response.default_content_type:
response.content_type = 'text/plain'
return value
+
return _render
+
_marker = object()
+
class JSON(object):
""" Renderer that returns a JSON-encoded string.
@@ -265,13 +264,15 @@ class JSON(object):
instances of the ``Foo`` class when they're encountered in your view
results."""
- self.components.registerAdapter(adapter, (type_or_iface,),
- IJSONAdapter)
+ self.components.registerAdapter(
+ adapter, (type_or_iface,), IJSONAdapter
+ )
def __call__(self, info):
""" Returns a plain JSON-encoded string with content-type
``application/json``. The content-type may be overridden by
setting ``request.response.content_type``."""
+
def _render(value, system):
request = system.get('request')
if request is not None:
@@ -290,17 +291,21 @@ class JSON(object):
return obj.__json__(request)
obj_iface = providedBy(obj)
adapters = self.components.adapters
- result = adapters.lookup((obj_iface,), IJSONAdapter,
- default=_marker)
+ result = adapters.lookup(
+ (obj_iface,), IJSONAdapter, default=_marker
+ )
if result is _marker:
raise TypeError('%r is not JSON serializable' % (obj,))
return result(obj, request)
+
return default
-json_renderer_factory = JSON() # bw compat
+
+json_renderer_factory = JSON() # bw compat
JSONP_VALID_CALLBACK = re.compile(r"^[$a-z_][$0-9a-z_\.\[\]]+[^.]$", re.I)
+
class JSONP(JSON):
""" `JSONP <https://en.wikipedia.org/wiki/JSONP>`_ renderer factory helper
which implements a hybrid json/jsonp renderer. JSONP is useful for
@@ -373,6 +378,7 @@ class JSONP(JSON):
``application/javascript`` if query parameter matching
``self.param_name`` is present in request.GET; otherwise returns
plain-JSON encoded string with content-type ``application/json``"""
+
def _render(value, system):
request = system.get('request')
default = self._make_default(request)
@@ -384,7 +390,9 @@ class JSONP(JSON):
if callback is not None:
if not JSONP_VALID_CALLBACK.match(callback):
- raise HTTPBadRequest('Invalid JSONP callback function name.')
+ raise HTTPBadRequest(
+ 'Invalid JSONP callback function name.'
+ )
ct = 'application/javascript'
body = '/**/{0}({1});'.format(callback, val)
@@ -392,8 +400,10 @@ class JSONP(JSON):
if response.content_type == response.default_content_type:
response.content_type = ct
return body
+
return _render
+
@implementer(IRendererInfo)
class RendererHelper(object):
def __init__(self, name=None, package=None, registry=None):
@@ -422,36 +432,36 @@ class RendererHelper(object):
def renderer(self):
factory = self.registry.queryUtility(IRendererFactory, name=self.type)
if factory is None:
- raise ValueError(
- 'No such renderer factory %s' % str(self.type))
+ raise ValueError('No such renderer factory %s' % str(self.type))
return factory(self)
def get_renderer(self):
return self.renderer
def render_view(self, request, response, view, context):
- system = {'view':view,
- 'renderer_name':self.name, # b/c
- 'renderer_info':self,
- 'context':context,
- 'request':request,
- 'req':request,
- 'get_csrf_token':partial(get_csrf_token, request),
- }
+ system = {
+ 'view': view,
+ 'renderer_name': self.name, # b/c
+ 'renderer_info': self,
+ 'context': context,
+ 'request': request,
+ 'req': request,
+ 'get_csrf_token': partial(get_csrf_token, request),
+ }
return self.render_to_response(response, system, request=request)
def render(self, value, system_values, request=None):
renderer = self.renderer
if system_values is None:
system_values = {
- 'view':None,
- 'renderer_name':self.name, # b/c
- 'renderer_info':self,
- 'context':getattr(request, 'context', None),
- 'request':request,
- 'req':request,
- 'get_csrf_token':partial(get_csrf_token, request),
- }
+ 'view': None,
+ 'renderer_name': self.name, # b/c
+ 'renderer_info': self,
+ 'context': getattr(request, 'context', None),
+ 'request': request,
+ 'req': request,
+ 'get_csrf_token': partial(get_csrf_token, request),
+ }
system_values = BeforeRender(system_values, value)
@@ -495,12 +505,14 @@ class RendererHelper(object):
registry = self.registry
return self.__class__(name=name, package=package, registry=registry)
+
class NullRendererHelper(RendererHelper):
""" Special renderer helper that has render_* methods which simply return
the value they are fed rather than converting them to response objects;
useful for testing purposes and special case view configuration
registrations that want to use the view configuration machinery but do
not want actual rendering to happen ."""
+
def __init__(self, name=None, package=None, registry=None):
# we override the initializer to avoid calling get_current_registry
# (it will return a reference to the global registry when this
@@ -526,4 +538,5 @@ class NullRendererHelper(RendererHelper):
def clone(self, name=None, package=None, registry=None):
return self
+
null_renderer = NullRendererHelper()
diff --git a/src/pyramid/request.py b/src/pyramid/request.py
index 201f1d648..907b4477f 100644
--- a/src/pyramid/request.py
+++ b/src/pyramid/request.py
@@ -11,32 +11,23 @@ from pyramid.interfaces import (
IRequestExtensions,
IResponse,
ISessionFactory,
- )
+)
-from pyramid.compat import (
- text_,
- bytes_,
- native_,
- iteritems_,
- )
+from pyramid.compat import text_, bytes_, native_, iteritems_
from pyramid.decorator import reify
from pyramid.i18n import LocalizerRequestMixin
from pyramid.response import Response, _get_response_factory
-from pyramid.security import (
- AuthenticationAPIMixin,
- AuthorizationAPIMixin,
- )
+from pyramid.security import AuthenticationAPIMixin, AuthorizationAPIMixin
from pyramid.url import URLMethodsMixin
-from pyramid.util import (
- InstancePropertyHelper,
- InstancePropertyMixin,
-)
+from pyramid.util import InstancePropertyHelper, InstancePropertyMixin
from pyramid.view import ViewMethodsMixin
+
class TemplateContext(object):
pass
+
class CallbackMethodsMixin(object):
@reify
def finished_callbacks(self):
@@ -146,6 +137,7 @@ class CallbackMethodsMixin(object):
callback = callbacks.popleft()
callback(self)
+
@implementer(IRequest)
class Request(
BaseRequest,
@@ -156,7 +148,7 @@ class Request(
AuthenticationAPIMixin,
AuthorizationAPIMixin,
ViewMethodsMixin,
- ):
+):
"""
A subclass of the :term:`WebOb` Request class. An instance of
this class is created by the :term:`router` and is provided to a
@@ -177,6 +169,7 @@ class Request(
release of this :app:`Pyramid` version. See
https://webob.org/ for further information.
"""
+
exception = None
exc_info = None
matchdict = None
@@ -201,7 +194,8 @@ class Request(
if factory is None:
raise AttributeError(
'No session factory registered '
- '(see the Sessions chapter of the Pyramid documentation)')
+ '(see the Sessions chapter of the Pyramid documentation)'
+ )
return factory(self)
@reify
@@ -244,13 +238,17 @@ def route_request_iface(name, bases=()):
# zope.interface.interface.Element.__init__ and
# https://github.com/Pylons/pyramid/issues/232; as a result, always pass
# __doc__ to the InterfaceClass constructor.
- iface = InterfaceClass('%s_IRequest' % name, bases=bases,
- __doc__="route_request_iface-generated interface")
+ iface = InterfaceClass(
+ '%s_IRequest' % name,
+ bases=bases,
+ __doc__="route_request_iface-generated interface",
+ )
# for exception view lookups
iface.combined = InterfaceClass(
'%s_combined_IRequest' % name,
bases=(iface, IRequest),
- __doc__='route_request_iface-generated combined interface')
+ __doc__='route_request_iface-generated combined interface',
+ )
return iface
@@ -258,8 +256,10 @@ def add_global_response_headers(request, headerlist):
def add_headers(request, response):
for k, v in headerlist:
response.headerlist.append((k, v))
+
request.add_response_callback(add_headers)
+
def call_app_with_subpath_as_path_info(request, app):
# Copy the request. Use the source request's subpath (if it exists) as
# the new request's PATH_INFO. Set the request copy's SCRIPT_NAME to the
@@ -280,11 +280,12 @@ def call_app_with_subpath_as_path_info(request, app):
new_script_name = ''
# compute new_path_info
- new_path_info = '/' + '/'.join([native_(x.encode('utf-8'), 'latin-1')
- for x in subpath])
+ new_path_info = '/' + '/'.join(
+ [native_(x.encode('utf-8'), 'latin-1') for x in subpath]
+ )
- if new_path_info != '/': # don't want a sole double-slash
- if path_info != '/': # if orig path_info is '/', we're already done
+ if new_path_info != '/': # don't want a sole double-slash
+ if path_info != '/': # if orig path_info is '/', we're already done
if path_info.endswith('/'):
# readd trailing slash stripped by subpath (traversal)
# conversion
@@ -314,6 +315,7 @@ def call_app_with_subpath_as_path_info(request, app):
return new_request.get_response(app)
+
def apply_request_extensions(request, extensions=None):
"""Apply request extensions (methods and properties) to an instance of
:class:`pyramid.interfaces.IRequest`. This method is dependent on the
@@ -331,4 +333,5 @@ def apply_request_extensions(request, extensions=None):
setattr(request, name, method)
InstancePropertyHelper.apply_properties(
- request, extensions.descriptors)
+ request, extensions.descriptors
+ )
diff --git a/src/pyramid/resource.py b/src/pyramid/resource.py
index 986c75e37..8ddf4c447 100644
--- a/src/pyramid/resource.py
+++ b/src/pyramid/resource.py
@@ -1,5 +1,6 @@
""" Backwards compatibility shim module (forever). """
-from pyramid.asset import * # b/w compat
-resolve_resource_spec = resolve_asset_spec
-resource_spec_from_abspath = asset_spec_from_abspath
-abspath_from_resource_spec = abspath_from_asset_spec
+from pyramid.asset import * # noqa b/w compat
+
+resolve_resource_spec = resolve_asset_spec # noqa
+resource_spec_from_abspath = asset_spec_from_abspath # noqa
+abspath_from_resource_spec = abspath_from_asset_spec # noqa
diff --git a/src/pyramid/response.py b/src/pyramid/response.py
index 1e2546ed0..38f9fa1ce 100644
--- a/src/pyramid/response.py
+++ b/src/pyramid/response.py
@@ -1,8 +1,5 @@
import mimetypes
-from os.path import (
- getmtime,
- getsize,
- )
+from os.path import getmtime, getsize
import venusian
@@ -18,17 +15,20 @@ def init_mimetypes(mimetypes):
return True
return False
+
# See http://bugs.python.org/issue5853 which is a recursion bug
# that seems to effect Python 2.6, Python 2.6.1, and 2.6.2 (a fix
# has been applied on the Python 2 trunk).
init_mimetypes(mimetypes)
-_BLOCK_SIZE = 4096 * 64 # 256K
+_BLOCK_SIZE = 4096 * 64 # 256K
+
@implementer(IResponse)
class Response(_Response):
pass
+
class FileResponse(Response):
"""
A Response object that can be used to serve a static file from disk
@@ -51,14 +51,21 @@ class FileResponse(Response):
binary file. This argument will be ignored if you also leave
``content-type`` as ``None``.
"""
- def __init__(self, path, request=None, cache_max_age=None,
- content_type=None, content_encoding=None):
+
+ def __init__(
+ self,
+ path,
+ request=None,
+ cache_max_age=None,
+ content_type=None,
+ content_encoding=None,
+ ):
if content_type is None:
content_type, content_encoding = _guess_type(path)
super(FileResponse, self).__init__(
conditional_response=True,
content_type=content_type,
- content_encoding=content_encoding
+ content_encoding=content_encoding,
)
self.last_modified = getmtime(path)
content_length = getsize(path)
@@ -76,6 +83,7 @@ class FileResponse(Response):
if cache_max_age is not None:
self.cache_expires = cache_max_age
+
class FileIter(object):
""" A fixed-block-size iterator for use as a WSGI app_iter.
@@ -84,6 +92,7 @@ class FileIter(object):
``block_size`` is an optional block size for iteration.
"""
+
def __init__(self, file, block_size=_BLOCK_SIZE):
self.file = file
self.block_size = block_size
@@ -97,7 +106,7 @@ class FileIter(object):
raise StopIteration
return val
- __next__ = next # py3
+ __next__ = next # py3
def close(self):
self.file.close()
@@ -166,7 +175,8 @@ class response_adapter(object):
Added the ``_depth`` and ``_category`` arguments.
"""
- venusian = venusian # for unit testing
+
+ venusian = venusian # for unit testing
def __init__(self, *types_or_ifaces, **kwargs):
self.types_or_ifaces = types_or_ifaces
@@ -180,8 +190,12 @@ class response_adapter(object):
config.add_response_adapter(wrapped, type_or_iface, **self.kwargs)
def __call__(self, wrapped):
- self.venusian.attach(wrapped, self.register, category=self.category,
- depth=self.depth + 1)
+ self.venusian.attach(
+ wrapped,
+ self.register,
+ category=self.category,
+ depth=self.depth + 1,
+ )
return wrapped
@@ -190,18 +204,14 @@ def _get_response_factory(registry):
`pyramid.interfaces.IResponseFactory`.
"""
response_factory = registry.queryUtility(
- IResponseFactory,
- default=lambda r: Response()
+ IResponseFactory, default=lambda r: Response()
)
return response_factory
def _guess_type(path):
- content_type, content_encoding = mimetypes.guess_type(
- path,
- strict=False
- )
+ content_type, content_encoding = mimetypes.guess_type(path, strict=False)
if content_type is None:
content_type = 'application/octet-stream'
# str-ifying content_type is a workaround for a bug in Python 2.7.7
diff --git a/src/pyramid/router.py b/src/pyramid/router.py
index 49b7b601b..19641aecd 100644
--- a/src/pyramid/router.py
+++ b/src/pyramid/router.py
@@ -1,7 +1,4 @@
-from zope.interface import (
- implementer,
- providedBy,
- )
+from zope.interface import implementer, providedBy
from pyramid.interfaces import (
IDebugLogger,
@@ -15,14 +12,14 @@ from pyramid.interfaces import (
IRoutesMapper,
ITraverser,
ITweens,
- )
+)
from pyramid.events import (
ContextFound,
NewRequest,
NewResponse,
BeforeTraversal,
- )
+)
from pyramid.httpexceptions import HTTPNotFound
from pyramid.request import Request
@@ -30,10 +27,8 @@ from pyramid.view import _call_view
from pyramid.request import apply_request_extensions
from pyramid.threadlocal import RequestContext
-from pyramid.traversal import (
- DefaultRootFactory,
- ResourceTreeTraverser,
- )
+from pyramid.traversal import DefaultRootFactory, ResourceTreeTraverser
+
@implementer(IRouter)
class Router(object):
@@ -49,12 +44,13 @@ class Router(object):
self.request_factory = q(IRequestFactory, default=Request)
self.request_extensions = q(IRequestExtensions)
self.execution_policy = q(
- IExecutionPolicy, default=default_execution_policy)
+ IExecutionPolicy, default=default_execution_policy
+ )
self.orig_handle_request = self.handle_request
tweens = q(ITweens)
if tweens is not None:
self.handle_request = tweens(self.handle_request, registry)
- self.root_policy = self.root_factory # b/w compat
+ self.root_policy = self.root_factory # b/w compat
self.registry = registry
settings = registry.settings
if settings is not None:
@@ -82,8 +78,7 @@ class Router(object):
match, route = info['match'], info['route']
if route is None:
if debug_routematch:
- msg = ('no route matched for url %s' %
- request.url)
+ msg = 'no route matched for url %s' % request.url
logger and logger.debug(msg)
else:
attrs['matchdict'] = match
@@ -96,20 +91,21 @@ class Router(object):
'path_info: %r, '
'pattern: %r, '
'matchdict: %r, '
- 'predicates: %r' % (
+ 'predicates: %r'
+ % (
request.url,
route.name,
request.path_info,
route.pattern,
match,
- ', '.join([p.text() for p in route.predicates]))
+ ', '.join([p.text() for p in route.predicates]),
)
+ )
logger and logger.debug(msg)
request.request_iface = registry.queryUtility(
- IRouteRequest,
- name=route.name,
- default=IRequest)
+ IRouteRequest, name=route.name, default=IRequest
+ )
root_factory = route.factory or self.root_factory
@@ -137,8 +133,8 @@ class Router(object):
tdict['subpath'],
tdict['traversed'],
tdict['virtual_root'],
- tdict['virtual_root_path']
- )
+ tdict['virtual_root_path'],
+ )
attrs.update(tdict)
@@ -149,12 +145,8 @@ class Router(object):
# find a view callable
context_iface = providedBy(context)
response = _call_view(
- registry,
- request,
- context,
- context_iface,
- view_name
- )
+ registry, request, context, context_iface, view_name
+ )
if response is None:
if self.debug_notfound:
@@ -162,11 +154,19 @@ class Router(object):
'debug_notfound of url %s; path_info: %r, '
'context: %r, view_name: %r, subpath: %r, '
'traversed: %r, root: %r, vroot: %r, '
- 'vroot_path: %r' % (
- request.url, request.path_info, context,
- view_name, subpath, traversed, root, vroot,
- vroot_path)
+ 'vroot_path: %r'
+ % (
+ request.url,
+ request.path_info,
+ context,
+ view_name,
+ subpath,
+ traversed,
+ root,
+ vroot,
+ vroot_path,
)
+ )
logger and logger.debug(msg)
else:
msg = request.path_info
@@ -270,6 +270,7 @@ class Router(object):
response = self.execution_policy(environ, self)
return response(environ, start_response)
+
def default_execution_policy(environ, router):
with router.request_context(environ) as request:
try:
diff --git a/src/pyramid/scaffolds/__init__.py b/src/pyramid/scaffolds/__init__.py
index 71a220e22..eff71d204 100644
--- a/src/pyramid/scaffolds/__init__.py
+++ b/src/pyramid/scaffolds/__init__.py
@@ -6,11 +6,13 @@ from pyramid.compat import native_
from pyramid.scaffolds.template import Template # API
+
class PyramidTemplate(Template):
"""
A class that can be used as a base class for Pyramid scaffolding
templates.
"""
+
def pre(self, command, output_dir, vars):
""" Overrides :meth:`pyramid.scaffolds.template.Template.pre`, adding
several variables to the default variables list (including
@@ -26,7 +28,7 @@ class PyramidTemplate(Template):
vars['package_logger'] = package_logger
return Template.pre(self, command, output_dir, vars)
- def post(self, command, output_dir, vars): # pragma: no cover
+ def post(self, command, output_dir, vars): # pragma: no cover
""" Overrides :meth:`pyramid.scaffolds.template.Template.post`, to
print "Welcome to Pyramid. Sorry for the convenience." after a
successful scaffolding rendering."""
@@ -42,24 +44,29 @@ class PyramidTemplate(Template):
Welcome to Pyramid. Sorry for the convenience.
%(separator)s
- """ % {'separator': separator})
+ """ # noqa: E501
+ % {'separator': separator}
+ )
self.out(msg)
return Template.post(self, command, output_dir, vars)
- def out(self, msg): # pragma: no cover (replaceable testing hook)
+ def out(self, msg): # pragma: no cover (replaceable testing hook)
print(msg)
+
class StarterProjectTemplate(PyramidTemplate):
_template_dir = 'starter'
summary = 'Pyramid starter project using URL dispatch and Jinja2'
+
class ZODBProjectTemplate(PyramidTemplate):
_template_dir = 'zodb'
summary = 'Pyramid project using ZODB, traversal, and Chameleon'
+
class AlchemyProjectTemplate(PyramidTemplate):
_template_dir = 'alchemy'
summary = (
- 'Pyramid project using SQLAlchemy, SQLite, URL dispatch, and '
- 'Jinja2')
+ 'Pyramid project using SQLAlchemy, SQLite, URL dispatch, and ' 'Jinja2'
+ )
diff --git a/src/pyramid/scaffolds/copydir.py b/src/pyramid/scaffolds/copydir.py
index 0914bb0d4..31e8dfb9e 100644
--- a/src/pyramid/scaffolds/copydir.py
+++ b/src/pyramid/scaffolds/copydir.py
@@ -11,7 +11,7 @@ from pyramid.compat import (
native_,
url_quote as compat_url_quote,
escape,
- )
+)
fsenc = sys.getfilesystemencoding()
@@ -22,9 +22,20 @@ class SkipTemplate(Exception):
Raise this exception during the substitution of your template
"""
-def copy_dir(source, dest, vars, verbosity, simulate, indent=0,
- sub_vars=True, interactive=False, overwrite=True,
- template_renderer=None, out_=sys.stdout):
+
+def copy_dir(
+ source,
+ dest,
+ vars,
+ verbosity,
+ simulate,
+ indent=0,
+ sub_vars=True,
+ interactive=False,
+ overwrite=True,
+ template_renderer=None,
+ out_=sys.stdout,
+):
"""
Copies the ``source`` directory to the ``dest`` directory.
@@ -49,10 +60,12 @@ def copy_dir(source, dest, vars, verbosity, simulate, indent=0,
``template_renderer(content_as_string, vars_as_dict,
filename=filename)``.
"""
+
def out(msg):
out_.write(msg)
out_.write('\n')
out_.flush()
+
# This allows you to use a leading +dot+ in filenames which would
# otherwise be skipped because leading dots make the file hidden:
vars.setdefault('dot', '.')
@@ -80,7 +93,7 @@ def copy_dir(source, dest, vars, verbosity, simulate, indent=0,
if verbosity >= 2:
reason = pad + reason % {'filename': full}
out(reason)
- continue # pragma: no cover
+ continue # pragma: no cover
if sub_vars:
dest_full = os.path.join(dest, substitute_filename(name, vars))
sub_file = False
@@ -90,18 +103,36 @@ def copy_dir(source, dest, vars, verbosity, simulate, indent=0,
if use_pkg_resources and pkg_resources.resource_isdir(source[0], full):
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, overwrite=overwrite,
- template_renderer=template_renderer, out_=out_)
+ copy_dir(
+ (source[0], full),
+ dest_full,
+ vars,
+ verbosity,
+ simulate,
+ 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, overwrite=overwrite,
- template_renderer=template_renderer, out_=out_)
+ copy_dir(
+ full,
+ dest_full,
+ vars,
+ verbosity,
+ simulate,
+ indent=indent + 1,
+ sub_vars=sub_vars,
+ interactive=interactive,
+ overwrite=overwrite,
+ template_renderer=template_renderer,
+ out_=out_,
+ )
continue
elif use_pkg_resources:
content = pkg_resources.resource_string(source[0], full)
@@ -111,12 +142,14 @@ def copy_dir(source, dest, vars, verbosity, simulate, indent=0,
if sub_file:
try:
content = substitute_content(
- content, vars, filename=full,
- template_renderer=template_renderer
- )
- except SkipTemplate:
- continue # pragma: no cover
- if content is None:
+ content,
+ vars,
+ filename=full,
+ template_renderer=template_renderer,
+ )
+ except SkipTemplate:
+ continue # pragma: no cover
+ if content is None:
continue # pragma: no cover
already_exists = os.path.exists(dest_full)
if already_exists:
@@ -124,27 +157,33 @@ def copy_dir(source, dest, vars, verbosity, simulate, indent=0,
old_content = f.read()
if old_content == content:
if verbosity:
- out('%s%s already exists (same content)' %
- (pad, dest_full))
- continue # pragma: no cover
+ out(
+ '%s%s already exists (same content)' % (pad, dest_full)
+ )
+ continue # pragma: no cover
if interactive:
if not query_interactive(
- native_(full, fsenc), native_(dest_full, fsenc),
- native_(content, fsenc), native_(old_content, fsenc),
- simulate=simulate, out_=out_):
+ native_(full, fsenc),
+ native_(dest_full, fsenc),
+ native_(content, fsenc),
+ native_(old_content, fsenc),
+ simulate=simulate,
+ out_=out_,
+ ):
continue
elif not overwrite:
- continue # pragma: no cover
+ continue # pragma: no cover
if verbosity and use_pkg_resources:
out('%sCopying %s to %s' % (pad, full, dest_full))
elif verbosity:
out(
- '%sCopying %s to %s' % (pad, os.path.basename(full),
- dest_full))
+ '%sCopying %s to %s' % (pad, os.path.basename(full), dest_full)
+ )
if not simulate:
with open(dest_full, 'wb') as f:
f.write(content)
+
def should_skip_file(name):
"""
Checks if a file should be skipped based on its name.
@@ -164,38 +203,60 @@ def should_skip_file(name):
return 'Skipping version control directory %(filename)s'
return None
+
# Overridden on user's request:
all_answer = None
-def query_interactive(src_fn, dest_fn, src_content, dest_content,
- simulate, out_=sys.stdout):
+
+def query_interactive(
+ src_fn, dest_fn, src_content, dest_content, simulate, out_=sys.stdout
+):
def out(msg):
out_.write(msg)
out_.write('\n')
out_.flush()
+
global all_answer
from difflib import unified_diff, context_diff
- u_diff = list(unified_diff(
- dest_content.splitlines(),
- src_content.splitlines(),
- dest_fn, src_fn))
- c_diff = list(context_diff(
- dest_content.splitlines(),
- src_content.splitlines(),
- dest_fn, src_fn))
- added = len([l for l in u_diff if l.startswith('+') and
- not l.startswith('+++')])
- removed = len([l for l in u_diff if l.startswith('-') and
- not l.startswith('---')])
+
+ u_diff = list(
+ unified_diff(
+ dest_content.splitlines(),
+ src_content.splitlines(),
+ dest_fn,
+ src_fn,
+ )
+ )
+ c_diff = list(
+ context_diff(
+ dest_content.splitlines(),
+ src_content.splitlines(),
+ dest_fn,
+ src_fn,
+ )
+ )
+ added = len(
+ [l for l in u_diff if l.startswith('+') and not l.startswith('+++')]
+ )
+ removed = len(
+ [l for l in u_diff if l.startswith('-') and not l.startswith('---')]
+ )
if added > removed:
msg = '; %i lines added' % (added - removed)
elif removed > added:
msg = '; %i lines removed' % (removed - added)
else:
msg = ''
- out('Replace %i bytes with %i bytes (%i/%i lines changed%s)' % (
- len(dest_content), len(src_content),
- removed, len(dest_content.splitlines()), msg))
+ out(
+ 'Replace %i bytes with %i bytes (%i/%i lines changed%s)'
+ % (
+ len(dest_content),
+ len(src_content),
+ removed,
+ len(dest_content.splitlines()),
+ msg,
+ )
+ )
prompt = 'Overwrite %s [y/n/d/B/?] ' % dest_fn
while 1:
if all_answer is None:
@@ -204,6 +265,7 @@ def query_interactive(src_fn, dest_fn, src_content, dest_content,
response = all_answer
if not response or response[0] == 'b':
import shutil
+
new_dest_fn = dest_fn + '.bak'
n = 0
while os.path.exists(new_dest_fn):
@@ -230,6 +292,7 @@ def query_interactive(src_fn, dest_fn, src_content, dest_content,
else:
out(query_usage)
+
query_usage = """\
Responses:
Y(es): Overwrite the file with the new content.
@@ -240,39 +303,47 @@ Responses:
Type "all Y/N/B" to use Y/N/B for answer to all future questions
"""
+
def makedirs(dir, verbosity, pad):
parent = os.path.dirname(os.path.abspath(dir))
if not os.path.exists(parent):
makedirs(parent, verbosity, pad) # pragma: no cover
os.mkdir(dir)
+
def substitute_filename(fn, vars):
for var, value in vars.items():
fn = fn.replace('+%s+' % var, str(value))
return fn
-def substitute_content(content, vars, filename='<string>',
- template_renderer=None):
+
+def substitute_content(
+ content, vars, filename='<string>', template_renderer=None
+):
v = standard_vars.copy()
v.update(vars)
return template_renderer(content, v, filename=filename)
+
def html_quote(s):
if s is None:
return ''
return escape(str(s), 1)
+
def url_quote(s):
if s is None:
return ''
return compat_url_quote(str(s))
+
def test(conf, true_cond, false_cond=None):
if conf:
return true_cond
else:
return false_cond
+
def skip_template(condition=True, *args):
"""
Raise SkipTemplate, which causes copydir to skip the template
@@ -286,6 +357,7 @@ def skip_template(condition=True, *args):
if condition:
raise SkipTemplate(*args)
+
standard_vars = {
'nothing': None,
'html_quote': html_quote,
@@ -297,5 +369,4 @@ standard_vars = {
'bool': bool,
'SkipTemplate': SkipTemplate,
'skip_template': skip_template,
- }
-
+}
diff --git a/src/pyramid/scaffolds/template.py b/src/pyramid/scaffolds/template.py
index e5098e815..60b543842 100644
--- a/src/pyramid/scaffolds/template.py
+++ b/src/pyramid/scaffolds/template.py
@@ -6,19 +6,18 @@ import re
import sys
import os
-from pyramid.compat import (
- native_,
- bytes_,
- )
+from pyramid.compat import native_, bytes_
from pyramid.scaffolds import copydir
fsenc = sys.getfilesystemencoding()
+
class Template(object):
""" Inherit from this base class and override methods to use the Pyramid
scaffolding system."""
- copydir = copydir # for testing
+
+ copydir = copydir # for testing
_template_dir = None
def __init__(self, name):
@@ -36,7 +35,10 @@ class Template(object):
try:
return bytes_(
substitute_escaped_double_braces(
- substitute_double_braces(content, TypeMapper(vars))), fsenc)
+ substitute_double_braces(content, TypeMapper(vars))
+ ),
+ fsenc,
+ )
except Exception as e:
_add_except(e, ' in file %s' % filename)
raise
@@ -54,7 +56,8 @@ class Template(object):
construct a path. If _template_dir is a tuple, it should be a
2-element tuple: ``(package_name, package_relative_path)``."""
assert self._template_dir is not None, (
- "Template %r didn't set _template_dir" % self)
+ "Template %r didn't set _template_dir" % self
+ )
if isinstance(self._template_dir, tuple):
return self._template_dir
else:
@@ -65,13 +68,13 @@ class Template(object):
self.write_files(command, output_dir, vars)
self.post(command, output_dir, vars)
- def pre(self, command, output_dir, vars): # pragma: no cover
+ def pre(self, command, output_dir, vars): # pragma: no cover
"""
Called before template is applied.
"""
pass
- def post(self, command, output_dir, vars): # pragma: no cover
+ def post(self, command, output_dir, vars): # pragma: no cover
"""
Called after template is applied.
"""
@@ -95,15 +98,15 @@ class Template(object):
overwrite=command.args.overwrite,
indent=1,
template_renderer=self.render_template,
- )
+ )
- def makedirs(self, dir): # pragma: no cover
+ def makedirs(self, dir): # pragma: no cover
return os.makedirs(dir)
- def exists(self, path): # pragma: no cover
+ def exists(self, path): # pragma: no cover
return os.path.exists(path)
- def out(self, msg): # pragma: no cover
+ def out(self, msg): # pragma: no cover
print(msg)
# hair for exit with usage when paster create is used under 1.3 instead
@@ -113,13 +116,15 @@ class Template(object):
# required_templates tuple is required to allow it to get as far as
# calling check_vars.
required_templates = ()
+
def check_vars(self, vars, other):
raise RuntimeError(
'Under Pyramid 1.3, you should use the "pcreate" command rather '
- 'than "paster create"')
+ 'than "paster create"'
+ )
-class TypeMapper(dict):
+class TypeMapper(dict):
def __getitem__(self, item):
options = item.split('|')
for op in options[:-1]:
@@ -135,6 +140,7 @@ class TypeMapper(dict):
else:
return str(value)
+
def eval_with_catch(expr, vars):
try:
return eval(expr, vars)
@@ -142,23 +148,32 @@ def eval_with_catch(expr, vars):
_add_except(e, 'in expression %r' % expr)
raise
+
double_brace_pattern = re.compile(r'{{(?P<braced>.*?)}}')
+
def substitute_double_braces(content, values):
def double_bracerepl(match):
value = match.group('braced').strip()
return values[value]
+
return double_brace_pattern.sub(double_bracerepl, content)
-escaped_double_brace_pattern = re.compile(r'\\{\\{(?P<escape_braced>[^\\]*?)\\}\\}')
+
+escaped_double_brace_pattern = re.compile(
+ r'\\{\\{(?P<escape_braced>[^\\]*?)\\}\\}'
+)
+
def substitute_escaped_double_braces(content):
def escaped_double_bracerepl(match):
value = match.group('escape_braced').strip()
return "{{%(value)s}}" % locals()
+
return escaped_double_brace_pattern.sub(escaped_double_bracerepl, content)
-def _add_except(exc, info): # pragma: no cover
+
+def _add_except(exc, info): # pragma: no cover
if not hasattr(exc, 'args') or exc.args is None:
return
args = list(exc.args)
@@ -168,5 +183,3 @@ def _add_except(exc, info): # pragma: no cover
args = [info]
exc.args = tuple(args)
return
-
-
diff --git a/src/pyramid/scaffolds/tests.py b/src/pyramid/scaffolds/tests.py
index 44680a464..cb8842dbe 100644
--- a/src/pyramid/scaffolds/tests.py
+++ b/src/pyramid/scaffolds/tests.py
@@ -15,12 +15,12 @@ class TemplateTest(object):
def make_venv(self, directory): # pragma: no cover
import virtualenv
from virtualenv import Logger
+
logger = Logger([(Logger.level_for_integer(2), sys.stdout)])
virtualenv.logger = logger
- virtualenv.create_environment(directory,
- site_packages=False,
- clear=False,
- unzip_setuptools=True)
+ virtualenv.create_environment(
+ directory, site_packages=False, clear=False, unzip_setuptools=True
+ )
def install(self, tmpl_name): # pragma: no cover
try:
@@ -36,14 +36,18 @@ class TemplateTest(object):
os.chdir('Dingle')
subprocess.check_call([pip, 'install', '.[testing]'])
if tmpl_name == 'alchemy':
- populate = os.path.join(self.directory, 'bin',
- 'initialize_Dingle_db')
+ populate = os.path.join(
+ self.directory, 'bin', 'initialize_Dingle_db'
+ )
subprocess.check_call([populate, 'development.ini'])
- subprocess.check_call([
- os.path.join(self.directory, 'bin', 'py.test')])
+ subprocess.check_call(
+ [os.path.join(self.directory, 'bin', 'py.test')]
+ )
pserve = os.path.join(self.directory, 'bin', 'pserve')
- for ininame, hastoolbar in (('development.ini', True),
- ('production.ini', False)):
+ for ininame, hastoolbar in (
+ ('development.ini', True),
+ ('production.ini', False),
+ ):
proc = subprocess.Popen([pserve, ininame])
try:
time.sleep(5)
@@ -66,10 +70,10 @@ class TemplateTest(object):
shutil.rmtree(self.directory)
os.chdir(self.old_cwd)
-if __name__ == '__main__': # pragma: no cover
+
+if __name__ == '__main__': # pragma: no cover
templates = ['starter', 'alchemy', 'zodb']
for name in templates:
test = TemplateTest()
test.install(name)
-
diff --git a/src/pyramid/scripting.py b/src/pyramid/scripting.py
index 087b55ccb..cbf9d5e32 100644
--- a/src/pyramid/scripting.py
+++ b/src/pyramid/scripting.py
@@ -1,16 +1,14 @@
from pyramid.config import global_registries
from pyramid.exceptions import ConfigurationError
-from pyramid.interfaces import (
- IRequestFactory,
- IRootFactory,
- )
+from pyramid.interfaces import IRequestFactory, IRootFactory
from pyramid.request import Request
from pyramid.request import apply_request_extensions
from pyramid.threadlocal import RequestContext
from pyramid.traversal import DefaultRootFactory
+
def get_root(app, request=None):
""" Return a tuple composed of ``(root, closer)`` when provided a
:term:`router` instance as the ``app`` argument. The ``root``
@@ -29,11 +27,14 @@ def get_root(app, request=None):
request.registry = registry
ctx = RequestContext(request)
ctx.begin()
+
def closer():
ctx.end()
+
root = app.root_factory(request)
return root, closer
+
def prepare(request=None, registry=None):
""" This function pushes data onto the Pyramid threadlocal stack
(request and registry), making those objects 'current'. It
@@ -80,9 +81,11 @@ def prepare(request=None, registry=None):
if registry is None:
registry = getattr(request, 'registry', global_registries.last)
if registry is None:
- raise ConfigurationError('No valid Pyramid applications could be '
- 'found, make sure one has been created '
- 'before trying to activate it.')
+ raise ConfigurationError(
+ 'No valid Pyramid applications could be '
+ 'found, make sure one has been created '
+ 'before trying to activate it.'
+ )
if request is None:
request = _make_request('/', registry)
# NB: even though _make_request might have already set registry on
@@ -92,10 +95,13 @@ def prepare(request=None, registry=None):
ctx = RequestContext(request)
ctx.begin()
apply_request_extensions(request)
+
def closer():
ctx.end()
- root_factory = registry.queryUtility(IRootFactory,
- default=DefaultRootFactory)
+
+ root_factory = registry.queryUtility(
+ IRootFactory, default=DefaultRootFactory
+ )
root = root_factory(request)
if getattr(request, 'context', None) is None:
request.context = root
@@ -107,6 +113,7 @@ def prepare(request=None, registry=None):
root_factory=root_factory,
)
+
class AppEnvironment(dict):
def __enter__(self):
return self
@@ -114,6 +121,7 @@ class AppEnvironment(dict):
def __exit__(self, type, value, traceback):
self['closer']()
+
def _make_request(path, registry=None):
""" Return a :meth:`pyramid.request.Request` object anchored at a
given path. The object returned will be generated from the supplied
diff --git a/src/pyramid/scripts/common.py b/src/pyramid/scripts/common.py
index f4b8027db..9181eea8e 100644
--- a/src/pyramid/scripts/common.py
+++ b/src/pyramid/scripts/common.py
@@ -1,5 +1,6 @@
import plaster
+
def parse_vars(args):
"""
Given variables like ``['a=b', 'c=d']`` turns it into ``{'a':
@@ -8,13 +9,12 @@ def parse_vars(args):
result = {}
for arg in args:
if '=' not in arg:
- raise ValueError(
- 'Variable assignment %r invalid (no "=")'
- % arg)
+ raise ValueError('Variable assignment %r invalid (no "=")' % arg)
name, value = arg.split('=', 1)
result[name] = value
return result
+
def get_config_loader(config_uri):
"""
Find a ``plaster.ILoader`` object supporting the "wsgi" protocol.
diff --git a/src/pyramid/scripts/pcreate.py b/src/pyramid/scripts/pcreate.py
index a6db520ce..f3dffefef 100644
--- a/src/pyramid/scripts/pcreate.py
+++ b/src/pyramid/scripts/pcreate.py
@@ -33,60 +33,88 @@ https://github.com/Pylons/?q=cookiecutter
""",
formatter_class=argparse.RawDescriptionHelpFormatter,
)
- parser.add_argument('-s', '--scaffold',
- dest='scaffold_name',
- action='append',
- help=("Add a scaffold to the create process "
- "(multiple -s args accepted)"))
- parser.add_argument('-t', '--template',
- dest='scaffold_name',
- action='append',
- help=('A backwards compatibility alias for '
- '-s/--scaffold. Add a scaffold to the '
- 'create process (multiple -t args accepted)'))
- parser.add_argument('-l', '--list',
- dest='list',
- action='store_true',
- help="List all available scaffold names")
- parser.add_argument('--list-templates',
- dest='list',
- action='store_true',
- help=("A backwards compatibility alias for -l/--list. "
- "List all available scaffold names."))
- parser.add_argument('--package-name',
- dest='package_name',
- action='store',
- help='Package name to use. The name provided is '
- 'assumed to be a valid Python package name, and '
- 'will not be validated. By default the package '
- 'name is derived from the value of '
- 'output_directory.')
- parser.add_argument('--simulate',
- dest='simulate',
- action='store_true',
- help='Simulate but do no work')
- parser.add_argument('--overwrite',
- dest='overwrite',
- action='store_true',
- help='Always overwrite')
- parser.add_argument('--interactive',
- dest='interactive',
- action='store_true',
- help='When a file would be overwritten, interrogate '
- '(this is the default, but you may specify it to '
- 'override --overwrite)')
- parser.add_argument('--ignore-conflicting-name',
- dest='force_bad_name',
- action='store_true',
- default=False,
- help='Do create a project even if the chosen name '
- 'is the name of an already existing / importable '
- 'package.')
- parser.add_argument('output_directory',
- nargs='?',
- default=None,
- help='The directory where the project will be '
- 'created.')
+ parser.add_argument(
+ '-s',
+ '--scaffold',
+ dest='scaffold_name',
+ action='append',
+ help=(
+ "Add a scaffold to the create process "
+ "(multiple -s args accepted)"
+ ),
+ )
+ parser.add_argument(
+ '-t',
+ '--template',
+ dest='scaffold_name',
+ action='append',
+ help=(
+ 'A backwards compatibility alias for '
+ '-s/--scaffold. Add a scaffold to the '
+ 'create process (multiple -t args accepted)'
+ ),
+ )
+ parser.add_argument(
+ '-l',
+ '--list',
+ dest='list',
+ action='store_true',
+ help="List all available scaffold names",
+ )
+ parser.add_argument(
+ '--list-templates',
+ dest='list',
+ action='store_true',
+ help=(
+ "A backwards compatibility alias for -l/--list. "
+ "List all available scaffold names."
+ ),
+ )
+ parser.add_argument(
+ '--package-name',
+ dest='package_name',
+ action='store',
+ help='Package name to use. The name provided is '
+ 'assumed to be a valid Python package name, and '
+ 'will not be validated. By default the package '
+ 'name is derived from the value of '
+ 'output_directory.',
+ )
+ parser.add_argument(
+ '--simulate',
+ dest='simulate',
+ action='store_true',
+ help='Simulate but do no work',
+ )
+ parser.add_argument(
+ '--overwrite',
+ dest='overwrite',
+ action='store_true',
+ help='Always overwrite',
+ )
+ parser.add_argument(
+ '--interactive',
+ dest='interactive',
+ action='store_true',
+ help='When a file would be overwritten, interrogate '
+ '(this is the default, but you may specify it to '
+ 'override --overwrite)',
+ )
+ parser.add_argument(
+ '--ignore-conflicting-name',
+ dest='force_bad_name',
+ action='store_true',
+ default=False,
+ help='Do create a project even if the chosen name '
+ 'is the name of an already existing / importable '
+ 'package.',
+ )
+ parser.add_argument(
+ 'output_directory',
+ nargs='?',
+ default=None,
+ help='The directory where the project will be ' 'created.',
+ )
pyramid_dist = pkg_resources.get_distribution("pyramid")
@@ -123,7 +151,8 @@ https://github.com/Pylons/?q=cookiecutter
project_name = os.path.basename(os.path.split(output_dir)[1])
if self.args.package_name is None:
pkg_name = _bad_chars_re.sub(
- '', project_name.lower().replace('-', '_'))
+ '', project_name.lower().replace('-', '_')
+ )
safe_name = pkg_resources.safe_name(project_name)
else:
pkg_name = self.args.package_name
@@ -170,9 +199,14 @@ https://github.com/Pylons/?q=cookiecutter
max_name = max([len(t.name) for t in scaffolds])
self.out('Available scaffolds:')
for scaffold in scaffolds:
- self.out(' %s:%s %s' % (
- scaffold.name,
- ' ' * (max_name - len(scaffold.name)), scaffold.summary))
+ self.out(
+ ' %s:%s %s'
+ % (
+ scaffold.name,
+ ' ' * (max_name - len(scaffold.name)),
+ scaffold.summary,
+ )
+ )
else:
self.out('No scaffolds available')
return 0
@@ -186,8 +220,10 @@ https://github.com/Pylons/?q=cookiecutter
scaffold = scaffold_class(entry.name)
scaffolds.append(scaffold)
except Exception as e: # pragma: no cover
- self.out('Warning: could not load entry point %s (%s: %s)' % (
- entry.name, e.__class__.__name__, e))
+ self.out(
+ 'Warning: could not load entry point %s (%s: %s)'
+ % (entry.name, e.__class__.__name__, e)
+ )
return scaffolds
def out(self, msg): # pragma: no cover
@@ -196,8 +232,10 @@ https://github.com/Pylons/?q=cookiecutter
def validate_input(self):
if not self.args.scaffold_name:
- self.out('You must provide at least one scaffold name: '
- '-s <scaffold name>')
+ self.out(
+ 'You must provide at least one scaffold name: '
+ '-s <scaffold name>'
+ )
self.out('')
self.show_scaffolds()
return False
@@ -213,11 +251,14 @@ https://github.com/Pylons/?q=cookiecutter
pkg_name = self.project_vars['package']
if pkg_name == 'site' and not self.args.force_bad_name:
- self.out('The package name "site" has a special meaning in '
- 'Python. Are you sure you want to use it as your '
- 'project\'s name?')
- return self.confirm_bad_name('Really use "{0}"?: '.format(
- pkg_name))
+ self.out(
+ 'The package name "site" has a special meaning in '
+ 'Python. Are you sure you want to use it as your '
+ 'project\'s name?'
+ )
+ return self.confirm_bad_name(
+ 'Really use "{0}"?: '.format(pkg_name)
+ )
# check if pkg_name can be imported (i.e. already exists in current
# $PYTHON_PATH, if so - let the user confirm
@@ -232,8 +273,10 @@ https://github.com/Pylons/?q=cookiecutter
if self.args.force_bad_name:
return True
- self.out('A package named "{0}" already exists, are you sure you want '
- 'to use it as your project\'s name?'.format(pkg_name))
+ self.out(
+ 'A package named "{0}" already exists, are you sure you want '
+ 'to use it as your project\'s name?'.format(pkg_name)
+ )
return self.confirm_bad_name('Really use "{0}"?: '.format(pkg_name))
def confirm_bad_name(self, prompt): # pragma: no cover
@@ -241,11 +284,14 @@ https://github.com/Pylons/?q=cookiecutter
return answer.strip().lower() == 'y'
def _warn_pcreate_deprecated(self):
- self.out('''\
+ self.out(
+ '''\
Note: As of Pyramid 1.8, this command is deprecated. Use a specific
cookiecutter instead:
https://github.com/pylons/?query=cookiecutter
-''')
+'''
+ )
+
if __name__ == '__main__': # pragma: no cover
sys.exit(main() or 0)
diff --git a/src/pyramid/scripts/pdistreport.py b/src/pyramid/scripts/pdistreport.py
index 1952e5d39..3ace9451e 100644
--- a/src/pyramid/scripts/pdistreport.py
+++ b/src/pyramid/scripts/pdistreport.py
@@ -4,19 +4,27 @@ import pkg_resources
import argparse
from operator import itemgetter
-def out(*args): # pragma: no cover
+
+def out(*args): # pragma: no cover
for arg in args:
sys.stdout.write(arg)
sys.stdout.write(' ')
sys.stdout.write('\n')
+
def get_parser():
parser = argparse.ArgumentParser(
- description="Show Python distribution versions and locations in use")
+ description="Show Python distribution versions and locations in use"
+ )
return parser
-def main(argv=sys.argv, pkg_resources=pkg_resources, platform=platform.platform,
- out=out):
+
+def main(
+ argv=sys.argv,
+ pkg_resources=pkg_resources,
+ platform=platform.platform,
+ out=out,
+):
# all args except argv are for unit testing purposes only
parser = get_parser()
parser.parse_args(argv[1:])
@@ -24,11 +32,13 @@ def main(argv=sys.argv, pkg_resources=pkg_resources, platform=platform.platform,
for distribution in pkg_resources.working_set:
name = distribution.project_name
packages.append(
- {'version': distribution.version,
- 'lowername': name.lower(),
- 'name': name,
- 'location':distribution.location}
- )
+ {
+ 'version': distribution.version,
+ 'lowername': name.lower(),
+ 'name': name,
+ 'location': distribution.location,
+ }
+ )
packages = sorted(packages, key=itemgetter('lowername'))
pyramid_version = pkg_resources.get_distribution('pyramid').version
plat = platform()
@@ -39,5 +49,6 @@ def main(argv=sys.argv, pkg_resources=pkg_resources, platform=platform.platform,
out(' ', package['name'], package['version'])
out(' ', package['location'])
-if __name__ == '__main__': # pragma: no cover
+
+if __name__ == '__main__': # pragma: no cover
sys.exit(main() or 0)
diff --git a/src/pyramid/scripts/prequest.py b/src/pyramid/scripts/prequest.py
index f0681afd7..e8f5ff8b3 100644
--- a/src/pyramid/scripts/prequest.py
+++ b/src/pyramid/scripts/prequest.py
@@ -8,10 +8,12 @@ from pyramid.request import Request
from pyramid.scripts.common import get_config_loader
from pyramid.scripts.common import parse_vars
+
def main(argv=sys.argv, quiet=False):
command = PRequestCommand(argv, quiet)
return command.run()
+
class PRequestCommand(object):
description = """\
Submit a HTTP request to a web application.
@@ -48,15 +50,16 @@ class PRequestCommand(object):
parser = argparse.ArgumentParser(
description=textwrap.dedent(description),
formatter_class=argparse.RawDescriptionHelpFormatter,
- )
+ )
parser.add_argument(
- '-n', '--app-name',
+ '-n',
+ '--app-name',
dest='app_name',
metavar='NAME',
help=(
"Load the named application from the config file (default 'main')"
),
- )
+ )
parser.add_argument(
'--header',
dest='headers',
@@ -67,47 +70,55 @@ class PRequestCommand(object):
),
)
parser.add_argument(
- '-d', '--display-headers',
+ '-d',
+ '--display-headers',
dest='display_headers',
action='store_true',
- help='Display status and headers before the response body'
- )
+ help='Display status and headers before the response body',
+ )
parser.add_argument(
- '-m', '--method',
+ '-m',
+ '--method',
dest='method',
- choices=['GET', 'HEAD', 'POST', 'PUT', 'PATCH','DELETE',
- 'PROPFIND', 'OPTIONS'],
+ choices=[
+ 'GET',
+ 'HEAD',
+ 'POST',
+ 'PUT',
+ 'PATCH',
+ 'DELETE',
+ 'PROPFIND',
+ 'OPTIONS',
+ ],
help='Request method type (GET, POST, PUT, PATCH, DELETE, '
- 'PROPFIND, OPTIONS)',
- )
+ 'PROPFIND, OPTIONS)',
+ )
parser.add_argument(
- '-l', '--login',
+ '-l',
+ '--login',
dest='login',
help='HTTP basic auth username:password pair',
- )
+ )
parser.add_argument(
'config_uri',
nargs='?',
default=None,
help='The URI to the configuration file.',
- )
+ )
parser.add_argument(
- 'path_info',
- nargs='?',
- default=None,
- help='The path of the request.',
- )
+ 'path_info', nargs='?', default=None, help='The path of the request.'
+ )
parser.add_argument(
'config_vars',
nargs='*',
default=(),
help="Variables required by the config file. For example, "
- "`http_port=%%(http_port)s` would expect `http_port=8080` to be "
- "passed here.",
- )
+ "`http_port=%%(http_port)s` would expect `http_port=8080` to be "
+ "passed here.",
+ )
_get_config_loader = staticmethod(get_config_loader)
stdin = sys.stdin
@@ -116,7 +127,7 @@ class PRequestCommand(object):
self.quiet = quiet
self.args = self.parser.parse_args(argv[1:])
- def out(self, msg): # pragma: no cover
+ def out(self, msg): # pragma: no cover
if not self.quiet:
print(msg)
@@ -153,7 +164,8 @@ class PRequestCommand(object):
if ':' not in item:
self.out(
"Bad --header=%s option, value must be in the form "
- "'name:value'" % item)
+ "'name:value'" % item
+ )
return 2
name, value = item.split(':', 1)
headers[name] = value.strip()
@@ -162,13 +174,13 @@ class PRequestCommand(object):
environ = {
'REQUEST_METHOD': request_method,
- 'SCRIPT_NAME': '', # may be empty if app is at the root
+ 'SCRIPT_NAME': '', # may be empty if app is at the root
'PATH_INFO': path,
'SERVER_NAME': 'localhost', # always mandatory
- 'SERVER_PORT': '80', # always mandatory
+ 'SERVER_PORT': '80', # always mandatory
'SERVER_PROTOCOL': 'HTTP/1.0',
'CONTENT_TYPE': 'text/plain',
- 'REMOTE_ADDR':'127.0.0.1',
+ 'REMOTE_ADDR': '127.0.0.1',
'wsgi.run_once': True,
'wsgi.multithread': False,
'wsgi.multiprocess': False,
@@ -178,7 +190,7 @@ class PRequestCommand(object):
'QUERY_STRING': qs,
'HTTP_ACCEPT': 'text/plain;q=1.0, */*;q=0.1',
'paste.command_request': True,
- }
+ }
if request_method in ('POST', 'PUT', 'PATCH'):
environ['wsgi.input'] = self.stdin
@@ -203,5 +215,6 @@ class PRequestCommand(object):
self.out(response.body)
return 0
-if __name__ == '__main__': # pragma: no cover
+
+if __name__ == '__main__': # pragma: no cover
sys.exit(main() or 0)
diff --git a/src/pyramid/scripts/proutes.py b/src/pyramid/scripts/proutes.py
index 69d61ae8f..2bce7d1de 100644
--- a/src/pyramid/scripts/proutes.py
+++ b/src/pyramid/scripts/proutes.py
@@ -110,7 +110,7 @@ def _get_view_module(view_callable):
if original_view.package_name is not None:
return '%s:%s' % (
original_view.package_name,
- original_view.docroot
+ original_view.docroot,
)
else:
return original_view.docroot
@@ -122,10 +122,7 @@ def _get_view_module(view_callable):
# for them and remove this logic
view_name = str(view_callable)
- view_module = '%s.%s' % (
- view_callable.__module__,
- view_name,
- )
+ view_module = '%s.%s' % (view_callable.__module__, view_name)
# If pyramid wraps something in wsgiapp or wsgiapp2 decorators
# that is currently returned as pyramid.router.decorator, lets
@@ -139,24 +136,17 @@ def _get_view_module(view_callable):
def get_route_data(route, registry):
pattern = _get_pattern(route)
- request_iface = registry.queryUtility(
- IRouteRequest,
- name=route.name
- )
+ request_iface = registry.queryUtility(IRouteRequest, name=route.name)
route_request_methods = None
view_request_methods_order = []
view_request_methods = {}
view_callable = None
- route_intr = registry.introspector.get(
- 'routes', route.name
- )
+ route_intr = registry.introspector.get('routes', route.name)
if request_iface is None:
- return [
- (route.name, _get_pattern(route), UNKNOWN_KEY, ANY_KEY)
- ]
+ return [(route.name, _get_pattern(route), UNKNOWN_KEY, ANY_KEY)]
view_callables = _find_views(registry, request_iface, Interface, '')
if view_callables:
@@ -188,7 +178,7 @@ def get_route_data(route, registry):
view_callable = getattr(view['callable'], view['attr'])
view_module = '%s.%s' % (
_get_view_module(view['callable']),
- view['attr']
+ view['attr'],
)
else:
view_callable = view['callable']
@@ -217,17 +207,11 @@ def get_route_data(route, registry):
for view_module in view_request_methods_order:
methods = view_request_methods[view_module]
- request_methods = _get_request_methods(
- route_request_methods,
- methods
- )
+ request_methods = _get_request_methods(route_request_methods, methods)
- final_routes.append((
- route.name,
- pattern,
- view_module,
- request_methods,
- ))
+ final_routes.append(
+ (route.name, pattern, view_module, request_methods)
+ )
return final_routes
@@ -251,43 +235,49 @@ class PRoutesCommand(object):
parser = argparse.ArgumentParser(
description=textwrap.dedent(description),
formatter_class=argparse.RawDescriptionHelpFormatter,
- )
- parser.add_argument('-g', '--glob',
- action='store',
- dest='glob',
- default='',
- help='Display routes matching glob pattern')
-
- parser.add_argument('-f', '--format',
- action='store',
- dest='format',
- default='',
- help=('Choose which columns to display, this will '
- 'override the format key in the [proutes] ini '
- 'section'))
+ )
+ parser.add_argument(
+ '-g',
+ '--glob',
+ action='store',
+ dest='glob',
+ default='',
+ help='Display routes matching glob pattern',
+ )
+
+ parser.add_argument(
+ '-f',
+ '--format',
+ action='store',
+ dest='format',
+ default='',
+ help=(
+ 'Choose which columns to display, this will '
+ 'override the format key in the [proutes] ini '
+ 'section'
+ ),
+ )
parser.add_argument(
'config_uri',
nargs='?',
default=None,
help='The URI to the configuration file.',
- )
+ )
parser.add_argument(
'config_vars',
nargs='*',
default=(),
help="Variables required by the config file. For example, "
- "`http_port=%%(http_port)s` would expect `http_port=8080` to be "
- "passed here.",
- )
+ "`http_port=%%(http_port)s` would expect `http_port=8080` to be "
+ "passed here.",
+ )
def __init__(self, argv, quiet=False):
self.args = self.parser.parse_args(argv[1:])
self.quiet = quiet
- self.available_formats = [
- 'name', 'pattern', 'view', 'method'
- ]
+ self.available_formats = ['name', 'pattern', 'view', 'method']
self.column_format = self.available_formats
def validate_formats(self, formats):
@@ -296,10 +286,7 @@ class PRoutesCommand(object):
if fmt not in self.available_formats:
invalid_formats.append(fmt)
- msg = (
- 'You provided invalid formats %s, '
- 'Available formats are %s'
- )
+ msg = 'You provided invalid formats %s, ' 'Available formats are %s'
if invalid_formats:
msg = msg % (invalid_formats, self.available_formats)
@@ -321,6 +308,7 @@ class PRoutesCommand(object):
def _get_mapper(self, registry):
from pyramid.config import Configurator
+
config = Configurator(registry=registry)
return config.get_routes_mapper()
@@ -361,25 +349,29 @@ class PRoutesCommand(object):
if len(routes) == 0:
return 0
- mapped_routes = [{
- 'name': 'Name',
- 'pattern': 'Pattern',
- 'view': 'View',
- 'method': 'Method'
- },{
- 'name': '----',
- 'pattern': '-------',
- 'view': '----',
- 'method': '------'
- }]
+ mapped_routes = [
+ {
+ 'name': 'Name',
+ 'pattern': 'Pattern',
+ 'view': 'View',
+ 'method': 'Method',
+ },
+ {
+ 'name': '----',
+ 'pattern': '-------',
+ 'view': '----',
+ 'method': '------',
+ },
+ ]
for route in routes:
route_data = get_route_data(route, registry)
for name, pattern, view, method in route_data:
if self.args.glob:
- match = (fnmatch.fnmatch(name, self.args.glob) or
- fnmatch.fnmatch(pattern, self.args.glob))
+ match = fnmatch.fnmatch(
+ name, self.args.glob
+ ) or fnmatch.fnmatch(pattern, self.args.glob)
if not match:
continue
@@ -395,12 +387,14 @@ class PRoutesCommand(object):
if len(method) > max_method:
max_method = len(method)
- mapped_routes.append({
- 'name': name,
- 'pattern': pattern,
- 'view': view,
- 'method': method
- })
+ mapped_routes.append(
+ {
+ 'name': name,
+ 'pattern': pattern,
+ 'view': view,
+ 'method': method,
+ }
+ )
fmt = _get_print_format(
self.column_format, max_name, max_pattern, max_view, max_method
diff --git a/src/pyramid/scripts/pserve.py b/src/pyramid/scripts/pserve.py
index 8ee6e1467..581479d65 100644
--- a/src/pyramid/scripts/pserve.py
+++ b/src/pyramid/scripts/pserve.py
@@ -46,67 +46,86 @@ class PServeCommand(object):
parser = argparse.ArgumentParser(
description=textwrap.dedent(description),
formatter_class=argparse.RawDescriptionHelpFormatter,
- )
+ )
parser.add_argument(
- '-n', '--app-name',
+ '-n',
+ '--app-name',
dest='app_name',
metavar='NAME',
- help="Load the named application (default main)")
+ help="Load the named application (default main)",
+ )
parser.add_argument(
- '-s', '--server',
+ '-s',
+ '--server',
dest='server',
metavar='SERVER_TYPE',
- help="Use the named server.")
+ help="Use the named server.",
+ )
parser.add_argument(
'--server-name',
dest='server_name',
metavar='SECTION_NAME',
- help=("Use the named server as defined in the configuration file "
- "(default: main)"))
+ help=(
+ "Use the named server as defined in the configuration file "
+ "(default: main)"
+ ),
+ )
parser.add_argument(
'--reload',
dest='reload',
action='store_true',
- help="Use auto-restart file monitor")
+ help="Use auto-restart file monitor",
+ )
parser.add_argument(
'--reload-interval',
dest='reload_interval',
default=1,
- help=("Seconds between checking files (low number can cause "
- "significant CPU usage)"))
+ help=(
+ "Seconds between checking files (low number can cause "
+ "significant CPU usage)"
+ ),
+ )
parser.add_argument(
- '-b', '--browser',
+ '-b',
+ '--browser',
dest='browser',
action='store_true',
- help=("Open a web browser to the server url. The server url is "
- "determined from the 'open_url' setting in the 'pserve' "
- "section of the configuration file."))
+ help=(
+ "Open a web browser to the server url. The server url is "
+ "determined from the 'open_url' setting in the 'pserve' "
+ "section of the configuration file."
+ ),
+ )
parser.add_argument(
- '-v', '--verbose',
+ '-v',
+ '--verbose',
default=default_verbosity,
dest='verbose',
action='count',
- help="Set verbose level (default " + str(default_verbosity) + ")")
+ help="Set verbose level (default " + str(default_verbosity) + ")",
+ )
parser.add_argument(
- '-q', '--quiet',
+ '-q',
+ '--quiet',
action='store_const',
const=0,
dest='verbose',
- help="Suppress verbose output")
+ help="Suppress verbose output",
+ )
parser.add_argument(
'config_uri',
nargs='?',
default=None,
help='The URI to the configuration file.',
- )
+ )
parser.add_argument(
'config_vars',
nargs='*',
default=(),
help="Variables required by the config file. For example, "
- "`http_port=%%(http_port)s` would expect `http_port=8080` to be "
- "passed here.",
- )
+ "`http_port=%%(http_port)s` would expect `http_port=8080` to be "
+ "passed here.",
+ )
_get_config_loader = staticmethod(get_config_loader) # for testing
@@ -187,18 +206,23 @@ class PServeCommand(object):
if not url:
url = self.guess_server_url(
- server_loader, server_name, config_vars)
+ server_loader, server_name, config_vars
+ )
if not url:
- self.out('WARNING: could not determine the server\'s url to '
- 'open the browser. To fix this set the "open_url" '
- 'setting in the [pserve] section of the '
- 'configuration file.')
+ self.out(
+ 'WARNING: could not determine the server\'s url to '
+ 'open the browser. To fix this set the "open_url" '
+ 'setting in the [pserve] section of the '
+ 'configuration file.'
+ )
else:
+
def open_browser():
time.sleep(1)
webbrowser.open(url)
+
t = threading.Thread(target=open_browser)
t.setDaemon(True)
t.start()
@@ -210,7 +234,7 @@ class PServeCommand(object):
'pyramid.scripts.pserve.main',
reload_interval=int(self.args.reload_interval),
verbose=self.args.verbose,
- worker_kwargs=self.worker_kwargs
+ worker_kwargs=self.worker_kwargs,
)
return 0
@@ -250,6 +274,7 @@ class PServeCommand(object):
# For paste.deploy server instantiation (egg:pyramid#wsgiref)
def wsgiref_server_runner(wsgi_app, global_conf, **kw): # pragma: no cover
from wsgiref.simple_server import make_server
+
host = kw.get('host', '0.0.0.0')
port = int(kw.get('port', 8080))
server = make_server(host, port, wsgi_app)
@@ -259,11 +284,18 @@ def wsgiref_server_runner(wsgi_app, global_conf, **kw): # pragma: no cover
# For paste.deploy server instantiation (egg:pyramid#cherrypy)
def cherrypy_server_runner(
- app, global_conf=None, host='127.0.0.1', port=None,
- ssl_pem=None, protocol_version=None, numthreads=None,
- server_name=None, max=None, request_queue_size=None,
- timeout=None
- ): # pragma: no cover
+ app,
+ global_conf=None,
+ host='127.0.0.1',
+ port=None,
+ ssl_pem=None,
+ protocol_version=None,
+ numthreads=None,
+ server_name=None,
+ max=None,
+ request_queue_size=None,
+ timeout=None,
+): # pragma: no cover
"""
Entry point for CherryPy's WSGI server
@@ -346,8 +378,7 @@ def cherrypy_server_runner(
except ImportError:
from cherrypy.wsgiserver import CherryPyWSGIServer as WSGIServer
- server = WSGIServer(bind_addr, app,
- server_name=server_name, **kwargs)
+ server = WSGIServer(bind_addr, app, server_name=server_name, **kwargs)
if ssl_pem is not None:
if PY2:
server.ssl_certificate = server.ssl_private_key = ssl_pem
@@ -368,8 +399,10 @@ def cherrypy_server_runner(
try:
protocol = is_ssl and 'https' or 'http'
if host == '0.0.0.0':
- print('serving on 0.0.0.0:%s view at %s://127.0.0.1:%s' %
- (port, protocol, port))
+ print(
+ 'serving on 0.0.0.0:%s view at %s://127.0.0.1:%s'
+ % (port, protocol, port)
+ )
else:
print('serving on %s://%s:%s' % (protocol, host, port))
server.start()
diff --git a/src/pyramid/scripts/pshell.py b/src/pyramid/scripts/pshell.py
index 4898eb39f..e63114d18 100644
--- a/src/pyramid/scripts/pshell.py
+++ b/src/pyramid/scripts/pshell.py
@@ -16,6 +16,7 @@ from pyramid.settings import aslist
from pyramid.scripts.common import get_config_loader
from pyramid.scripts.common import parse_vars
+
def main(argv=sys.argv, quiet=False):
command = PShellCommand(argv, quiet)
return command.run()
@@ -49,38 +50,52 @@ class PShellCommand(object):
parser = argparse.ArgumentParser(
description=textwrap.dedent(description),
formatter_class=argparse.RawDescriptionHelpFormatter,
- )
- parser.add_argument('-p', '--python-shell',
- action='store',
- dest='python_shell',
- default='',
- help=('Select the shell to use. A list of possible '
- 'shells is available using the --list-shells '
- 'option.'))
- parser.add_argument('-l', '--list-shells',
- dest='list',
- action='store_true',
- help='List all available shells.')
- parser.add_argument('--setup',
- dest='setup',
- help=("A callable that will be passed the environment "
- "before it is made available to the shell. This "
- "option will override the 'setup' key in the "
- "[pshell] ini section."))
- parser.add_argument('config_uri',
- nargs='?',
- default=None,
- help='The URI to the configuration file.')
+ )
+ parser.add_argument(
+ '-p',
+ '--python-shell',
+ action='store',
+ dest='python_shell',
+ default='',
+ help=(
+ 'Select the shell to use. A list of possible '
+ 'shells is available using the --list-shells '
+ 'option.'
+ ),
+ )
+ parser.add_argument(
+ '-l',
+ '--list-shells',
+ dest='list',
+ action='store_true',
+ help='List all available shells.',
+ )
+ parser.add_argument(
+ '--setup',
+ dest='setup',
+ help=(
+ "A callable that will be passed the environment "
+ "before it is made available to the shell. This "
+ "option will override the 'setup' key in the "
+ "[pshell] ini section."
+ ),
+ )
+ parser.add_argument(
+ 'config_uri',
+ nargs='?',
+ default=None,
+ help='The URI to the configuration file.',
+ )
parser.add_argument(
'config_vars',
nargs='*',
default=(),
help="Variables required by the config file. For example, "
- "`http_port=%%(http_port)s` would expect `http_port=8080` to be "
- "passed here.",
- )
+ "`http_port=%%(http_port)s` would expect `http_port=8080` to be "
+ "passed here.",
+ )
- default_runner = python_shell_runner # testing
+ default_runner = python_shell_runner # testing
loaded_objects = {}
object_help = {}
@@ -107,7 +122,7 @@ class PShellCommand(object):
self.loaded_objects[k] = self.resolver.maybe_resolve(v)
self.object_help[k] = v
- def out(self, msg): # pragma: no cover
+ def out(self, msg): # pragma: no cover
if not self.quiet:
print(msg)
@@ -152,8 +167,9 @@ class PShellCommand(object):
env_help['root'] = 'Root of the default resource tree.'
env_help['registry'] = 'Active Pyramid registry.'
env_help['request'] = 'Active request object.'
- env_help['root_factory'] = (
- 'Default root factory used to create `root`.')
+ env_help[
+ 'root_factory'
+ ] = 'Default root factory used to create `root`.'
# load the pshell section of the ini file
env.update(self.loaded_objects)
@@ -236,6 +252,7 @@ class PShellCommand(object):
# by default prioritize all shells above python
preferred_shells = [k for k in shells.keys() if k != 'python']
max_weight = len(preferred_shells)
+
def order(x):
# invert weight to reverse sort the list
# (closer to the front is higher priority)
@@ -243,6 +260,7 @@ class PShellCommand(object):
return preferred_shells.index(x[0].lower()) - max_weight
except ValueError:
return 1
+
sorted_shells = sorted(shells.items(), key=order)
if len(sorted_shells) > 0:
@@ -266,5 +284,5 @@ class PShellCommand(object):
return shell
-if __name__ == '__main__': # pragma: no cover
+if __name__ == '__main__': # pragma: no cover
sys.exit(main() or 0)
diff --git a/src/pyramid/scripts/ptweens.py b/src/pyramid/scripts/ptweens.py
index d5cbebe12..e6a5c5ac7 100644
--- a/src/pyramid/scripts/ptweens.py
+++ b/src/pyramid/scripts/ptweens.py
@@ -10,10 +10,12 @@ from pyramid.paster import bootstrap
from pyramid.paster import setup_logging
from pyramid.scripts.common import parse_vars
+
def main(argv=sys.argv, quiet=False):
command = PTweensCommand(argv, quiet)
return command.run()
+
class PTweensCommand(object):
description = """\
Print all implicit and explicit tween objects used by a Pyramid
@@ -31,25 +33,27 @@ class PTweensCommand(object):
parser = argparse.ArgumentParser(
description=textwrap.dedent(description),
formatter_class=argparse.RawDescriptionHelpFormatter,
- )
+ )
- parser.add_argument('config_uri',
- nargs='?',
- default=None,
- help='The URI to the configuration file.')
+ parser.add_argument(
+ 'config_uri',
+ nargs='?',
+ default=None,
+ help='The URI to the configuration file.',
+ )
parser.add_argument(
'config_vars',
nargs='*',
default=(),
help="Variables required by the config file. For example, "
- "`http_port=%%(http_port)s` would expect `http_port=8080` to be "
- "passed here.",
- )
+ "`http_port=%%(http_port)s` would expect `http_port=8080` to be "
+ "passed here.",
+ )
stdout = sys.stdout
- bootstrap = staticmethod(bootstrap) # testing
- setup_logging = staticmethod(setup_logging) # testing
+ bootstrap = staticmethod(bootstrap) # testing
+ setup_logging = staticmethod(setup_logging) # testing
def __init__(self, argv, quiet=False):
self.quiet = quiet
@@ -57,10 +61,11 @@ class PTweensCommand(object):
def _get_tweens(self, registry):
from pyramid.config import Configurator
+
config = Configurator(registry=registry)
return config.registry.queryUtility(ITweens)
- def out(self, msg): # pragma: no cover
+ def out(self, msg): # pragma: no cover
if not self.quiet:
print(msg)
@@ -86,8 +91,10 @@ class PTweensCommand(object):
if tweens is not None:
explicit = tweens.explicit
if explicit:
- self.out('"pyramid.tweens" config value set '
- '(explicitly ordered tweens used)')
+ self.out(
+ '"pyramid.tweens" config value set '
+ '(explicitly ordered tweens used)'
+ )
self.out('')
self.out('Explicit Tween Chain (used)')
self.out('')
@@ -97,13 +104,16 @@ class PTweensCommand(object):
self.out('')
self.show_chain(tweens.implicit())
else:
- self.out('"pyramid.tweens" config value NOT set '
- '(implicitly ordered tweens used)')
+ self.out(
+ '"pyramid.tweens" config value NOT set '
+ '(implicitly ordered tweens used)'
+ )
self.out('')
self.out('Implicit Tween Chain')
self.out('')
self.show_chain(tweens.implicit())
return 0
-if __name__ == '__main__': # pragma: no cover
+
+if __name__ == '__main__': # pragma: no cover
sys.exit(main() or 0)
diff --git a/src/pyramid/scripts/pviews.py b/src/pyramid/scripts/pviews.py
index c0df2f078..891dc4709 100644
--- a/src/pyramid/scripts/pviews.py
+++ b/src/pyramid/scripts/pviews.py
@@ -9,10 +9,12 @@ from pyramid.request import Request
from pyramid.scripts.common import parse_vars
from pyramid.view import _find_views
+
def main(argv=sys.argv, quiet=False):
command = PViewsCommand(argv, quiet)
return command.run()
+
class PViewsCommand(object):
description = """\
Print, for a given URL, the views that might match. Underneath each
@@ -31,38 +33,41 @@ class PViewsCommand(object):
parser = argparse.ArgumentParser(
description=textwrap.dedent(description),
formatter_class=argparse.RawDescriptionHelpFormatter,
- )
+ )
- parser.add_argument('config_uri',
- nargs='?',
- default=None,
- help='The URI to the configuration file.')
+ parser.add_argument(
+ 'config_uri',
+ nargs='?',
+ default=None,
+ help='The URI to the configuration file.',
+ )
- parser.add_argument('url',
- nargs='?',
- default=None,
- help='The path info portion of the URL.')
+ parser.add_argument(
+ 'url',
+ nargs='?',
+ default=None,
+ help='The path info portion of the URL.',
+ )
parser.add_argument(
'config_vars',
nargs='*',
default=(),
help="Variables required by the config file. For example, "
- "`http_port=%%(http_port)s` would expect `http_port=8080` to be "
- "passed here.",
- )
+ "`http_port=%%(http_port)s` would expect `http_port=8080` to be "
+ "passed here.",
+ )
-
- bootstrap = staticmethod(bootstrap) # testing
- setup_logging = staticmethod(setup_logging) # testing
+ bootstrap = staticmethod(bootstrap) # testing
+ setup_logging = staticmethod(setup_logging) # testing
def __init__(self, argv, quiet=False):
self.quiet = quiet
self.args = self.parser.parse_args(argv[1:])
- def out(self, msg): # pragma: no cover
+ def out(self, msg): # pragma: no cover
if not self.quiet:
print(msg)
-
+
def _find_multi_routes(self, mapper, request):
infos = []
path = request.environ['PATH_INFO']
@@ -70,7 +75,7 @@ class PViewsCommand(object):
for route in mapper.get_routes():
match = route.match(path)
if match is not None:
- info = {'match':match, 'route':route}
+ info = {'match': match, 'route': route}
infos.append(info)
return infos
@@ -99,22 +104,17 @@ class PViewsCommand(object):
@implementer(IMultiView)
class RoutesMultiView(object):
-
def __init__(self, infos, context_iface, root_factory, request):
self.views = []
for info in infos:
match, route = info['match'], info['route']
if route is not None:
request_iface = registry.queryUtility(
- IRouteRequest,
- name=route.name,
- default=IRequest)
+ IRouteRequest, name=route.name, default=IRequest
+ )
views = _find_views(
- request.registry,
- request_iface,
- context_iface,
- ''
- )
+ request.registry, request_iface, context_iface, ''
+ )
if not views:
continue
view = views[0]
@@ -148,9 +148,8 @@ class PViewsCommand(object):
attrs['matched_route'] = route
request.environ['bfg.routes.matchdict'] = match
request_iface = registry.queryUtility(
- IRouteRequest,
- name=route.name,
- default=IRequest)
+ IRouteRequest, name=route.name, default=IRequest
+ )
root_factory = route.factory or root_factory
if len(infos) > 1:
routes_multiview = infos
@@ -171,11 +170,8 @@ class PViewsCommand(object):
context_iface = providedBy(context)
if routes_multiview is None:
views = _find_views(
- request.registry,
- request_iface,
- context_iface,
- view_name,
- )
+ request.registry, request_iface, context_iface, view_name
+ )
if views:
view = views[0]
else:
@@ -186,11 +182,8 @@ class PViewsCommand(object):
# routes are not registered with a view name
if view is None:
views = _find_views(
- request.registry,
- request_iface,
- context_iface,
- '',
- )
+ request.registry, request_iface, context_iface, ''
+ )
if views:
view = views[0]
else:
@@ -285,5 +278,6 @@ class PViewsCommand(object):
env['closer']()
return 0
-if __name__ == '__main__': # pragma: no cover
+
+if __name__ == '__main__': # pragma: no cover
sys.exit(main() or 0)
diff --git a/src/pyramid/security.py b/src/pyramid/security.py
index 0bdca090b..2e3896976 100644
--- a/src/pyramid/security.py
+++ b/src/pyramid/security.py
@@ -7,7 +7,7 @@ from pyramid.interfaces import (
ISecuredView,
IView,
IViewClassifier,
- )
+)
from pyramid.compat import map_
from pyramid.threadlocal import get_current_registry
@@ -17,6 +17,7 @@ Authenticated = 'system.Authenticated'
Allow = 'Allow'
Deny = 'Deny'
+
class AllPermissionsList(object):
""" Stand in 'permission list' to represent all permissions """
@@ -29,94 +30,105 @@ class AllPermissionsList(object):
def __eq__(self, other):
return isinstance(other, self.__class__)
+
ALL_PERMISSIONS = AllPermissionsList()
DENY_ALL = (Deny, Everyone, ALL_PERMISSIONS)
NO_PERMISSION_REQUIRED = '__no_permission_required__'
+
def _get_registry(request):
try:
reg = request.registry
except AttributeError:
- reg = get_current_registry() # b/c
+ reg = get_current_registry() # b/c
return reg
+
def _get_authentication_policy(request):
registry = _get_registry(request)
return registry.queryUtility(IAuthenticationPolicy)
+
def has_permission(permission, context, request):
"""
A function that calls :meth:`pyramid.request.Request.has_permission`
and returns its result.
-
+
.. deprecated:: 1.5
Use :meth:`pyramid.request.Request.has_permission` instead.
.. versionchanged:: 1.5a3
If context is None, then attempt to use the context attribute of self;
if not set, then the AttributeError is propagated.
- """
+ """
return request.has_permission(permission, context)
+
deprecated(
'has_permission',
'As of Pyramid 1.5 the "pyramid.security.has_permission" API is now '
'deprecated. It will be removed in Pyramid 1.8. Use the '
- '"has_permission" method of the Pyramid request instead.'
- )
+ '"has_permission" method of the Pyramid request instead.',
+)
def authenticated_userid(request):
"""
A function that returns the value of the property
:attr:`pyramid.request.Request.authenticated_userid`.
-
+
.. deprecated:: 1.5
Use :attr:`pyramid.request.Request.authenticated_userid` instead.
- """
+ """
return request.authenticated_userid
+
deprecated(
'authenticated_userid',
'As of Pyramid 1.5 the "pyramid.security.authenticated_userid" API is now '
'deprecated. It will be removed in Pyramid 1.8. Use the '
- '"authenticated_userid" attribute of the Pyramid request instead.'
- )
+ '"authenticated_userid" attribute of the Pyramid request instead.',
+)
+
def unauthenticated_userid(request):
- """
+ """
A function that returns the value of the property
:attr:`pyramid.request.Request.unauthenticated_userid`.
-
+
.. deprecated:: 1.5
Use :attr:`pyramid.request.Request.unauthenticated_userid` instead.
- """
+ """
return request.unauthenticated_userid
+
deprecated(
'unauthenticated_userid',
'As of Pyramid 1.5 the "pyramid.security.unauthenticated_userid" API is '
'now deprecated. It will be removed in Pyramid 1.8. Use the '
- '"unauthenticated_userid" attribute of the Pyramid request instead.'
- )
+ '"unauthenticated_userid" attribute of the Pyramid request instead.',
+)
+
def effective_principals(request):
"""
A function that returns the value of the property
:attr:`pyramid.request.Request.effective_principals`.
-
+
.. deprecated:: 1.5
Use :attr:`pyramid.request.Request.effective_principals` instead.
- """
+ """
return request.effective_principals
+
deprecated(
'effective_principals',
'As of Pyramid 1.5 the "pyramid.security.effective_principals" API is '
'now deprecated. It will be removed in Pyramid 1.8. Use the '
- '"effective_principals" attribute of the Pyramid request instead.'
- )
+ '"effective_principals" attribute of the Pyramid request instead.',
+)
+
def remember(request, userid, **kw):
"""
@@ -154,6 +166,7 @@ def remember(request, userid, **kw):
return []
return policy.remember(request, userid, **kw)
+
def forget(request):
"""
Return a sequence of header tuples (e.g. ``[('Set-Cookie',
@@ -172,12 +185,13 @@ def forget(request):
If no :term:`authentication policy` is in use, this function will
always return an empty sequence.
- """
+ """
policy = _get_authentication_policy(request)
if policy is None:
return []
return policy.forget(request)
+
def principals_allowed_by_permission(context, permission):
""" Provided a ``context`` (a resource object), and a ``permission``
(a string or unicode object), if an :term:`authorization policy` is
@@ -201,6 +215,7 @@ def principals_allowed_by_permission(context, permission):
return [Everyone]
return policy.principals_allowed_by_permission(context, permission)
+
def view_execution_permitted(context, request, name=''):
""" If the view specified by ``context`` and ``name`` is protected
by a :term:`permission`, check the permission associated with the
@@ -222,12 +237,15 @@ def view_execution_permitted(context, request, name=''):
if view is None:
view = reg.adapters.lookup(provides, IView, name=name)
if view is None:
- raise TypeError('No registered view satisfies the constraints. '
- 'It would not make sense to claim that this view '
- '"is" or "is not" permitted.')
+ raise TypeError(
+ 'No registered view satisfies the constraints. '
+ 'It would not make sense to claim that this view '
+ '"is" or "is not" permitted.'
+ )
return Allowed(
- 'Allowed: view name %r in context %r (no permission defined)' %
- (name, context))
+ 'Allowed: view name %r in context %r (no permission defined)'
+ % (name, context)
+ )
return view.__permitted__(context, request)
@@ -255,9 +273,12 @@ class PermitsResult(int):
return self.msg
def __repr__(self):
- return '<%s instance at %s with msg %r>' % (self.__class__.__name__,
- id(self),
- self.msg)
+ return '<%s instance at %s with msg %r>' % (
+ self.__class__.__name__,
+ id(self),
+ self.msg,
+ )
+
class Denied(PermitsResult):
"""
@@ -268,8 +289,10 @@ class Denied(PermitsResult):
the deny.
"""
+
boolval = 0
+
class Allowed(PermitsResult):
"""
An instance of ``Allowed`` is returned when a security-related
@@ -279,8 +302,10 @@ class Allowed(PermitsResult):
the allow.
"""
+
boolval = 1
+
class ACLPermitsResult(PermitsResult):
def __new__(cls, ace, acl, permission, principals, context):
"""
@@ -294,17 +319,12 @@ class ACLPermitsResult(PermitsResult):
searched.
"""
- fmt = ('%s permission %r via ACE %r in ACL %r on context %r for '
- 'principals %r')
+ fmt = (
+ '%s permission %r via ACE %r in ACL %r on context %r for '
+ 'principals %r'
+ )
inst = PermitsResult.__new__(
- cls,
- fmt,
- cls.__name__,
- permission,
- ace,
- acl,
- context,
- principals,
+ cls, fmt, cls.__name__, permission, ace, acl, context, principals
)
inst.permission = permission
inst.ace = ace
@@ -313,6 +333,7 @@ class ACLPermitsResult(PermitsResult):
inst.context = context
return inst
+
class ACLDenied(ACLPermitsResult, Denied):
"""
An instance of ``ACLDenied`` is a specialization of
@@ -326,6 +347,7 @@ class ACLDenied(ACLPermitsResult, Denied):
"""
+
class ACLAllowed(ACLPermitsResult, Allowed):
"""
An instance of ``ACLAllowed`` is a specialization of
@@ -339,8 +361,8 @@ class ACLAllowed(ACLPermitsResult, Allowed):
"""
-class AuthenticationAPIMixin(object):
+class AuthenticationAPIMixin(object):
def _get_authentication_policy(self):
reg = _get_registry(self)
return reg.queryUtility(IAuthenticationPolicy)
@@ -389,8 +411,8 @@ class AuthenticationAPIMixin(object):
return [Everyone]
return policy.effective_principals(self)
-class AuthorizationAPIMixin(object):
+class AuthorizationAPIMixin(object):
def has_permission(self, permission, context=None):
""" Given a permission and an optional context, returns an instance of
:data:`pyramid.security.Allowed` if the permission is granted to this
@@ -421,7 +443,9 @@ class AuthorizationAPIMixin(object):
return Allowed('No authentication policy in use.')
authz_policy = reg.queryUtility(IAuthorizationPolicy)
if authz_policy is None:
- raise ValueError('Authentication policy registered without '
- 'authorization policy') # should never happen
+ raise ValueError(
+ 'Authentication policy registered without '
+ 'authorization policy'
+ ) # should never happen
principals = authn_policy.effective_principals(self)
return authz_policy.permits(context, principals, permission)
diff --git a/src/pyramid/session.py b/src/pyramid/session.py
index b953fa184..9d4ef6dbb 100644
--- a/src/pyramid/session.py
+++ b/src/pyramid/session.py
@@ -9,22 +9,10 @@ import warnings
from zope.deprecation import deprecated
from zope.interface import implementer
-from webob.cookies import (
- JSONSerializer,
- SignedSerializer,
-)
+from webob.cookies import JSONSerializer, SignedSerializer
-from pyramid.compat import (
- pickle,
- PY2,
- text_,
- bytes_,
- native_,
- )
-from pyramid.csrf import (
- check_csrf_origin,
- check_csrf_token,
-)
+from pyramid.compat import pickle, PY2, text_, bytes_, native_
+from pyramid.csrf import check_csrf_origin, check_csrf_token
from pyramid.interfaces import ISession
from pyramid.util import strings_differ
@@ -33,25 +21,31 @@ from pyramid.util import strings_differ
def manage_accessed(wrapped):
""" Decorator which causes a cookie to be renewed when an accessor
method is called."""
+
def accessed(session, *arg, **kw):
session.accessed = now = int(time.time())
if session._reissue_time is not None:
if now - session.renewed > session._reissue_time:
session.changed()
return wrapped(session, *arg, **kw)
+
accessed.__doc__ = wrapped.__doc__
return accessed
+
def manage_changed(wrapped):
""" Decorator which causes a cookie to be set when a setter method
is called."""
+
def changed(session, *arg, **kw):
session.accessed = int(time.time())
session.changed()
return wrapped(session, *arg, **kw)
+
changed.__doc__ = wrapped.__doc__
return changed
+
def signed_serialize(data, secret):
""" Serialize any pickleable structure (``data``) and sign it
using the ``secret`` (must be a string). Return the
@@ -82,6 +76,7 @@ def signed_serialize(data, secret):
sig = hmac.new(secret, pickled, hashlib.sha1).hexdigest()
return sig + native_(base64.b64encode(pickled))
+
deprecated(
'signed_serialize',
'This function will be removed in Pyramid 2.0. It is using pickle-based '
@@ -89,6 +84,7 @@ deprecated(
'attacks.',
)
+
def signed_deserialize(serialized, secret, hmac=hmac):
""" Deserialize the value returned from ``signed_serialize``. If
the value cannot be deserialized for any reason, a
@@ -111,8 +107,10 @@ def signed_deserialize(serialized, secret, hmac=hmac):
"""
# hmac parameterized only for unit tests
try:
- input_sig, pickled = (bytes_(serialized[:40]),
- base64.b64decode(bytes_(serialized[40:])))
+ input_sig, pickled = (
+ bytes_(serialized[:40]),
+ base64.b64decode(bytes_(serialized[40:])),
+ )
except (binascii.Error, TypeError) as e:
# Badly formed data can make base64 die
raise ValueError('Badly formed base64 data: %s' % e)
@@ -131,6 +129,7 @@ def signed_deserialize(serialized, secret, hmac=hmac):
return pickle.loads(pickled)
+
deprecated(
'signed_deserialize',
'This function will be removed in Pyramid 2.0. It is using pickle-based '
@@ -149,6 +148,7 @@ class PickleSerializer(object):
Defaults to :attr:`pickle.HIGHEST_PROTOCOL`.
"""
+
def __init__(self, protocol=pickle.HIGHEST_PROTOCOL):
self.protocol = protocol
@@ -180,7 +180,7 @@ def BaseCookieSessionFactory(
timeout=1200,
reissue_time=0,
set_on_exception=True,
- ):
+):
"""
Configure a :term:`session factory` which will provide cookie-based
sessions. The return value of this function is a :term:`session factory`,
@@ -280,7 +280,9 @@ def BaseCookieSessionFactory(
_cookie_samesite = samesite
_cookie_on_exception = set_on_exception
_timeout = timeout if timeout is None else int(timeout)
- _reissue_time = reissue_time if reissue_time is None else int(reissue_time)
+ _reissue_time = (
+ reissue_time if reissue_time is None else int(reissue_time)
+ )
# dirty flag
_dirty = False
@@ -330,13 +332,15 @@ def BaseCookieSessionFactory(
def changed(self):
if not self._dirty:
self._dirty = True
+
def set_cookie_callback(request, response):
self._set_cookie(response)
- self.request = None # explicitly break cycle for gc
+ self.request = None # explicitly break cycle for gc
+
self.request.add_response_callback(set_cookie_callback)
def invalidate(self):
- self.clear() # XXX probably needs to unset cookie
+ self.clear() # XXX probably needs to unset cookie
# non-modifying dictionary methods
get = manage_accessed(dict.get)
@@ -398,16 +402,18 @@ def BaseCookieSessionFactory(
def _set_cookie(self, response):
if not self._cookie_on_exception:
exception = getattr(self.request, 'exception', None)
- if exception is not None: # dont set a cookie during exceptions
+ if (
+ exception is not None
+ ): # dont set a cookie during exceptions
return False
- cookieval = native_(serializer.dumps(
- (self.accessed, self.created, dict(self))
- ))
+ cookieval = native_(
+ serializer.dumps((self.accessed, self.created, dict(self)))
+ )
if len(cookieval) > 4064:
raise ValueError(
- 'Cookie value is too long to store (%s bytes)' %
- len(cookieval)
- )
+ 'Cookie value is too long to store (%s bytes)'
+ % len(cookieval)
+ )
response.set_cookie(
self._cookie_name,
value=cookieval,
@@ -417,7 +423,7 @@ def BaseCookieSessionFactory(
secure=self._cookie_secure,
httponly=self._cookie_httponly,
samesite=self._cookie_samesite,
- )
+ )
return True
return CookieSession
@@ -436,7 +442,7 @@ def UnencryptedCookieSessionFactoryConfig(
cookie_on_exception=True,
signed_serialize=signed_serialize,
signed_deserialize=signed_deserialize,
- ):
+):
"""
.. deprecated:: 1.5
Use :func:`pyramid.session.SignedCookieSessionFactory` instead.
@@ -530,18 +536,19 @@ def UnencryptedCookieSessionFactoryConfig(
httponly=cookie_httponly,
samesite=cookie_samesite,
timeout=timeout,
- reissue_time=0, # to keep session.accessed == session.renewed
+ reissue_time=0, # to keep session.accessed == session.renewed
set_on_exception=cookie_on_exception,
)
+
deprecated(
'UnencryptedCookieSessionFactoryConfig',
'The UnencryptedCookieSessionFactoryConfig callable is deprecated as of '
'Pyramid 1.5. Use ``pyramid.session.SignedCookieSessionFactory`` instead.'
' Caveat: Cookies generated using SignedCookieSessionFactory are not '
'compatible with cookies generated using UnencryptedCookieSessionFactory, '
- 'so existing user session data will be destroyed if you switch to it.'
- )
+ 'so existing user session data will be destroyed if you switch to it.',
+)
def SignedCookieSessionFactory(
@@ -559,7 +566,7 @@ def SignedCookieSessionFactory(
hashalg='sha512',
salt='pyramid.session.',
serializer=None,
- ):
+):
"""
.. versionadded:: 1.5
@@ -681,11 +688,8 @@ def SignedCookieSessionFactory(
)
signed_serializer = SignedSerializer(
- secret,
- salt,
- hashalg,
- serializer=serializer,
- )
+ secret, salt, hashalg, serializer=serializer
+ )
return BaseCookieSessionFactory(
signed_serializer,
@@ -701,12 +705,17 @@ def SignedCookieSessionFactory(
set_on_exception=set_on_exception,
)
+
check_csrf_origin = check_csrf_origin # api
-deprecated('check_csrf_origin',
- 'pyramid.session.check_csrf_origin is deprecated as of Pyramid '
- '1.9. Use pyramid.csrf.check_csrf_origin instead.')
+deprecated(
+ 'check_csrf_origin',
+ 'pyramid.session.check_csrf_origin is deprecated as of Pyramid '
+ '1.9. Use pyramid.csrf.check_csrf_origin instead.',
+)
check_csrf_token = check_csrf_token # api
-deprecated('check_csrf_token',
- 'pyramid.session.check_csrf_token is deprecated as of Pyramid '
- '1.9. Use pyramid.csrf.check_csrf_token instead.')
+deprecated(
+ 'check_csrf_token',
+ 'pyramid.session.check_csrf_token is deprecated as of Pyramid '
+ '1.9. Use pyramid.csrf.check_csrf_token instead.',
+)
diff --git a/src/pyramid/settings.py b/src/pyramid/settings.py
index 8a498d572..af9433840 100644
--- a/src/pyramid/settings.py
+++ b/src/pyramid/settings.py
@@ -3,6 +3,7 @@ from pyramid.compat import string_types
truthy = frozenset(('t', 'true', 'y', 'yes', 'on', '1'))
falsey = frozenset(('f', 'false', 'n', 'no', 'off', '0'))
+
def asbool(s):
""" Return the boolean value ``True`` if the case-lowered value of string
input ``s`` is a :term:`truthy string`. If ``s`` is already one of the
@@ -14,11 +15,13 @@ def asbool(s):
s = str(s).strip()
return s.lower() in truthy
+
def aslist_cronly(value):
if isinstance(value, string_types):
value = filter(None, [x.strip() for x in value.splitlines()])
return list(value)
+
def aslist(value, flatten=True):
""" Return a list of strings, separating the input based on newlines
and, if flatten=True (the default), also split on spaces within
diff --git a/src/pyramid/static.py b/src/pyramid/static.py
index 70fdf877b..58ad97a46 100644
--- a/src/pyramid/static.py
+++ b/src/pyramid/static.py
@@ -2,47 +2,25 @@
import json
import os
-from os.path import (
- getmtime,
- normcase,
- normpath,
- join,
- isdir,
- exists,
- )
-
-from pkg_resources import (
- resource_exists,
- resource_filename,
- resource_isdir,
- )
-
-from pyramid.asset import (
- abspath_from_asset_spec,
- resolve_asset_spec,
-)
-
-from pyramid.compat import (
- lru_cache,
- text_,
-)
-
-from pyramid.httpexceptions import (
- HTTPNotFound,
- HTTPMovedPermanently,
- )
+from os.path import getmtime, normcase, normpath, join, isdir, exists
+
+from pkg_resources import resource_exists, resource_filename, resource_isdir
+
+from pyramid.asset import abspath_from_asset_spec, resolve_asset_spec
+
+from pyramid.compat import lru_cache, text_
+
+from pyramid.httpexceptions import HTTPNotFound, HTTPMovedPermanently
from pyramid.path import caller_package
-from pyramid.response import (
- _guess_type,
- FileResponse,
-)
+from pyramid.response import _guess_type, FileResponse
from pyramid.traversal import traversal_path_info
slash = text_('/')
+
class static_view(object):
""" An instance of this class is a callable which can act as a
:app:`Pyramid` :term:`view callable`; this view will serve
@@ -88,8 +66,14 @@ class static_view(object):
to override the assets it contains.
"""
- def __init__(self, root_dir, cache_max_age=3600, package_name=None,
- use_subpath=False, index='index.html'):
+ def __init__(
+ self,
+ root_dir,
+ cache_max_age=3600,
+ package_name=None,
+ use_subpath=False,
+ index='index.html',
+ ):
# package_name is for bw compat; it is preferred to pass in a
# package-relative path as root_dir
# (e.g. ``anotherpackage:foo/static``).
@@ -113,20 +97,21 @@ class static_view(object):
if path is None:
raise HTTPNotFound('Out of bounds: %s' % request.url)
- if self.package_name: # package resource
+ if self.package_name: # package resource
resource_path = '%s/%s' % (self.docroot.rstrip('/'), path)
if resource_isdir(self.package_name, resource_path):
if not request.path_url.endswith('/'):
self.add_slash_redirect(request)
resource_path = '%s/%s' % (
- resource_path.rstrip('/'), self.index
+ resource_path.rstrip('/'),
+ self.index,
)
if not resource_exists(self.package_name, resource_path):
raise HTTPNotFound(request.url)
filepath = resource_filename(self.package_name, resource_path)
- else: # filesystem file
+ else: # filesystem file
# os.path.normpath converts / to \ on windows
filepath = normcase(normpath(join(self.norm_docroot, path)))
@@ -139,8 +124,12 @@ class static_view(object):
content_type, content_encoding = _guess_type(filepath)
return FileResponse(
- filepath, request, self.cache_max_age,
- content_type, content_encoding=None)
+ filepath,
+ request,
+ self.cache_max_age,
+ content_type,
+ content_encoding=None,
+ )
def add_slash_redirect(self, request):
url = request.path_url + '/'
@@ -149,14 +138,19 @@ class static_view(object):
url = url + '?' + qs
raise HTTPMovedPermanently(url)
+
_seps = set(['/', os.sep])
+
+
def _contains_slash(item):
for sep in _seps:
if sep in item:
return True
+
_has_insecure_pathelement = set(['..', '.', '']).intersection
+
@lru_cache(1000)
def _secure_path(path_tuple):
if _has_insecure_pathelement(path_tuple):
@@ -166,9 +160,10 @@ def _secure_path(path_tuple):
return None
if any([_contains_slash(item) for item in path_tuple]):
return None
- encoded = slash.join(path_tuple) # will be unicode
+ encoded = slash.join(path_tuple) # will be unicode
return encoded
+
class QueryStringCacheBuster(object):
"""
An implementation of :class:`~pyramid.interfaces.ICacheBuster` which adds
@@ -182,6 +177,7 @@ class QueryStringCacheBuster(object):
.. versionadded:: 1.6
"""
+
def __init__(self, param='x'):
self.param = param
@@ -194,6 +190,7 @@ class QueryStringCacheBuster(object):
kw['_query'] = tuple(query) + ((self.param, token),)
return subpath, kw
+
class QueryStringConstantCacheBuster(QueryStringCacheBuster):
"""
An implementation of :class:`~pyramid.interfaces.ICacheBuster` which adds
@@ -207,6 +204,7 @@ class QueryStringConstantCacheBuster(QueryStringCacheBuster):
.. versionadded:: 1.6
"""
+
def __init__(self, token, param='x'):
super(QueryStringConstantCacheBuster, self).__init__(param=param)
self._token = token
@@ -214,6 +212,7 @@ class QueryStringConstantCacheBuster(QueryStringCacheBuster):
def tokenize(self, request, subpath, kw):
return self._token
+
class ManifestCacheBuster(object):
"""
An implementation of :class:`~pyramid.interfaces.ICacheBuster` which
@@ -255,13 +254,15 @@ class ManifestCacheBuster(object):
.. versionadded:: 1.6
"""
- exists = staticmethod(exists) # testing
- getmtime = staticmethod(getmtime) # testing
+
+ exists = staticmethod(exists) # testing
+ getmtime = staticmethod(getmtime) # testing
def __init__(self, manifest_spec, reload=False):
package_name = caller_package().__name__
self.manifest_path = abspath_from_asset_spec(
- manifest_spec, package_name)
+ manifest_spec, package_name
+ )
self.reload = reload
self._mtime = None
diff --git a/src/pyramid/testing.py b/src/pyramid/testing.py
index 4986c0e27..e2549f0b9 100644
--- a/src/pyramid/testing.py
+++ b/src/pyramid/testing.py
@@ -2,22 +2,11 @@ import copy
import os
from contextlib import contextmanager
-from zope.interface import (
- implementer,
- alsoProvides,
- )
+from zope.interface import implementer, alsoProvides
-from pyramid.interfaces import (
- IRequest,
- ISession,
- )
+from pyramid.interfaces import IRequest, ISession
-from pyramid.compat import (
- PY3,
- PYPY,
- class_types,
- text_,
- )
+from pyramid.compat import PY3, PYPY, class_types, text_
from pyramid.config import Configurator
from pyramid.decorator import reify
@@ -30,12 +19,9 @@ from pyramid.security import (
Everyone,
AuthenticationAPIMixin,
AuthorizationAPIMixin,
- )
+)
-from pyramid.threadlocal import (
- get_current_registry,
- manager,
- )
+from pyramid.threadlocal import get_current_registry, manager
from pyramid.i18n import LocalizerRequestMixin
from pyramid.request import CallbackMethodsMixin
@@ -46,17 +32,27 @@ from pyramid.view import ViewMethodsMixin
_marker = object()
+
class DummyRootFactory(object):
__parent__ = None
__name__ = None
+
def __init__(self, request):
if 'bfg.routes.matchdict' in request:
self.__dict__.update(request['bfg.routes.matchdict'])
+
class DummySecurityPolicy(object):
""" A standin for both an IAuthentication and IAuthorization policy """
- def __init__(self, userid=None, groupids=(), permissive=True,
- remember_result=None, forget_result=None):
+
+ def __init__(
+ self,
+ userid=None,
+ groupids=(),
+ permissive=True,
+ remember_result=None,
+ forget_result=None,
+ ):
self.userid = userid
self.groupids = groupids
self.permissive = permissive
@@ -95,6 +91,7 @@ class DummySecurityPolicy(object):
def principals_allowed_by_permission(self, context, permission):
return self.effective_principals(None)
+
class DummyTemplateRenderer(object):
"""
An instance of this class is returned from
@@ -103,6 +100,7 @@ class DummyTemplateRenderer(object):
assertion which compares data passed to the renderer by the view
function against expected key/value pairs.
"""
+
def __init__(self, string_response=''):
self._received = {}
self._string_response = string_response
@@ -113,9 +111,11 @@ class DummyTemplateRenderer(object):
# source code, *everything* is an API!
def _get_string_response(self):
return self._string_response
+
def _set_string_response(self, response):
self._string_response = response
self._implementation.response = response
+
string_response = property(_get_string_response, _set_string_response)
def implementation(self):
@@ -151,19 +151,23 @@ class DummyTemplateRenderer(object):
if myval is _marker:
raise AssertionError(
'A value for key "%s" was not passed to the renderer'
- % k)
+ % k
+ )
if myval != v:
raise AssertionError(
- '\nasserted value for %s: %r\nactual value: %r' % (
- k, v, myval))
+ '\nasserted value for %s: %r\nactual value: %r'
+ % (k, v, myval)
+ )
return True
class DummyResource:
""" A dummy :app:`Pyramid` :term:`resource` object."""
- def __init__(self, __name__=None, __parent__=None, __provides__=None,
- **kw):
+
+ def __init__(
+ self, __name__=None, __parent__=None, __provides__=None, **kw
+ ):
""" The resource's ``__name__`` attribute will be set to the
value of the ``__name__`` argument, and the resource's
``__parent__`` attribute will be set to the value of the
@@ -250,12 +254,15 @@ class DummyResource:
inst.__parent__ = __parent__
return inst
-DummyModel = DummyResource # b/w compat (forever)
+
+DummyModel = DummyResource # b/w compat (forever)
+
@implementer(ISession)
class DummySession(dict):
created = None
new = True
+
def changed(self):
pass
@@ -286,6 +293,7 @@ class DummySession(dict):
token = self.new_csrf_token()
return token
+
@implementer(IRequest)
class DummyRequest(
URLMethodsMixin,
@@ -295,7 +303,7 @@ class DummyRequest(
AuthenticationAPIMixin,
AuthorizationAPIMixin,
ViewMethodsMixin,
- ):
+):
""" A DummyRequest object (incompletely) imitates a :term:`request` object.
The ``params``, ``environ``, ``headers``, ``path``, and
@@ -322,6 +330,7 @@ class DummyRequest(
a Request, use the :class:`pyramid.request.Request` class itself rather
than this class while writing tests.
"""
+
method = 'GET'
application_url = 'http://example.com'
host = 'example.com:80'
@@ -333,8 +342,16 @@ class DummyRequest(
_registry = None
request_iface = IRequest
- def __init__(self, params=None, environ=None, headers=None, path='/',
- cookies=None, post=None, **kw):
+ def __init__(
+ self,
+ params=None,
+ environ=None,
+ headers=None,
+ path='/',
+ cookies=None,
+ post=None,
+ **kw
+ ):
if environ is None:
environ = {}
if params is None:
@@ -369,7 +386,7 @@ class DummyRequest(
self.context = None
self.root = None
self.virtual_root = None
- self.marshalled = params # repoze.monty
+ self.marshalled = params # repoze.monty
self.session = DummySession()
self.__dict__.update(kw)
@@ -391,11 +408,18 @@ class DummyRequest(
f = _get_response_factory(self.registry)
return f(self)
+
have_zca = True
-def setUp(registry=None, request=None, hook_zca=True, autocommit=True,
- settings=None, package=None):
+def setUp(
+ registry=None,
+ request=None,
+ hook_zca=True,
+ autocommit=True,
+ settings=None,
+ package=None,
+):
"""
Set :app:`Pyramid` registry and request thread locals for the
duration of a single unit test.
@@ -462,8 +486,9 @@ def setUp(registry=None, request=None, hook_zca=True, autocommit=True,
registry = Registry('testing')
if package is None:
package = caller_package()
- config = Configurator(registry=registry, autocommit=autocommit,
- package=package)
+ config = Configurator(
+ registry=registry, autocommit=autocommit, package=package
+ )
if settings is None:
settings = {}
if getattr(registry, 'settings', None) is None:
@@ -486,12 +511,13 @@ def setUp(registry=None, request=None, hook_zca=True, autocommit=True,
global have_zca
try:
have_zca and hook_zca and config.hook_zca()
- except ImportError: # pragma: no cover
+ except ImportError: # pragma: no cover
# (dont choke on not being able to import z.component)
have_zca = False
config.begin(request=request)
return config
+
def tearDown(unhook_zca=True):
"""Undo the effects of :func:`pyramid.testing.setUp`. Use this
function in the ``tearDown`` method of a unit test that uses
@@ -507,8 +533,9 @@ def tearDown(unhook_zca=True):
if unhook_zca and have_zca:
try:
from zope.component import getSiteManager
+
getSiteManager.reset()
- except ImportError: # pragma: no cover
+ except ImportError: # pragma: no cover
have_zca = False
info = manager.pop()
manager.clear()
@@ -524,6 +551,7 @@ def tearDown(unhook_zca=True):
# understand, let's not blow up
pass
+
def cleanUp(*arg, **kw):
""" An alias for :func:`pyramid.testing.setUp`. """
package = kw.get('package', None)
@@ -532,6 +560,7 @@ def cleanUp(*arg, **kw):
kw['package'] = package
return setUp(*arg, **kw)
+
class DummyRendererFactory(object):
""" Registered by
:meth:`pyramid.config.Configurator.testing_add_renderer` as
@@ -540,9 +569,10 @@ class DummyRendererFactory(object):
wild believing they can register either. The ``factory`` argument
passed to this constructor is usually the *real* template renderer
factory, found when ``testing_add_renderer`` is called."""
+
def __init__(self, name, factory):
self.name = name
- self.factory = factory # the "real" renderer factory reg'd previously
+ self.factory = factory # the "real" renderer factory reg'd previously
self.renderers = {}
def add(self, spec, renderer):
@@ -562,8 +592,9 @@ class DummyRendererFactory(object):
if self.factory:
renderer = self.factory(info)
else:
- raise KeyError('No testing renderer registered for %r' %
- spec)
+ raise KeyError(
+ 'No testing renderer registered for %r' % spec
+ )
return renderer
@@ -571,15 +602,19 @@ class MockTemplate(object):
def __init__(self, response):
self._received = {}
self.response = response
+
def __getattr__(self, attrname):
return self
+
def __getitem__(self, attrname):
return self
+
def __call__(self, *arg, **kw):
self._received.update(kw)
return self.response
-def skip_on(*platforms): # pragma: no cover
+
+def skip_on(*platforms): # pragma: no cover
skip = False
for platform in platforms:
if skip_on.os_name.startswith(platform):
@@ -596,22 +631,26 @@ def skip_on(*platforms): # pragma: no cover
else:
return func
else:
+
def wrapper(*args, **kw):
if skip:
return
return func(*args, **kw)
+
wrapper.__name__ = func.__name__
wrapper.__doc__ = func.__doc__
return wrapper
+
return decorator
-skip_on.os_name = os.name # for testing
+
+
+skip_on.os_name = os.name # for testing
+
@contextmanager
-def testConfig(registry=None,
- request=None,
- hook_zca=True,
- autocommit=True,
- settings=None):
+def testConfig(
+ registry=None, request=None, hook_zca=True, autocommit=True, settings=None
+):
"""Returns a context manager for test set up.
This context manager calls :func:`pyramid.testing.setUp` when
@@ -630,11 +669,13 @@ def testConfig(registry=None,
req = DummyRequest()
resp = myview(req)
"""
- config = setUp(registry=registry,
- request=request,
- hook_zca=hook_zca,
- autocommit=autocommit,
- settings=settings)
+ config = setUp(
+ registry=registry,
+ request=request,
+ hook_zca=hook_zca,
+ autocommit=autocommit,
+ settings=settings,
+ )
try:
yield config
finally:
diff --git a/src/pyramid/threadlocal.py b/src/pyramid/threadlocal.py
index e8f825715..7eca5b0f0 100644
--- a/src/pyramid/threadlocal.py
+++ b/src/pyramid/threadlocal.py
@@ -2,6 +2,7 @@ import threading
from pyramid.registry import global_registry
+
class ThreadLocalManager(threading.local):
def __init__(self, default=None):
# http://code.google.com/p/google-app-engine-django/issues/detail?id=119
@@ -15,7 +16,7 @@ class ThreadLocalManager(threading.local):
def push(self, info):
self.stack.append(info)
- set = push # b/c
+ set = push # b/c
def pop(self):
if self.stack:
@@ -30,11 +31,14 @@ class ThreadLocalManager(threading.local):
def clear(self):
self.stack[:] = []
+
def defaults():
return {'request': None, 'registry': global_registry}
+
manager = ThreadLocalManager(default=defaults)
+
def get_current_request():
"""
Return the currently active request or ``None`` if no request
@@ -49,7 +53,10 @@ def get_current_request():
"""
return manager.get()['request']
-def get_current_registry(context=None): # context required by getSiteManager API
+
+def get_current_registry(
+ context=None
+): # context required by getSiteManager API
"""
Return the currently active :term:`application registry` or the
global application registry if no request is currently active.
@@ -63,6 +70,7 @@ def get_current_registry(context=None): # context required by getSiteManager API
"""
return manager.get()['registry']
+
class RequestContext(object):
def __init__(self, request):
self.request = request
diff --git a/src/pyramid/traversal.py b/src/pyramid/traversal.py
index d8f4690fd..338b49083 100644
--- a/src/pyramid/traversal.py
+++ b/src/pyramid/traversal.py
@@ -6,7 +6,7 @@ from pyramid.interfaces import (
IRequestFactory,
ITraverser,
VH_ROOT_KEY,
- )
+)
from pyramid.compat import (
PY2,
@@ -19,18 +19,19 @@ from pyramid.compat import (
decode_path_info,
unquote_bytes_to_wsgi,
lru_cache,
- )
+)
from pyramid.encode import url_quote
from pyramid.exceptions import URLDecodeError
from pyramid.location import lineage
from pyramid.threadlocal import get_current_registry
-PATH_SEGMENT_SAFE = "~!$&'()*+,;=:@" # from webob
+PATH_SEGMENT_SAFE = "~!$&'()*+,;=:@" # from webob
PATH_SAFE = PATH_SEGMENT_SAFE + "/"
empty = text_('')
+
def find_root(resource):
""" Find the root node in the resource tree to which ``resource``
belongs. Note that ``resource`` should be :term:`location`-aware.
@@ -43,6 +44,7 @@ def find_root(resource):
break
return resource
+
def find_resource(resource, path):
""" Given a resource object and a string or tuple representing a path
(such as the return value of :func:`pyramid.traversal.resource_path` or
@@ -101,7 +103,9 @@ def find_resource(resource, path):
raise KeyError('%r has no subelement %s' % (context, view_name))
return context
-find_model = find_resource # b/w compat (forever)
+
+find_model = find_resource # b/w compat (forever)
+
def find_interface(resource, class_or_interface):
"""
@@ -121,6 +125,7 @@ def find_interface(resource, class_or_interface):
if test(location):
return location
+
def resource_path(resource, *elements):
""" Return a string object representing the absolute physical path of the
resource object based on its position in the resource tree, e.g
@@ -166,7 +171,9 @@ def resource_path(resource, *elements):
# which caches the joined result for us
return _join_path_tuple(resource_path_tuple(resource, *elements))
-model_path = resource_path # b/w compat (forever)
+
+model_path = resource_path # b/w compat (forever)
+
def traverse(resource, path):
"""Given a resource object as ``resource`` and a string or tuple
@@ -314,7 +321,8 @@ def traverse(resource, path):
request_factory = reg.queryUtility(IRequestFactory)
if request_factory is None:
- from pyramid.request import Request # avoid circdep
+ from pyramid.request import Request # avoid circdep
+
request_factory = Request
request = request_factory.blank(path)
@@ -325,6 +333,7 @@ def traverse(resource, path):
return traverser(request)
+
def resource_path_tuple(resource, *elements):
"""
Return a tuple representing the absolute physical path of the
@@ -360,21 +369,26 @@ def resource_path_tuple(resource, *elements):
The :term:`root` resource *must* have a ``__name__`` attribute with a
value of either ``None`` or the empty string for path tuples to be
generated properly. If the root resource has a non-null ``__name__``
- attribute, its name will be the first element in the generated path tuple
- rather than the empty string.
+ attribute, its name will be the first element in the generated path
+ tuple rather than the empty string.
"""
return tuple(_resource_path_list(resource, *elements))
+
model_path_tuple = resource_path_tuple # b/w compat (forever)
+
def _resource_path_list(resource, *elements):
- """ Implementation detail shared by resource_path and resource_path_tuple"""
+ """ Implementation detail shared by resource_path and
+ resource_path_tuple"""
path = [loc.__name__ or '' for loc in lineage(resource)]
path.reverse()
path.extend(elements)
return path
-_model_path_list = _resource_path_list # b/w compat, not an API
+
+_model_path_list = _resource_path_list # b/w compat, not an API
+
def virtual_root(resource, request):
"""
@@ -412,7 +426,7 @@ def virtual_root(resource, request):
vpath, rpath = url_adapter.virtual_path, url_adapter.physical_path
if rpath != vpath and rpath.endswith(vpath):
- vroot_path = rpath[:-len(vpath)]
+ vroot_path = rpath[: -len(vpath)]
return find_resource(resource, vroot_path)
try:
@@ -420,6 +434,7 @@ def virtual_root(resource, request):
except AttributeError:
return find_root(resource)
+
def traversal_path(path):
""" Variant of :func:`pyramid.traversal.traversal_path_info` suitable for
decoding paths that are URL-encoded.
@@ -435,8 +450,9 @@ def traversal_path(path):
# must not possess characters outside ascii
path = path.encode('ascii')
# we unquote this path exactly like a PEP 3333 server would
- path = unquote_bytes_to_wsgi(path) # result will be a native string
- return traversal_path_info(path) # result will be a tuple of unicode
+ path = unquote_bytes_to_wsgi(path) # result will be a native string
+ return traversal_path_info(path) # result will be a tuple of unicode
+
@lru_cache(1000)
def traversal_path_info(path):
@@ -501,19 +517,20 @@ def traversal_path_info(path):
This function does not generate the same type of tuples that
:func:`pyramid.traversal.resource_path_tuple` does. In particular, the
- leading empty string is not present in the tuple it returns, unlike tuples
- returned by :func:`pyramid.traversal.resource_path_tuple`. As a result,
- tuples generated by ``traversal_path`` are not resolveable by the
- :func:`pyramid.traversal.find_resource` API. ``traversal_path`` is a
- function mostly used by the internals of :app:`Pyramid` and by people
+ leading empty string is not present in the tuple it returns, unlike
+ tuples returned by :func:`pyramid.traversal.resource_path_tuple`. As a
+ result, tuples generated by ``traversal_path`` are not resolveable by
+ the :func:`pyramid.traversal.find_resource` API. ``traversal_path`` is
+ a function mostly used by the internals of :app:`Pyramid` and by people
writing their own traversal machinery, as opposed to users writing
applications in :app:`Pyramid`.
"""
try:
- path = decode_path_info(path) # result will be Unicode
+ path = decode_path_info(path) # result will be Unicode
except UnicodeDecodeError as e:
raise URLDecodeError(e.encoding, e.object, e.start, e.end, e.reason)
- return split_path_info(path) # result will be tuple of Unicode
+ return split_path_info(path) # result will be tuple of Unicode
+
@lru_cache(1000)
def split_path_info(path):
@@ -531,6 +548,7 @@ def split_path_info(path):
clean.append(segment)
return tuple(clean)
+
_segment_cache = {}
quote_path_segment_doc = """ \
@@ -574,7 +592,9 @@ if PY2:
try:
return _segment_cache[(segment, safe)]
except KeyError:
- if segment.__class__ is text_type: #isinstance slighly slower (~15%)
+ if (
+ segment.__class__ is text_type
+ ): # isinstance slighly slower (~15%)
result = url_quote(segment.encode('utf-8'), safe)
else:
result = url_quote(str(segment), safe)
@@ -582,7 +602,10 @@ if PY2:
# will generate exactly one Python bytecode (STORE_SUBSCR)
_segment_cache[(segment, safe)] = result
return result
+
+
else:
+
def quote_path_segment(segment, safe=PATH_SEGMENT_SAFE):
""" %s """ % quote_path_segment_doc
# The bit of this code that deals with ``_segment_cache`` is an
@@ -601,8 +624,10 @@ else:
_segment_cache[(segment, safe)] = result
return result
+
slash = text_('/')
+
@implementer(ITraverser)
class ResourceTreeTraverser(object):
""" A resource tree traverser that should be used (for speed) when
@@ -610,7 +635,6 @@ class ResourceTreeTraverser(object):
``__parent__`` attribute (ie. every resource in the tree is
:term:`location` aware) ."""
-
VH_ROOT_KEY = VH_ROOT_KEY
VIEW_SELECTOR = '@@'
@@ -647,14 +671,17 @@ class ResourceTreeTraverser(object):
# if environ['PATH_INFO'] is just not there
path = slash
except UnicodeDecodeError as e:
- raise URLDecodeError(e.encoding, e.object, e.start, e.end,
- e.reason)
+ raise URLDecodeError(
+ e.encoding, e.object, e.start, e.end, e.reason
+ )
if self.VH_ROOT_KEY in environ:
# HTTP_X_VHM_ROOT
vroot_path = decode_path_info(environ[self.VH_ROOT_KEY])
vroot_tuple = split_path_info(vroot_path)
- vpath = vroot_path + path # both will (must) be unicode or asciistr
+ vpath = (
+ vroot_path + path
+ ) # both will (must) be unicode or asciistr
vroot_idx = len(vroot_tuple) - 1
else:
vroot_tuple = ()
@@ -664,7 +691,7 @@ class ResourceTreeTraverser(object):
root = self.root
ob = vroot = root
- if vpath == slash: # invariant: vpath must not be empty
+ if vpath == slash: # invariant: vpath must not be empty
# prevent a call to traversal_path if we know it's going
# to return the empty tuple
vpath_tuple = ()
@@ -677,44 +704,60 @@ class ResourceTreeTraverser(object):
vpath_tuple = split_path_info(vpath)
for segment in vpath_tuple:
if segment[:2] == view_selector:
- return {'context': ob,
- 'view_name': segment[2:],
- 'subpath': vpath_tuple[i + 1:],
- 'traversed': vpath_tuple[:vroot_idx + i + 1],
- 'virtual_root': vroot,
- 'virtual_root_path': vroot_tuple,
- 'root': root}
+ return {
+ 'context': ob,
+ 'view_name': segment[2:],
+ 'subpath': vpath_tuple[i + 1 :],
+ 'traversed': vpath_tuple[: vroot_idx + i + 1],
+ 'virtual_root': vroot,
+ 'virtual_root_path': vroot_tuple,
+ 'root': root,
+ }
try:
getitem = ob.__getitem__
except AttributeError:
- return {'context': ob,
- 'view_name': segment,
- 'subpath': vpath_tuple[i + 1:],
- 'traversed': vpath_tuple[:vroot_idx + i + 1],
- 'virtual_root': vroot,
- 'virtual_root_path': vroot_tuple,
- 'root': root}
+ return {
+ 'context': ob,
+ 'view_name': segment,
+ 'subpath': vpath_tuple[i + 1 :],
+ 'traversed': vpath_tuple[: vroot_idx + i + 1],
+ 'virtual_root': vroot,
+ 'virtual_root_path': vroot_tuple,
+ 'root': root,
+ }
try:
next = getitem(segment)
except KeyError:
- return {'context': ob,
- 'view_name': segment,
- 'subpath': vpath_tuple[i + 1:],
- 'traversed': vpath_tuple[:vroot_idx + i + 1],
- 'virtual_root': vroot,
- 'virtual_root_path': vroot_tuple,
- 'root': root}
+ return {
+ 'context': ob,
+ 'view_name': segment,
+ 'subpath': vpath_tuple[i + 1 :],
+ 'traversed': vpath_tuple[: vroot_idx + i + 1],
+ 'virtual_root': vroot,
+ 'virtual_root_path': vroot_tuple,
+ 'root': root,
+ }
if i == vroot_idx:
vroot = next
ob = next
i += 1
- return {'context':ob, 'view_name':empty, 'subpath':subpath,
- 'traversed':vpath_tuple, 'virtual_root':vroot,
- 'virtual_root_path':vroot_tuple, 'root':root}
+ return {
+ 'context': ob,
+ 'view_name': empty,
+ 'subpath': subpath,
+ 'traversed': vpath_tuple,
+ 'virtual_root': vroot,
+ 'virtual_root_path': vroot_tuple,
+ 'root': root,
+ }
+
+
+ModelGraphTraverser = (
+ ResourceTreeTraverser
+) # b/w compat, not API, used in wild
-ModelGraphTraverser = ResourceTreeTraverser # b/w compat, not API, used in wild
@implementer(IResourceURL)
class ResourceURL(object):
@@ -742,19 +785,24 @@ class ResourceURL(object):
vroot_path_tuple = tuple(vroot_path.split('/'))
numels = len(vroot_path_tuple)
virtual_path_tuple = ('',) + physical_path_tuple[numels:]
- virtual_path = physical_path[len(vroot_path):]
+ virtual_path = physical_path[len(vroot_path) :]
- self.virtual_path = virtual_path # IResourceURL attr
+ self.virtual_path = virtual_path # IResourceURL attr
self.physical_path = physical_path # IResourceURL attr
- self.virtual_path_tuple = virtual_path_tuple # IResourceURL attr (1.5)
- self.physical_path_tuple = physical_path_tuple # IResourceURL attr (1.5)
+ self.virtual_path_tuple = virtual_path_tuple # IResourceURL attr (1.5)
+ self.physical_path_tuple = (
+ physical_path_tuple
+ ) # IResourceURL attr (1.5)
+
@lru_cache(1000)
def _join_path_tuple(tuple):
return tuple and '/'.join([quote_path_segment(x) for x in tuple]) or '/'
+
class DefaultRootFactory:
__parent__ = None
__name__ = None
+
def __init__(self, request):
pass
diff --git a/src/pyramid/tweens.py b/src/pyramid/tweens.py
index 740b6961c..839c53b8f 100644
--- a/src/pyramid/tweens.py
+++ b/src/pyramid/tweens.py
@@ -3,6 +3,7 @@ import sys
from pyramid.compat import reraise
from pyramid.httpexceptions import HTTPNotFound
+
def _error_handler(request, exc):
# NOTE: we do not need to delete exc_info because this function
# should never be in the call stack of the exception
@@ -17,6 +18,7 @@ def _error_handler(request, exc):
return response
+
def excview_tween_factory(handler, registry):
""" A :term:`tween` factory which produces a tween that catches an
exception raised by downstream tweens (or the main Pyramid request
@@ -43,6 +45,7 @@ def excview_tween_factory(handler, registry):
return excview_tween
+
MAIN = 'MAIN'
INGRESS = 'INGRESS'
EXCVIEW = 'pyramid.tweens.excview_tween_factory'
diff --git a/src/pyramid/url.py b/src/pyramid/url.py
index 852aa5e55..00dd13bfe 100644
--- a/src/pyramid/url.py
+++ b/src/pyramid/url.py
@@ -2,21 +2,10 @@
import os
-from pyramid.interfaces import (
- IResourceURL,
- IRoutesMapper,
- IStaticURLInfo,
- )
+from pyramid.interfaces import IResourceURL, IRoutesMapper, IStaticURLInfo
-from pyramid.compat import (
- bytes_,
- lru_cache,
- string_types,
- )
-from pyramid.encode import (
- url_quote,
- urlencode,
-)
+from pyramid.compat import bytes_, lru_cache, string_types
+from pyramid.encode import url_quote, urlencode
from pyramid.path import caller_package
from pyramid.threadlocal import get_current_registry
@@ -25,11 +14,12 @@ from pyramid.traversal import (
quote_path_segment,
PATH_SAFE,
PATH_SEGMENT_SAFE,
- )
+)
-QUERY_SAFE = "/?:@!$&'()*+,;=" # RFC 3986
+QUERY_SAFE = "/?:@!$&'()*+,;=" # RFC 3986
ANCHOR_SAFE = QUERY_SAFE
+
def parse_url_overrides(request, kw):
"""
Parse special arguments passed when generating urls.
@@ -48,7 +38,7 @@ def parse_url_overrides(request, kw):
anchor = kw.pop('_anchor', '')
if app_url is None:
- if (scheme is not None or host is not None or port is not None):
+ if scheme is not None or host is not None or port is not None:
app_url = request._partial_application_url(scheme, host, port)
else:
app_url = request.application_url
@@ -66,6 +56,7 @@ def parse_url_overrides(request, kw):
return app_url, qs, frag
+
class URLMethodsMixin(object):
""" Request methods mixin for BaseRequest having to do with URL
generation """
@@ -115,7 +106,7 @@ class URLMethodsMixin(object):
if port:
url += ':%s' % port
- url_encoding = getattr(self, 'url_encoding', 'utf-8') # webob 1.2b3+
+ url_encoding = getattr(self, 'url_encoding', 'utf-8') # webob 1.2b3+
bscript_name = bytes_(self.script_name, url_encoding)
return url + url_quote(bscript_name, PATH_SAFE)
@@ -181,10 +172,10 @@ class URLMethodsMixin(object):
Python data structures that are passed as ``_query`` which are
sequences or dictionaries are turned into a string under the same
- rules as when run through :func:`urllib.urlencode` with the ``doseq``
- argument equal to ``True``. This means that sequences can be passed
- as values, and a k=v pair will be placed into the query string for
- each value.
+ rules as when run through :func:`urllib.urlencode` with the
+ ``doseq`` argument equal to ``True``. This means that sequences can
+ be passed as values, and a k=v pair will be placed into the query
+ string for each value.
If a keyword argument ``_anchor`` is present, its string
representation will be quoted per :rfc:`3986#section-3.5` and used as
@@ -209,7 +200,7 @@ class URLMethodsMixin(object):
``_host='foo.com'``, and the URL that would have been generated
without the host replacement is ``http://example.com/a``, the result
will be ``http://foo.com/a``.
-
+
Note that if ``_scheme`` is passed as ``https``, and ``_port`` is not
passed, the ``_port`` value is assumed to have been passed as
``443``. Likewise, if ``_scheme`` is passed as ``http`` and
@@ -255,7 +246,7 @@ class URLMethodsMixin(object):
try:
reg = self.registry
except AttributeError:
- reg = get_current_registry() # b/c
+ reg = get_current_registry() # b/c
mapper = reg.getUtility(IRoutesMapper)
route = mapper.get_route(route_name)
@@ -267,7 +258,7 @@ class URLMethodsMixin(object):
app_url, qs, anchor = parse_url_overrides(self, kw)
- path = route.generate(kw) # raises KeyError if generate fails
+ path = route.generate(kw) # raises KeyError if generate fails
if elements:
suffix = _join_elements(elements)
@@ -372,10 +363,10 @@ class URLMethodsMixin(object):
Python data structures that are passed as ``query`` which are
sequences or dictionaries are turned into a string under the same
- rules as when run through :func:`urllib.urlencode` with the ``doseq``
- argument equal to ``True``. This means that sequences can be passed
- as values, and a k=v pair will be placed into the query string for
- each value.
+ rules as when run through :func:`urllib.urlencode` with the
+ ``doseq`` argument equal to ``True``. This means that sequences can
+ be passed as values, and a k=v pair will be placed into the query
+ string for each value.
If a keyword argument ``anchor`` is present, its string
representation will be used as a named anchor in the generated URL
@@ -399,7 +390,7 @@ class URLMethodsMixin(object):
``host='foo.com'``, and the URL that would have been generated
without the host replacement is ``http://example.com/a``, the result
will be ``http://foo.com/a``.
-
+
If ``scheme`` is passed as ``https``, and an explicit ``port`` is not
passed, the ``port`` value is assumed to have been passed as ``443``.
Likewise, if ``scheme`` is passed as ``http`` and ``port`` is not
@@ -424,11 +415,11 @@ class URLMethodsMixin(object):
If the ``resource`` passed in has a ``__resource_url__`` method, it
will be used to generate the URL (scheme, host, port, path) for the
base resource which is operated upon by this function.
-
+
.. seealso::
See also :ref:`overriding_resource_url_generation`.
-
+
If ``route_name`` is passed, this function will delegate its URL
production to the ``route_url`` function. Calling
``resource_url(someresource, 'element1', 'element2', query={'a':1},
@@ -481,21 +472,21 @@ class URLMethodsMixin(object):
is passed, the ``__resource_url__`` method of the resource passed is
ignored unconditionally. This feature is incompatible with
resources which generate their own URLs.
-
+
.. note::
- If the :term:`resource` used is the result of a :term:`traversal`, it
- must be :term:`location`-aware. The resource can also be the context
- of a :term:`URL dispatch`; contexts found this way do not need to be
- location-aware.
+ If the :term:`resource` used is the result of a :term:`traversal`,
+ it must be :term:`location`-aware. The resource can also be the
+ context of a :term:`URL dispatch`; contexts found this way do not
+ need to be location-aware.
.. note::
If a 'virtual root path' is present in the request environment (the
value of the WSGI environ key ``HTTP_X_VHM_ROOT``), and the resource
- was obtained via :term:`traversal`, the URL path will not include the
- virtual root prefix (it will be stripped off the left hand side of
- the generated URL).
+ was obtained via :term:`traversal`, the URL path will not include
+ the virtual root prefix (it will be stripped off the left hand side
+ of the generated URL).
.. note::
@@ -522,7 +513,7 @@ class URLMethodsMixin(object):
try:
reg = self.registry
except AttributeError:
- reg = get_current_registry() # b/c
+ reg = get_current_registry() # b/c
url_adapter = reg.queryMultiAdapter((resource, self), IResourceURL)
if url_adapter is None:
@@ -531,9 +522,7 @@ class URLMethodsMixin(object):
virtual_path = getattr(url_adapter, 'virtual_path', None)
urlkw = {}
- for name in (
- 'app_url', 'scheme', 'host', 'port', 'query', 'anchor'
- ):
+ for name in ('app_url', 'scheme', 'host', 'port', 'query', 'anchor'):
val = kw.get(name, None)
if val is not None:
urlkw['_' + name] = val
@@ -583,7 +572,7 @@ class URLMethodsMixin(object):
return resource_url + suffix + qs + anchor
- model_url = resource_url # b/w compat forever
+ model_url = resource_url # b/w compat forever
def resource_path(self, resource, *elements, **kw):
"""
@@ -651,7 +640,7 @@ class URLMethodsMixin(object):
try:
reg = self.registry
except AttributeError:
- reg = get_current_registry() # b/c
+ reg = get_current_registry() # b/c
info = reg.queryUtility(IStaticURLInfo)
if info is None:
@@ -803,6 +792,7 @@ def route_url(route_name, request, *elements, **kw):
"""
return request.route_url(route_name, *elements, **kw)
+
def route_path(route_name, request, *elements, **kw):
"""
This is a backwards compatibility function. Its result is the same as
@@ -814,6 +804,7 @@ def route_path(route_name, request, *elements, **kw):
"""
return request.route_path(route_name, *elements, **kw)
+
def resource_url(resource, request, *elements, **kw):
"""
This is a backwards compatibility function. Its result is the same as
@@ -825,7 +816,8 @@ def resource_url(resource, request, *elements, **kw):
"""
return request.resource_url(resource, *elements, **kw)
-model_url = resource_url # b/w compat (forever)
+
+model_url = resource_url # b/w compat (forever)
def static_url(path, request, **kw):
@@ -865,6 +857,7 @@ def static_path(path, request, **kw):
path = '%s:%s' % (package.__name__, path)
return request.static_path(path, **kw)
+
def current_route_url(request, *elements, **kw):
"""
This is a backwards compatibility function. Its result is the same as
@@ -877,6 +870,7 @@ def current_route_url(request, *elements, **kw):
"""
return request.current_route_url(*elements, **kw)
+
def current_route_path(request, *elements, **kw):
"""
This is a backwards compatibility function. Its result is the same as
@@ -889,6 +883,9 @@ def current_route_path(request, *elements, **kw):
"""
return request.current_route_path(*elements, **kw)
+
@lru_cache(1000)
def _join_elements(elements):
- return '/'.join([quote_path_segment(s, safe=PATH_SEGMENT_SAFE) for s in elements])
+ return '/'.join(
+ [quote_path_segment(s, safe=PATH_SEGMENT_SAFE) for s in elements]
+ )
diff --git a/src/pyramid/urldispatch.py b/src/pyramid/urldispatch.py
index a61071845..de8a69d2a 100644
--- a/src/pyramid/urldispatch.py
+++ b/src/pyramid/urldispatch.py
@@ -1,10 +1,7 @@
import re
from zope.interface import implementer
-from pyramid.interfaces import (
- IRoutesMapper,
- IRoute,
- )
+from pyramid.interfaces import IRoutesMapper, IRoute
from pyramid.compat import (
PY2,
@@ -15,30 +12,29 @@ from pyramid.compat import (
binary_type,
is_nonstr_iter,
decode_path_info,
- )
+)
from pyramid.exceptions import URLDecodeError
-from pyramid.traversal import (
- quote_path_segment,
- split_path_info,
- PATH_SAFE,
- )
+from pyramid.traversal import quote_path_segment, split_path_info, PATH_SAFE
_marker = object()
+
@implementer(IRoute)
class Route(object):
- def __init__(self, name, pattern, factory=None, predicates=(),
- pregenerator=None):
+ def __init__(
+ self, name, pattern, factory=None, predicates=(), pregenerator=None
+ ):
self.pattern = pattern
- self.path = pattern # indefinite b/w compat, not in interface
+ self.path = pattern # indefinite b/w compat, not in interface
self.match, self.generate = _compile_route(pattern)
self.name = name
self.factory = factory
self.predicates = predicates
self.pregenerator = pregenerator
+
@implementer(IRoutesMapper)
class RoutesMapper(object):
def __init__(self):
@@ -59,8 +55,15 @@ class RoutesMapper(object):
def get_route(self, name):
return self.routes.get(name)
- def connect(self, name, pattern, factory=None, predicates=(),
- pregenerator=None, static=False):
+ def connect(
+ self,
+ name,
+ pattern,
+ factory=None,
+ predicates=(),
+ pregenerator=None,
+ static=False,
+ ):
if name in self.routes:
oldroute = self.routes[name]
if oldroute in self.routelist:
@@ -86,18 +89,21 @@ class RoutesMapper(object):
except KeyError:
path = '/'
except UnicodeDecodeError as e:
- raise URLDecodeError(e.encoding, e.object, e.start, e.end, e.reason)
+ raise URLDecodeError(
+ e.encoding, e.object, e.start, e.end, e.reason
+ )
for route in self.routelist:
match = route.match(path)
if match is not None:
preds = route.predicates
- info = {'match':match, 'route':route}
+ info = {'match': match, 'route': route}
if preds and not all((p(info, request) for p in preds)):
continue
return info
- return {'route':None, 'match':None}
+ return {'route': None, 'match': None}
+
# stolen from bobo and modified
old_route_re = re.compile(r'(\:[_a-zA-Z]\w*)')
@@ -109,10 +115,12 @@ star_at_end = re.compile(r'\*(\w*)$')
# (\{[a-zA-Z][^\}]*\}) but that choked when supplied with e.g. {foo:\d{4}}.
route_re = re.compile(r'(\{[_a-zA-Z][^{}]*(?:\{[^{}]*\}[^{}]*)*\})')
+
def update_pattern(matchobj):
name = matchobj.group(0)
return '{%s}' % name[1:]
+
def _compile_route(route):
# This function really wants to consume Unicode patterns natively, but if
# someone passes us a bytestring, we allow it by converting it to Unicode
@@ -126,7 +134,8 @@ def _compile_route(route):
raise ValueError(
'The pattern value passed to add_route must be '
'either a Unicode string or a plain string without '
- 'any non-ASCII characters (you provided %r).' % route)
+ 'any non-ASCII characters (you provided %r).' % route
+ )
if old_route_re.search(route) and not route_re.search(route):
route = old_route_re.sub(update_pattern, route)
@@ -145,17 +154,19 @@ def _compile_route(route):
pat.reverse()
rpat = []
gen = []
- prefix = pat.pop() # invar: always at least one element (route='/'+route)
+ prefix = pat.pop() # invar: always at least one element (route='/'+route)
# We want to generate URL-encoded URLs, so we url-quote the prefix, being
# careful not to quote any embedded slashes. We have to replace '%' with
# '%%' afterwards, as the strings that go into "gen" are used as string
# replacement targets.
- gen.append(quote_path_segment(prefix, safe='/').replace('%', '%%')) # native
- rpat.append(re.escape(prefix)) # unicode
+ gen.append(
+ quote_path_segment(prefix, safe='/').replace('%', '%%')
+ ) # native
+ rpat.append(re.escape(prefix)) # unicode
while pat:
- name = pat.pop() # unicode
+ name = pat.pop() # unicode
name = name[1:-1]
if ':' in name:
# reg may contain colons as well,
@@ -163,12 +174,12 @@ def _compile_route(route):
name, reg = name.split(':', 1)
else:
reg = '[^/]+'
- gen.append('%%(%s)s' % native_(name)) # native
- name = '(?P<%s>%s)' % (name, reg) # unicode
+ gen.append('%%(%s)s' % native_(name)) # native
+ name = '(?P<%s>%s)' % (name, reg) # unicode
rpat.append(name)
- s = pat.pop() # unicode
+ s = pat.pop() # unicode
if s:
- rpat.append(re.escape(s)) # unicode
+ rpat.append(re.escape(s)) # unicode
# We want to generate URL-encoded URLs, so we url-quote this
# literal in the pattern, being careful not to quote the embedded
# slashes. We have to replace '%' with '%%' afterwards, as the
@@ -177,12 +188,13 @@ def _compile_route(route):
gen.append(quote_path_segment(s, safe='/').replace('%', '%%'))
if remainder:
- rpat.append('(?P<%s>.*?)' % remainder) # unicode
- gen.append('%%(%s)s' % native_(remainder)) # native
+ rpat.append('(?P<%s>.*?)' % remainder) # unicode
+ gen.append('%%(%s)s' % native_(remainder)) # native
- pattern = ''.join(rpat) + '$' # unicode
+ pattern = ''.join(rpat) + '$' # unicode
match = re.compile(pattern).match
+
def matcher(path):
# This function really wants to consume Unicode patterns natively,
# but if someone passes us a bytestring, we allow it by converting it
@@ -227,9 +239,7 @@ def _compile_route(route):
if k == remainder:
# a stararg argument
if is_nonstr_iter(v):
- v = '/'.join(
- [q(x) for x in v]
- ) # native
+ v = '/'.join([q(x) for x in v]) # native
else:
if v.__class__ not in string_types:
v = str(v)
@@ -243,7 +253,7 @@ def _compile_route(route):
# at this point, the value will be a native string
newdict[k] = v
- result = gen % newdict # native string result
+ result = gen % newdict # native string result
return result
return matcher, generator
diff --git a/src/pyramid/util.py b/src/pyramid/util.py
index 6655455bf..bebf9e7d3 100644
--- a/src/pyramid/util.py
+++ b/src/pyramid/util.py
@@ -1,5 +1,6 @@
from contextlib import contextmanager
import functools
+
try:
# py2.7.7+ and py3.3+ have native comparison support
from hmac import compare_digest
@@ -8,10 +9,7 @@ except ImportError: # pragma: no cover
import inspect
import weakref
-from pyramid.exceptions import (
- ConfigurationError,
- CyclicDependencyError,
- )
+from pyramid.exceptions import ConfigurationError, CyclicDependencyError
from pyramid.compat import (
getargspec,
@@ -22,8 +20,8 @@ from pyramid.compat import (
bytes_,
text_,
PY2,
- native_
- )
+ native_,
+)
from pyramid.path import DottedNameResolver as _DottedNameResolver
@@ -31,21 +29,26 @@ _marker = object()
class DottedNameResolver(_DottedNameResolver):
- def __init__(self, package=None): # default to package = None for bw compat
+ def __init__(
+ self, package=None
+ ): # default to package = None for bw compat
_DottedNameResolver.__init__(self, package)
+
def is_string_or_iterable(v):
if isinstance(v, string_types):
return True
if hasattr(v, '__iter__'):
return True
+
def as_sorted_tuple(val):
if not is_nonstr_iter(val):
val = (val,)
val = tuple(sorted(val))
return val
+
class InstancePropertyHelper(object):
"""A helper object for assigning properties and descriptors to instances.
It is not normally possible to do this because descriptors must be
@@ -56,6 +59,7 @@ class InstancePropertyHelper(object):
per-property and then invoking :meth:`.apply` on target objects.
"""
+
def __init__(self):
self.properties = {}
@@ -81,7 +85,8 @@ class InstancePropertyHelper(object):
name = callable.__name__
fn = callable
if reify:
- import pyramid.decorator # avoid circular import
+ import pyramid.decorator # avoid circular import
+
fn = pyramid.decorator.reify(fn)
elif not is_property:
fn = property(fn)
@@ -141,6 +146,7 @@ class InstancePropertyHelper(object):
if self.properties:
self.apply_properties(target, self.properties)
+
class InstancePropertyMixin(object):
""" Mixin that will allow an instance to add properties at
run-time as if they had been defined via @property or @reify
@@ -200,7 +206,9 @@ class InstancePropertyMixin(object):
1
"""
InstancePropertyHelper.set_property(
- self, callable, name=name, reify=reify)
+ self, callable, name=name, reify=reify
+ )
+
class WeakOrderedSet(object):
""" Maintain a set of items.
@@ -268,6 +276,7 @@ class WeakOrderedSet(object):
oid = self._order[-1]
return self._items[oid]()
+
def strings_differ(string1, string2, compare_digest=compare_digest):
"""Check whether two strings differ while avoiding timing attacks.
@@ -299,6 +308,7 @@ def strings_differ(string1, string2, compare_digest=compare_digest):
invalid_bits += a != b
return invalid_bits != 0
+
def object_description(object):
""" Produce a human-consumable text description of ``object``,
usually involving a Python dotted name. For example:
@@ -345,11 +355,12 @@ def object_description(object):
return text_('module %s' % modulename)
if inspect.ismethod(object):
oself = getattr(object, '__self__', None)
- if oself is None: # pragma: no cover
+ if oself is None: # pragma: no cover
oself = getattr(object, 'im_self', None)
- return text_('method %s of class %s.%s' %
- (object.__name__, modulename,
- oself.__class__.__name__))
+ return text_(
+ 'method %s of class %s.%s'
+ % (object.__name__, modulename, oself.__class__.__name__)
+ )
if inspect.isclass(object):
dottedname = '%s.%s' % (modulename, object.__name__)
@@ -359,12 +370,14 @@ def object_description(object):
return text_('function %s' % dottedname)
return text_('object %s' % str(object))
+
def shortrepr(object, closer):
r = str(object)
if len(r) > 100:
r = r[:100] + ' ... %s' % closer
return r
+
class Sentinel(object):
def __init__(self, repr):
self.repr = repr
@@ -372,19 +385,18 @@ class Sentinel(object):
def __repr__(self):
return self.repr
+
FIRST = Sentinel('FIRST')
LAST = Sentinel('LAST')
+
class TopologicalSorter(object):
""" A utility class which can be used to perform topological sorts against
tuple-like data."""
+
def __init__(
- self,
- default_before=LAST,
- default_after=None,
- first=FIRST,
- last=LAST,
- ):
+ self, default_before=LAST, default_after=None, first=FIRST, last=LAST
+ ):
self.names = []
self.req_before = set()
self.req_after = set()
@@ -414,7 +426,7 @@ class TopologicalSorter(object):
self.req_before.remove(name)
for u in before:
self.order.remove((name, u))
-
+
def add(self, name, val, after=None, before=None):
""" Add a node to the sort input. The ``name`` should be a string or
any other hashable object, the ``val`` should be the sortable (doesn't
@@ -454,7 +466,6 @@ class TopologicalSorter(object):
self.order += [(name, o) for o in before]
self.req_before.add(name)
-
def sorted(self):
""" Returns the sort input values in topologically sorted order"""
order = [(self.first, self.last)]
@@ -469,7 +480,7 @@ class TopologicalSorter(object):
def add_node(node):
if node not in graph:
roots.append(node)
- graph[node] = [0] # 0 = number of arcs coming into this node
+ graph[node] = [0] # 0 = number of arcs coming into this node
def add_arc(fromnode, tonode):
graph[fromnode].append(tonode)
@@ -482,7 +493,7 @@ class TopologicalSorter(object):
has_before, has_after = set(), set()
for a, b in order:
- if a in names and b in names: # deal with missing dependencies
+ if a in names and b in names: # deal with missing dependencies
add_arc(a, b)
has_before.add(a)
has_after.add(b)
@@ -507,7 +518,7 @@ class TopologicalSorter(object):
for child in children:
arcs = graph[child][0]
arcs -= 1
- graph[child][0] = arcs
+ graph[child][0] = arcs
if arcs == 0:
roots.insert(0, child)
del graph[root]
@@ -542,6 +553,7 @@ def get_callable_name(name):
)
raise ConfigurationError(msg % name)
+
@contextmanager
def hide_attrs(obj, *attrs):
"""
@@ -574,9 +586,11 @@ def is_same_domain(host, pattern):
return False
pattern = pattern.lower()
- return (pattern[0] == "." and
- (host.endswith(pattern) or host == pattern[1:]) or
- pattern == host)
+ return (
+ pattern[0] == "."
+ and (host.endswith(pattern) or host == pattern[1:])
+ or pattern == host
+ )
def make_contextmanager(fn):
@@ -590,6 +604,7 @@ def make_contextmanager(fn):
@functools.wraps(fn)
def wrapper(*a, **kw):
yield fn(*a, **kw)
+
return wrapper
diff --git a/src/pyramid/view.py b/src/pyramid/view.py
index 769328344..9f58e72ae 100644
--- a/src/pyramid/view.py
+++ b/src/pyramid/view.py
@@ -13,31 +13,26 @@ from pyramid.interfaces import (
IViewClassifier,
IRequest,
IExceptionViewClassifier,
- )
+)
from pyramid.compat import decode_path_info
from pyramid.compat import reraise as reraise_
-from pyramid.exceptions import (
- ConfigurationError,
- PredicateMismatch,
-)
+from pyramid.exceptions import ConfigurationError, PredicateMismatch
from pyramid.httpexceptions import (
HTTPNotFound,
HTTPTemporaryRedirect,
default_exceptionresponse_view,
- )
+)
-from pyramid.threadlocal import (
- get_current_registry,
- manager,
- )
+from pyramid.threadlocal import get_current_registry, manager
from pyramid.util import hide_attrs
_marker = object()
+
def render_view_to_response(context, request, name='', secure=True):
""" Call the :term:`view callable` configured with a :term:`view
configuration` that matches the :term:`view name` ``name``
@@ -84,9 +79,9 @@ def render_view_to_response(context, request, name='', secure=True):
name,
secure=secure,
request_iface=request_iface,
- )
+ )
- return response # NB: might be None
+ return response # NB: might be None
def render_view_to_iterable(context, request, name='', secure=True):
@@ -119,6 +114,7 @@ def render_view_to_iterable(context, request, name='', secure=True):
return None
return response.app_iter
+
def render_view(context, request, name='', secure=True):
""" Call the :term:`view callable` configured with a :term:`view
configuration` that matches the :term:`view name` ``name``
@@ -146,6 +142,7 @@ def render_view(context, request, name='', secure=True):
return None
return b''.join(iterable)
+
class view_config(object):
""" A function, class or method :term:`decorator` which allows a
developer to create view registrations nearer to a :term:`view
@@ -201,19 +198,21 @@ class view_config(object):
See the :py:func:`venusian.attach` function in Venusian for more
information about the ``_depth`` and ``_category`` arguments.
-
+
.. seealso::
-
+
See also :ref:`mapping_views_using_a_decorator_section` for
details about using :class:`pyramid.view.view_config`.
.. warning::
-
+
``view_config`` will work ONLY on module top level members
because of the limitation of ``venusian.Scanner.scan``.
"""
- venusian = venusian # for testing injection
+
+ venusian = venusian # for testing injection
+
def __init__(self, **settings):
if 'for_' in settings:
if settings.get('context') is None:
@@ -229,8 +228,9 @@ class view_config(object):
config = context.config.with_package(info.module)
config.add_view(view=ob, **settings)
- info = self.venusian.attach(wrapped, callback, category=category,
- depth=depth + 1)
+ info = self.venusian.attach(
+ wrapped, callback, category=category, depth=depth + 1
+ )
if info.scope == 'class':
# if the decorator was attached to a method in a class, or
@@ -239,10 +239,12 @@ class view_config(object):
if settings.get('attr') is None:
settings['attr'] = wrapped.__name__
- settings['_info'] = info.codeinfo # fbo "action_method"
+ settings['_info'] = info.codeinfo # fbo "action_method"
return wrapped
-bfg_view = view_config # bw compat (forever)
+
+bfg_view = view_config # bw compat (forever)
+
class view_defaults(view_config):
""" A class :term:`decorator` which, when applied to a class, will
@@ -257,6 +259,7 @@ class view_defaults(view_config):
wrapped.__view_defaults__ = self.__dict__.copy()
return wrapped
+
class AppendSlashNotFoundViewFactory(object):
""" There can only be one :term:`Not Found view` in any
:app:`Pyramid` application. Even if you use
@@ -292,7 +295,10 @@ class AppendSlashNotFoundViewFactory(object):
.. deprecated:: 1.3
"""
- def __init__(self, notfound_view=None, redirect_class=HTTPTemporaryRedirect):
+
+ def __init__(
+ self, notfound_view=None, redirect_class=HTTPTemporaryRedirect
+ ):
if notfound_view is None:
notfound_view = default_exceptionresponse_view
self.notfound_view = notfound_view
@@ -309,9 +315,12 @@ class AppendSlashNotFoundViewFactory(object):
qs = request.query_string
if qs:
qs = '?' + qs
- return self.redirect_class(location=request.path + '/' + qs)
+ return self.redirect_class(
+ location=request.path + '/' + qs
+ )
return self.notfound_view(context, request)
+
append_slash_notfound_view = AppendSlashNotFoundViewFactory()
append_slash_notfound_view.__doc__ = """\
For behavior like Django's ``APPEND_SLASH=True``, use this view as the
@@ -337,6 +346,7 @@ view as the Not Found view::
"""
+
class notfound_view_config(object):
"""
.. versionadded:: 1.3
@@ -392,7 +402,8 @@ class notfound_view_config(object):
return HTTPNotFound('not found')
The above means that a redirect to a slash-appended route will be
- attempted, but instead of :class:`~pyramid.httpexceptions.HTTPTemporaryRedirect`
+ attempted, but instead of
+ :class:`~pyramid.httpexceptions.HTTPTemporaryRedirect`
being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will
be used` for the redirect response if a slash-appended route is found.
@@ -417,8 +428,9 @@ class notfound_view_config(object):
config = context.config.with_package(info.module)
config.add_notfound_view(view=ob, **settings)
- info = self.venusian.attach(wrapped, callback, category=category,
- depth=depth + 1)
+ info = self.venusian.attach(
+ wrapped, callback, category=category, depth=depth + 1
+ )
if info.scope == 'class':
# if the decorator was attached to a method in a class, or
@@ -427,9 +439,10 @@ class notfound_view_config(object):
if settings.get('attr') is None:
settings['attr'] = wrapped.__name__
- settings['_info'] = info.codeinfo # fbo "action_method"
+ settings['_info'] = info.codeinfo # fbo "action_method"
return wrapped
+
class forbidden_view_config(object):
"""
.. versionadded:: 1.3
@@ -479,8 +492,9 @@ class forbidden_view_config(object):
config = context.config.with_package(info.module)
config.add_forbidden_view(view=ob, **settings)
- info = self.venusian.attach(wrapped, callback, category=category,
- depth=depth + 1)
+ info = self.venusian.attach(
+ wrapped, callback, category=category, depth=depth + 1
+ )
if info.scope == 'class':
# if the decorator was attached to a method in a class, or
@@ -489,9 +503,10 @@ class forbidden_view_config(object):
if settings.get('attr') is None:
settings['attr'] = wrapped.__name__
- settings['_info'] = info.codeinfo # fbo "action_method"
+ settings['_info'] = info.codeinfo # fbo "action_method"
return wrapped
+
class exception_view_config(object):
"""
.. versionadded:: 1.8
@@ -526,6 +541,7 @@ class exception_view_config(object):
Added the ``_depth`` and ``_category`` arguments.
"""
+
venusian = venusian
def __init__(self, *args, **settings):
@@ -545,8 +561,9 @@ class exception_view_config(object):
config = context.config.with_package(info.module)
config.add_exception_view(view=ob, **settings)
- info = self.venusian.attach(wrapped, callback, category=category,
- depth=depth + 1)
+ info = self.venusian.attach(
+ wrapped, callback, category=category, depth=depth + 1
+ )
if info.scope == 'class':
# if the decorator was attached to a method in a class, or
@@ -555,9 +572,10 @@ class exception_view_config(object):
if settings.get('attr') is None:
settings['attr'] = wrapped.__name__
- settings['_info'] = info.codeinfo # fbo "action_method"
+ settings['_info'] = info.codeinfo # fbo "action_method"
return wrapped
+
def _find_views(
registry,
request_iface,
@@ -565,7 +583,7 @@ def _find_views(
view_name,
view_types=None,
view_classifier=None,
- ):
+):
if view_types is None:
view_types = (IView, ISecuredView, IMultiView)
if view_classifier is None:
@@ -581,9 +599,7 @@ def _find_views(
source_ifaces = (view_classifier, req_type, ctx_type)
for view_type in view_types:
view_callable = registered(
- source_ifaces,
- view_type,
- name=view_name,
+ source_ifaces, view_type, name=view_name
)
if view_callable is not None:
views.append(view_callable)
@@ -599,6 +615,7 @@ def _find_views(
return views
+
def _call_view(
registry,
request,
@@ -609,7 +626,7 @@ def _call_view(
view_classifier=None,
secure=True,
request_iface=None,
- ):
+):
if request_iface is None:
request_iface = getattr(request, 'request_iface', IRequest)
view_callables = _find_views(
@@ -619,7 +636,7 @@ def _call_view(
view_name,
view_types=view_types,
view_classifier=view_classifier,
- )
+ )
pme = None
response = None
@@ -631,10 +648,8 @@ def _call_view(
# the view will have a __call_permissive__ attribute if it's
# secured; otherwise it won't.
view_callable = getattr(
- view_callable,
- '__call_permissive__',
- view_callable
- )
+ view_callable, '__call_permissive__', view_callable
+ )
# if this view is secured, it will raise a Forbidden
# appropriately if the executing user does not have the proper
@@ -649,15 +664,13 @@ def _call_view(
return response
+
class ViewMethodsMixin(object):
""" Request methods mixin for BaseRequest having to do with executing
views """
+
def invoke_exception_view(
- self,
- exc_info=None,
- request=None,
- secure=True,
- reraise=False,
+ self, exc_info=None, request=None, secure=True, reraise=False
):
""" Executes an exception view related to the request it's called upon.
The arguments it takes are these:
@@ -742,7 +755,7 @@ class ViewMethodsMixin(object):
view_classifier=IExceptionViewClassifier,
secure=secure,
request_iface=request_iface.combined,
- )
+ )
except Exception:
if reraise:
reraise_(*exc_info)
diff --git a/src/pyramid/viewderivers.py b/src/pyramid/viewderivers.py
index d914a4752..fbe0c252c 100644
--- a/src/pyramid/viewderivers.py
+++ b/src/pyramid/viewderivers.py
@@ -1,15 +1,9 @@
import inspect
-from zope.interface import (
- implementer,
- provider,
- )
+from zope.interface import implementer, provider
from pyramid.security import NO_PERMISSION_REQUIRED
-from pyramid.csrf import (
- check_csrf_origin,
- check_csrf_token,
-)
+from pyramid.csrf import check_csrf_origin, check_csrf_token
from pyramid.response import Response
from pyramid.interfaces import (
@@ -21,21 +15,13 @@ from pyramid.interfaces import (
IResponse,
IViewMapper,
IViewMapperFactory,
- )
+)
-from pyramid.compat import (
- is_bound_method,
- is_unbound_method,
- )
+from pyramid.compat import is_bound_method, is_unbound_method
-from pyramid.exceptions import (
- ConfigurationError,
- )
+from pyramid.exceptions import ConfigurationError
from pyramid.httpexceptions import HTTPForbidden
-from pyramid.util import (
- object_description,
- takes_one_arg,
-)
+from pyramid.util import object_description, takes_one_arg
from pyramid.view import render_view_to_response
from pyramid import renderers
@@ -47,9 +33,11 @@ def view_description(view):
# custom view mappers might not add __text__
return object_description(view)
+
def requestonly(view, attr=None):
return takes_one_arg(view, attr=attr, argname='request')
+
@implementer(IViewMapper)
@provider(IViewMapperFactory)
class DefaultViewMapper(object):
@@ -58,10 +46,12 @@ class DefaultViewMapper(object):
def __call__(self, view):
if is_unbound_method(view) and self.attr is None:
- raise ConfigurationError((
- 'Unbound method calls are not supported, please set the class '
- 'as your `view` and the method as your `attr`'
- ))
+ raise ConfigurationError(
+ (
+ 'Unbound method calls are not supported, please set the '
+ 'class as your `view` and the method as your `attr`'
+ )
+ )
if inspect.isclass(view):
view = self.map_class(view)
@@ -76,7 +66,9 @@ class DefaultViewMapper(object):
else:
mapped_view = self.map_class_native(view)
mapped_view.__text__ = 'method %s of %s' % (
- self.attr or '__call__', object_description(view))
+ self.attr or '__call__',
+ object_description(view),
+ )
return mapped_view
def map_nonclass(self, view):
@@ -98,11 +90,15 @@ class DefaultViewMapper(object):
# bound method.
if is_bound_method(view):
_mapped_view = mapped_view
+
def mapped_view(context, request):
return _mapped_view(context, request)
+
if self.attr is not None:
mapped_view.__text__ = 'attr %s of %s' % (
- self.attr, object_description(view))
+ self.attr,
+ object_description(view),
+ )
else:
mapped_view.__text__ = object_description(view)
return mapped_view
@@ -110,6 +106,7 @@ class DefaultViewMapper(object):
def map_class_requestonly(self, view):
# its a class that has an __init__ which only accepts request
attr = self.attr
+
def _class_requestonly_view(context, request):
inst = view(request)
request.__view__ = inst
@@ -118,12 +115,14 @@ class DefaultViewMapper(object):
else:
response = getattr(inst, attr)()
return response
+
return _class_requestonly_view
def map_class_native(self, view):
# its a class that has an __init__ which accepts both context and
# request
attr = self.attr
+
def _class_view(context, request):
inst = view(context, request)
request.__view__ = inst
@@ -132,18 +131,21 @@ class DefaultViewMapper(object):
else:
response = getattr(inst, attr)()
return response
+
return _class_view
def map_nonclass_requestonly(self, view):
# its a function that has a __call__ which accepts only a single
# request argument
attr = self.attr
+
def _requestonly_view(context, request):
if attr is None:
response = view(request)
else:
response = getattr(view, attr)(request)
return response
+
return _requestonly_view
def map_nonclass_attr(self, view):
@@ -152,6 +154,7 @@ class DefaultViewMapper(object):
def _attr_view(context, request):
response = getattr(view, self.attr)(context, request)
return response
+
return _attr_view
@@ -159,8 +162,10 @@ def wraps_view(wrapper):
def inner(view, info):
wrapper_view = wrapper(view, info)
return preserve_view_attrs(view, wrapper_view)
+
return inner
+
def preserve_view_attrs(view, wrapper):
if view is None:
return wrapper
@@ -185,9 +190,16 @@ def preserve_view_attrs(view, wrapper):
# attrs that may not exist on "view", but, if so, must be attached to
# "wrapped view"
- for attr in ('__permitted__', '__call_permissive__', '__permission__',
- '__predicated__', '__predicates__', '__accept__',
- '__order__', '__text__'):
+ for attr in (
+ '__permitted__',
+ '__call_permissive__',
+ '__permission__',
+ '__predicated__',
+ '__predicates__',
+ '__accept__',
+ '__order__',
+ '__text__',
+ ):
try:
setattr(wrapper, attr, getattr(view, attr))
except AttributeError:
@@ -195,6 +207,7 @@ def preserve_view_attrs(view, wrapper):
return wrapper
+
def mapped_view(view, info):
mapper = info.options.get('mapper')
if mapper is None:
@@ -207,29 +220,37 @@ def mapped_view(view, info):
mapped_view = mapper(**info.options)(view)
return mapped_view
+
mapped_view.options = ('mapper', 'attr')
+
def owrapped_view(view, info):
wrapper_viewname = info.options.get('wrapper')
viewname = info.options.get('name')
if not wrapper_viewname:
return view
+
def _owrapped_view(context, request):
response = view(context, request)
request.wrapped_response = response
request.wrapped_body = response.body
request.wrapped_view = view
- wrapped_response = render_view_to_response(context, request,
- wrapper_viewname)
+ wrapped_response = render_view_to_response(
+ context, request, wrapper_viewname
+ )
if wrapped_response is None:
raise ValueError(
'No wrapper view named %r found when executing view '
- 'named %r' % (wrapper_viewname, viewname))
+ 'named %r' % (wrapper_viewname, viewname)
+ )
return wrapped_response
+
return _owrapped_view
+
owrapped_view.options = ('name', 'wrapper')
+
def http_cached_view(view, info):
if info.settings.get('prevent_http_cache', False):
return view
@@ -247,27 +268,33 @@ def http_cached_view(view, info):
except ValueError:
raise ConfigurationError(
'If http_cache parameter is a tuple or list, it must be '
- 'in the form (seconds, options); not %s' % (seconds,))
+ 'in the form (seconds, options); not %s' % (seconds,)
+ )
def wrapper(context, request):
response = view(context, request)
- prevent_caching = getattr(response.cache_control, 'prevent_auto',
- False)
+ prevent_caching = getattr(
+ response.cache_control, 'prevent_auto', False
+ )
if not prevent_caching:
response.cache_expires(seconds, **options)
return response
return wrapper
+
http_cached_view.options = ('http_cache',)
+
def secured_view(view, info):
for wrapper in (_secured_view, _authdebug_view):
view = wraps_view(wrapper)(view, info)
return view
+
secured_view.options = ('permission',)
+
def _secured_view(view, info):
permission = explicit_val = info.options.get('permission')
if permission is None:
@@ -287,18 +314,23 @@ def _secured_view(view, info):
return view
if authn_policy and authz_policy and (permission is not None):
+
def permitted(context, request):
principals = authn_policy.effective_principals(request)
return authz_policy.permits(context, principals, permission)
+
def secured_view(context, request):
result = permitted(context, request)
if result:
return view(context, request)
view_name = getattr(view, '__name__', view)
msg = getattr(
- request, 'authdebug_message',
- 'Unauthorized: %s failed permission check' % view_name)
+ request,
+ 'authdebug_message',
+ 'Unauthorized: %s failed permission check' % view_name,
+ )
raise HTTPForbidden(msg, result=result)
+
wrapped_view = secured_view
wrapped_view.__call_permissive__ = view
wrapped_view.__permitted__ = permitted
@@ -306,6 +338,7 @@ def _secured_view(view, info):
return wrapped_view
+
def _authdebug_view(view, info):
wrapped_view = view
settings = info.settings
@@ -321,6 +354,7 @@ def _authdebug_view(view, info):
return view
if settings and settings.get('debug_authorization', False):
+
def authdebug_view(context, request):
view_name = getattr(request, 'view_name', None)
@@ -331,24 +365,29 @@ def _authdebug_view(view, info):
msg = 'Allowed (no permission registered)'
else:
principals = authn_policy.effective_principals(request)
- msg = str(authz_policy.permits(
- context, principals, permission))
+ msg = str(
+ authz_policy.permits(context, principals, permission)
+ )
else:
msg = 'Allowed (no authorization policy in use)'
view_name = getattr(request, 'view_name', None)
url = getattr(request, 'url', None)
- msg = ('debug_authorization of url %s (view name %r against '
- 'context %r): %s' % (url, view_name, context, msg))
+ msg = (
+ 'debug_authorization of url %s (view name %r against '
+ 'context %r): %s' % (url, view_name, context, msg)
+ )
if logger:
logger.debug(msg)
if request is not None:
request.authdebug_message = msg
return view(context, request)
+
wrapped_view = authdebug_view
return wrapped_view
+
def rendered_view(view, info):
# one way or another this wrapper must produce a Response (unless
# the renderer is a NullRendererHelper)
@@ -360,23 +399,29 @@ def rendered_view(view, info):
# a view registration.
def viewresult_to_response(context, request):
result = view(context, request)
- if result.__class__ is Response: # common case
+ if result.__class__ is Response: # common case
response = result
else:
response = info.registry.queryAdapterOrSelf(result, IResponse)
if response is None:
if result is None:
- append = (' You may have forgotten to return a value '
- 'from the view callable.')
+ append = (
+ ' You may have forgotten to return a value '
+ 'from the view callable.'
+ )
elif isinstance(result, dict):
- append = (' You may have forgotten to define a '
- 'renderer in the view configuration.')
+ append = (
+ ' You may have forgotten to define a '
+ 'renderer in the view configuration.'
+ )
else:
append = ''
- msg = ('Could not convert return value of the view '
- 'callable %s into a response object. '
- 'The value returned was %r.' + append)
+ msg = (
+ 'Could not convert return value of the view '
+ 'callable %s into a response object. '
+ 'The value returned was %r.' + append
+ )
raise ValueError(msg % (view_description(view), result))
@@ -389,7 +434,7 @@ def rendered_view(view, info):
def rendered_view(context, request):
result = view(context, request)
- if result.__class__ is Response: # potential common case
+ if result.__class__ is Response: # potential common case
response = result
else:
# this must adapt, it can't do a simple interface check
@@ -403,7 +448,8 @@ def rendered_view(view, info):
view_renderer = renderers.RendererHelper(
name=renderer_name,
package=info.package,
- registry=info.registry)
+ registry=info.registry,
+ )
else:
view_renderer = renderer.clone()
if '__view__' in attrs:
@@ -411,21 +457,26 @@ def rendered_view(view, info):
else:
view_inst = getattr(view, '__original_view__', view)
response = view_renderer.render_view(
- request, result, view_inst, context)
+ request, result, view_inst, context
+ )
return response
return rendered_view
+
rendered_view.options = ('renderer',)
+
def decorated_view(view, info):
decorator = info.options.get('decorator')
if decorator is None:
return view
return decorator(view)
+
decorated_view.options = ('decorator',)
+
def csrf_view(view, info):
explicit_val = info.options.get('require_csrf')
defaults = info.registry.queryUtility(IDefaultCSRFOptions)
@@ -443,29 +494,29 @@ def csrf_view(view, info):
callback = defaults.callback
enabled = (
- explicit_val is True or
+ explicit_val is True
+ or
# fallback to the default val if not explicitly enabled
# but only if the view is not an exception view
- (
- explicit_val is not False and default_val and
- not info.exception_only
- )
+ (explicit_val is not False and default_val and not info.exception_only)
)
# disable if both header and token are disabled
enabled = enabled and (token or header)
wrapped_view = view
if enabled:
+
def csrf_view(context, request):
- if (
- request.method not in safe_methods and
- (callback is None or callback(request))
+ if request.method not in safe_methods and (
+ callback is None or callback(request)
):
check_csrf_origin(request, raises=True)
check_csrf_token(request, token, header, raises=True)
return view(context, request)
+
wrapped_view = csrf_view
return wrapped_view
+
csrf_view.options = ('require_csrf',)
VIEW = 'VIEW'
diff --git a/src/pyramid/wsgi.py b/src/pyramid/wsgi.py
index 1c1bded32..b3f3803e4 100644
--- a/src/pyramid/wsgi.py
+++ b/src/pyramid/wsgi.py
@@ -1,6 +1,7 @@
from functools import wraps
from pyramid.request import call_app_with_subpath_as_path_info
+
def wsgiapp(wrapped):
""" Decorator to turn a WSGI application into a :app:`Pyramid`
:term:`view callable`. This decorator differs from the
@@ -41,6 +42,7 @@ def wsgiapp(wrapped):
return wraps(wrapped)(decorator)
return wraps(wrapped, ('__module__', '__doc__'))(decorator)
+
def wsgiapp2(wrapped):
""" Decorator to turn a WSGI application into a :app:`Pyramid`
view callable. This decorator differs from the