summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pyramid/asset.py19
-rw-r--r--src/pyramid/authentication.py346
-rw-r--r--src/pyramid/authorization.py42
-rw-r--r--src/pyramid/compat.py63
-rw-r--r--src/pyramid/config/__init__.py305
-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.py144
-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.py45
-rw-r--r--src/pyramid/config/util.py35
-rw-r--r--src/pyramid/config/views.py563
-rw-r--r--src/pyramid/config/zca.py4
-rw-r--r--src/pyramid/csrf.py64
-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.py312
-rw-r--r--src/pyramid/i18n.py65
-rw-r--r--src/pyramid/interfaces.py369
-rw-r--r--src/pyramid/location.py3
-rw-r--r--src/pyramid/paster.py5
-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.py3
-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.py98
-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.py141
-rw-r--r--src/pyramid/tweens.py3
-rw-r--r--src/pyramid/url.py53
-rw-r--r--src/pyramid/urldispatch.py78
-rw-r--r--src/pyramid/util.py69
-rw-r--r--src/pyramid/view.py100
-rw-r--r--src/pyramid/viewderivers.py171
-rw-r--r--src/pyramid/wsgi.py2
65 files changed, 3328 insertions, 2125 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..f4c2b51ef 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
@@ -586,24 +602,25 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy):
"""
- 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
@@ -987,7 +1045,8 @@ class AuthTktCookieHelper(object):
"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
+ "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
@@ -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..4df279e94 100644
--- a/src/pyramid/compat.py
+++ b/src/pyramid/compat.py
@@ -7,6 +7,7 @@ WIN = platform.system() == 'Windows'
try: # pragma: no cover
import __pypy__
+
PYPY = True
except: # pragma: no cover
__pypy__ = None
@@ -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..ab5edfefe 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,7 +388,9 @@ 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:
#
@@ -424,7 +410,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 +454,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 +466,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 +533,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 +542,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 +585,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 +629,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 +667,8 @@ class Configurator(
info=action_info,
includepath=self.includepath,
introspectables=introspectables,
- )
)
+ )
self.action_state.action(**action)
def _get_action_state(self):
@@ -663,7 +685,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 +709,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 +822,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 +843,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 +909,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 +937,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 +963,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 +984,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 +1045,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 +1053,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 +1104,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 +1131,8 @@ class ActionState(object):
info=info,
order=order,
introspectables=introspectables,
- )
)
+ )
self.actions.append(action)
def execute_actions(self, clear=True, introspector=None):
@@ -1179,8 +1214,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 +1237,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 +1326,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 +1387,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 +1401,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 +1432,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 +1452,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..46b8921cd 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`
@@ -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..a90008784 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):
"""
@@ -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..627b78b6f 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
@@ -133,11 +131,8 @@ class PredicateList(object):
## 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..277b207fd 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*
@@ -804,42 +807,48 @@ 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 +865,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 +888,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 +899,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 +940,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 +1031,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 +1104,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 +1128,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 +1155,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 +1190,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 +1209,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 +1221,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 +1246,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 +1265,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 +1281,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 +1310,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 +1348,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 +1412,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 +1438,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 +1455,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 +1475,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 +1567,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 +1614,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 +1657,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 +1691,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 +1729,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 +1758,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
@@ -1794,13 +1832,18 @@ class ViewsConfiguratorMixin(object):
"""
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 +1868,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 +1884,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 +1894,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 +1910,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 +1959,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 +2112,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 +2153,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 +2164,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 +2181,7 @@ class ViewDeriverInfo(object):
def settings(self):
return self.registry.settings
+
@implementer(IStaticURLInfo)
class StaticURLInfo(object):
def __init__(self):
@@ -2134,12 +2191,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 +2205,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 +2222,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 +2250,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 +2269,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 +2295,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 +2306,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 +2343,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 +2378,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..582d6a641 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
@@ -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..359601399 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,6 +155,7 @@ def _no_escape(value):
value = text_type(value)
return value
+
@implementer(IExceptionResponse)
class HTTPException(Response, Exception):
@@ -195,18 +192,23 @@ class HTTPException(Response, Exception):
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
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
############################################################
+
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)
############################################################
## 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
############################################################
+
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
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
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
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,10 +1162,11 @@ 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
@@ -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..9f5f898be 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
@@ -112,8 +114,9 @@ class Localizer(object):
"""
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):
@@ -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,6 +173,7 @@ 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
@@ -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
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..26a9d7025 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
@@ -1209,19 +1351,22 @@ 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')
+
+ 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 +1405,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 +1435,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 +1471,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 +1506,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..b8542d1b9 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
@@ -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..eda479476 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
@@ -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..1454114fd 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
+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
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..95c51a2d8 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})
+ """
+ % {'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..9e256f73c 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,22 +30,26 @@ 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`
@@ -56,15 +61,16 @@ def has_permission(permission, context, request):
.. 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):
@@ -74,15 +80,17 @@ def authenticated_userid(request):
.. 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):
"""
@@ -91,15 +99,17 @@ def unauthenticated_userid(request):
.. 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):
"""
@@ -108,15 +118,17 @@ def effective_principals(request):
.. 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..322f57ed6 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
@@ -365,8 +374,10 @@ def resource_path_tuple(resource, *elements):
"""
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"""
path = [loc.__name__ or '' for loc in lineage(resource)]
@@ -374,7 +385,9 @@ def _resource_path_list(resource, *elements):
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 +425,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 +433,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 +449,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):
@@ -510,10 +525,11 @@ def traversal_path_info(path):
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 +547,7 @@ def split_path_info(path):
clean.append(segment)
return tuple(clean)
+
_segment_cache = {}
quote_path_segment_doc = """ \
@@ -574,7 +591,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 +601,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 +623,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 +634,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 +670,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 +690,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 +703,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 +784,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..c6cf3da7f 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)
@@ -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)
@@ -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..c45b976bb 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
@@ -213,7 +210,9 @@ class view_config(object):
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
@@ -417,8 +427,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 +438,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 +491,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 +502,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 +540,7 @@ class exception_view_config(object):
Added the ``_depth`` and ``_category`` arguments.
"""
+
venusian = venusian
def __init__(self, *args, **settings):
@@ -545,8 +560,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 +571,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 +582,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 +598,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 +614,7 @@ def _find_views(
return views
+
def _call_view(
registry,
request,
@@ -609,7 +625,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 +635,7 @@ def _call_view(
view_name,
view_types=view_types,
view_classifier=view_classifier,
- )
+ )
pme = None
response = None
@@ -631,10 +647,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 +663,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 +754,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..0b4758554 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