Merge pull request #3388 from mmerickel/black
format source using black
2 files added
181 files modified
New file |
| | |
| | | [flake8] |
| | | ignore = |
| | | # E203: whitespace before ':' (black fails to be PEP8 compliant) |
| | | E203 |
| | | # E731: do not assign a lambda expression, use a def |
| | | E731 |
| | | # W503: line break before binary operator (flake8 is not PEP8 compliant) |
| | | W503 |
| | | exclude = |
| | | src/pyramid/compat.py |
| | | src/pyramid/scaffolds/alchemy |
| | | src/pyramid/scaffolds/starter |
| | | src/pyramid/scaffolds/zodb |
| | | tests/fixtures |
| | | tests/pkgs |
| | | tests/test_config/pkgs |
| | | tests/test_config/path |
| | | show-source = True |
| | |
| | | env: TOXENV=pypy |
| | | - python: pypy3 |
| | | env: TOXENV=pypy3 |
| | | - python: 3.5 |
| | | - python: 3.6 |
| | | env: TOXENV=py2-cover,py3-cover,coverage |
| | | - python: 3.5 |
| | | env: TOXENV=docs |
| | | - python: 3.5 |
| | | - python: 3.6 |
| | | env: TOXENV=lint |
| | | - python: 3.7 |
| | | env: TOXENV=py37 |
| | |
| | | include CONTRIBUTORS.txt LICENSE.txt COPYRIGHT.txt |
| | | |
| | | include contributing.md RELEASING.txt |
| | | include .coveragerc tox.ini appveyor.yml .travis.yml rtd.txt |
| | | include .coveragerc .flake8 setup.cfg pyproject.toml |
| | | include tox.ini appveyor.yml .travis.yml rtd.txt |
| | | graft .github |
| | | |
| | | include HACKING.txt hacking-tox.ini |
New file |
| | |
| | | [build-system] |
| | | requires = ["setuptools", "wheel"] |
| | | |
| | | [tool.black] |
| | | line-length = 79 |
| | | skip-string-normalization = true |
| | | py36 = false |
| | | exclude = ''' |
| | | /( |
| | | \.git |
| | | | \.mypy_cache |
| | | | \.tox |
| | | | \.venv |
| | | | \.pytest_cache |
| | | | dist |
| | | | build |
| | | | docs |
| | | | src/pyramid/scaffolds/alchemy |
| | | | src/pyramid/scaffolds/starter |
| | | | src/pyramid/scaffolds/zodb |
| | | )/ |
| | | ''' |
| | | |
| | | # This next section only exists for people that have their editors |
| | | # automatically call isort, black already sorts entries on its own when run. |
| | | [tool.isort] |
| | | multi_line_output = 3 |
| | | include_trailing_comma = true |
| | | force_grid_wrap = 0 |
| | | combine_as_imports = true |
| | | line_length = 79 |
| | |
| | | [metadata] |
| | | license_file = LICENSE.txt |
| | | |
| | | [flake8] |
| | | ignore = |
| | | # E121: continuation line under-indented for hanging indent |
| | | E121, |
| | | # E123: closing bracket does not match indentation of opening bracket's line |
| | | E123, |
| | | # E125: continuation line with same indent as next logical line |
| | | E125, |
| | | # E127: continuation line over-indented for visual indent |
| | | E127, |
| | | # E128: continuation line under-indented for visual indent |
| | | E128, |
| | | # E129: visually indented line with same indent as next logical line |
| | | E129, |
| | | # E201: whitespace after '(' |
| | | E201, |
| | | # E202: whitespace before ')' |
| | | E202, |
| | | # E231: missing whitespace after ',', ';', or ':' |
| | | E231, |
| | | # E261: at least two spaces before inline comment |
| | | E261, |
| | | # E262: inline comment should start with '# ' |
| | | E262, |
| | | # E265: block comment should start with '# ' |
| | | E265, |
| | | # E266: too many leading '#' for block comment |
| | | E266, |
| | | # E301: expected 1 blank line, found 0 |
| | | E301, |
| | | # E302: expected 2 blank lines, found 0 |
| | | E302, |
| | | # E303: too many blank lines (3) |
| | | E303, |
| | | # E305: expected 2 blank lines after class or function definition, found 1 |
| | | E305, |
| | | # E306: expected 1 blank line before a nested definition, found 0 |
| | | E306, |
| | | # E501: line too long (82 > 79 characters) |
| | | E501, |
| | | # E731: do not assign a lambda expression, use a def |
| | | E731, |
| | | # W291: trailing whitespace |
| | | W291, |
| | | # W293: blank line contains whitespace |
| | | W293, |
| | | # W391: blank line at end of file |
| | | W391, |
| | | # W503: line break before binary operator |
| | | W503 |
| | | exclude = pyramid/tests/,pyramid/compat.py,pyramid/resource.py |
| | | show-source = True |
| | | |
| | | [check-manifest] |
| | | ignore = |
| | | .gitignore |
| | |
| | | 'virtualenv', # for scaffolding tests |
| | | ] |
| | | |
| | | setup(name='pyramid', |
| | | version='1.10.dev0', |
| | | description='The Pyramid Web Framework, a Pylons project', |
| | | long_description=README + '\n\n' + CHANGES, |
| | | classifiers=[ |
| | | "Development Status :: 6 - Mature", |
| | | "Intended Audience :: Developers", |
| | | "Programming Language :: Python", |
| | | "Programming Language :: Python :: 2.7", |
| | | "Programming Language :: Python :: 3", |
| | | "Programming Language :: Python :: 3.4", |
| | | "Programming Language :: Python :: 3.5", |
| | | "Programming Language :: Python :: 3.6", |
| | | "Programming Language :: Python :: 3.7", |
| | | "Programming Language :: Python :: Implementation :: CPython", |
| | | "Programming Language :: Python :: Implementation :: PyPy", |
| | | "Framework :: Pyramid", |
| | | "Topic :: Internet :: WWW/HTTP", |
| | | "Topic :: Internet :: WWW/HTTP :: WSGI", |
| | | "License :: Repoze Public License", |
| | | ], |
| | | keywords='web wsgi pylons pyramid', |
| | | author="Chris McDonough, Agendaless Consulting", |
| | | author_email="pylons-discuss@googlegroups.com", |
| | | url="https://trypyramid.com", |
| | | license="BSD-derived (http://www.repoze.org/LICENSE.txt)", |
| | | packages=find_packages('src', exclude=['tests']), |
| | | package_dir={'': 'src'}, |
| | | include_package_data=True, |
| | | zip_safe=False, |
| | | python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*', |
| | | install_requires=install_requires, |
| | | extras_require={ |
| | | ':python_version<"3.2"': ['repoze.lru >= 0.4'], |
| | | 'testing': testing_extras, |
| | | 'docs': docs_extras, |
| | | }, |
| | | tests_require=tests_require, |
| | | test_suite="tests", |
| | | entry_points="""\ |
| | | setup( |
| | | name='pyramid', |
| | | version='1.10.dev0', |
| | | description='The Pyramid Web Framework, a Pylons project', |
| | | long_description=README + '\n\n' + CHANGES, |
| | | classifiers=[ |
| | | "Development Status :: 6 - Mature", |
| | | "Intended Audience :: Developers", |
| | | "Programming Language :: Python", |
| | | "Programming Language :: Python :: 2.7", |
| | | "Programming Language :: Python :: 3", |
| | | "Programming Language :: Python :: 3.4", |
| | | "Programming Language :: Python :: 3.5", |
| | | "Programming Language :: Python :: 3.6", |
| | | "Programming Language :: Python :: 3.7", |
| | | "Programming Language :: Python :: Implementation :: CPython", |
| | | "Programming Language :: Python :: Implementation :: PyPy", |
| | | "Framework :: Pyramid", |
| | | "Topic :: Internet :: WWW/HTTP", |
| | | "Topic :: Internet :: WWW/HTTP :: WSGI", |
| | | "License :: Repoze Public License", |
| | | ], |
| | | keywords='web wsgi pylons pyramid', |
| | | author="Chris McDonough, Agendaless Consulting", |
| | | author_email="pylons-discuss@googlegroups.com", |
| | | url="https://trypyramid.com", |
| | | license="BSD-derived (http://www.repoze.org/LICENSE.txt)", |
| | | packages=find_packages('src', exclude=['tests']), |
| | | package_dir={'': 'src'}, |
| | | include_package_data=True, |
| | | zip_safe=False, |
| | | python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*', |
| | | install_requires=install_requires, |
| | | extras_require={ |
| | | ':python_version<"3.2"': ['repoze.lru >= 0.4'], |
| | | 'testing': testing_extras, |
| | | 'docs': docs_extras, |
| | | }, |
| | | tests_require=tests_require, |
| | | test_suite="tests", |
| | | entry_points="""\ |
| | | [pyramid.scaffold] |
| | | starter=pyramid.scaffolds:StarterProjectTemplate |
| | | zodb=pyramid.scaffolds:ZODBProjectTemplate |
| | |
| | | [paste.server_runner] |
| | | wsgiref = pyramid.scripts.pserve:wsgiref_server_runner |
| | | cherrypy = pyramid.scripts.pserve:cherrypy_server_runner |
| | | """ |
| | | ) |
| | | """, |
| | | ) |
| | |
| | | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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: |
| | | return filename |
| | | return pkg_resources.resource_filename(pname, filename) |
| | | |
| | |
| | | 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 |
| | |
| | | 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. |
| | |
| | | |
| | | 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) |
| | |
| | | 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 |
| | | |
| | |
| | | self.debug and self._log( |
| | | 'repoze.who identity is None, returning None', |
| | | 'authenticated_userid', |
| | | request) |
| | | request, |
| | | ) |
| | | return None |
| | | |
| | | userid = identity['repoze.who.userid'] |
| | |
| | | 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): |
| | |
| | | |
| | | 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: |
| | |
| | | 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) |
| | |
| | | return [] |
| | | identity = self._get_identity(request) |
| | | return identifier.forget(request.environ, identity) |
| | | |
| | | |
| | | @implementer(IAuthenticationPolicy) |
| | | class RemoteUserAuthenticationPolicy(CallbackAuthenticationPolicy): |
| | |
| | | forgetting the user. This will be application-specific and can |
| | | be done somewhere else or in a subclass.""" |
| | | return [] |
| | | |
| | | |
| | | @implementer(IAuthenticationPolicy) |
| | | class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy): |
| | |
| | | .. versionchanged:: 1.10 |
| | | |
| | | Added the ``samesite`` option and made the default ``'Lax'``. |
| | | |
| | | |
| | | Objects of this class implement the interface described by |
| | | :class:`pyramid.interfaces.IAuthenticationPolicy`. |
| | | |
| | | """ |
| | | |
| | | def __init__(self, |
| | | secret, |
| | | callback=None, |
| | | cookie_name='auth_tkt', |
| | | secure=False, |
| | | include_ip=False, |
| | | timeout=None, |
| | | reissue_time=None, |
| | | max_age=None, |
| | | path="/", |
| | | http_only=False, |
| | | wild_domain=True, |
| | | debug=False, |
| | | hashalg='sha512', |
| | | parent_domain=False, |
| | | domain=None, |
| | | samesite='Lax', |
| | | ): |
| | | def __init__( |
| | | self, |
| | | secret, |
| | | callback=None, |
| | | cookie_name='auth_tkt', |
| | | secure=False, |
| | | include_ip=False, |
| | | timeout=None, |
| | | reissue_time=None, |
| | | max_age=None, |
| | | path="/", |
| | | http_only=False, |
| | | wild_domain=True, |
| | | debug=False, |
| | | hashalg='sha512', |
| | | parent_domain=False, |
| | | domain=None, |
| | | samesite='Lax', |
| | | ): |
| | | self.cookie = AuthTktCookieHelper( |
| | | secret, |
| | | cookie_name=cookie_name, |
| | |
| | | parent_domain=parent_domain, |
| | | domain=domain, |
| | | samesite=samesite, |
| | | ) |
| | | ) |
| | | self.callback = callback |
| | | self.debug = debug |
| | | |
| | |
| | | """ 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): |
| | |
| | | |
| | | """ |
| | | |
| | | 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 |
| | |
| | | |
| | | 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): |
| | |
| | | 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'): |
| | |
| | | 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') |
| | |
| | | # 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): |
| | | """ |
| | |
| | | :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() |
| | | |
| | |
| | | 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 |
| | |
| | | |
| | | 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 |
| | | |
| | |
| | | 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) |
| | |
| | | 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 |
| | | |
| | |
| | | "userid is of type {}, and is not supported by the " |
| | | "AuthTktAuthenticationPolicy. Explicitly converting to string " |
| | | "and storing as base64. Subsequent requests will receive a " |
| | | "string as the userid, it will not be decoded back to the type " |
| | | "provided.".format(type(userid)), RuntimeWarning |
| | | "string as the userid, it will not be decoded back to the " |
| | | "type provided.".format(type(userid)), |
| | | RuntimeWarning, |
| | | ) |
| | | encoding, encoder = self.userid_type_encoders.get(text_type) |
| | | userid = str(userid) |
| | |
| | | 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): |
| | |
| | | |
| | | ``realm`` |
| | | |
| | | Default: ``"Realm"``. The Basic Auth Realm string. Usually displayed to |
| | | the user by the browser in the login dialog. |
| | | Default: ``"Realm"``. The Basic Auth Realm string. Usually displayed |
| | | to the user by the browser in the login dialog. |
| | | |
| | | ``debug`` |
| | | |
| | |
| | | return response |
| | | return HTTPForbidden() |
| | | """ |
| | | |
| | | def __init__(self, check, realm='Realm', debug=False): |
| | | self.check = check |
| | | self.realm = realm |
| | |
| | | |
| | | |
| | | HTTPBasicCredentials = namedtuple( |
| | | 'HTTPBasicCredentials', ['username', 'password']) |
| | | 'HTTPBasicCredentials', ['username', 'password'] |
| | | ) |
| | | |
| | | |
| | | 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 |
| | |
| | | |
| | | 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) |
| | |
| | | |
| | | 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): |
| | |
| | | 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 |
| | |
| | | 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) |
| | | |
| | |
| | | |
| | | try: # pragma: no cover |
| | | import __pypy__ |
| | | |
| | | PYPY = True |
| | | except: # pragma: no cover |
| | | except BaseException: # pragma: no cover |
| | | __pypy__ = None |
| | | PYPY = False |
| | | |
| | |
| | | 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 |
| | |
| | | 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``""" |
| | |
| | | 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 |
| | |
| | | |
| | | |
| | | 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)``""" |
| | | if isinstance(s, text_type): |
| | | return s |
| | | return str(s, encoding, errors) |
| | | |
| | | |
| | | native_.__doc__ = """ |
| | | Python 3: If ``s`` is an instance of ``text_type``, return ``s``, otherwise |
| | |
| | | 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: |
| | |
| | | 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): |
| | |
| | | |
| | | |
| | | if PY2: # pragma: no cover |
| | | |
| | | def iteritems_(d): |
| | | return d.iteritems() |
| | | |
| | |
| | | |
| | | def iterkeys_(d): |
| | | return d.iterkeys() |
| | | |
| | | |
| | | else: # pragma: no cover |
| | | |
| | | def iteritems_(d): |
| | | return d.items() |
| | | |
| | |
| | | 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' |
| | |
| | | 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): |
| | |
| | | |
| | | 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: |
| | |
| | | else: |
| | | from itertools import zip_longest |
| | | |
| | | |
| | | def is_unbound_method(fn): |
| | | """ |
| | | This consistently verifies that the callable is bound to a |
| | |
| | | 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 |
| | | |
| | |
| | | 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 |
| | | |
| | |
| | | |
| | | 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 |
| | |
| | | PHASE2_CONFIG = PHASE2_CONFIG # api |
| | | PHASE3_CONFIG = PHASE3_CONFIG # api |
| | | |
| | | |
| | | class Configurator( |
| | | TestingConfiguratorMixin, |
| | | TweensConfiguratorMixin, |
| | |
| | | SettingsConfiguratorMixin, |
| | | FactoriesConfiguratorMixin, |
| | | AdaptersConfiguratorMixin, |
| | | ): |
| | | ): |
| | | """ |
| | | A Configurator is used to configure a :app:`Pyramid` |
| | | :term:`application registry`. |
| | |
| | | ``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 = () |
| | |
| | | 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: |
| | |
| | | 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 |
| | |
| | | if exceptionresponse_view is not None: |
| | | exceptionresponse_view = self.maybe_dotted(exceptionresponse_view) |
| | | self.add_view(exceptionresponse_view, context=IExceptionResponse) |
| | | self.add_view(exceptionresponse_view,context=WebobWSGIHTTPException) |
| | | self.add_view( |
| | | exceptionresponse_view, context=WebobWSGIHTTPException |
| | | ) |
| | | |
| | | # commit below because: |
| | | # |
| | | # - the default exceptionresponse_view requires the superdefault view |
| | | # mapper, so we need to configure it before adding default_view_mapper |
| | | # mapper, so we need to configure it before adding |
| | | # default_view_mapper |
| | | # |
| | | # - superdefault renderers should be overrideable without requiring |
| | | # the user to commit before calling config.add_renderer |
| | |
| | | # 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) |
| | |
| | | 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): |
| | |
| | | _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 |
| | | |
| | |
| | | |
| | | introspector = property( |
| | | _get_introspector, _set_introspector, _del_introspector |
| | | ) |
| | | ) |
| | | |
| | | def get_predlist(self, name): |
| | | predlist = self.registry.queryUtility(IPredicateList, name=name) |
| | |
| | | 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: |
| | |
| | | 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``). |
| | |
| | | """ |
| | | # 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 = {} |
| | |
| | | info=action_info, |
| | | includepath=self.includepath, |
| | | introspectables=introspectables, |
| | | ) |
| | | ) |
| | | ) |
| | | self.action_state.action(**action) |
| | | |
| | | def _get_action_state(self): |
| | |
| | | |
| | | action_state = property(_get_action_state, _set_action_state) |
| | | |
| | | _ctx = action_state # bw compat |
| | | _ctx = action_state # bw compat |
| | | |
| | | def commit(self): |
| | | """ |
| | |
| | | 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 |
| | |
| | | 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): |
| | |
| | | root_package=self.root_package, |
| | | autocommit=self.autocommit, |
| | | route_prefix=self.route_prefix, |
| | | ) |
| | | ) |
| | | configurator.basepath = os.path.dirname(sourcefile) |
| | | configurator.includepath = self.includepath + (spec,) |
| | | |
| | |
| | | autocommit=self.autocommit, |
| | | route_prefix=self.route_prefix, |
| | | introspection=self.introspection, |
| | | ) |
| | | ) |
| | | configurator.basepath = self.basepath |
| | | configurator.includepath = self.includepath |
| | | configurator.info = self.info |
| | |
| | | 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. |
| | |
| | | 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. |
| | |
| | | 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 |
| | |
| | | |
| | | """ |
| | | 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} |
| | |
| | | |
| | | 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 |
| | |
| | | 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: |
| | |
| | | info=info, |
| | | order=order, |
| | | introspectables=introspectables, |
| | | ) |
| | | ) |
| | | ) |
| | | self.actions.append(action) |
| | | |
| | | def execute_actions(self, clear=True, introspector=None): |
| | |
| | | if self.actions: |
| | | all_actions.extend(self.actions) |
| | | action_iter = resolveConflicts( |
| | | self.actions, |
| | | state=conflict_state, |
| | | self.actions, state=conflict_state |
| | | ) |
| | | self.actions = [] |
| | | |
| | |
| | | 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 |
| | | |
| | |
| | | |
| | | # 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) |
| | |
| | | # 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']) |
| | | |
| | |
| | | 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']) |
| | | |
| | |
| | | |
| | | |
| | | 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 = {} |
| | |
| | | info=info, |
| | | order=order, |
| | | introspectables=introspectables, |
| | | ) |
| | | ) |
| | | |
| | | |
| | | global_registries = WeakOrderedSet() |
| | |
| | | |
| | | 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 |
| | | |
| | |
| | | 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 |
| | | |
| | |
| | | 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 |
| | | |
| | |
| | | derived_subscriber = subscriber |
| | | |
| | | if eventonly(subscriber): |
| | | |
| | | def derived_subscriber(*arg): |
| | | return subscriber(arg[0]) |
| | | |
| | | if hasattr(subscriber, '__name__'): |
| | | update_wrapper(derived_subscriber, subscriber) |
| | | |
| | |
| | | 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 |
| | | |
| | |
| | | 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): |
| | |
| | | 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,)) |
| | |
| | | """ |
| | | 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,)) |
| | |
| | | """ |
| | | 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') |
| | |
| | | |
| | | 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): |
| | |
| | | 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.""" |
| | |
| | | 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.""" |
| | |
| | | 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() |
| | |
| | | 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() |
| | |
| | | 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() |
| | |
| | | if result is not None: |
| | | return result |
| | | return pkg_resources.DefaultProvider.resource_listdir( |
| | | self, resource_name) |
| | | self, resource_name |
| | | ) |
| | | |
| | | |
| | | @implementer(IPackageOverrides) |
| | |
| | | |
| | | 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): |
| | |
| | | the empty string, as returned by the ``FileOverride``. |
| | | |
| | | """ |
| | | |
| | | def __init__(self, package, prefix): |
| | | self.package = package |
| | | if hasattr(package, '__name__'): |
| | |
| | | An asset source relative to a path in the filesystem. |
| | | |
| | | """ |
| | | |
| | | def __init__(self, prefix): |
| | | self.prefix = prefix |
| | | |
| | |
| | | |
| | | |
| | | 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 |
| | |
| | | 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 = '' |
| | |
| | | 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 |
| | |
| | | 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) |
| | |
| | | (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 |
| | |
| | | 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 |
| | |
| | | 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,)) |
| | | |
| | |
| | | |
| | | 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,)) |
| | | |
| | |
| | | |
| | | 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,)) |
| | | |
| | |
| | | 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 |
| | |
| | | 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: |
| | |
| | | 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): |
| | |
| | | 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,)) |
| | | |
| | |
| | | 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 |
| | |
| | | :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,)) |
| | | |
| | |
| | | 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) |
| | |
| | | tdirs.insert(0, directory) |
| | | |
| | | self.action(None, register, introspectables=introspectables) |
| | | |
| | |
| | | import zope.deprecation |
| | | |
| | | zope.deprecation.moved('pyramid.predicates', 'Pyramid 1.10') |
| | |
| | | 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 |
| | |
| | | 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): |
| | | """ |
| | |
| | | # 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,), |
| | | ) |
| | |
| | | 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 |
| | | |
| | |
| | | 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` |
| | |
| | | For backwards compatibility purposes (as of :app:`Pyramid` 1.0), a |
| | | ``path`` keyword argument passed to this function will be used to |
| | | represent the pattern value if the ``pattern`` argument is |
| | | ``None``. If both ``path`` and ``pattern`` are passed, ``pattern`` |
| | | wins. |
| | | ``None``. If both ``path`` and ``pattern`` are passed, |
| | | ``pattern`` wins. |
| | | |
| | | xhr |
| | | |
| | |
| | | """ |
| | | 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)] |
| | | |
| | |
| | | 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: |
| | |
| | | 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 |
| | |
| | | |
| | | 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 |
| | |
| | | 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,) |
| | |
| | | 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() |
| | |
| | | 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 |
| | | |
| | |
| | | |
| | | # 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`. |
| | |
| | | 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 |
| | |
| | | ('effective_principals', p.EffectivePrincipalsPredicate), |
| | | ('custom', p.CustomPredicate), |
| | | ('traverse', p.TraversePredicate), |
| | | ): |
| | | ): |
| | | self.add_route_predicate(name, factory) |
| | | |
| | | def get_routes_mapper(self): |
| | |
| | | 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('/') |
| | |
| | | IDefaultPermission, |
| | | PHASE1_CONFIG, |
| | | PHASE2_CONFIG, |
| | | ) |
| | | ) |
| | | |
| | | from pyramid.csrf import LegacySessionCSRFStoragePolicy |
| | | from pyramid.exceptions import ConfigurationError |
| | |
| | | |
| | | from pyramid.config.util import action_method |
| | | |
| | | class SecurityConfiguratorMixin(object): |
| | | |
| | | class SecurityConfiguratorMixin(object): |
| | | def add_default_security(self): |
| | | self.set_csrf_storage_policy(LegacySessionCSRFStoragePolicy()) |
| | | |
| | |
| | | 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) |
| | |
| | | :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 |
| | |
| | | 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): |
| | |
| | | :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): |
| | | """ |
| | |
| | | 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,)) |
| | | |
| | |
| | | |
| | | """ |
| | | 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): |
| | |
| | | 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,)) |
| | | |
| | |
| | | |
| | | from pyramid.settings import asbool, aslist |
| | | |
| | | |
| | | class SettingsConfiguratorMixin(object): |
| | | def _set_settings(self, mapping): |
| | | if mapping is None: |
| | |
| | | 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) |
| | |
| | | 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] |
| | |
| | | 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`. |
| | |
| | | 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 |
| | |
| | | :func:`pyramid.traversal.find_resource` is called with an |
| | | equivalent path string or tuple. |
| | | """ |
| | | |
| | | class DummyTraverserFactory: |
| | | def __init__(self, context): |
| | | self.context = context |
| | |
| | | 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): |
| | |
| | | """ |
| | | event_iface = self.maybe_dotted(event_iface) |
| | | L = [] |
| | | |
| | | def subscriber(*event): |
| | | L.extend(event) |
| | | |
| | | self.add_subscriber(subscriber, event_iface) |
| | | return L |
| | | |
| | |
| | | |
| | | """ |
| | | 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 |
| | | |
| | | |
| | |
| | | |
| | | 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): |
| | |
| | | - An iterable of any combination of the above. This allows the user |
| | | to specify fallbacks if the desired tween is not included, as well |
| | | as compatibility with multiple other tweens. |
| | | |
| | | |
| | | ``under`` means 'closer to the main Pyramid application than', |
| | | ``over`` means 'closer to the request ingress than'. |
| | | |
| | |
| | | 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) |
| | |
| | | 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 |
| | | |
| | |
| | | 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) |
| | |
| | | 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 |
| | |
| | | introspectables.append(intr) |
| | | self.action(discriminator, register, introspectables=introspectables) |
| | | |
| | | |
| | | @implementer(ITweens) |
| | | class Tweens(object): |
| | | def __init__(self): |
| | |
| | | default_before=None, |
| | | default_after=INGRESS, |
| | | first=INGRESS, |
| | | last=MAIN) |
| | | last=MAIN, |
| | | ) |
| | | self.explicit = [] |
| | | |
| | | def add_explicit(self, name, factory): |
| | |
| | | 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): |
| | |
| | | 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 = [] |
| | |
| | | # 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: |
| | |
| | | |
| | | .. versionadded:: 1.5 |
| | | """ |
| | | |
| | | def __init__(self, value): |
| | | self.value = value |
| | | |
| | |
| | | # under = after |
| | | # over = before |
| | | |
| | | class PredicateList(object): |
| | | |
| | | class PredicateList(object): |
| | | def __init__(self): |
| | | self.sorter = TopologicalSorter() |
| | | self.last_added = None |
| | |
| | | def add(self, name, factory, weighs_more_than=None, weighs_less_than=None): |
| | | # Predicates should be added to a predicate list in (presumed) |
| | | # computation expense order. |
| | | ## if weighs_more_than is None and weighs_less_than is None: |
| | | ## weighs_more_than = self.last_added or FIRST |
| | | ## weighs_less_than = LAST |
| | | # if weighs_more_than is None and weighs_less_than is None: |
| | | # weighs_more_than = self.last_added or FIRST |
| | | # weighs_less_than = LAST |
| | | self.last_added = name |
| | | self.sorter.add( |
| | | name, |
| | | factory, |
| | | after=weighs_more_than, |
| | | before=weighs_less_than, |
| | | ) |
| | | name, factory, after=weighs_more_than, before=weighs_less_than |
| | | ) |
| | | |
| | | def names(self): |
| | | # Return the list of valid predicate names. |
| | |
| | | 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,) |
| | |
| | | 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)) |
| | | |
| | |
| | | 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: |
| | |
| | | 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 ( |
| | |
| | | IViewDeriverInfo, |
| | | IViewMapperFactory, |
| | | PHASE1_CONFIG, |
| | | ) |
| | | ) |
| | | |
| | | from pyramid import renderers |
| | | |
| | |
| | | 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 |
| | | |
| | |
| | | |
| | | 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 |
| | |
| | | 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 = {} |
| | |
| | | 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 |
| | |
| | | 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: |
| | |
| | | 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): |
| | |
| | | for decorator in reversed(decorators): |
| | | view_callable = decorator(view_callable) |
| | | return view_callable |
| | | |
| | | return decorated |
| | | |
| | | |
| | | class ViewsConfiguratorMixin(object): |
| | | @viewdefaults |
| | |
| | | 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* |
| | |
| | | If CSRF checking is performed, the checked value will be the value of |
| | | ``request.params[check_name]``. This value will be compared against |
| | | the value of ``policy.get_csrf_token()`` (where ``policy`` is an |
| | | implementation of :meth:`pyramid.interfaces.ICSRFStoragePolicy`), and the |
| | | check will pass if these two values are the same. If the check |
| | | implementation of :meth:`pyramid.interfaces.ICSRFStoragePolicy`), and |
| | | the check will pass if these two values are the same. If the check |
| | | passes, the associated view will be permitted to execute. If the |
| | | check fails, the associated view will not be permitted to execute. |
| | | |
| | |
| | | """ |
| | | 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) |
| | | |
| | |
| | | |
| | | 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_ |
| | |
| | | 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: |
| | |
| | | |
| | | 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 |
| | |
| | | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | |
| | | 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 |
| | | |
| | |
| | | derived_view, |
| | | (classifier, request_iface, context), |
| | | view_iface, |
| | | name |
| | | ) |
| | | name, |
| | | ) |
| | | |
| | | else: |
| | | # - A view or multiview was already registered for this |
| | |
| | | # 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 |
| | |
| | | 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) |
| | |
| | | |
| | | 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) |
| | |
| | | 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 |
| | | |
| | |
| | | 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 |
| | |
| | | ('physical_path', p.PhysicalPathPredicate), |
| | | ('effective_principals', p.EffectivePrincipalsPredicate), |
| | | ('custom', p.CustomPredicate), |
| | | ): |
| | | ): |
| | | self.add_view_predicate(name, factory) |
| | | |
| | | def add_default_accept_view_order(self): |
| | |
| | | |
| | | @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 |
| | |
| | | .. 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] |
| | |
| | | |
| | | 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): |
| | |
| | | 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' |
| | |
| | | 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: |
| | |
| | | ) |
| | | 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 |
| | |
| | | ] |
| | | 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 |
| | |
| | | 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, |
| | |
| | | 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) |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | config.add_notfound_view(append_slash=HTTPMovedPermanently) |
| | | |
| | | The above means that a redirect to a slash-appended route will be |
| | | attempted, but instead of :class:`~pyramid.httpexceptions.HTTPTemporaryRedirect` |
| | | attempted, but instead of |
| | | :class:`~pyramid.httpexceptions.HTTPTemporaryRedirect` |
| | | being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will |
| | | be used` for the redirect response if a slash-appended route is found. |
| | | |
| | |
| | | |
| | | .. versionchanged: 1.10 |
| | | |
| | | Default response was changed from :class:`~pyramid.httpexceptions.HTTPFound` |
| | | Default response was changed from |
| | | :class:`~pyramid.httpexceptions.HTTPFound` |
| | | to :class:`~pyramid.httpexceptions.HTTPTemporaryRedirect`. |
| | | |
| | | """ |
| | | for arg in ( |
| | | 'name', 'permission', 'context', 'for_', 'require_csrf', |
| | | 'name', |
| | | 'permission', |
| | | 'context', |
| | | 'for_', |
| | | 'require_csrf', |
| | | 'exception_only', |
| | | ): |
| | | if arg in view_options: |
| | | raise ConfigurationError( |
| | | '%s may not be used as an argument to add_notfound_view' |
| | | % (arg,)) |
| | | % (arg,) |
| | | ) |
| | | |
| | | if view is None: |
| | | view = default_exceptionresponse_view |
| | |
| | | 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) |
| | |
| | | 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 |
| | |
| | | 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. |
| | |
| | | .. 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 |
| | |
| | | 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): |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | def settings(self): |
| | | return self.registry.settings |
| | | |
| | | |
| | | @implementer(IStaticURLInfo) |
| | | class StaticURLInfo(object): |
| | | def __init__(self): |
| | |
| | | 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) |
| | |
| | | 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 |
| | |
| | | # 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 = '/' |
| | |
| | | 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 |
| | |
| | | |
| | | # 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: |
| | |
| | | # 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 |
| | | |
| | |
| | | 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 = '/' |
| | |
| | | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | from pyramid.threadlocal import get_current_registry |
| | | |
| | | |
| | | class ZCAConfiguratorMixin(object): |
| | | def hook_zca(self): |
| | | """ Call :func:`zope.component.getSiteManager.sethook` with the |
| | |
| | | :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() |
| | |
| | | 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) |
| | |
| | | .. 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() |
| | |
| | | """ 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) |
| | |
| | | .. versionadded:: 1.9 |
| | | |
| | | """ |
| | | |
| | | _token_factory = staticmethod(lambda: text_(uuid.uuid4().hex)) |
| | | |
| | | def __init__(self, key='_csrft_'): |
| | |
| | | """ 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) |
| | |
| | | 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, |
| | |
| | | """ 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 |
| | | |
| | |
| | | """ 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): |
| | |
| | | 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 |
| | |
| | | Check the ``Origin`` of the request to see if it is a cross site request or |
| | | not. |
| | | |
| | | If the value supplied by the ``Origin`` or ``Referer`` header isn't one of the |
| | | trusted origins and ``raises`` is ``True``, this function will raise a |
| | | If the value supplied by the ``Origin`` or ``Referer`` header isn't one of |
| | | the trusted origins and ``raises`` is ``True``, this function will raise a |
| | | :exc:`pyramid.exceptions.BadCSRFOrigin` exception, but if ``raises`` is |
| | | ``False``, this function will return ``False`` instead. If the CSRF origin |
| | | checks are successful this function will return ``True`` unconditionally. |
| | |
| | | Moved from :mod:`pyramid.session` to :mod:`pyramid.csrf` |
| | | |
| | | """ |
| | | |
| | | def _fail(reason): |
| | | if raises: |
| | | raise BadCSRFOrigin(reason) |
| | |
| | | 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"]): |
| | |
| | | |
| | | # 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." |
| | |
| | | >>> f.jammy |
| | | 2 |
| | | """ |
| | | |
| | | def __init__(self, wrapped): |
| | | self.wrapped = wrapped |
| | | update_wrapper(self, wrapped) |
| | |
| | | val = self.wrapped(inst) |
| | | setattr(inst, self.wrapped.__name__, val) |
| | | return val |
| | | |
| | |
| | | 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') |
| | | elif cls is not binary_type: |
| | | val = str(val).encode('utf-8') |
| | | return _url_quote(val, safe=safe) |
| | | |
| | | |
| | | # bw compat api (dnr) |
| | | 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 |
| | |
| | | import venusian |
| | | |
| | | from zope.interface import ( |
| | | implementer, |
| | | Interface |
| | | ) |
| | | from zope.interface import implementer, Interface |
| | | |
| | | from pyramid.interfaces import ( |
| | | IContextFound, |
| | |
| | | IApplicationCreated, |
| | | IBeforeRender, |
| | | IBeforeTraversal, |
| | | ) |
| | | ) |
| | | |
| | | |
| | | class subscriber(object): |
| | | """ Decorator activated via a :term:`scan` which treats the function |
| | |
| | | Added the ``_depth`` and ``_category`` arguments. |
| | | |
| | | """ |
| | | venusian = venusian # for unit testing |
| | | |
| | | venusian = venusian # for unit testing |
| | | |
| | | def __init__(self, *ifaces, **predicates): |
| | | self.ifaces = ifaces |
| | |
| | | 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): |
| | |
| | | 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): |
| | |
| | | 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): |
| | |
| | | |
| | | def __init__(self, request): |
| | | self.request = request |
| | | |
| | | |
| | | @implementer(IContextFound) |
| | | 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): |
| | |
| | | :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): |
| | |
| | | |
| | | See also :class:`pyramid.interfaces.IBeforeRender`. |
| | | """ |
| | | |
| | | def __init__(self, system, rendering_val=None): |
| | | dict.__init__(self, system) |
| | | self.rendering_val = rendering_val |
| | | |
| | |
| | | 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' |
| | | |
| | |
| | | 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 " |
| | |
| | | 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 ' |
| | |
| | | '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): |
| | | """ |
| | |
| | | exception view. |
| | | """ |
| | | |
| | | |
| | | class URLDecodeError(UnicodeDecodeError): |
| | | """ |
| | | This exception is raised when :app:`Pyramid` cannot |
| | |
| | | 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 |
| | |
| | | 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) |
| | |
| | | class CyclicDependencyError(Exception): |
| | | """ The exception raised when the Pyramid topological sorter detects a |
| | | cyclic dependency.""" |
| | | |
| | | def __init__(self, cycles): |
| | | self.cycles = cycles |
| | | |
| | |
| | | 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: |
| | |
| | | value = text_type(value) |
| | | return value |
| | | |
| | | |
| | | @implementer(IExceptionResponse) |
| | | class HTTPException(Response, Exception): |
| | | |
| | | ## You should set in subclasses: |
| | | # You should set in subclasses: |
| | | # code = 200 |
| | | # title = 'OK' |
| | | # explanation = 'why this happens' |
| | |
| | | # implies that this class' ``exception`` property always returns |
| | | # ``self`` (it exists only for bw compat at this point). |
| | | # |
| | | # - documentation improvements (Pyramid-specific docstrings where necessary) |
| | | # - documentation improvements (Pyramid-specific docstrings where |
| | | # necessary) |
| | | # |
| | | code = 520 |
| | | title = 'Unknown Error' |
| | | explanation = '' |
| | | body_template_obj = Template('''\ |
| | | body_template_obj = Template( |
| | | '''\ |
| | | ${explanation}${br}${br} |
| | | ${detail} |
| | | ${html_comment} |
| | | ''') |
| | | ''' |
| | | ) |
| | | |
| | | plain_template_obj = Template('''\ |
| | | plain_template_obj = Template( |
| | | '''\ |
| | | ${status} |
| | | |
| | | ${body}''') |
| | | ${body}''' |
| | | ) |
| | | |
| | | html_template_obj = Template('''\ |
| | | html_template_obj = Template( |
| | | '''\ |
| | | <html> |
| | | <head> |
| | | <title>${status}</title> |
| | |
| | | <h1>${status}</h1> |
| | | ${body} |
| | | </body> |
| | | </html>''') |
| | | </html>''' |
| | | ) |
| | | |
| | | ## Set this to True for responses that should have no request body |
| | | # Set this to True for responses that should have no request body |
| | | empty_body = False |
| | | |
| | | def __init__(self, detail=None, headers=None, comment=None, |
| | | body_template=None, json_formatter=None, **kw): |
| | | def __init__( |
| | | self, |
| | | detail=None, |
| | | headers=None, |
| | | comment=None, |
| | | body_template=None, |
| | | json_formatter=None, |
| | | **kw |
| | | ): |
| | | status = '%s %s' % (self.code, self.title) |
| | | Response.__init__(self, status=status, **kw) |
| | | Exception.__init__(self, detail) |
| | |
| | | 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: |
| | |
| | | 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] |
| | | |
| | |
| | | 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) |
| | |
| | | '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 |
| | |
| | | # 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 |
| | |
| | | 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): |
| | | """ |
| | |
| | | This is an exception which indicates that an error has occurred, |
| | | and that any work in progress should not be committed. |
| | | """ |
| | | |
| | | |
| | | class HTTPRedirection(HTTPException): |
| | | """ |
| | |
| | | condition. |
| | | """ |
| | | |
| | | |
| | | class HTTPSuccessful(HTTPException): |
| | | """ |
| | | Base class for exceptions with status codes in the 200s (successful |
| | | responses) |
| | | """ |
| | | |
| | | |
| | | ############################################################ |
| | | ## 2xx success |
| | | # 2xx success |
| | | ############################################################ |
| | | |
| | | |
| | | class HTTPOk(HTTPSuccessful): |
| | | """ |
| | |
| | | |
| | | code: 200, title: OK |
| | | """ |
| | | |
| | | code = 200 |
| | | title = 'OK' |
| | | |
| | | |
| | | class HTTPCreated(HTTPSuccessful): |
| | | """ |
| | |
| | | |
| | | code: 201, title: Created |
| | | """ |
| | | |
| | | code = 201 |
| | | title = 'Created' |
| | | |
| | | |
| | | class HTTPAccepted(HTTPSuccessful): |
| | | """ |
| | |
| | | |
| | | code: 202, title: Accepted |
| | | """ |
| | | |
| | | code = 202 |
| | | title = 'Accepted' |
| | | explanation = 'The request is accepted for processing.' |
| | | |
| | | |
| | | class HTTPNonAuthoritativeInformation(HTTPSuccessful): |
| | | """ |
| | |
| | | |
| | | code: 203, title: Non-Authoritative Information |
| | | """ |
| | | |
| | | code = 203 |
| | | title = 'Non-Authoritative Information' |
| | | |
| | | |
| | | class HTTPNoContent(HTTPSuccessful): |
| | | """ |
| | |
| | | |
| | | code: 204, title: No Content |
| | | """ |
| | | |
| | | code = 204 |
| | | title = 'No Content' |
| | | empty_body = True |
| | | |
| | | |
| | | class HTTPResetContent(HTTPSuccessful): |
| | | """ |
| | |
| | | |
| | | code: 205, title: Reset Content |
| | | """ |
| | | |
| | | code = 205 |
| | | title = 'Reset Content' |
| | | empty_body = True |
| | | |
| | | |
| | | class HTTPPartialContent(HTTPSuccessful): |
| | | """ |
| | |
| | | |
| | | code: 206, title: Partial Content |
| | | """ |
| | | |
| | | code = 206 |
| | | title = 'Partial Content' |
| | | |
| | | ## FIXME: add 207 Multi-Status (but it's complicated) |
| | | |
| | | # FIXME: add 207 Multi-Status (but it's complicated) |
| | | |
| | | ############################################################ |
| | | ## 3xx redirection |
| | | # 3xx redirection |
| | | ############################################################ |
| | | |
| | | |
| | | class _HTTPMove(HTTPRedirection): |
| | | """ |
| | |
| | | |
| | | You must provide a ``location`` keyword argument. |
| | | """ |
| | | |
| | | # differences from webob.exc._HTTPMove: |
| | | # |
| | | # - ${location} isn't wrapped in an <a> tag in body |
| | |
| | | # - ``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): |
| | | """ |
| | |
| | | |
| | | code: 300, title: Multiple Choices |
| | | """ |
| | | |
| | | code = 300 |
| | | title = 'Multiple Choices' |
| | | |
| | | |
| | | class HTTPMovedPermanently(_HTTPMove): |
| | | """ |
| | |
| | | |
| | | code: 301, title: Moved Permanently |
| | | """ |
| | | |
| | | code = 301 |
| | | title = 'Moved Permanently' |
| | | |
| | | |
| | | 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): |
| | |
| | | |
| | | code: 303, title: See Other |
| | | """ |
| | | |
| | | code = 303 |
| | | title = 'See Other' |
| | | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | code: 307, title: Temporary Redirect |
| | | """ |
| | | |
| | | code = 307 |
| | | title = 'Temporary Redirect' |
| | | |
| | | |
| | | class HTTPPermanentRedirect(_HTTPMove): |
| | | """ |
| | |
| | | |
| | | code: 308, title: Permanent Redirect |
| | | """ |
| | | |
| | | code = 308 |
| | | title = 'Permanent Redirect' |
| | | |
| | | |
| | | ############################################################ |
| | | ## 4xx client error |
| | | # 4xx client error |
| | | ############################################################ |
| | | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | 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 |
| | |
| | | # |
| | | 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): |
| | | """ |
| | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | code: 411, title: Length Required |
| | | """ |
| | | |
| | | code = 411 |
| | | title = 'Length Required' |
| | | explanation = ('Content-Length header required.') |
| | | explanation = 'Content-Length header required.' |
| | | |
| | | |
| | | class HTTPPreconditionFailed(HTTPClientError): |
| | | """ |
| | |
| | | |
| | | code: 412, title: Precondition Failed |
| | | """ |
| | | |
| | | code = 412 |
| | | title = 'Precondition Failed' |
| | | explanation = ('Request precondition failed.') |
| | | explanation = 'Request precondition failed.' |
| | | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | code: 417, title: Expectation Failed |
| | | """ |
| | | |
| | | code = 417 |
| | | title = 'Expectation Failed' |
| | | explanation = ('Expectation failed.') |
| | | explanation = 'Expectation failed.' |
| | | |
| | | |
| | | class HTTPUnprocessableEntity(HTTPClientError): |
| | | """ |
| | |
| | | |
| | | code: 422, title: Unprocessable Entity |
| | | """ |
| | | ## Note: from WebDAV |
| | | |
| | | # Note: from WebDAV |
| | | code = 422 |
| | | title = 'Unprocessable Entity' |
| | | explanation = 'Unable to process the contained instructions' |
| | | |
| | | |
| | | class HTTPLocked(HTTPClientError): |
| | | """ |
| | |
| | | |
| | | code: 423, title: Locked |
| | | """ |
| | | ## Note: from WebDAV |
| | | |
| | | # Note: from WebDAV |
| | | code = 423 |
| | | title = 'Locked' |
| | | explanation = ('The resource is locked') |
| | | explanation = 'The resource is locked' |
| | | |
| | | |
| | | class HTTPFailedDependency(HTTPClientError): |
| | | """ |
| | |
| | | |
| | | code: 424, title: Failed Dependency |
| | | """ |
| | | ## Note: from WebDAV |
| | | |
| | | # Note: from WebDAV |
| | | code = 424 |
| | | title = 'Failed Dependency' |
| | | explanation = ( |
| | | 'The method could not be performed because the requested ' |
| | | 'action dependended on another action and that action failed') |
| | | 'action dependended on another action and that action failed' |
| | | ) |
| | | |
| | | |
| | | class HTTPPreconditionRequired(HTTPClientError): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | code: 431, title: Request Header Fields Too Large |
| | | """ |
| | | |
| | | code = 431 |
| | | title = 'Request Header Fields Too Large' |
| | | explanation = ( |
| | | 'The requests header fields were too large.') |
| | | explanation = 'The requests header fields were too large.' |
| | | |
| | | |
| | | ############################################################ |
| | | ## 5xx Server Error |
| | | # 5xx Server Error |
| | | ############################################################ |
| | | # Response status codes beginning with the digit "5" indicate cases in |
| | | # which the server is aware that it has erred or is incapable of |
| | |
| | | # 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 |
| | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | code: 502, title: Bad Gateway |
| | | """ |
| | | |
| | | code = 502 |
| | | title = 'Bad Gateway' |
| | | explanation = ('Bad gateway.') |
| | | explanation = 'Bad gateway.' |
| | | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | 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:: |
| | |
| | | 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: |
| | |
| | | from translationstring import ( |
| | | Translator, |
| | | Pluralizer, |
| | | TranslationString, # API |
| | | TranslationStringFactory, # API |
| | | ) |
| | | TranslationString, # API |
| | | TranslationStringFactory, # API |
| | | ) |
| | | |
| | | from pyramid.compat import PY2 |
| | | from pyramid.decorator import reify |
| | |
| | | ILocalizer, |
| | | ITranslationDirectories, |
| | | ILocaleNegotiator, |
| | | ) |
| | | ) |
| | | |
| | | from pyramid.threadlocal import get_current_registry |
| | | |
| | |
| | | |
| | | DEFAULT_PLURAL = lambda n: int(n != 1) |
| | | |
| | | |
| | | class Localizer(object): |
| | | """ |
| | | An object providing translation and pluralizations related to |
| | |
| | | :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 |
| | |
| | | and ``plural`` objects should be unicode strings. There is no |
| | | reason to use translation string objects as arguments as all |
| | | metadata is ignored. |
| | | |
| | | |
| | | ``n`` represents the number of elements. ``domain`` is the |
| | | translation domain to use to do the pluralization, and ``mapping`` |
| | | is the interpolation mapping that should be used on the result. If |
| | | the ``domain`` is not supplied, a default domain is used (usually |
| | | ``messages``). |
| | | |
| | | |
| | | Example:: |
| | | |
| | | num = 1 |
| | |
| | | num, |
| | | mapping={'num':num}) |
| | | |
| | | |
| | | |
| | | """ |
| | | if self.pluralizer is None: |
| | | self.pluralizer = Pluralizer(self.translations) |
| | | return self.pluralizer(singular, plural, n, domain=domain, |
| | | mapping=mapping) |
| | | return self.pluralizer( |
| | | singular, plural, n, domain=domain, mapping=mapping |
| | | ) |
| | | |
| | | |
| | | def default_locale_negotiator(request): |
| | |
| | | the request object (possibly set by a view or a listener for an |
| | | :term:`event`). If the attribute exists and it is not ``None``, |
| | | its value will be used. |
| | | |
| | | |
| | | - Then it looks for the ``request.params['_LOCALE_']`` value. |
| | | |
| | | - Then it looks for the ``request.cookies['_LOCALE_']`` value. |
| | |
| | | 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.""" |
| | |
| | | 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: |
| | |
| | | locale_name = settings.get('default_locale_name', 'en') |
| | | |
| | | return locale_name |
| | | |
| | | |
| | | def get_locale_name(request): |
| | | """ |
| | |
| | | """ |
| | | return request.locale_name |
| | | |
| | | |
| | | def make_localizer(current_locale_name, translation_directories): |
| | | """ Create a :class:`pyramid.i18n.Localizer` object |
| | | corresponding to the provided locale name from the |
| | | corresponding to the provided locale name from the |
| | | translations found in the list of translation directories.""" |
| | | translations = Translations() |
| | | translations._catalog = {} |
| | |
| | | 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): |
| | | """ |
| | |
| | | corresponding to the current request's locale name. |
| | | """ |
| | | return request.localizer |
| | | |
| | | |
| | | class Translations(gettext.GNUTranslations, object): |
| | | """An extended translation catalog class (ripped off from Babel) """ |
| | |
| | | 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. |
| | |
| | | domain. |
| | | """ |
| | | return self._domains.get(domain, self).gettext(message) |
| | | |
| | | |
| | | def ldgettext(self, domain, message): |
| | | """Like ``lgettext()``, but look the message up in the specified |
| | | """Like ``lgettext()``, but look the message up in the specified |
| | | domain. |
| | | """ |
| | | """ |
| | | return self._domains.get(domain, self).lgettext(message) |
| | | |
| | | |
| | | def dugettext(self, domain, message): |
| | | """Like ``ugettext()``, but look the message up in the specified |
| | | domain. |
| | |
| | | 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 |
| | |
| | | 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 |
| | | |
| | |
| | | def locale_name(self): |
| | | locale_name = negotiate_locale_name(self) |
| | | return locale_name |
| | | |
| | | |
| | |
| | | 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 |
| | |
| | | :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): |
| | | """ |
| | |
| | | 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 |
| | |
| | | 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. |
| | |
| | | :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 |
| | |
| | | |
| | | 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 |
| | |
| | | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | |
| | | 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 |
| | |
| | | |
| | | 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 |
| | |
| | | |
| | | 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 |
| | |
| | | :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 |
| | |
| | | def clear(): |
| | | """ Clear all values from the dictionary """ |
| | | |
| | | |
| | | class IBeforeRender(IDict): |
| | | """ |
| | | Subscribers to this event may introspect and modify the set of |
| | |
| | | |
| | | 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): |
| | |
| | | :class:`pyramid.interfaces.IRenderer`. ``info`` is an |
| | | object that implements :class:`pyramid.interfaces.IRendererInfo`. |
| | | """ |
| | | |
| | | |
| | | class IRenderer(Interface): |
| | | def __call__(value, system): |
| | |
| | | view), and ``request`` (the request object passed to the |
| | | view).""" |
| | | |
| | | |
| | | class ITemplateRenderer(IRenderer): |
| | | def implementation(): |
| | | """ Return the object that the underlying templating system |
| | |
| | | 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): |
| | |
| | | request)``. The callable returned should itself return a Response |
| | | object. An IViewMapper is returned by |
| | | :class:`pyramid.interfaces.IViewMapperFactory`.""" |
| | | |
| | | |
| | | class IViewMapperFactory(Interface): |
| | | def __call__(self, **kw): |
| | |
| | | to extension developers who want to modify potential view callable |
| | | invocation signatures and response values. |
| | | """ |
| | | |
| | | |
| | | class IAuthenticationPolicy(Interface): |
| | | """ An object representing a Pyramid authentication policy. """ |
| | |
| | | |
| | | """ |
| | | |
| | | |
| | | 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 |
| | |
| | | ``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``, |
| | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | """ |
| | | |
| | | |
| | | class IStaticURLInfo(Interface): |
| | | """ A policy for generating URLs to static assets """ |
| | | |
| | | def add(config, name, spec, **extra): |
| | | """ Add a new static info registration """ |
| | | |
| | |
| | | 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``""" |
| | | |
| | |
| | | """ 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__ """ |
| | | |
| | |
| | | """ 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): |
| | |
| | | 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): |
| | | """ |
| | |
| | | a view registry. |
| | | |
| | | """ |
| | | |
| | | registry = Attribute( |
| | | """Component architecture registry local to this application.""") |
| | | """Component architecture registry local to this application.""" |
| | | ) |
| | | |
| | | def request_context(environ): |
| | | """ |
| | |
| | | |
| | | """ |
| | | |
| | | |
| | | class IExecutionPolicy(Interface): |
| | | def __call__(environ, router): |
| | | """ |
| | |
| | | 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): |
| | |
| | | |
| | | """ |
| | | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | 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.""" |
| | |
| | | """ 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): |
| | |
| | | ``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. |
| | | |
| | |
| | | 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, |
| | |
| | | |
| | | 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 |
| | |
| | | method = getattr(introspector, methodname) |
| | | method((i.category_name, i.discriminator), |
| | | (category_name, discriminator)) |
| | | """ |
| | | """ # noqa: E501 |
| | | |
| | | def __hash__(): |
| | | |
| | |
| | | return hash((self.category_name,) + (self.discriminator,)) |
| | | """ |
| | | |
| | | |
| | | class IActionInfo(Interface): |
| | | """ Class which provides code introspection capability associated with an |
| | | action. The ParserInfo class used by ZCML implements the same interface.""" |
| | | file = Attribute( |
| | | 'Filename of action-invoking code as a string') |
| | | action. The ParserInfo class used by ZCML implements the same interface. |
| | | """ |
| | | |
| | | file = Attribute('Filename of action-invoking code as a string') |
| | | line = Attribute( |
| | | 'Starting line number in file (as an integer) of action-invoking code.' |
| | | 'This will be ``None`` if the value could not be determined.') |
| | | 'This will be ``None`` if the value could not be determined.' |
| | | ) |
| | | |
| | | def __str__(): |
| | | """ Return a representation of the action information (including |
| | | source code from file, if possible) """ |
| | | |
| | | |
| | | class IAssetDescriptor(Interface): |
| | | """ |
| | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | """ |
| | | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | .. versionadded:: 1.6 |
| | | """ |
| | | |
| | | def __call__(request, subpath, kw): |
| | | """ |
| | | Modifies a subpath and/or keyword arguments from which a static asset |
| | |
| | | ``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. |
| | |
| | | # |
| | | ############################################################################## |
| | | |
| | | |
| | | def inside(resource1, resource2): |
| | | """Is ``resource1`` 'inside' ``resource2``? Return ``True`` if so, else |
| | | ``False``. |
| | |
| | | resource1 = resource1.__parent__ |
| | | |
| | | return False |
| | | |
| | | |
| | | def lineage(resource): |
| | | """ |
| | |
| | | |
| | | Calling ``lineage(thing2)`` will return a generator. When we turn |
| | | it into a list, we will get:: |
| | | |
| | | |
| | | list(lineage(thing2)) |
| | | [ <Thing object at thing2>, <Thing object at thing1> ] |
| | | """ |
| | |
| | | resource = resource.__parent__ |
| | | except AttributeError: |
| | | resource = None |
| | | |
| | |
| | | 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`` |
| | |
| | | """ |
| | | 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 |
| | |
| | | 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``. |
| | |
| | | """ |
| | | 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 |
| | |
| | | for you if none is provided. You can mutate the request's ``environ`` |
| | | later to setup a specific host/port/scheme/etc. |
| | | |
| | | ``options`` Is passed to get_app for use as variable assignments like |
| | | ``options`` Is passed to get_app for use as variable assignments like |
| | | {'http_port': 8080} and then use %(http_port)s in the |
| | | config file. |
| | | |
| | |
| | | env = prepare(request) |
| | | env['app'] = app |
| | | return env |
| | | |
| | |
| | | |
| | | 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): |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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): |
| | |
| | | except ImportError: |
| | | raise ValueError( |
| | | 'The dotted name %r cannot be imported' % (package,) |
| | | ) |
| | | ) |
| | | package = sys.modules[package] |
| | | self.package = package_of(package) |
| | | |
| | |
| | | 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 |
| | |
| | | 'relative spec %r irresolveable without package' % (spec,) |
| | | ) |
| | | return PkgResourcesAssetDescriptor(package_name, path) |
| | | |
| | | |
| | | class DottedNameResolver(Resolver): |
| | | """ A class used to resolve a :term:`dotted Python name` to a package or |
| | |
| | | :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 |
| | |
| | | if not package: |
| | | raise ValueError( |
| | | 'relative name %r irresolveable without package' % (value,) |
| | | ) |
| | | ) |
| | | if value in ['.', ':']: |
| | | value = package.__name__ |
| | | else: |
| | |
| | | |
| | | 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 == '.': |
| | |
| | | raise ValueError( |
| | | 'relative name %r irresolveable without ' |
| | | 'package' % (value,) |
| | | ) |
| | | ) |
| | | module = module.split('.') |
| | | name.pop(0) |
| | | while not name[0]: |
| | |
| | | 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): |
| | |
| | | |
| | | 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) |
| | |
| | | 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) |
| | | |
| | |
| | | from pyramid.traversal import ( |
| | | find_interface, |
| | | traversal_path, |
| | | resource_path_tuple |
| | | ) |
| | | |
| | | from pyramid.urldispatch import _compile_route |
| | | from pyramid.util import ( |
| | | as_sorted_tuple, |
| | | object_description, |
| | | resource_path_tuple, |
| | | ) |
| | | |
| | | from pyramid.urldispatch import _compile_route |
| | | from pyramid.util import as_sorted_tuple, object_description |
| | | |
| | | _marker = object() |
| | | |
| | | |
| | | class XHRPredicate(object): |
| | | def __init__(self, val, config): |
| | |
| | | |
| | | def __call__(self, context, request): |
| | | return bool(request.is_xhr) is self.val |
| | | |
| | | |
| | | class RequestMethodPredicate(object): |
| | | def __init__(self, val, config): |
| | |
| | | def __call__(self, context, request): |
| | | return request.method in self.val |
| | | |
| | | |
| | | class PathInfoPredicate(object): |
| | | def __init__(self, val, config): |
| | | self.orig = val |
| | |
| | | |
| | | 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) |
| | |
| | | |
| | | 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 |
| | |
| | | if v is not None and actual != v: |
| | | return False |
| | | return True |
| | | |
| | | |
| | | class HeaderPredicate(object): |
| | | def __init__(self, val, config): |
| | |
| | | return False |
| | | return self.val.match(val) is not None |
| | | |
| | | |
| | | class AcceptPredicate(object): |
| | | _is_using_deprecated_ranges = False |
| | | |
| | |
| | | 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) |
| | |
| | | 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 |
| | |
| | | |
| | | 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 |
| | | |
| | |
| | | if request.matchdict.get(k) != v: |
| | | return False |
| | | return True |
| | | |
| | | |
| | | |
| | | class CustomPredicate(object): |
| | | def __init__(self, func, config): |
| | | self.func = func |
| | |
| | | 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 |
| | |
| | | |
| | | 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 |
| | |
| | | def __init__(self, val, config): |
| | | _, self.tgenerate = _compile_route(val) |
| | | self.val = val |
| | | |
| | | |
| | | def text(self): |
| | | return 'traverse matchdict pseudo-predicate' |
| | | |
| | |
| | | # 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 |
| | | |
| | |
| | | val = 'csrf_token' |
| | | return self.check_csrf_token(request, val, raises=False) |
| | | return True |
| | | |
| | | |
| | | class PhysicalPathPredicate(object): |
| | | def __init__(self, val, config): |
| | |
| | | if getattr(context, '__name__', _marker) is not _marker: |
| | | return resource_path_tuple(context) == self.val |
| | | return False |
| | | |
| | | |
| | | class EffectivePrincipalsPredicate(object): |
| | | def __init__(self, val, config): |
| | |
| | | return True |
| | | return False |
| | | |
| | | |
| | | class Notted(object): |
| | | def __init__(self, predicate): |
| | | self.predicate = predicate |
| | |
| | | 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`. |
| | |
| | | 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 |
| | |
| | | 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)`` |
| | |
| | | self._settings = settings |
| | | |
| | | settings = property(_get_settings, _set_settings) |
| | | |
| | | |
| | | @implementer(IIntrospector) |
| | | 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): |
| | |
| | | |
| | | 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: |
| | |
| | | |
| | | 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: |
| | |
| | | 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 |
| | |
| | | |
| | | 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) |
| | |
| | | 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 |
| | |
| | | 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 |
| | | |
| | |
| | | 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 |
| | |
| | | v = v.resolve() |
| | | return v |
| | | |
| | | |
| | | class predvalseq(tuple): |
| | | """ A subtype of tuple used to represent a sequence of predicate values """ |
| | | |
| | | |
| | | global_registry = Registry('global') |
| | |
| | | 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 |
| | |
| | | from pyramid.util import hide_attrs |
| | | |
| | | # API |
| | | |
| | | |
| | | def render(renderer_name, value, request=None, package=None): |
| | | """ Using the renderer ``renderer_name`` (a template |
| | |
| | | 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 |
| | |
| | | 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: |
| | |
| | | result = helper.render_to_response(value, None, request=request) |
| | | |
| | | return result |
| | | |
| | | |
| | | def get_renderer(renderer_name, package=None, registry=None): |
| | | """ Return the renderer object for the renderer ``renderer_name``. |
| | |
| | | """ |
| | | 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 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. |
| | |
| | | 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: |
| | |
| | | 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 |
| | |
| | | ``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) |
| | |
| | | |
| | | 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) |
| | |
| | | if response.content_type == response.default_content_type: |
| | | response.content_type = ct |
| | | return body |
| | | |
| | | return _render |
| | | |
| | | |
| | | @implementer(IRendererInfo) |
| | | 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) |
| | | |
| | |
| | | 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 |
| | |
| | | def clone(self, name=None, package=None, registry=None): |
| | | return self |
| | | |
| | | |
| | | null_renderer = NullRendererHelper() |
| | |
| | | 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 |
| | |
| | | callback = callbacks.popleft() |
| | | callback(self) |
| | | |
| | | |
| | | @implementer(IRequest) |
| | | class Request( |
| | | BaseRequest, |
| | |
| | | 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 |
| | |
| | | release of this :app:`Pyramid` version. See |
| | | https://webob.org/ for further information. |
| | | """ |
| | | |
| | | exception = None |
| | | exc_info = None |
| | | matchdict = None |
| | |
| | | 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 |
| | |
| | | # 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 |
| | | |
| | | |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | |
| | | 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 |
| | |
| | | setattr(request, name, method) |
| | | |
| | | InstancePropertyHelper.apply_properties( |
| | | request, extensions.descriptors) |
| | | request, extensions.descriptors |
| | | ) |
| | |
| | | """ Backwards compatibility shim module (forever). """ |
| | | from pyramid.asset import * # b/w compat |
| | | resolve_resource_spec = resolve_asset_spec |
| | | resource_spec_from_abspath = asset_spec_from_abspath |
| | | abspath_from_resource_spec = abspath_from_asset_spec |
| | | from pyramid.asset import * # noqa b/w compat |
| | | |
| | | resolve_resource_spec = resolve_asset_spec # noqa |
| | | resource_spec_from_abspath = asset_spec_from_abspath # noqa |
| | | abspath_from_resource_spec = abspath_from_asset_spec # noqa |
| | |
| | | import mimetypes |
| | | from os.path import ( |
| | | getmtime, |
| | | getsize, |
| | | ) |
| | | from os.path import getmtime, getsize |
| | | |
| | | import venusian |
| | | |
| | |
| | | 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): |
| | | """ |
| | |
| | | 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) |
| | |
| | | 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. |
| | | |
| | |
| | | |
| | | ``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 |
| | |
| | | raise StopIteration |
| | | return val |
| | | |
| | | __next__ = next # py3 |
| | | __next__ = next # py3 |
| | | |
| | | def close(self): |
| | | self.file.close() |
| | |
| | | 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 |
| | |
| | | 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 |
| | | |
| | | |
| | |
| | | `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 |
| | |
| | | from zope.interface import ( |
| | | implementer, |
| | | providedBy, |
| | | ) |
| | | from zope.interface import implementer, providedBy |
| | | |
| | | from pyramid.interfaces import ( |
| | | IDebugLogger, |
| | |
| | | IRoutesMapper, |
| | | ITraverser, |
| | | ITweens, |
| | | ) |
| | | ) |
| | | |
| | | from pyramid.events import ( |
| | | ContextFound, |
| | | NewRequest, |
| | | NewResponse, |
| | | BeforeTraversal, |
| | | ) |
| | | ) |
| | | |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from pyramid.request import Request |
| | |
| | | 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): |
| | |
| | | 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: |
| | |
| | | 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 |
| | |
| | | '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 |
| | | |
| | |
| | | tdict['subpath'], |
| | | tdict['traversed'], |
| | | tdict['virtual_root'], |
| | | tdict['virtual_root_path'] |
| | | ) |
| | | tdict['virtual_root_path'], |
| | | ) |
| | | |
| | | attrs.update(tdict) |
| | | |
| | |
| | | # 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: |
| | |
| | | '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 |
| | |
| | | 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: |
| | |
| | | |
| | | 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 |
| | |
| | | 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.""" |
| | |
| | | |
| | | Welcome to Pyramid. Sorry for the convenience. |
| | | %(separator)s |
| | | """ % {'separator': separator}) |
| | | """ # noqa: E501 |
| | | % {'separator': separator} |
| | | ) |
| | | |
| | | self.out(msg) |
| | | return Template.post(self, command, output_dir, vars) |
| | | |
| | | def out(self, msg): # pragma: no cover (replaceable testing hook) |
| | | def out(self, msg): # pragma: no cover (replaceable testing hook) |
| | | print(msg) |
| | | |
| | | |
| | | class StarterProjectTemplate(PyramidTemplate): |
| | | _template_dir = 'starter' |
| | | summary = 'Pyramid starter project using URL dispatch and Jinja2' |
| | | |
| | | |
| | | class ZODBProjectTemplate(PyramidTemplate): |
| | | _template_dir = 'zodb' |
| | | summary = 'Pyramid project using ZODB, traversal, and Chameleon' |
| | | |
| | | |
| | | class AlchemyProjectTemplate(PyramidTemplate): |
| | | _template_dir = 'alchemy' |
| | | summary = ( |
| | | 'Pyramid project using SQLAlchemy, SQLite, URL dispatch, and ' |
| | | 'Jinja2') |
| | | 'Pyramid project using SQLAlchemy, SQLite, URL dispatch, and ' 'Jinja2' |
| | | ) |
| | |
| | | native_, |
| | | url_quote as compat_url_quote, |
| | | escape, |
| | | ) |
| | | ) |
| | | |
| | | fsenc = sys.getfilesystemencoding() |
| | | |
| | |
| | | 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. |
| | | |
| | |
| | | ``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', '.') |
| | |
| | | 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 |
| | |
| | | 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) |
| | |
| | | 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: |
| | |
| | | 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): |
| | | """ |
| | |
| | | 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: |
| | |
| | | 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): |
| | |
| | | else: |
| | | out(query_usage) |
| | | |
| | | |
| | | query_usage = """\ |
| | | Responses: |
| | | Y(es): Overwrite the file with the new content. |
| | |
| | | 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): |
| | | """ |
| | |
| | | if condition: |
| | | raise SkipTemplate(*args) |
| | | |
| | | |
| | | standard_vars = { |
| | | 'nothing': None, |
| | | 'html_quote': html_quote, |
| | |
| | | 'bool': bool, |
| | | 'SkipTemplate': SkipTemplate, |
| | | 'skip_template': skip_template, |
| | | } |
| | | |
| | | } |
| | |
| | | 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): |
| | |
| | | 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 |
| | |
| | | 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: |
| | |
| | | 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. |
| | | """ |
| | |
| | | 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 |
| | |
| | | # 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): |
| | | |
| | | def __getitem__(self, item): |
| | | options = item.split('|') |
| | | for op in options[:-1]: |
| | |
| | | else: |
| | | return str(value) |
| | | |
| | | |
| | | def eval_with_catch(expr, vars): |
| | | try: |
| | | return eval(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) |
| | |
| | | args = [info] |
| | | exc.args = tuple(args) |
| | | return |
| | | |
| | | |
| | |
| | | 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: |
| | |
| | | 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) |
| | |
| | | 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) |
| | | |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | root_factory=root_factory, |
| | | ) |
| | | |
| | | |
| | | class AppEnvironment(dict): |
| | | def __enter__(self): |
| | | return self |
| | |
| | | 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 |
| | |
| | | import plaster |
| | | |
| | | |
| | | def parse_vars(args): |
| | | """ |
| | | Given variables like ``['a=b', 'c=d']`` turns it into ``{'a': |
| | |
| | | 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. |
| | |
| | | """, |
| | | 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") |
| | | |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | |
| | | 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 |
| | |
| | | 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) |
| | |
| | | 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:]) |
| | |
| | | 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() |
| | |
| | | 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) |
| | |
| | | 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 = """\ |
| | |
| | | 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', |
| | |
| | | ), |
| | | ) |
| | | 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 |
| | |
| | | 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) |
| | | |
| | |
| | | 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() |
| | |
| | | |
| | | 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, |
| | |
| | | '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 |
| | |
| | | self.out(response.body) |
| | | return 0 |
| | | |
| | | if __name__ == '__main__': # pragma: no cover |
| | | |
| | | if __name__ == '__main__': # pragma: no cover |
| | | sys.exit(main() or 0) |
| | |
| | | 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 |
| | |
| | | # 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 |
| | |
| | | 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: |
| | |
| | | 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'] |
| | |
| | | |
| | | 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 |
| | | |
| | |
| | | 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( |
| | | '-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( |
| | | '-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): |
| | |
| | | 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) |
| | |
| | | |
| | | def _get_mapper(self, registry): |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator(registry=registry) |
| | | return config.get_routes_mapper() |
| | | |
| | |
| | | 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 |
| | | |
| | |
| | | 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 |
| | |
| | | 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 |
| | | |
| | |
| | | |
| | | 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() |
| | |
| | | '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 |
| | | |
| | |
| | | # 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) |
| | |
| | | |
| | | # 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 |
| | | |
| | |
| | | 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 |
| | |
| | | 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() |
| | |
| | | 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() |
| | |
| | | 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 = {} |
| | |
| | | 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) |
| | | |
| | |
| | | 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) |
| | |
| | | # 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) |
| | |
| | | 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: |
| | |
| | | return shell |
| | | |
| | | |
| | | if __name__ == '__main__': # pragma: no cover |
| | | if __name__ == '__main__': # pragma: no cover |
| | | sys.exit(main() or 0) |
| | |
| | | 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 = """\ |
| | |
| | | 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 |
| | |
| | | |
| | | 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) |
| | | |
| | |
| | | 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('') |
| | |
| | | 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) |
| | |
| | | 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 = """\ |
| | |
| | | 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'] |
| | |
| | | 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 |
| | | |
| | |
| | | |
| | | @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] |
| | |
| | | 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 |
| | |
| | | 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: |
| | |
| | | # 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: |
| | |
| | | env['closer']() |
| | | return 0 |
| | | |
| | | if __name__ == '__main__': # pragma: no cover |
| | | |
| | | if __name__ == '__main__': # pragma: no cover |
| | | sys.exit(main() or 0) |
| | |
| | | ISecuredView, |
| | | IView, |
| | | IViewClassifier, |
| | | ) |
| | | ) |
| | | |
| | | from pyramid.compat import map_ |
| | | from pyramid.threadlocal import get_current_registry |
| | |
| | | Authenticated = 'system.Authenticated' |
| | | Allow = 'Allow' |
| | | Deny = 'Deny' |
| | | |
| | | |
| | | class AllPermissionsList(object): |
| | | """ Stand in 'permission list' to represent all permissions """ |
| | |
| | | def __eq__(self, other): |
| | | return isinstance(other, self.__class__) |
| | | |
| | | |
| | | ALL_PERMISSIONS = AllPermissionsList() |
| | | DENY_ALL = (Deny, Everyone, ALL_PERMISSIONS) |
| | | |
| | | NO_PERMISSION_REQUIRED = '__no_permission_required__' |
| | | |
| | | |
| | | def _get_registry(request): |
| | | try: |
| | | reg = request.registry |
| | | except AttributeError: |
| | | reg = get_current_registry() # b/c |
| | | reg = get_current_registry() # b/c |
| | | return reg |
| | | |
| | | |
| | | def _get_authentication_policy(request): |
| | | registry = _get_registry(request) |
| | | return registry.queryUtility(IAuthenticationPolicy) |
| | | |
| | | |
| | | def has_permission(permission, context, request): |
| | | """ |
| | | A function that calls :meth:`pyramid.request.Request.has_permission` |
| | | and returns its result. |
| | | |
| | | |
| | | .. deprecated:: 1.5 |
| | | Use :meth:`pyramid.request.Request.has_permission` instead. |
| | | |
| | | .. versionchanged:: 1.5a3 |
| | | If context is None, then attempt to use the context attribute of self; |
| | | if not set, then the AttributeError is propagated. |
| | | """ |
| | | """ |
| | | return request.has_permission(permission, context) |
| | | |
| | | |
| | | deprecated( |
| | | 'has_permission', |
| | | 'As of Pyramid 1.5 the "pyramid.security.has_permission" API is now ' |
| | | 'deprecated. It will be removed in Pyramid 1.8. Use the ' |
| | | '"has_permission" method of the Pyramid request instead.' |
| | | ) |
| | | '"has_permission" method of the Pyramid request instead.', |
| | | ) |
| | | |
| | | |
| | | def authenticated_userid(request): |
| | | """ |
| | | A function that returns the value of the property |
| | | :attr:`pyramid.request.Request.authenticated_userid`. |
| | | |
| | | |
| | | .. deprecated:: 1.5 |
| | | Use :attr:`pyramid.request.Request.authenticated_userid` instead. |
| | | """ |
| | | """ |
| | | return request.authenticated_userid |
| | | |
| | | |
| | | deprecated( |
| | | 'authenticated_userid', |
| | | 'As of Pyramid 1.5 the "pyramid.security.authenticated_userid" API is now ' |
| | | 'deprecated. It will be removed in Pyramid 1.8. Use the ' |
| | | '"authenticated_userid" attribute of the Pyramid request instead.' |
| | | ) |
| | | '"authenticated_userid" attribute of the Pyramid request instead.', |
| | | ) |
| | | |
| | | |
| | | def unauthenticated_userid(request): |
| | | """ |
| | | """ |
| | | A function that returns the value of the property |
| | | :attr:`pyramid.request.Request.unauthenticated_userid`. |
| | | |
| | | |
| | | .. deprecated:: 1.5 |
| | | Use :attr:`pyramid.request.Request.unauthenticated_userid` instead. |
| | | """ |
| | | """ |
| | | return request.unauthenticated_userid |
| | | |
| | | |
| | | deprecated( |
| | | 'unauthenticated_userid', |
| | | 'As of Pyramid 1.5 the "pyramid.security.unauthenticated_userid" API is ' |
| | | 'now deprecated. It will be removed in Pyramid 1.8. Use the ' |
| | | '"unauthenticated_userid" attribute of the Pyramid request instead.' |
| | | ) |
| | | '"unauthenticated_userid" attribute of the Pyramid request instead.', |
| | | ) |
| | | |
| | | |
| | | def effective_principals(request): |
| | | """ |
| | | A function that returns the value of the property |
| | | :attr:`pyramid.request.Request.effective_principals`. |
| | | |
| | | |
| | | .. deprecated:: 1.5 |
| | | Use :attr:`pyramid.request.Request.effective_principals` instead. |
| | | """ |
| | | """ |
| | | return request.effective_principals |
| | | |
| | | |
| | | deprecated( |
| | | 'effective_principals', |
| | | 'As of Pyramid 1.5 the "pyramid.security.effective_principals" API is ' |
| | | 'now deprecated. It will be removed in Pyramid 1.8. Use the ' |
| | | '"effective_principals" attribute of the Pyramid request instead.' |
| | | ) |
| | | '"effective_principals" attribute of the Pyramid request instead.', |
| | | ) |
| | | |
| | | |
| | | def remember(request, userid, **kw): |
| | | """ |
| | |
| | | return [] |
| | | return policy.remember(request, userid, **kw) |
| | | |
| | | |
| | | def forget(request): |
| | | """ |
| | | Return a sequence of header tuples (e.g. ``[('Set-Cookie', |
| | |
| | | |
| | | 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`` |
| | |
| | | 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 |
| | |
| | | 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) |
| | | |
| | | |
| | |
| | | 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): |
| | | """ |
| | |
| | | the deny. |
| | | |
| | | """ |
| | | |
| | | boolval = 0 |
| | | |
| | | |
| | | class Allowed(PermitsResult): |
| | | """ |
| | |
| | | the allow. |
| | | |
| | | """ |
| | | |
| | | boolval = 1 |
| | | |
| | | |
| | | class ACLPermitsResult(PermitsResult): |
| | | def __new__(cls, ace, acl, permission, principals, context): |
| | |
| | | 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 |
| | |
| | | inst.principals = principals |
| | | inst.context = context |
| | | return inst |
| | | |
| | | |
| | | class ACLDenied(ACLPermitsResult, Denied): |
| | | """ |
| | |
| | | |
| | | """ |
| | | |
| | | |
| | | class ACLAllowed(ACLPermitsResult, Allowed): |
| | | """ |
| | | An instance of ``ACLAllowed`` is a specialization of |
| | |
| | | |
| | | """ |
| | | |
| | | class AuthenticationAPIMixin(object): |
| | | |
| | | class AuthenticationAPIMixin(object): |
| | | def _get_authentication_policy(self): |
| | | reg = _get_registry(self) |
| | | return reg.queryUtility(IAuthenticationPolicy) |
| | |
| | | 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 |
| | |
| | | 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) |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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 ' |
| | | 'serialization, which is considered vulnerable to remote code execution ' |
| | | 'attacks.', |
| | | ) |
| | | |
| | | |
| | | def signed_deserialize(serialized, secret, hmac=hmac): |
| | | """ Deserialize the value returned from ``signed_serialize``. If |
| | |
| | | """ |
| | | # 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) |
| | |
| | | raise ValueError('Invalid signature') |
| | | |
| | | return pickle.loads(pickled) |
| | | |
| | | |
| | | deprecated( |
| | | 'signed_deserialize', |
| | |
| | | Defaults to :attr:`pickle.HIGHEST_PROTOCOL`. |
| | | |
| | | """ |
| | | |
| | | def __init__(self, protocol=pickle.HIGHEST_PROTOCOL): |
| | | self.protocol = protocol |
| | | |
| | |
| | | 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`, |
| | |
| | | _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 |
| | |
| | | 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) |
| | |
| | | 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, |
| | |
| | | secure=self._cookie_secure, |
| | | httponly=self._cookie_httponly, |
| | | samesite=self._cookie_samesite, |
| | | ) |
| | | ) |
| | | return True |
| | | |
| | | return CookieSession |
| | |
| | | cookie_on_exception=True, |
| | | signed_serialize=signed_serialize, |
| | | signed_deserialize=signed_deserialize, |
| | | ): |
| | | ): |
| | | """ |
| | | .. deprecated:: 1.5 |
| | | Use :func:`pyramid.session.SignedCookieSessionFactory` instead. |
| | |
| | | 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', |
| | |
| | | '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( |
| | |
| | | hashalg='sha512', |
| | | salt='pyramid.session.', |
| | | serializer=None, |
| | | ): |
| | | ): |
| | | """ |
| | | .. versionadded:: 1.5 |
| | | |
| | |
| | | ) |
| | | |
| | | signed_serializer = SignedSerializer( |
| | | secret, |
| | | salt, |
| | | hashalg, |
| | | serializer=serializer, |
| | | ) |
| | | secret, salt, hashalg, serializer=serializer |
| | | ) |
| | | |
| | | return BaseCookieSessionFactory( |
| | | signed_serializer, |
| | |
| | | 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.', |
| | | ) |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | import json |
| | | import os |
| | | |
| | | from os.path import ( |
| | | getmtime, |
| | | normcase, |
| | | normpath, |
| | | join, |
| | | isdir, |
| | | exists, |
| | | ) |
| | | from os.path import getmtime, normcase, normpath, join, isdir, exists |
| | | |
| | | from pkg_resources import ( |
| | | resource_exists, |
| | | resource_filename, |
| | | resource_isdir, |
| | | ) |
| | | from pkg_resources import resource_exists, resource_filename, resource_isdir |
| | | |
| | | from pyramid.asset import ( |
| | | abspath_from_asset_spec, |
| | | resolve_asset_spec, |
| | | ) |
| | | from pyramid.asset import abspath_from_asset_spec, resolve_asset_spec |
| | | |
| | | from pyramid.compat import ( |
| | | lru_cache, |
| | | text_, |
| | | ) |
| | | from pyramid.compat import lru_cache, text_ |
| | | |
| | | from pyramid.httpexceptions import ( |
| | | HTTPNotFound, |
| | | HTTPMovedPermanently, |
| | | ) |
| | | 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 |
| | |
| | | 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``). |
| | |
| | | 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))) |
| | |
| | | |
| | | 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 + '/' |
| | |
| | | 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): |
| | |
| | | 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): |
| | | """ |
| | |
| | | |
| | | .. versionadded:: 1.6 |
| | | """ |
| | | |
| | | def __init__(self, param='x'): |
| | | self.param = param |
| | | |
| | |
| | | else: |
| | | kw['_query'] = tuple(query) + ((self.param, token),) |
| | | return subpath, kw |
| | | |
| | | |
| | | class QueryStringConstantCacheBuster(QueryStringCacheBuster): |
| | | """ |
| | |
| | | |
| | | .. versionadded:: 1.6 |
| | | """ |
| | | |
| | | def __init__(self, token, param='x'): |
| | | super(QueryStringConstantCacheBuster, self).__init__(param=param) |
| | | self._token = token |
| | | |
| | | def tokenize(self, request, subpath, kw): |
| | | return self._token |
| | | |
| | | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | |
| | | _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 |
| | |
| | | def principals_allowed_by_permission(self, context, permission): |
| | | return self.effective_principals(None) |
| | | |
| | | |
| | | class DummyTemplateRenderer(object): |
| | | """ |
| | | An instance of this class is returned from |
| | |
| | | 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 |
| | |
| | | # 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): |
| | |
| | | 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 |
| | |
| | | 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 |
| | | |
| | |
| | | token = self.new_csrf_token() |
| | | return token |
| | | |
| | | |
| | | @implementer(IRequest) |
| | | class DummyRequest( |
| | | URLMethodsMixin, |
| | |
| | | AuthenticationAPIMixin, |
| | | AuthorizationAPIMixin, |
| | | ViewMethodsMixin, |
| | | ): |
| | | ): |
| | | """ A DummyRequest object (incompletely) imitates a :term:`request` object. |
| | | |
| | | The ``params``, ``environ``, ``headers``, ``path``, and |
| | |
| | | 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' |
| | |
| | | _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: |
| | |
| | | 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) |
| | | |
| | |
| | | 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. |
| | |
| | | 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: |
| | |
| | | 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 |
| | |
| | | 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() |
| | |
| | | # understand, let's not blow up |
| | | pass |
| | | |
| | | |
| | | def cleanUp(*arg, **kw): |
| | | """ An alias for :func:`pyramid.testing.setUp`. """ |
| | | package = kw.get('package', None) |
| | |
| | | package = caller_package() |
| | | kw['package'] = package |
| | | return setUp(*arg, **kw) |
| | | |
| | | |
| | | class DummyRendererFactory(object): |
| | | """ Registered by |
| | |
| | | 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): |
| | |
| | | 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 |
| | | |
| | | |
| | |
| | | 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): |
| | |
| | | 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 |
| | |
| | | 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: |
| | |
| | | |
| | | 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 |
| | |
| | | def push(self, info): |
| | | self.stack.append(info) |
| | | |
| | | set = push # b/c |
| | | set = push # b/c |
| | | |
| | | def pop(self): |
| | | if self.stack: |
| | |
| | | def clear(self): |
| | | self.stack[:] = [] |
| | | |
| | | |
| | | def defaults(): |
| | | return {'request': None, 'registry': global_registry} |
| | | |
| | | |
| | | manager = ThreadLocalManager(default=defaults) |
| | | |
| | | |
| | | 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. |
| | |
| | | """ |
| | | return manager.get()['registry'] |
| | | |
| | | |
| | | class RequestContext(object): |
| | | def __init__(self, request): |
| | | self.request = request |
| | |
| | | IRequestFactory, |
| | | ITraverser, |
| | | VH_ROOT_KEY, |
| | | ) |
| | | ) |
| | | |
| | | from pyramid.compat import ( |
| | | PY2, |
| | |
| | | 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`` |
| | |
| | | resource = location |
| | | break |
| | | return resource |
| | | |
| | | |
| | | def find_resource(resource, path): |
| | | """ Given a resource object and a string or tuple representing a 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): |
| | | """ |
| | |
| | | for location in lineage(resource): |
| | | if test(location): |
| | | return location |
| | | |
| | | |
| | | def resource_path(resource, *elements): |
| | | """ Return a string object representing the absolute physical path of the |
| | |
| | | # 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 |
| | |
| | | |
| | | 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) |
| | |
| | | traverser = ResourceTreeTraverser(resource) |
| | | |
| | | return traverser(request) |
| | | |
| | | |
| | | def resource_path_tuple(resource, *elements): |
| | | """ |
| | |
| | | The :term:`root` resource *must* have a ``__name__`` attribute with a |
| | | value of either ``None`` or the empty string for path tuples to be |
| | | generated properly. If the root resource has a non-null ``__name__`` |
| | | attribute, its name will be the first element in the generated path tuple |
| | | rather than the empty string. |
| | | attribute, its name will be the first element in the generated path |
| | | tuple rather than the empty string. |
| | | """ |
| | | return tuple(_resource_path_list(resource, *elements)) |
| | | |
| | | |
| | | model_path_tuple = resource_path_tuple # b/w compat (forever) |
| | | |
| | | |
| | | def _resource_path_list(resource, *elements): |
| | | """ Implementation detail shared by resource_path and resource_path_tuple""" |
| | | """ Implementation detail shared by resource_path and |
| | | resource_path_tuple""" |
| | | path = [loc.__name__ or '' for loc in lineage(resource)] |
| | | path.reverse() |
| | | path.extend(elements) |
| | | return path |
| | | |
| | | _model_path_list = _resource_path_list # b/w compat, not an API |
| | | |
| | | _model_path_list = _resource_path_list # b/w compat, not an API |
| | | |
| | | |
| | | def virtual_root(resource, request): |
| | | """ |
| | |
| | | |
| | | 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: |
| | | return request.root |
| | | except AttributeError: |
| | | return find_root(resource) |
| | | |
| | | |
| | | def traversal_path(path): |
| | | """ Variant of :func:`pyramid.traversal.traversal_path_info` suitable for |
| | |
| | | # 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): |
| | |
| | | |
| | | This function does not generate the same type of tuples that |
| | | :func:`pyramid.traversal.resource_path_tuple` does. In particular, the |
| | | leading empty string is not present in the tuple it returns, unlike tuples |
| | | returned by :func:`pyramid.traversal.resource_path_tuple`. As a result, |
| | | tuples generated by ``traversal_path`` are not resolveable by the |
| | | :func:`pyramid.traversal.find_resource` API. ``traversal_path`` is a |
| | | function mostly used by the internals of :app:`Pyramid` and by people |
| | | leading empty string is not present in the tuple it returns, unlike |
| | | tuples returned by :func:`pyramid.traversal.resource_path_tuple`. As a |
| | | result, tuples generated by ``traversal_path`` are not resolveable by |
| | | the :func:`pyramid.traversal.find_resource` API. ``traversal_path`` is |
| | | a function mostly used by the internals of :app:`Pyramid` and by people |
| | | writing their own traversal machinery, as opposed to users writing |
| | | applications in :app:`Pyramid`. |
| | | """ |
| | | try: |
| | | path = decode_path_info(path) # result will be Unicode |
| | | path = decode_path_info(path) # result will be Unicode |
| | | except UnicodeDecodeError as e: |
| | | raise URLDecodeError(e.encoding, e.object, e.start, e.end, e.reason) |
| | | return split_path_info(path) # result will be tuple of Unicode |
| | | return split_path_info(path) # result will be tuple of Unicode |
| | | |
| | | |
| | | @lru_cache(1000) |
| | | def split_path_info(path): |
| | |
| | | else: |
| | | clean.append(segment) |
| | | return tuple(clean) |
| | | |
| | | |
| | | _segment_cache = {} |
| | | |
| | |
| | | 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) |
| | |
| | | # 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 |
| | |
| | | _segment_cache[(segment, safe)] = result |
| | | return result |
| | | |
| | | |
| | | slash = text_('/') |
| | | |
| | | |
| | | @implementer(ITraverser) |
| | | class ResourceTreeTraverser(object): |
| | |
| | | every resource in the tree supplies a ``__name__`` and |
| | | ``__parent__`` attribute (ie. every resource in the tree is |
| | | :term:`location` aware) .""" |
| | | |
| | | |
| | | VH_ROOT_KEY = VH_ROOT_KEY |
| | | VIEW_SELECTOR = '@@' |
| | |
| | | # 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 = () |
| | |
| | | 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 = () |
| | |
| | | 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): |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | reraise(*exc_info) |
| | | |
| | | return response |
| | | |
| | | |
| | | def excview_tween_factory(handler, registry): |
| | | """ A :term:`tween` factory which produces a tween that catches an |
| | |
| | | |
| | | return excview_tween |
| | | |
| | | |
| | | MAIN = 'MAIN' |
| | | INGRESS = 'INGRESS' |
| | | EXCVIEW = 'pyramid.tweens.excview_tween_factory' |
| | |
| | | |
| | | 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 |
| | | |
| | |
| | | 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): |
| | | """ |
| | |
| | | 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 |
| | |
| | | frag = '#' + url_quote(anchor, ANCHOR_SAFE) |
| | | |
| | | return app_url, qs, frag |
| | | |
| | | |
| | | class URLMethodsMixin(object): |
| | | """ Request methods mixin for BaseRequest having to do with URL |
| | |
| | | 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) |
| | | |
| | |
| | | |
| | | Python data structures that are passed as ``_query`` which are |
| | | sequences or dictionaries are turned into a string under the same |
| | | rules as when run through :func:`urllib.urlencode` with the ``doseq`` |
| | | argument equal to ``True``. This means that sequences can be passed |
| | | as values, and a k=v pair will be placed into the query string for |
| | | each value. |
| | | rules as when run through :func:`urllib.urlencode` with the |
| | | ``doseq`` argument equal to ``True``. This means that sequences can |
| | | be passed as values, and a k=v pair will be placed into the query |
| | | string for each value. |
| | | |
| | | If a keyword argument ``_anchor`` is present, its string |
| | | representation will be quoted per :rfc:`3986#section-3.5` and used as |
| | |
| | | ``_host='foo.com'``, and the URL that would have been generated |
| | | without the host replacement is ``http://example.com/a``, the result |
| | | will be ``http://foo.com/a``. |
| | | |
| | | |
| | | Note that if ``_scheme`` is passed as ``https``, and ``_port`` is not |
| | | passed, the ``_port`` value is assumed to have been passed as |
| | | ``443``. Likewise, if ``_scheme`` is passed as ``http`` and |
| | |
| | | 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) |
| | | |
| | |
| | | |
| | | 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) |
| | |
| | | |
| | | Python data structures that are passed as ``query`` which are |
| | | sequences or dictionaries are turned into a string under the same |
| | | rules as when run through :func:`urllib.urlencode` with the ``doseq`` |
| | | argument equal to ``True``. This means that sequences can be passed |
| | | as values, and a k=v pair will be placed into the query string for |
| | | each value. |
| | | rules as when run through :func:`urllib.urlencode` with the |
| | | ``doseq`` argument equal to ``True``. This means that sequences can |
| | | be passed as values, and a k=v pair will be placed into the query |
| | | string for each value. |
| | | |
| | | If a keyword argument ``anchor`` is present, its string |
| | | representation will be used as a named anchor in the generated URL |
| | |
| | | ``host='foo.com'``, and the URL that would have been generated |
| | | without the host replacement is ``http://example.com/a``, the result |
| | | will be ``http://foo.com/a``. |
| | | |
| | | |
| | | If ``scheme`` is passed as ``https``, and an explicit ``port`` is not |
| | | passed, the ``port`` value is assumed to have been passed as ``443``. |
| | | Likewise, if ``scheme`` is passed as ``http`` and ``port`` is not |
| | |
| | | If the ``resource`` passed in has a ``__resource_url__`` method, it |
| | | will be used to generate the URL (scheme, host, port, path) for the |
| | | base resource which is operated upon by this function. |
| | | |
| | | |
| | | .. seealso:: |
| | | |
| | | See also :ref:`overriding_resource_url_generation`. |
| | | |
| | | |
| | | If ``route_name`` is passed, this function will delegate its URL |
| | | production to the ``route_url`` function. Calling |
| | | ``resource_url(someresource, 'element1', 'element2', query={'a':1}, |
| | |
| | | is passed, the ``__resource_url__`` method of the resource passed is |
| | | ignored unconditionally. This feature is incompatible with |
| | | resources which generate their own URLs. |
| | | |
| | | |
| | | .. note:: |
| | | |
| | | If the :term:`resource` used is the result of a :term:`traversal`, it |
| | | must be :term:`location`-aware. The resource can also be the context |
| | | of a :term:`URL dispatch`; contexts found this way do not need to be |
| | | location-aware. |
| | | If the :term:`resource` used is the result of a :term:`traversal`, |
| | | it must be :term:`location`-aware. The resource can also be the |
| | | context of a :term:`URL dispatch`; contexts found this way do not |
| | | need to be location-aware. |
| | | |
| | | .. note:: |
| | | |
| | | If a 'virtual root path' is present in the request environment (the |
| | | value of the WSGI environ key ``HTTP_X_VHM_ROOT``), and the resource |
| | | was obtained via :term:`traversal`, the URL path will not include the |
| | | virtual root prefix (it will be stripped off the left hand side of |
| | | the generated URL). |
| | | was obtained via :term:`traversal`, the URL path will not include |
| | | the virtual root prefix (it will be stripped off the left hand side |
| | | of the generated URL). |
| | | |
| | | .. note:: |
| | | |
| | |
| | | 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: |
| | |
| | | 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 |
| | |
| | | |
| | | 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): |
| | | """ |
| | |
| | | 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: |
| | |
| | | """ |
| | | 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 |
| | |
| | | See :meth:`pyramid.request.Request.route_path` for more information. |
| | | """ |
| | | return request.route_path(route_name, *elements, **kw) |
| | | |
| | | |
| | | 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): |
| | |
| | | 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 |
| | |
| | | information. |
| | | """ |
| | | return request.current_route_url(*elements, **kw) |
| | | |
| | | |
| | | 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] |
| | | ) |
| | |
| | | import re |
| | | from zope.interface import implementer |
| | | |
| | | from pyramid.interfaces import ( |
| | | IRoutesMapper, |
| | | IRoute, |
| | | ) |
| | | from pyramid.interfaces import IRoutesMapper, IRoute |
| | | |
| | | from pyramid.compat import ( |
| | | PY2, |
| | |
| | | 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 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: |
| | |
| | | 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*)') |
| | |
| | | # (\{[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 |
| | |
| | | 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) |
| | |
| | | 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, |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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) |
| | |
| | | # 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 |
| | |
| | | from contextlib import contextmanager |
| | | import functools |
| | | |
| | | try: |
| | | # py2.7.7+ and py3.3+ have native comparison support |
| | | from hmac import compare_digest |
| | |
| | | import inspect |
| | | import weakref |
| | | |
| | | from pyramid.exceptions import ( |
| | | ConfigurationError, |
| | | CyclicDependencyError, |
| | | ) |
| | | from pyramid.exceptions import ConfigurationError, CyclicDependencyError |
| | | |
| | | from pyramid.compat import ( |
| | | getargspec, |
| | |
| | | bytes_, |
| | | text_, |
| | | PY2, |
| | | native_ |
| | | ) |
| | | native_, |
| | | ) |
| | | |
| | | from pyramid.path import DottedNameResolver as _DottedNameResolver |
| | | |
| | |
| | | |
| | | |
| | | 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): |
| | |
| | | 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. |
| | |
| | | per-property and then invoking :meth:`.apply` on target objects. |
| | | |
| | | """ |
| | | |
| | | def __init__(self): |
| | | self.properties = {} |
| | | |
| | |
| | | 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) |
| | |
| | | """ Apply all configured properties to the ``target`` instance.""" |
| | | if self.properties: |
| | | self.apply_properties(target, self.properties) |
| | | |
| | | |
| | | class InstancePropertyMixin(object): |
| | | """ Mixin that will allow an instance to add properties at |
| | |
| | | 1 |
| | | """ |
| | | InstancePropertyHelper.set_property( |
| | | self, callable, name=name, reify=reify) |
| | | self, callable, name=name, reify=reify |
| | | ) |
| | | |
| | | |
| | | class WeakOrderedSet(object): |
| | | """ Maintain a set of items. |
| | |
| | | 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. |
| | | |
| | |
| | | for a, b in zip(left, right): |
| | | invalid_bits += a != b |
| | | return invalid_bits != 0 |
| | | |
| | | |
| | | def object_description(object): |
| | | """ Produce a human-consumable text description of ``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__) |
| | |
| | | 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): |
| | |
| | | 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() |
| | |
| | | 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 |
| | |
| | | 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)] |
| | |
| | | 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) |
| | |
| | | |
| | | 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) |
| | |
| | | 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] |
| | |
| | | ) |
| | | raise ConfigurationError(msg % name) |
| | | |
| | | |
| | | @contextmanager |
| | | def hide_attrs(obj, *attrs): |
| | | """ |
| | |
| | | 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): |
| | |
| | | @functools.wraps(fn) |
| | | def wrapper(*a, **kw): |
| | | yield fn(*a, **kw) |
| | | |
| | | return wrapper |
| | | |
| | | |
| | |
| | | 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 |
| | |
| | | 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): |
| | |
| | | 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`` |
| | |
| | | if iterable is None: |
| | | return None |
| | | return b''.join(iterable) |
| | | |
| | | |
| | | class view_config(object): |
| | | """ A function, class or method :term:`decorator` which allows a |
| | |
| | | |
| | | See the :py:func:`venusian.attach` function in Venusian for more |
| | | information about the ``_depth`` and ``_category`` arguments. |
| | | |
| | | |
| | | .. seealso:: |
| | | |
| | | |
| | | See also :ref:`mapping_views_using_a_decorator_section` for |
| | | details about using :class:`pyramid.view.view_config`. |
| | | |
| | | .. warning:: |
| | | |
| | | |
| | | ``view_config`` will work ONLY on module top level members |
| | | because of the limitation of ``venusian.Scanner.scan``. |
| | | |
| | | """ |
| | | venusian = venusian # for testing injection |
| | | |
| | | venusian = venusian # for testing injection |
| | | |
| | | def __init__(self, **settings): |
| | | if 'for_' in settings: |
| | | if settings.get('context') is None: |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | def __call__(self, wrapped): |
| | | wrapped.__view_defaults__ = self.__dict__.copy() |
| | | return wrapped |
| | | |
| | | |
| | | class AppendSlashNotFoundViewFactory(object): |
| | | """ There can only be one :term:`Not Found view` in any |
| | |
| | | .. 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 |
| | |
| | | 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__ = """\ |
| | |
| | | .. deprecated:: 1.3 |
| | | |
| | | """ |
| | | |
| | | |
| | | class notfound_view_config(object): |
| | | """ |
| | |
| | | return HTTPNotFound('not found') |
| | | |
| | | The above means that a redirect to a slash-appended route will be |
| | | attempted, but instead of :class:`~pyramid.httpexceptions.HTTPTemporaryRedirect` |
| | | attempted, but instead of |
| | | :class:`~pyramid.httpexceptions.HTTPTemporaryRedirect` |
| | | being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will |
| | | be used` for the redirect response if a slash-appended route is found. |
| | | |
| | |
| | | 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 |
| | |
| | | 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): |
| | | """ |
| | |
| | | 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 |
| | |
| | | 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): |
| | | """ |
| | |
| | | Added the ``_depth`` and ``_category`` arguments. |
| | | |
| | | """ |
| | | |
| | | venusian = venusian |
| | | |
| | | def __init__(self, *args, **settings): |
| | |
| | | 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 |
| | |
| | | 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, |
| | |
| | | view_name, |
| | | view_types=None, |
| | | view_classifier=None, |
| | | ): |
| | | ): |
| | | if view_types is None: |
| | | view_types = (IView, ISecuredView, IMultiView) |
| | | if view_classifier is None: |
| | |
| | | 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) |
| | |
| | | |
| | | return views |
| | | |
| | | |
| | | def _call_view( |
| | | registry, |
| | | request, |
| | |
| | | view_classifier=None, |
| | | secure=True, |
| | | request_iface=None, |
| | | ): |
| | | ): |
| | | if request_iface is None: |
| | | request_iface = getattr(request, 'request_iface', IRequest) |
| | | view_callables = _find_views( |
| | |
| | | view_name, |
| | | view_types=view_types, |
| | | view_classifier=view_classifier, |
| | | ) |
| | | ) |
| | | |
| | | pme = None |
| | | response = None |
| | |
| | | # 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 |
| | |
| | | |
| | | 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: |
| | |
| | | view_classifier=IExceptionViewClassifier, |
| | | secure=secure, |
| | | request_iface=request_iface.combined, |
| | | ) |
| | | ) |
| | | except Exception: |
| | | if reraise: |
| | | reraise_(*exc_info) |
| | |
| | | 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 ( |
| | |
| | | IResponse, |
| | | IViewMapper, |
| | | IViewMapperFactory, |
| | | ) |
| | | |
| | | from pyramid.compat import ( |
| | | is_bound_method, |
| | | is_unbound_method, |
| | | ) |
| | | |
| | | from pyramid.exceptions import ( |
| | | ConfigurationError, |
| | | ) |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | from pyramid.util import ( |
| | | object_description, |
| | | takes_one_arg, |
| | | ) |
| | | |
| | | from pyramid.compat import is_bound_method, is_unbound_method |
| | | |
| | | from pyramid.exceptions import ConfigurationError |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | from pyramid.util import object_description, takes_one_arg |
| | | from pyramid.view import render_view_to_response |
| | | from pyramid import renderers |
| | | |
| | |
| | | # 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) |
| | |
| | | |
| | | 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) |
| | |
| | | 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): |
| | |
| | | # 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 |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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): |
| | |
| | | def _attr_view(context, request): |
| | | response = getattr(view, self.attr)(context, request) |
| | | return response |
| | | |
| | | return _attr_view |
| | | |
| | | |
| | |
| | | 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: |
| | |
| | | |
| | | # 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: |
| | | pass |
| | | |
| | | return wrapper |
| | | |
| | | |
| | | def mapped_view(view, info): |
| | | mapper = info.options.get('mapper') |
| | |
| | | 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): |
| | |
| | | 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') |
| | |
| | | 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 |
| | | wrapped_view.__permission__ = permission |
| | | |
| | | return wrapped_view |
| | | |
| | | |
| | | def _authdebug_view(view, info): |
| | | wrapped_view = view |
| | |
| | | return view |
| | | |
| | | if settings and settings.get('debug_authorization', False): |
| | | |
| | | def authdebug_view(context, request): |
| | | view_name = getattr(request, 'view_name', None) |
| | | |
| | |
| | | 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 |
| | |
| | | # 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)) |
| | | |
| | |
| | | |
| | | 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 |
| | |
| | | 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: |
| | |
| | | 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') |
| | |
| | | return view |
| | | return decorator(view) |
| | | |
| | | |
| | | decorated_view.options = ('decorator',) |
| | | |
| | | |
| | | def csrf_view(view, info): |
| | | explicit_val = info.options.get('require_csrf') |
| | |
| | | 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' |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | |
| | | def dummy_extend(*args): |
| | | """used to test Configurator.extend""" |
| | |
| | | from webob import Response |
| | | |
| | | |
| | | def rdf_view(request): |
| | | """ """ |
| | | return Response('rdf') |
| | | |
| | | |
| | | def juri_view(request): |
| | | """ """ |
| | | return Response('juri') |
| | | |
| | | |
| | | def includeme(config): |
| | | config.add_route('rdf', 'licenses/:license_code/:license_version/rdf') |
| | | config.add_route('juri', |
| | | 'licenses/:license_code/:license_version/:jurisdiction') |
| | | config.add_route( |
| | | 'juri', 'licenses/:license_code/:license_version/:jurisdiction' |
| | | ) |
| | | config.add_view(rdf_view, route_name='rdf') |
| | | config.add_view(juri_view, route_name='juri') |
| | |
| | | from pyramid.authentication import AuthTktAuthenticationPolicy |
| | | from pyramid.authorization import ACLAuthorizationPolicy |
| | | |
| | | |
| | | def aview(request): |
| | | return Response('a view') |
| | | |
| | | |
| | | def routeview(request): |
| | | return Response('route view') |
| | | |
| | | |
| | | def protectedview(request): |
| | | return Response('protected view') |
| | | |
| | | |
| | | def includeme(config): |
| | | # purposely sorta-randomly ordered (route comes after view naming it, |
| | |
| | | config.add_view(protectedview, name='protected', permission='view') |
| | | config.add_view(routeview, route_name='aroute') |
| | | config.add_route('aroute', '/route') |
| | | config.set_authentication_policy(AuthTktAuthenticationPolicy( |
| | | 'seekri1t', hashalg='sha512')) |
| | | config.set_authentication_policy( |
| | | AuthTktAuthenticationPolicy('seekri1t', hashalg='sha512') |
| | | ) |
| | | config.set_authorization_policy(ACLAuthorizationPolicy()) |
| | | config.include('tests.pkgs.conflictapp.included') |
| | |
| | | from webob import Response |
| | | |
| | | def bview(request): return Response('b view') |
| | | |
| | | def bview(request): # pragma: no cover |
| | | return Response('b view') |
| | | |
| | | |
| | | def includeme(config): |
| | | config.add_view(bview) |
| | |
| | | from pyramid.security import NO_PERMISSION_REQUIRED |
| | | from pyramid.view import view_config |
| | | |
| | | |
| | | @view_config(name='x') |
| | | def x_view(request): # pragma: no cover |
| | | return Response('this is private!') |
| | | def x_view(request): # pragma: no cover |
| | | return Response('this is private!') |
| | | |
| | | |
| | | @view_config(name='y', permission='private2') |
| | | def y_view(request): # pragma: no cover |
| | | return Response('this is private too!') |
| | | |
| | | def y_view(request): # pragma: no cover |
| | | return Response('this is private too!') |
| | | |
| | | |
| | | @view_config(name='z', permission=NO_PERMISSION_REQUIRED) |
| | | def z_view(request): |
| | | return Response('this is public') |
| | | return Response('this is public') |
| | | |
| | | |
| | | def includeme(config): |
| | | from pyramid.authorization import ACLAuthorizationPolicy |
| | | from pyramid.authentication import AuthTktAuthenticationPolicy |
| | | authn_policy = AuthTktAuthenticationPolicy('seekt1t', hashalg='sha512') |
| | | authz_policy = ACLAuthorizationPolicy() |
| | | config.scan('tests.pkgs.defpermbugapp') |
| | | config._set_authentication_policy(authn_policy) |
| | | config._set_authorization_policy(authz_policy) |
| | | config.set_default_permission('private') |
| | | |
| | | from pyramid.authorization import ACLAuthorizationPolicy |
| | | from pyramid.authentication import AuthTktAuthenticationPolicy |
| | | |
| | | authn_policy = AuthTktAuthenticationPolicy('seekt1t', hashalg='sha512') |
| | | authz_policy = ACLAuthorizationPolicy() |
| | | config.scan('tests.pkgs.defpermbugapp') |
| | | config._set_authentication_policy(authn_policy) |
| | | config._set_authorization_policy(authz_policy) |
| | | config.set_default_permission('private') |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.events import subscriber |
| | | |
| | | |
| | | class Yup(object): |
| | | def __init__(self, val, config): |
| | | self.val = val |
| | |
| | | def __call__(self, event): |
| | | return getattr(event.response, 'yup', False) |
| | | |
| | | |
| | | class Foo(object): |
| | | def __init__(self, response): |
| | | self.response = response |
| | | |
| | | |
| | | class Bar(object): |
| | | pass |
| | | |
| | | |
| | | @subscriber(Foo) |
| | | def foo(event): |
| | | event.response.text += 'foo ' |
| | | |
| | | |
| | | @subscriber(Foo, yup=True) |
| | | def fooyup(event): |
| | | event.response.text += 'fooyup ' |
| | | |
| | | |
| | | |
| | | @subscriber([Foo, Bar]) |
| | | def foobar(event): |
| | | event.response.text += 'foobar ' |
| | | |
| | | |
| | | @subscriber([Foo, Bar]) |
| | | def foobar2(event, context): |
| | | event.response.text += 'foobar2 ' |
| | | |
| | | |
| | | @subscriber([Foo, Bar], yup=True) |
| | | def foobaryup(event): |
| | | event.response.text += 'foobaryup ' |
| | | |
| | | |
| | | @subscriber([Foo, Bar], yup=True) |
| | | def foobaryup2(event, context): |
| | | event.response.text += 'foobaryup2 ' |
| | | |
| | | |
| | | @view_config(name='sendfoo') |
| | | def sendfoo(request): |
| | |
| | | request.registry.notify(Foo(response)) |
| | | return response |
| | | |
| | | |
| | | @view_config(name='sendfoobar') |
| | | def sendfoobar(request): |
| | | response = request.response |
| | |
| | | request.registry.notify(Foo(response), Bar()) |
| | | return response |
| | | |
| | | |
| | | def includeme(config): |
| | | config.add_subscriber_predicate('yup', Yup) |
| | | config.scan('tests.pkgs.eventonly') |
| | | |
| | |
| | | from pyramid.httpexceptions import HTTPException |
| | | |
| | | |
| | | def includeme(config): |
| | | config.add_route('route_raise_exception', 'route_raise_exception') |
| | | config.add_route('route_raise_httpexception', 'route_raise_httpexception') |
| | | config.add_route('route_raise_exception2', 'route_raise_exception2', |
| | | factory='.models.route_factory') |
| | | config.add_route('route_raise_exception3', 'route_raise_exception3', |
| | | factory='.models.route_factory2') |
| | | config.add_route( |
| | | 'route_raise_exception2', |
| | | 'route_raise_exception2', |
| | | factory='.models.route_factory', |
| | | ) |
| | | config.add_route( |
| | | 'route_raise_exception3', |
| | | 'route_raise_exception3', |
| | | factory='.models.route_factory2', |
| | | ) |
| | | config.add_route('route_raise_exception4', 'route_raise_exception4') |
| | | config.add_view('.views.maybe') |
| | | config.add_view('.views.no', context='.models.NotAnException') |
| | | config.add_view('.views.yes', context=".models.AnException") |
| | | config.add_view('.views.raise_exception', name='raise_exception') |
| | | config.add_view('.views.raise_exception', |
| | | route_name='route_raise_exception') |
| | | config.add_view('.views.raise_exception', |
| | | route_name='route_raise_exception2') |
| | | config.add_view('.views.raise_exception', |
| | | route_name='route_raise_exception3') |
| | | config.add_view('.views.whoa', context='.models.AnException', |
| | | route_name='route_raise_exception3') |
| | | config.add_view('.views.raise_exception', |
| | | route_name='route_raise_exception4') |
| | | config.add_view('.views.whoa', context='.models.AnException', |
| | | route_name='route_raise_exception4') |
| | | config.add_view('.views.raise_httpexception', |
| | | route_name='route_raise_httpexception') |
| | | config.add_view( |
| | | '.views.raise_exception', route_name='route_raise_exception' |
| | | ) |
| | | config.add_view( |
| | | '.views.raise_exception', route_name='route_raise_exception2' |
| | | ) |
| | | config.add_view( |
| | | '.views.raise_exception', route_name='route_raise_exception3' |
| | | ) |
| | | config.add_view( |
| | | '.views.whoa', |
| | | context='.models.AnException', |
| | | route_name='route_raise_exception3', |
| | | ) |
| | | config.add_view( |
| | | '.views.raise_exception', route_name='route_raise_exception4' |
| | | ) |
| | | config.add_view( |
| | | '.views.whoa', |
| | | context='.models.AnException', |
| | | route_name='route_raise_exception4', |
| | | ) |
| | | config.add_view( |
| | | '.views.raise_httpexception', route_name='route_raise_httpexception' |
| | | ) |
| | | config.add_view('.views.catch_httpexception', context=HTTPException) |
| | | |
| | | |
| | |
| | | |
| | | class NotAnException(object): |
| | | pass |
| | | |
| | | |
| | | class AnException(Exception): |
| | | pass |
| | | |
| | | |
| | | class RouteContext(object): |
| | | pass |
| | | |
| | | |
| | | class RouteContext2(object): |
| | | pass |
| | | |
| | | |
| | | def route_factory(*arg): |
| | | return RouteContext() |
| | | |
| | | |
| | | def route_factory2(*arg): |
| | | return RouteContext2() |
| | |
| | | from .models import AnException |
| | | from pyramid.httpexceptions import HTTPBadRequest |
| | | |
| | | |
| | | def no(request): |
| | | return Response('no') |
| | | |
| | | |
| | | def yes(request): |
| | | return Response('yes') |
| | | |
| | | |
| | | |
| | | def maybe(request): |
| | | return Response('maybe') |
| | | |
| | | |
| | | def whoa(request): |
| | | return Response('whoa') |
| | | |
| | | |
| | | def raise_exception(request): |
| | | raise AnException() |
| | | |
| | | |
| | | def raise_httpexception(request): |
| | | raise HTTPBadRequest |
| | | |
| | | |
| | | def catch_httpexception(request): |
| | | return Response('caught') |
| | |
| | | config.add_view('.views.exception_view', context=RuntimeError) |
| | | config.add_view('.views.protected_view', name='protected.html') |
| | | config.add_view('.views.erroneous_view', name='error.html') |
| | | config.add_view('.views.fixture_view', name='dummyskin.html', |
| | | request_type='.views.IDummy') |
| | | config.add_view( |
| | | '.views.fixture_view', |
| | | name='dummyskin.html', |
| | | request_type='.views.IDummy', |
| | | ) |
| | | from .models import fixture, IFixture |
| | | |
| | | config.registry.registerUtility(fixture, IFixture) |
| | | config.add_view('.views.fixture_view', name='another.html') |
| | | |
| | | |
| | |
| | | from zope.interface import Interface |
| | | |
| | | |
| | | class IFixture(Interface): |
| | | pass |
| | | |
| | | |
| | | def fixture(): |
| | | """ """ |
| | | |
| | |
| | | from webob import Response |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | |
| | | |
| | | def fixture_view(context, request): |
| | | """ """ |
| | | return Response('fixture') |
| | | |
| | | |
| | | def erroneous_view(context, request): |
| | | """ """ |
| | | raise RuntimeError() |
| | | |
| | | |
| | | def exception_view(context, request): |
| | | """ """ |
| | | return Response('supressed') |
| | | |
| | | |
| | | def protected_view(context, request): |
| | | """ """ |
| | | raise HTTPForbidden() |
| | | |
| | | |
| | | class IDummy(Interface): |
| | | pass |
| | |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | from pyramid.compat import bytes_ |
| | | |
| | | def x_view(request): # pragma: no cover |
| | | return Response('this is private!') |
| | | |
| | | def x_view(request): # pragma: no cover |
| | | return Response('this is private!') |
| | | |
| | | |
| | | def forbidden_view(context, request): |
| | | msg = context.message |
| | | result = context.result |
| | | message = msg + '\n' + str(result) |
| | | resp = HTTPForbidden() |
| | | resp.body = bytes_(message) |
| | | return resp |
| | | msg = context.message |
| | | result = context.result |
| | | message = msg + '\n' + str(result) |
| | | resp = HTTPForbidden() |
| | | resp.body = bytes_(message) |
| | | return resp |
| | | |
| | | |
| | | def includeme(config): |
| | | from pyramid.authentication import AuthTktAuthenticationPolicy |
| | | from pyramid.authorization import ACLAuthorizationPolicy |
| | | authn_policy = AuthTktAuthenticationPolicy('seekr1t', hashalg='sha512') |
| | | authz_policy = ACLAuthorizationPolicy() |
| | | config._set_authentication_policy(authn_policy) |
| | | config._set_authorization_policy(authz_policy) |
| | | config.add_view(x_view, name='x', permission='private') |
| | | config.add_view(forbidden_view, context=HTTPForbidden) |
| | | from pyramid.authentication import AuthTktAuthenticationPolicy |
| | | from pyramid.authorization import ACLAuthorizationPolicy |
| | | |
| | | authn_policy = AuthTktAuthenticationPolicy('seekr1t', hashalg='sha512') |
| | | authz_policy = ACLAuthorizationPolicy() |
| | | config._set_authentication_policy(authn_policy) |
| | | config._set_authorization_policy(authz_policy) |
| | | config.add_view(x_view, name='x', permission='private') |
| | | config.add_view(forbidden_view, context=HTTPForbidden) |
| | |
| | | from pyramid.authentication import AuthTktAuthenticationPolicy |
| | | from pyramid.authorization import ACLAuthorizationPolicy |
| | | |
| | | |
| | | @forbidden_view_config(route_name='foo') |
| | | def foo_forbidden(request): # pragma: no cover |
| | | def foo_forbidden(request): # pragma: no cover |
| | | return Response('foo_forbidden') |
| | | |
| | | |
| | | @forbidden_view_config() |
| | | def forbidden(request): |
| | | return Response('generic_forbidden') |
| | | |
| | | |
| | | @view_config(route_name='foo') |
| | | def foo(request): # pragma: no cover |
| | | def foo(request): # pragma: no cover |
| | | return Response('OK foo') |
| | | |
| | | |
| | | @view_config(route_name='bar') |
| | | def bar(request): # pragma: no cover |
| | | def bar(request): # pragma: no cover |
| | | return Response('OK bar') |
| | | |
| | | |
| | | def includeme(config): |
| | | authn_policy = AuthTktAuthenticationPolicy('seekri1', hashalg='sha512') |
| | |
| | | config.add_route('foo', '/foo') |
| | | config.add_route('bar', '/bar') |
| | | config.scan('tests.pkgs.forbiddenview') |
| | | |
| | |
| | | def includeme(config): |
| | | # <!-- we want this view to "win" --> |
| | | config.add_route('route', 'abc') |
| | | config.add_view('.views.route_view', route_name='route') |
| | | # <!-- .. even though this one has a more specific context --> |
| | | config.add_view('.views.global_view', |
| | | context='pyramid.traversal.DefaultRootFactory') |
| | | config.add_view('.views.global2_view', |
| | | context='pyramid.traversal.DefaultRootFactory', |
| | | name='global2') |
| | | config.add_route('route2', 'def') |
| | | # <!-- we want this view to win for route2 even though global view with |
| | | # context is more specific --> |
| | | config.add_view('.views.route2_view', route_name='route2') |
| | | # <!-- we want this view to "win" --> |
| | | config.add_route('route', 'abc') |
| | | config.add_view('.views.route_view', route_name='route') |
| | | # <!-- .. even though this one has a more specific context --> |
| | | config.add_view( |
| | | '.views.global_view', context='pyramid.traversal.DefaultRootFactory' |
| | | ) |
| | | config.add_view( |
| | | '.views.global2_view', |
| | | context='pyramid.traversal.DefaultRootFactory', |
| | | name='global2', |
| | | ) |
| | | config.add_route('route2', 'def') |
| | | # <!-- we want this view to win for route2 even though global view with |
| | | # context is more specific --> |
| | | config.add_view('.views.route2_view', route_name='route2') |
| | | |
| | | # <!-- the global view should be found for this route --> |
| | | config.add_route('route3', 'ghi', use_global_views=True) |
| | | # <!-- the global view should not be found for this route --> |
| | | config.add_route('route4', 'jkl') |
| | | # <!-- the global view should not be found for this route (/global2) --> |
| | | config.add_route('route5', 'mno/*traverse') |
| | | # <!-- the global view should be found for this route (/global2) --> |
| | | config.add_route('route6', 'pqr/*traverse', use_global_views=True) |
| | | config.add_route('route7', 'error') |
| | | config.add_view('.views.erroneous_view', route_name='route7') |
| | | config.add_route('route8', 'error2') |
| | | config.add_view('.views.erroneous_view', route_name='route8') |
| | | # <!-- we want this view to "win" for route7 as exception view --> |
| | | config.add_view('.views.exception_view', context=RuntimeError) |
| | | # <!-- we want this view to "win" for route8 as exception view--> |
| | | config.add_view('.views.exception2_view', context=RuntimeError, |
| | | route_name='route8') |
| | | config.add_route('route9', 'error_sub') |
| | | config.add_view('.views.erroneous_sub_view', route_name='route9') |
| | | # <!-- we want this view to "win" for route9 as exception view... --> |
| | | config.add_view('.views.exception2_view', context='.views.SuperException', |
| | | route_name='route9') |
| | | # <!-- ...even if we have more context-specialized view for exception --> |
| | | config.add_view('.views.exception_view', context='.views.SubException') |
| | | # <!-- the global view should be found for this route --> |
| | | config.add_route('route3', 'ghi', use_global_views=True) |
| | | # <!-- the global view should not be found for this route --> |
| | | config.add_route('route4', 'jkl') |
| | | # <!-- the global view should not be found for this route (/global2) --> |
| | | config.add_route('route5', 'mno/*traverse') |
| | | # <!-- the global view should be found for this route (/global2) --> |
| | | config.add_route('route6', 'pqr/*traverse', use_global_views=True) |
| | | config.add_route('route7', 'error') |
| | | config.add_view('.views.erroneous_view', route_name='route7') |
| | | config.add_route('route8', 'error2') |
| | | config.add_view('.views.erroneous_view', route_name='route8') |
| | | # <!-- we want this view to "win" for route7 as exception view --> |
| | | config.add_view('.views.exception_view', context=RuntimeError) |
| | | # <!-- we want this view to "win" for route8 as exception view--> |
| | | config.add_view( |
| | | '.views.exception2_view', context=RuntimeError, route_name='route8' |
| | | ) |
| | | config.add_route('route9', 'error_sub') |
| | | config.add_view('.views.erroneous_sub_view', route_name='route9') |
| | | # <!-- we want this view to "win" for route9 as exception view... --> |
| | | config.add_view( |
| | | '.views.exception2_view', |
| | | context='.views.SuperException', |
| | | route_name='route9', |
| | | ) |
| | | # <!-- ...even if we have more context-specialized view for exception --> |
| | | config.add_view('.views.exception_view', context='.views.SubException') |
| | |
| | | from webob import Response |
| | | |
| | | |
| | | def route_view(request): |
| | | """ """ |
| | | return Response('route') |
| | | |
| | | |
| | | def global_view(request): |
| | | """ """ |
| | | return Response('global') |
| | | |
| | | |
| | | def global2_view(request): |
| | | """ """ |
| | | return Response('global2') |
| | | |
| | | |
| | | def route2_view(request): |
| | | """ """ |
| | | return Response('route2') |
| | | |
| | | |
| | | def exception_view(request): |
| | | """ """ |
| | | return Response('supressed') |
| | | |
| | | |
| | | def exception2_view(request): |
| | | """ """ |
| | | return Response('supressed2') |
| | | |
| | | |
| | | def erroneous_view(request): |
| | | """ """ |
| | | raise RuntimeError() |
| | | |
| | | |
| | | def erroneous_sub_view(request): |
| | | """ """ |
| | | raise SubException() |
| | | |
| | | |
| | | class SuperException(Exception): |
| | | """ """ |
| | | |
| | | |
| | | class SubException(SuperException): |
| | | """ """ |
| | |
| | | from pyramid.response import Response |
| | | |
| | | |
| | | def aview(request): |
| | | return Response('root') |
| | | |
| | | |
| | | def configure(config): |
| | | config.add_view(aview) |
| | | config.include('tests.pkgs.includeapp1.two.configure') |
| | | config.commit() |
| | | |
| | |
| | | from pyramid.response import Response |
| | | |
| | | |
| | | def aview(request): |
| | | return Response('three') |
| | | |
| | | |
| | | def configure(config): |
| | | config.add_view(aview, name='three') |
| | | config.include('tests.pkgs.includeapp1.two.configure') # should not cycle |
| | | config.add_view(aview) # will be overridden by root when resolved |
| | | |
| | | config.include('tests.pkgs.includeapp1.two.configure') # should not cycle |
| | | config.add_view(aview) # will be overridden by root when resolved |
| | |
| | | from pyramid.response import Response |
| | | |
| | | |
| | | def aview(request): |
| | | return Response('two') |
| | | |
| | | |
| | | def configure(config): |
| | | config.add_view(aview, name='two') |
| | | config.include('tests.pkgs.includeapp1.three.configure') |
| | | config.add_view(aview) # will be overridden by root when resolved |
| | | config.add_view(aview) # will be overridden by root when resolved |
| | |
| | | from pyramid.view import notfound_view_config, view_config |
| | | from pyramid.response import Response |
| | | |
| | | |
| | | @notfound_view_config(route_name='foo', append_slash=True) |
| | | def foo_notfound(request): # pragma: no cover |
| | | def foo_notfound(request): # pragma: no cover |
| | | return Response('foo_notfound') |
| | | |
| | | |
| | | @notfound_view_config(route_name='baz') |
| | | def baz_notfound(request): |
| | | return Response('baz_notfound') |
| | | |
| | | |
| | | @notfound_view_config(append_slash=True) |
| | | def notfound(request): |
| | | return Response('generic_notfound') |
| | | |
| | | |
| | | @view_config(route_name='bar') |
| | | def bar(request): |
| | | return Response('OK bar') |
| | | |
| | | |
| | | @view_config(route_name='foo2') |
| | | def foo2(request): |
| | | return Response('OK foo2') |
| | | |
| | | |
| | | def includeme(config): |
| | | config.add_route('foo', '/foo') |
| | |
| | | config.add_route('bar', '/bar/') |
| | | config.add_route('baz', '/baz') |
| | | config.scan('tests.pkgs.notfoundview') |
| | | |
| | |
| | | from pyramid.security import view_execution_permitted |
| | | from pyramid.response import Response |
| | | |
| | | def x_view(request): # pragma: no cover |
| | | return Response('this is private!') |
| | | |
| | | def x_view(request): # pragma: no cover |
| | | return Response('this is private!') |
| | | |
| | | |
| | | def test(context, request): |
| | | # should return false |
| | | msg = 'Allow ./x? %s' % repr(view_execution_permitted( |
| | | context, request, 'x')) |
| | | return Response(escape(msg)) |
| | | msg = 'Allow ./x? %s' % repr( |
| | | view_execution_permitted(context, request, 'x') |
| | | ) |
| | | return Response(escape(msg)) |
| | | |
| | | |
| | | def includeme(config): |
| | | from pyramid.authentication import AuthTktAuthenticationPolicy |
| | | from pyramid.authorization import ACLAuthorizationPolicy |
| | | authn_policy = AuthTktAuthenticationPolicy('seekt1t', hashalg='sha512') |
| | | authz_policy = ACLAuthorizationPolicy() |
| | | config.set_authentication_policy(authn_policy) |
| | | config.set_authorization_policy(authz_policy) |
| | | config.add_view(test, name='test') |
| | | config.add_view(x_view, name='x', permission='private') |
| | | from pyramid.authentication import AuthTktAuthenticationPolicy |
| | | from pyramid.authorization import ACLAuthorizationPolicy |
| | | |
| | | authn_policy = AuthTktAuthenticationPolicy('seekt1t', hashalg='sha512') |
| | | authz_policy = ACLAuthorizationPolicy() |
| | | config.set_authentication_policy(authn_policy) |
| | | config.set_authorization_policy(authz_policy) |
| | | config.add_view(test, name='test') |
| | | config.add_view(x_view, name='x', permission='private') |
| | |
| | | from pyramid.view import view_config |
| | | |
| | | |
| | | @view_config(name='one', renderer='json') |
| | | def one(request): |
| | | return {'name':'One!'} |
| | | return {'name': 'One!'} |
| | | |
| | | |
| | | def includeme(config): |
| | | config.scan() |
| | | |
| | |
| | | from pyramid.view import view_config |
| | | |
| | | |
| | | @view_config(name='two', renderer='json') |
| | | def two(request): |
| | | return {'nameagain':'Two!'} |
| | | |
| | | return {'nameagain': 'Two!'} |
| | |
| | | def includeme(config): |
| | | config.add_route('gameactions_pet_get_pets', '/pet', |
| | | request_method='GET') |
| | | config.add_route('gameactions_pet_care_for_pet', '/pet', |
| | | request_method='POST') |
| | | config.add_view('.views.PetRESTView', |
| | | route_name='gameactions_pet_get_pets', |
| | | attr='GET', |
| | | permission='view', |
| | | renderer='json') |
| | | config.add_view('.views.PetRESTView', |
| | | route_name='gameactions_pet_care_for_pet', |
| | | attr='POST', |
| | | permission='view', |
| | | renderer='json') |
| | | config.add_route('gameactions_pet_get_pets', '/pet', request_method='GET') |
| | | config.add_route( |
| | | 'gameactions_pet_care_for_pet', '/pet', request_method='POST' |
| | | ) |
| | | config.add_view( |
| | | '.views.PetRESTView', |
| | | route_name='gameactions_pet_get_pets', |
| | | attr='GET', |
| | | permission='view', |
| | | renderer='json', |
| | | ) |
| | | config.add_view( |
| | | '.views.PetRESTView', |
| | | route_name='gameactions_pet_care_for_pet', |
| | | attr='POST', |
| | | permission='view', |
| | | renderer='json', |
| | | ) |
| | |
| | | from pyramid.response import Response |
| | | |
| | | |
| | | class BaseRESTView(object): |
| | | def __init__(self, context, request): |
| | | self.context = context |
| | | self.request = request |
| | | |
| | | |
| | | |
| | | class PetRESTView(BaseRESTView): |
| | | """ REST Controller to control action of an avatar """ |
| | | |
| | | def __init__(self, context, request): |
| | | super(PetRESTView, self).__init__(context, request) |
| | | |
| | | def GET(self): |
| | | return Response('gotten') |
| | | |
| | |
| | | import os |
| | | |
| | | |
| | | def includeme(config): |
| | | here = here = os.path.dirname(__file__) |
| | | here = here = os.path.dirname(__file__) |
| | | fixtures = os.path.normpath(os.path.join(here, '..', '..', 'fixtures')) |
| | | config.add_static_view('/', fixtures) |
| | | |
| | |
| | | def includeme(config): |
| | | config.add_static_view('/', 'tests:fixtures') |
| | | |
| | |
| | | config.add_static_view('/static', 'tests:fixtures') |
| | | config.include(includeme2, route_prefix='/prefix') |
| | | |
| | | |
| | | def includeme2(config): |
| | | config.add_static_view('/static', 'tests:fixtures/static') |
| | | |
| | |
| | | class RootFactory(object): |
| | | __acl__ = [('Allow', 'fred', 'view')] |
| | | |
| | | def __init__(self, request): |
| | | pass |
| | | |
| | | |
| | | class LocalRootFactory(object): |
| | | __acl__ = [('Allow', 'bob', 'view')] |
| | | |
| | | def __init__(self, request): |
| | | pass |
| | | |
| | | |
| | | |
| | | def includeme(config): |
| | | from pyramid.authentication import RemoteUserAuthenticationPolicy |
| | | from pyramid.authorization import ACLAuthorizationPolicy |
| | | authn_policy = RemoteUserAuthenticationPolicy() |
| | | authz_policy = ACLAuthorizationPolicy() |
| | | config._set_authentication_policy(authn_policy) |
| | | config._set_authorization_policy(authz_policy) |
| | | config.add_static_view('allowed', 'tests:fixtures/static/') |
| | | config.add_static_view('protected', 'tests:fixtures/static/', |
| | | permission='view') |
| | | config.add_static_view('factory_protected', |
| | | 'tests:fixtures/static/', |
| | | permission='view', |
| | | factory=LocalRootFactory) |
| | | from pyramid.authentication import RemoteUserAuthenticationPolicy |
| | | from pyramid.authorization import ACLAuthorizationPolicy |
| | | |
| | | authn_policy = RemoteUserAuthenticationPolicy() |
| | | authz_policy = ACLAuthorizationPolicy() |
| | | config._set_authentication_policy(authn_policy) |
| | | config._set_authorization_policy(authz_policy) |
| | | config.add_static_view('allowed', 'tests:fixtures/static/') |
| | | config.add_static_view( |
| | | 'protected', 'tests:fixtures/static/', permission='view' |
| | | ) |
| | | config.add_static_view( |
| | | 'factory_protected', |
| | | 'tests:fixtures/static/', |
| | | permission='view', |
| | | factory=LocalRootFactory, |
| | | ) |
| | |
| | | from pyramid.config import Configurator |
| | | from pyramid.request import Request |
| | | |
| | | |
| | | def view_one(request): |
| | | subreq = Request.blank('/view_two') |
| | | response = request.invoke_subrequest(subreq, use_tweens=False) |
| | | return response |
| | | |
| | | |
| | | def view_two(request): |
| | | # check that request.foo is valid for a subrequest |
| | | return 'This came from view_two, foo=%s' % (request.foo,) |
| | | |
| | | |
| | | def view_three(request): |
| | | subreq = Request.blank('/view_four') |
| | | try: |
| | | return request.invoke_subrequest(subreq, use_tweens=True) |
| | | except: # pragma: no cover |
| | | except Exception: # pragma: no cover |
| | | request.response.body = b'Value error raised' |
| | | return request.response |
| | | |
| | | |
| | | def view_four(request): |
| | | raise ValueError('foo') |
| | | |
| | | |
| | | def view_five(request): |
| | | subreq = Request.blank('/view_four') |
| | |
| | | request.response.body = b'Value error raised' |
| | | return request.response |
| | | |
| | | |
| | | def excview(request): |
| | | request.response.status_int = 500 |
| | | request.response.body = b'Bad stuff happened' |
| | | return request.response |
| | | |
| | | |
| | | def main(): |
| | | config = Configurator() |
| | |
| | | config.add_view(view_five, route_name='five') |
| | | config.add_request_method(lambda r: 'bar', 'foo', property=True) |
| | | return config |
| | | |
| | |
| | | def includeme(config): |
| | | config.scan('tests.pkgs.viewdecoratorapp') |
| | | |
| | |
| | | from pyramid.view import view_config |
| | | |
| | | |
| | | @view_config(renderer='json', name='first') |
| | | def first(request): |
| | | return {'result':'OK1'} |
| | | return {'result': 'OK1'} |
| | | |
| | | @view_config( |
| | | renderer='json', |
| | | name='second') |
| | | |
| | | @view_config(renderer='json', name='second') |
| | | def second(request): |
| | | return {'result':'OK2'} |
| | | |
| | | return {'result': 'OK2'} |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.wsgi import wsgiapp2 |
| | | |
| | | |
| | | @view_config(name='hello', renderer='string') |
| | | @wsgiapp2 |
| | | def hello(environ, start_response): |
| | |
| | | start_response('200 OK', response_headers) |
| | | return [b'Hello!'] |
| | | |
| | | |
| | | def main(): |
| | | from pyramid.config import Configurator |
| | | |
| | | c = Configurator() |
| | | c.scan() |
| | | return c |
| | |
| | | |
| | | here = os.path.abspath(os.path.dirname(__file__)) |
| | | |
| | | |
| | | class Test_resolve_asset_spec(unittest.TestCase): |
| | | def _callFUT(self, spec, package_name='__main__'): |
| | | from pyramid.resource import resolve_asset_spec |
| | | |
| | | return resolve_asset_spec(spec, package_name) |
| | | |
| | | def test_abspath(self): |
| | |
| | | package_name, filename = self._callFUT(path, pkg) |
| | | self.assertEqual(package_name, 'tests') |
| | | self.assertEqual(filename, 'test_asset.py') |
| | | |
| | | |
| | | def test_abs_spec(self): |
| | | pkg = 'tests' |
| | | path = 'pyramid.nottests:test_asset.py' |
| | |
| | | |
| | | def test_package_name_is_package_object(self): |
| | | import tests |
| | | |
| | | pkg = tests |
| | | path = 'test_asset.py' |
| | | package_name, filename = self._callFUT(path, pkg) |
| | |
| | | class Test_abspath_from_asset_spec(unittest.TestCase): |
| | | def _callFUT(self, spec, pname='__main__'): |
| | | from pyramid.resource import abspath_from_asset_spec |
| | | |
| | | return abspath_from_asset_spec(spec, pname) |
| | | |
| | | def test_pname_is_None_before_resolve_asset_spec(self): |
| | |
| | | result = self._callFUT('abc', 'tests') |
| | | self.assertEqual(result, os.path.join(here, 'abc')) |
| | | |
| | | |
| | | class Test_asset_spec_from_abspath(unittest.TestCase): |
| | | def _callFUT(self, abspath, package): |
| | | from pyramid.asset import asset_spec_from_abspath |
| | | |
| | | return asset_spec_from_abspath(abspath, package) |
| | | |
| | | def test_package_name_is_main(self): |
| | |
| | | result = self._callFUT(here, pkg) |
| | | self.assertEqual(result, here) |
| | | |
| | | |
| | | class DummyPackage: |
| | | def __init__(self, name): |
| | | self.__name__ = name |
| | | |
| | |
| | | import unittest |
| | | import warnings |
| | | from pyramid import testing |
| | | from pyramid.compat import ( |
| | | text_, |
| | | bytes_, |
| | | ) |
| | | from pyramid.compat import text_, bytes_ |
| | | |
| | | |
| | | class TestCallbackAuthenticationPolicyDebugging(unittest.TestCase): |
| | | def setUp(self): |
| | | from pyramid.interfaces import IDebugLogger |
| | | |
| | | self.config = testing.setUp() |
| | | self.config.registry.registerUtility(self, IDebugLogger) |
| | | self.messages = [] |
| | |
| | | |
| | | def _makeOne(self, userid=None, callback=None): |
| | | from pyramid.authentication import CallbackAuthenticationPolicy |
| | | |
| | | class MyAuthenticationPolicy(CallbackAuthenticationPolicy): |
| | | def unauthenticated_userid(self, request): |
| | | return userid |
| | | |
| | | policy = MyAuthenticationPolicy() |
| | | policy.debug = True |
| | | policy.callback = callback |
| | |
| | | self.messages[0], |
| | | 'tests.test_authentication.MyAuthenticationPolicy.' |
| | | 'authenticated_userid: call to unauthenticated_userid returned ' |
| | | 'None; returning None') |
| | | 'None; returning None', |
| | | ) |
| | | |
| | | def test_authenticated_userid_no_callback(self): |
| | | request = DummyRequest(registry=self.config.registry) |
| | |
| | | self.assertEqual(len(self.messages), 1) |
| | | self.assertEqual( |
| | | self.messages[0], |
| | | "tests.test_authentication.MyAuthenticationPolicy." |
| | | "tests.test_authentication.MyAuthenticationPolicy." |
| | | "authenticated_userid: there was no groupfinder callback; " |
| | | "returning 'fred'") |
| | | "returning 'fred'", |
| | | ) |
| | | |
| | | def test_authenticated_userid_with_callback_fail(self): |
| | | request = DummyRequest(registry=self.config.registry) |
| | | |
| | | def callback(userid, request): |
| | | return None |
| | | |
| | | policy = self._makeOne(userid='fred', callback=callback) |
| | | self.assertEqual(policy.authenticated_userid(request), None) |
| | | self.assertEqual(len(self.messages), 1) |
| | |
| | | self.messages[0], |
| | | 'tests.test_authentication.MyAuthenticationPolicy.' |
| | | 'authenticated_userid: groupfinder callback returned None; ' |
| | | 'returning None') |
| | | 'returning None', |
| | | ) |
| | | |
| | | def test_authenticated_userid_with_callback_success(self): |
| | | request = DummyRequest(registry=self.config.registry) |
| | | |
| | | def callback(userid, request): |
| | | return [] |
| | | |
| | | policy = self._makeOne(userid='fred', callback=callback) |
| | | self.assertEqual(policy.authenticated_userid(request), 'fred') |
| | | self.assertEqual(len(self.messages), 1) |
| | |
| | | self.messages[0], |
| | | "tests.test_authentication.MyAuthenticationPolicy." |
| | | "authenticated_userid: groupfinder callback returned []; " |
| | | "returning 'fred'") |
| | | "returning 'fred'", |
| | | ) |
| | | |
| | | def test_authenticated_userid_fails_cleaning_as_Authenticated(self): |
| | | request = DummyRequest(registry=self.config.registry) |
| | |
| | | "tests.test_authentication.MyAuthenticationPolicy." |
| | | "authenticated_userid: use of userid 'system.Authenticated' is " |
| | | "disallowed by any built-in Pyramid security policy, returning " |
| | | "None") |
| | | "None", |
| | | ) |
| | | |
| | | def test_authenticated_userid_fails_cleaning_as_Everyone(self): |
| | | request = DummyRequest(registry=self.config.registry) |
| | |
| | | "tests.test_authentication.MyAuthenticationPolicy." |
| | | "authenticated_userid: use of userid 'system.Everyone' is " |
| | | "disallowed by any built-in Pyramid security policy, returning " |
| | | "None") |
| | | "None", |
| | | ) |
| | | |
| | | def test_effective_principals_no_unauthenticated_userid(self): |
| | | request = DummyRequest(registry=self.config.registry) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.effective_principals(request), |
| | | ['system.Everyone']) |
| | | self.assertEqual( |
| | | policy.effective_principals(request), ['system.Everyone'] |
| | | ) |
| | | self.assertEqual(len(self.messages), 1) |
| | | self.assertEqual( |
| | | self.messages[0], |
| | | "tests.test_authentication.MyAuthenticationPolicy." |
| | | "effective_principals: unauthenticated_userid returned None; " |
| | | "returning ['system.Everyone']") |
| | | "returning ['system.Everyone']", |
| | | ) |
| | | |
| | | def test_effective_principals_no_callback(self): |
| | | request = DummyRequest(registry=self.config.registry) |
| | | policy = self._makeOne(userid='fred') |
| | | self.assertEqual( |
| | | policy.effective_principals(request), |
| | | ['system.Everyone', 'system.Authenticated', 'fred']) |
| | | ['system.Everyone', 'system.Authenticated', 'fred'], |
| | | ) |
| | | self.assertEqual(len(self.messages), 2) |
| | | self.assertEqual( |
| | | self.messages[0], |
| | | 'tests.test_authentication.MyAuthenticationPolicy.' |
| | | 'effective_principals: groupfinder callback is None, so groups ' |
| | | 'is []') |
| | | 'is []', |
| | | ) |
| | | self.assertEqual( |
| | | self.messages[1], |
| | | "tests.test_authentication.MyAuthenticationPolicy." |
| | | "effective_principals: returning effective principals: " |
| | | "['system.Everyone', 'system.Authenticated', 'fred']") |
| | | "['system.Everyone', 'system.Authenticated', 'fred']", |
| | | ) |
| | | |
| | | def test_effective_principals_with_callback_fail(self): |
| | | request = DummyRequest(registry=self.config.registry) |
| | | |
| | | def callback(userid, request): |
| | | return None |
| | | |
| | | policy = self._makeOne(userid='fred', callback=callback) |
| | | self.assertEqual( |
| | | policy.effective_principals(request), ['system.Everyone']) |
| | | policy.effective_principals(request), ['system.Everyone'] |
| | | ) |
| | | self.assertEqual(len(self.messages), 2) |
| | | self.assertEqual( |
| | | self.messages[0], |
| | | 'tests.test_authentication.MyAuthenticationPolicy.' |
| | | 'effective_principals: groupfinder callback returned None as ' |
| | | 'groups') |
| | | 'groups', |
| | | ) |
| | | self.assertEqual( |
| | | self.messages[1], |
| | | "tests.test_authentication.MyAuthenticationPolicy." |
| | | "effective_principals: returning effective principals: " |
| | | "['system.Everyone']") |
| | | "['system.Everyone']", |
| | | ) |
| | | |
| | | def test_effective_principals_with_callback_success(self): |
| | | request = DummyRequest(registry=self.config.registry) |
| | | |
| | | def callback(userid, request): |
| | | return [] |
| | | |
| | | policy = self._makeOne(userid='fred', callback=callback) |
| | | self.assertEqual( |
| | | policy.effective_principals(request), |
| | | ['system.Everyone', 'system.Authenticated', 'fred']) |
| | | ['system.Everyone', 'system.Authenticated', 'fred'], |
| | | ) |
| | | self.assertEqual(len(self.messages), 2) |
| | | self.assertEqual( |
| | | self.messages[0], |
| | | 'tests.test_authentication.MyAuthenticationPolicy.' |
| | | 'effective_principals: groupfinder callback returned [] as groups') |
| | | 'effective_principals: groupfinder callback returned [] as groups', |
| | | ) |
| | | self.assertEqual( |
| | | self.messages[1], |
| | | "tests.test_authentication.MyAuthenticationPolicy." |
| | | "effective_principals: returning effective principals: " |
| | | "['system.Everyone', 'system.Authenticated', 'fred']") |
| | | "['system.Everyone', 'system.Authenticated', 'fred']", |
| | | ) |
| | | |
| | | def test_effective_principals_with_unclean_principal_Authenticated(self): |
| | | request = DummyRequest(registry=self.config.registry) |
| | | policy = self._makeOne(userid='system.Authenticated') |
| | | self.assertEqual( |
| | | policy.effective_principals(request), |
| | | ['system.Everyone']) |
| | | policy.effective_principals(request), ['system.Everyone'] |
| | | ) |
| | | self.assertEqual(len(self.messages), 1) |
| | | self.assertEqual( |
| | | self.messages[0], |
| | | "tests.test_authentication.MyAuthenticationPolicy." |
| | | "effective_principals: unauthenticated_userid returned disallowed " |
| | | "'system.Authenticated'; returning ['system.Everyone'] as if it " |
| | | "was None") |
| | | "was None", |
| | | ) |
| | | |
| | | def test_effective_principals_with_unclean_principal_Everyone(self): |
| | | request = DummyRequest(registry=self.config.registry) |
| | | policy = self._makeOne(userid='system.Everyone') |
| | | self.assertEqual( |
| | | policy.effective_principals(request), |
| | | ['system.Everyone']) |
| | | policy.effective_principals(request), ['system.Everyone'] |
| | | ) |
| | | self.assertEqual(len(self.messages), 1) |
| | | self.assertEqual( |
| | | self.messages[0], |
| | | "tests.test_authentication.MyAuthenticationPolicy." |
| | | "effective_principals: unauthenticated_userid returned disallowed " |
| | | "'system.Everyone'; returning ['system.Everyone'] as if it " |
| | | "was None") |
| | | "was None", |
| | | ) |
| | | |
| | | |
| | | class TestRepozeWho1AuthenticationPolicy(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.authentication import RepozeWho1AuthenticationPolicy |
| | | |
| | | return RepozeWho1AuthenticationPolicy |
| | | |
| | | def _makeOne(self, identifier_name='auth_tkt', callback=None): |
| | |
| | | def test_class_implements_IAuthenticationPolicy(self): |
| | | from zope.interface.verify import verifyClass |
| | | from pyramid.interfaces import IAuthenticationPolicy |
| | | |
| | | verifyClass(IAuthenticationPolicy, self._getTargetClass()) |
| | | |
| | | def test_instance_implements_IAuthenticationPolicy(self): |
| | | from zope.interface.verify import verifyObject |
| | | from pyramid.interfaces import IAuthenticationPolicy |
| | | |
| | | verifyObject(IAuthenticationPolicy, self._makeOne()) |
| | | |
| | | def test_unauthenticated_userid_returns_None(self): |
| | |
| | | |
| | | def test_unauthenticated_userid(self): |
| | | request = DummyRequest( |
| | | {'repoze.who.identity':{'repoze.who.userid':'fred'}}) |
| | | {'repoze.who.identity': {'repoze.who.userid': 'fred'}} |
| | | ) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.unauthenticated_userid(request), 'fred') |
| | | |
| | |
| | | |
| | | def test_authenticated_userid(self): |
| | | request = DummyRequest( |
| | | {'repoze.who.identity':{'repoze.who.userid':'fred'}}) |
| | | {'repoze.who.identity': {'repoze.who.userid': 'fred'}} |
| | | ) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.authenticated_userid(request), 'fred') |
| | | |
| | | def test_authenticated_userid_repoze_who_userid_is_None(self): |
| | | request = DummyRequest( |
| | | {'repoze.who.identity':{'repoze.who.userid':None}}) |
| | | {'repoze.who.identity': {'repoze.who.userid': None}} |
| | | ) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.authenticated_userid(request), None) |
| | | |
| | | def test_authenticated_userid_with_callback_returns_None(self): |
| | | request = DummyRequest( |
| | | {'repoze.who.identity':{'repoze.who.userid':'fred'}}) |
| | | {'repoze.who.identity': {'repoze.who.userid': 'fred'}} |
| | | ) |
| | | |
| | | def callback(identity, request): |
| | | return None |
| | | |
| | | policy = self._makeOne(callback=callback) |
| | | self.assertEqual(policy.authenticated_userid(request), None) |
| | | |
| | | def test_authenticated_userid_with_callback_returns_something(self): |
| | | request = DummyRequest( |
| | | {'repoze.who.identity':{'repoze.who.userid':'fred'}}) |
| | | {'repoze.who.identity': {'repoze.who.userid': 'fred'}} |
| | | ) |
| | | |
| | | def callback(identity, request): |
| | | return ['agroup'] |
| | | |
| | | policy = self._makeOne(callback=callback) |
| | | self.assertEqual(policy.authenticated_userid(request), 'fred') |
| | | |
| | | def test_authenticated_userid_unclean_principal_Authenticated(self): |
| | | request = DummyRequest( |
| | | {'repoze.who.identity':{'repoze.who.userid':'system.Authenticated'}} |
| | | ) |
| | | { |
| | | 'repoze.who.identity': { |
| | | 'repoze.who.userid': 'system.Authenticated' |
| | | } |
| | | } |
| | | ) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.authenticated_userid(request), None) |
| | | |
| | | def test_authenticated_userid_unclean_principal_Everyone(self): |
| | | request = DummyRequest( |
| | | {'repoze.who.identity':{'repoze.who.userid':'system.Everyone'}} |
| | | ) |
| | | {'repoze.who.identity': {'repoze.who.userid': 'system.Everyone'}} |
| | | ) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.authenticated_userid(request), None) |
| | | |
| | | def test_effective_principals_None(self): |
| | | from pyramid.security import Everyone |
| | | |
| | | request = DummyRequest({}) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.effective_principals(request), [Everyone]) |
| | |
| | | def test_effective_principals_userid_only(self): |
| | | from pyramid.security import Everyone |
| | | from pyramid.security import Authenticated |
| | | |
| | | request = DummyRequest( |
| | | {'repoze.who.identity':{'repoze.who.userid':'fred'}}) |
| | | {'repoze.who.identity': {'repoze.who.userid': 'fred'}} |
| | | ) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.effective_principals(request), |
| | | [Everyone, Authenticated, 'fred']) |
| | | self.assertEqual( |
| | | policy.effective_principals(request), |
| | | [Everyone, Authenticated, 'fred'], |
| | | ) |
| | | |
| | | def test_effective_principals_userid_and_groups(self): |
| | | from pyramid.security import Everyone |
| | | from pyramid.security import Authenticated |
| | | |
| | | request = DummyRequest( |
| | | {'repoze.who.identity':{'repoze.who.userid':'fred', |
| | | 'groups':['quux', 'biz']}}) |
| | | { |
| | | 'repoze.who.identity': { |
| | | 'repoze.who.userid': 'fred', |
| | | 'groups': ['quux', 'biz'], |
| | | } |
| | | } |
| | | ) |
| | | |
| | | def callback(identity, request): |
| | | return identity['groups'] |
| | | |
| | | policy = self._makeOne(callback=callback) |
| | | self.assertEqual(policy.effective_principals(request), |
| | | [Everyone, Authenticated, 'fred', 'quux', 'biz']) |
| | | self.assertEqual( |
| | | policy.effective_principals(request), |
| | | [Everyone, Authenticated, 'fred', 'quux', 'biz'], |
| | | ) |
| | | |
| | | def test_effective_principals_userid_callback_returns_None(self): |
| | | from pyramid.security import Everyone |
| | | |
| | | request = DummyRequest( |
| | | {'repoze.who.identity':{'repoze.who.userid':'fred', |
| | | 'groups':['quux', 'biz']}}) |
| | | { |
| | | 'repoze.who.identity': { |
| | | 'repoze.who.userid': 'fred', |
| | | 'groups': ['quux', 'biz'], |
| | | } |
| | | } |
| | | ) |
| | | |
| | | def callback(identity, request): |
| | | return None |
| | | |
| | | policy = self._makeOne(callback=callback) |
| | | self.assertEqual(policy.effective_principals(request), [Everyone]) |
| | | |
| | | def test_effective_principals_repoze_who_userid_is_None(self): |
| | | from pyramid.security import Everyone |
| | | |
| | | request = DummyRequest( |
| | | {'repoze.who.identity':{'repoze.who.userid':None}} |
| | | ) |
| | | {'repoze.who.identity': {'repoze.who.userid': None}} |
| | | ) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.effective_principals(request), [Everyone]) |
| | | |
| | | def test_effective_principals_repoze_who_userid_is_unclean_Everyone(self): |
| | | from pyramid.security import Everyone |
| | | |
| | | request = DummyRequest( |
| | | {'repoze.who.identity':{'repoze.who.userid':'system.Everyone'}} |
| | | ) |
| | | {'repoze.who.identity': {'repoze.who.userid': 'system.Everyone'}} |
| | | ) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.effective_principals(request), [Everyone]) |
| | | |
| | | def test_effective_principals_repoze_who_userid_is_unclean_Authenticated( |
| | | self): |
| | | self |
| | | ): |
| | | from pyramid.security import Everyone |
| | | |
| | | request = DummyRequest( |
| | | {'repoze.who.identity':{'repoze.who.userid':'system.Authenticated'}} |
| | | ) |
| | | { |
| | | 'repoze.who.identity': { |
| | | 'repoze.who.userid': 'system.Authenticated' |
| | | } |
| | | } |
| | | ) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.effective_principals(request), [Everyone]) |
| | | |
| | |
| | | |
| | | def test_remember(self): |
| | | authtkt = DummyWhoPlugin() |
| | | request = DummyRequest( |
| | | {'repoze.who.plugins':{'auth_tkt':authtkt}}) |
| | | request = DummyRequest({'repoze.who.plugins': {'auth_tkt': authtkt}}) |
| | | policy = self._makeOne() |
| | | result = policy.remember(request, 'fred') |
| | | self.assertEqual(result[0], request.environ) |
| | | self.assertEqual(result[1], {'repoze.who.userid':'fred'}) |
| | | self.assertEqual(result[1], {'repoze.who.userid': 'fred'}) |
| | | |
| | | def test_remember_kwargs(self): |
| | | authtkt = DummyWhoPlugin() |
| | | request = DummyRequest( |
| | | {'repoze.who.plugins':{'auth_tkt':authtkt}}) |
| | | request = DummyRequest({'repoze.who.plugins': {'auth_tkt': authtkt}}) |
| | | policy = self._makeOne() |
| | | result = policy.remember(request, 'fred', max_age=23) |
| | | self.assertEqual(result[1], {'repoze.who.userid':'fred', 'max_age': 23}) |
| | | self.assertEqual( |
| | | result[1], {'repoze.who.userid': 'fred', 'max_age': 23} |
| | | ) |
| | | |
| | | def test_forget_no_plugins(self): |
| | | request = DummyRequest({}) |
| | |
| | | def test_forget(self): |
| | | authtkt = DummyWhoPlugin() |
| | | request = DummyRequest( |
| | | {'repoze.who.plugins':{'auth_tkt':authtkt}, |
| | | 'repoze.who.identity':{'repoze.who.userid':'fred'}, |
| | | }) |
| | | { |
| | | 'repoze.who.plugins': {'auth_tkt': authtkt}, |
| | | 'repoze.who.identity': {'repoze.who.userid': 'fred'}, |
| | | } |
| | | ) |
| | | policy = self._makeOne() |
| | | result = policy.forget(request) |
| | | self.assertEqual(result[0], request.environ) |
| | | self.assertEqual(result[1], request.environ['repoze.who.identity']) |
| | | |
| | | |
| | | class TestRemoteUserAuthenticationPolicy(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.authentication import RemoteUserAuthenticationPolicy |
| | | |
| | | return RemoteUserAuthenticationPolicy |
| | | |
| | | def _makeOne(self, environ_key='REMOTE_USER', callback=None): |
| | |
| | | def test_class_implements_IAuthenticationPolicy(self): |
| | | from zope.interface.verify import verifyClass |
| | | from pyramid.interfaces import IAuthenticationPolicy |
| | | |
| | | verifyClass(IAuthenticationPolicy, self._getTargetClass()) |
| | | |
| | | def test_instance_implements_IAuthenticationPolicy(self): |
| | | from zope.interface.verify import verifyObject |
| | | from pyramid.interfaces import IAuthenticationPolicy |
| | | |
| | | verifyObject(IAuthenticationPolicy, self._makeOne()) |
| | | |
| | | def test_unauthenticated_userid_returns_None(self): |
| | |
| | | self.assertEqual(policy.unauthenticated_userid(request), None) |
| | | |
| | | def test_unauthenticated_userid(self): |
| | | request = DummyRequest({'REMOTE_USER':'fred'}) |
| | | request = DummyRequest({'REMOTE_USER': 'fred'}) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.unauthenticated_userid(request), 'fred') |
| | | |
| | |
| | | self.assertEqual(policy.authenticated_userid(request), None) |
| | | |
| | | def test_authenticated_userid(self): |
| | | request = DummyRequest({'REMOTE_USER':'fred'}) |
| | | request = DummyRequest({'REMOTE_USER': 'fred'}) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.authenticated_userid(request), 'fred') |
| | | |
| | | def test_effective_principals_None(self): |
| | | from pyramid.security import Everyone |
| | | |
| | | request = DummyRequest({}) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.effective_principals(request), [Everyone]) |
| | |
| | | def test_effective_principals(self): |
| | | from pyramid.security import Everyone |
| | | from pyramid.security import Authenticated |
| | | request = DummyRequest({'REMOTE_USER':'fred'}) |
| | | |
| | | request = DummyRequest({'REMOTE_USER': 'fred'}) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.effective_principals(request), |
| | | [Everyone, Authenticated, 'fred']) |
| | | self.assertEqual( |
| | | policy.effective_principals(request), |
| | | [Everyone, Authenticated, 'fred'], |
| | | ) |
| | | |
| | | def test_remember(self): |
| | | request = DummyRequest({'REMOTE_USER':'fred'}) |
| | | request = DummyRequest({'REMOTE_USER': 'fred'}) |
| | | policy = self._makeOne() |
| | | result = policy.remember(request, 'fred') |
| | | self.assertEqual(result, []) |
| | | |
| | | def test_forget(self): |
| | | request = DummyRequest({'REMOTE_USER':'fred'}) |
| | | request = DummyRequest({'REMOTE_USER': 'fred'}) |
| | | policy = self._makeOne() |
| | | result = policy.forget(request) |
| | | self.assertEqual(result, []) |
| | | |
| | | |
| | | class TestAuthTktAuthenticationPolicy(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.authentication import AuthTktAuthenticationPolicy |
| | | |
| | | return AuthTktAuthenticationPolicy |
| | | |
| | | def _makeOne(self, callback, cookieidentity, **kw): |
| | |
| | | def test_allargs(self): |
| | | # pass all known args |
| | | inst = self._getTargetClass()( |
| | | 'secret', callback=None, cookie_name=None, secure=False, |
| | | include_ip=False, timeout=None, reissue_time=None, |
| | | hashalg='sha512', samesite=None, |
| | | ) |
| | | 'secret', |
| | | callback=None, |
| | | cookie_name=None, |
| | | secure=False, |
| | | include_ip=False, |
| | | timeout=None, |
| | | reissue_time=None, |
| | | hashalg='sha512', |
| | | samesite=None, |
| | | ) |
| | | self.assertEqual(inst.callback, None) |
| | | |
| | | def test_hashalg_override(self): |
| | |
| | | self.assertEqual(policy.unauthenticated_userid(request), None) |
| | | |
| | | def test_unauthenticated_userid(self): |
| | | request = DummyRequest({'REMOTE_USER':'fred'}) |
| | | policy = self._makeOne(None, {'userid':'fred'}) |
| | | request = DummyRequest({'REMOTE_USER': 'fred'}) |
| | | policy = self._makeOne(None, {'userid': 'fred'}) |
| | | self.assertEqual(policy.unauthenticated_userid(request), 'fred') |
| | | |
| | | def test_authenticated_userid_no_cookie_identity(self): |
| | |
| | | |
| | | def test_authenticated_userid_callback_returns_None(self): |
| | | request = DummyRequest({}) |
| | | |
| | | def callback(userid, request): |
| | | return None |
| | | policy = self._makeOne(callback, {'userid':'fred'}) |
| | | |
| | | policy = self._makeOne(callback, {'userid': 'fred'}) |
| | | self.assertEqual(policy.authenticated_userid(request), None) |
| | | |
| | | def test_authenticated_userid(self): |
| | | request = DummyRequest({}) |
| | | |
| | | def callback(userid, request): |
| | | return True |
| | | policy = self._makeOne(callback, {'userid':'fred'}) |
| | | |
| | | policy = self._makeOne(callback, {'userid': 'fred'}) |
| | | self.assertEqual(policy.authenticated_userid(request), 'fred') |
| | | |
| | | def test_effective_principals_no_cookie_identity(self): |
| | | from pyramid.security import Everyone |
| | | |
| | | request = DummyRequest({}) |
| | | policy = self._makeOne(None, None) |
| | | self.assertEqual(policy.effective_principals(request), [Everyone]) |
| | | |
| | | def test_effective_principals_callback_returns_None(self): |
| | | from pyramid.security import Everyone |
| | | |
| | | request = DummyRequest({}) |
| | | |
| | | def callback(userid, request): |
| | | return None |
| | | policy = self._makeOne(callback, {'userid':'fred'}) |
| | | |
| | | policy = self._makeOne(callback, {'userid': 'fred'}) |
| | | self.assertEqual(policy.effective_principals(request), [Everyone]) |
| | | |
| | | def test_effective_principals(self): |
| | | from pyramid.security import Everyone |
| | | from pyramid.security import Authenticated |
| | | |
| | | request = DummyRequest({}) |
| | | |
| | | def callback(userid, request): |
| | | return ['group.foo'] |
| | | policy = self._makeOne(callback, {'userid':'fred'}) |
| | | self.assertEqual(policy.effective_principals(request), |
| | | [Everyone, Authenticated, 'fred', 'group.foo']) |
| | | |
| | | policy = self._makeOne(callback, {'userid': 'fred'}) |
| | | self.assertEqual( |
| | | policy.effective_principals(request), |
| | | [Everyone, Authenticated, 'fred', 'group.foo'], |
| | | ) |
| | | |
| | | def test_remember(self): |
| | | request = DummyRequest({}) |
| | |
| | | request = DummyRequest({}) |
| | | policy = self._makeOne(None, None) |
| | | result = policy.remember(request, 'fred', a=1, b=2) |
| | | self.assertEqual(policy.cookie.kw, {'a':1, 'b':2}) |
| | | self.assertEqual(policy.cookie.kw, {'a': 1, 'b': 2}) |
| | | self.assertEqual(result, []) |
| | | |
| | | def test_forget(self): |
| | |
| | | def test_class_implements_IAuthenticationPolicy(self): |
| | | from zope.interface.verify import verifyClass |
| | | from pyramid.interfaces import IAuthenticationPolicy |
| | | |
| | | verifyClass(IAuthenticationPolicy, self._getTargetClass()) |
| | | |
| | | def test_instance_implements_IAuthenticationPolicy(self): |
| | | from zope.interface.verify import verifyObject |
| | | from pyramid.interfaces import IAuthenticationPolicy |
| | | |
| | | verifyObject(IAuthenticationPolicy, self._makeOne(None, None)) |
| | | |
| | | |
| | | class TestAuthTktCookieHelper(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.authentication import AuthTktCookieHelper |
| | | |
| | | return AuthTktCookieHelper |
| | | |
| | | def _makeOne(self, *arg, **kw): |
| | |
| | | return helper |
| | | |
| | | def _makeRequest(self, cookie=None, ipv6=False): |
| | | environ = {'wsgi.version': (1,0)} |
| | | environ = {'wsgi.version': (1, 0)} |
| | | |
| | | if ipv6 is False: |
| | | environ['REMOTE_ADDR'] = '1.1.1.1' |
| | |
| | | return D |
| | | |
| | | def _parseHeaders(self, headers): |
| | | return [ self._parseHeader(header) for header in headers ] |
| | | return [self._parseHeader(header) for header in headers] |
| | | |
| | | def _parseHeader(self, header): |
| | | cookie = self._parseCookie(header[1]) |
| | |
| | | |
| | | def _parseCookie(self, cookie): |
| | | from pyramid.compat import SimpleCookie |
| | | |
| | | cookies = SimpleCookie() |
| | | cookies.load(cookie) |
| | | return cookies.get('auth_tkt') |
| | | |
| | | def test_init_cookie_str_reissue_invalid(self): |
| | | self.assertRaises(ValueError, self._makeOne, 'secret', reissue_time='invalid value') |
| | | self.assertRaises( |
| | | ValueError, self._makeOne, 'secret', reissue_time='invalid value' |
| | | ) |
| | | |
| | | def test_init_cookie_str_timeout_invalid(self): |
| | | self.assertRaises(ValueError, self._makeOne, 'secret', timeout='invalid value') |
| | | self.assertRaises( |
| | | ValueError, self._makeOne, 'secret', timeout='invalid value' |
| | | ) |
| | | |
| | | def test_init_cookie_str_max_age_invalid(self): |
| | | self.assertRaises(ValueError, self._makeOne, 'secret', max_age='invalid value') |
| | | self.assertRaises( |
| | | ValueError, self._makeOne, 'secret', max_age='invalid value' |
| | | ) |
| | | |
| | | def test_identify_nocookie(self): |
| | | helper = self._makeOne('secret') |
| | |
| | | self.assertEqual(helper.auth_tkt.secret, 'secret') |
| | | environ = request.environ |
| | | self.assertEqual(environ['REMOTE_USER_TOKENS'], ()) |
| | | self.assertEqual(environ['REMOTE_USER_DATA'],'') |
| | | self.assertEqual(environ['AUTH_TYPE'],'cookie') |
| | | self.assertEqual(environ['REMOTE_USER_DATA'], '') |
| | | self.assertEqual(environ['AUTH_TYPE'], 'cookie') |
| | | |
| | | def test_identify_good_cookie_include_ipv6(self): |
| | | helper = self._makeOne('secret', include_ip=True) |
| | |
| | | self.assertEqual(helper.auth_tkt.secret, 'secret') |
| | | environ = request.environ |
| | | self.assertEqual(environ['REMOTE_USER_TOKENS'], ()) |
| | | self.assertEqual(environ['REMOTE_USER_DATA'],'') |
| | | self.assertEqual(environ['AUTH_TYPE'],'cookie') |
| | | self.assertEqual(environ['REMOTE_USER_DATA'], '') |
| | | self.assertEqual(environ['AUTH_TYPE'], 'cookie') |
| | | |
| | | def test_identify_good_cookie_dont_include_ip(self): |
| | | helper = self._makeOne('secret', include_ip=False) |
| | |
| | | self.assertEqual(helper.auth_tkt.secret, 'secret') |
| | | environ = request.environ |
| | | self.assertEqual(environ['REMOTE_USER_TOKENS'], ()) |
| | | self.assertEqual(environ['REMOTE_USER_DATA'],'') |
| | | self.assertEqual(environ['AUTH_TYPE'],'cookie') |
| | | self.assertEqual(environ['REMOTE_USER_DATA'], '') |
| | | self.assertEqual(environ['AUTH_TYPE'], 'cookie') |
| | | |
| | | def test_identify_good_cookie_int_useridtype(self): |
| | | helper = self._makeOne('secret', include_ip=False) |
| | |
| | | self.assertEqual(result['timestamp'], 0) |
| | | environ = request.environ |
| | | self.assertEqual(environ['REMOTE_USER_TOKENS'], ()) |
| | | self.assertEqual(environ['REMOTE_USER_DATA'],'userid_type:int') |
| | | self.assertEqual(environ['AUTH_TYPE'],'cookie') |
| | | self.assertEqual(environ['REMOTE_USER_DATA'], 'userid_type:int') |
| | | self.assertEqual(environ['AUTH_TYPE'], 'cookie') |
| | | |
| | | def test_identify_nonuseridtype_user_data(self): |
| | | helper = self._makeOne('secret', include_ip=False) |
| | |
| | | self.assertEqual(result['timestamp'], 0) |
| | | environ = request.environ |
| | | self.assertEqual(environ['REMOTE_USER_TOKENS'], ()) |
| | | self.assertEqual(environ['REMOTE_USER_DATA'],'bogus:int') |
| | | self.assertEqual(environ['AUTH_TYPE'],'cookie') |
| | | self.assertEqual(environ['REMOTE_USER_DATA'], 'bogus:int') |
| | | self.assertEqual(environ['AUTH_TYPE'], 'cookie') |
| | | |
| | | def test_identify_good_cookie_unknown_useridtype(self): |
| | | helper = self._makeOne('secret', include_ip=False) |
| | |
| | | self.assertEqual(result['timestamp'], 0) |
| | | environ = request.environ |
| | | self.assertEqual(environ['REMOTE_USER_TOKENS'], ()) |
| | | self.assertEqual(environ['REMOTE_USER_DATA'],'userid_type:unknown') |
| | | self.assertEqual(environ['AUTH_TYPE'],'cookie') |
| | | self.assertEqual(environ['REMOTE_USER_DATA'], 'userid_type:unknown') |
| | | self.assertEqual(environ['AUTH_TYPE'], 'cookie') |
| | | |
| | | def test_identify_good_cookie_b64str_useridtype(self): |
| | | from base64 import b64encode |
| | | |
| | | helper = self._makeOne('secret', include_ip=False) |
| | | helper.auth_tkt.userid = b64encode(b'encoded').strip() |
| | | helper.auth_tkt.user_data = 'userid_type:b64str' |
| | |
| | | self.assertEqual(result['timestamp'], 0) |
| | | environ = request.environ |
| | | self.assertEqual(environ['REMOTE_USER_TOKENS'], ()) |
| | | self.assertEqual(environ['REMOTE_USER_DATA'],'userid_type:b64str') |
| | | self.assertEqual(environ['AUTH_TYPE'],'cookie') |
| | | self.assertEqual(environ['REMOTE_USER_DATA'], 'userid_type:b64str') |
| | | self.assertEqual(environ['AUTH_TYPE'], 'cookie') |
| | | |
| | | def test_identify_good_cookie_b64unicode_useridtype(self): |
| | | from base64 import b64encode |
| | | |
| | | helper = self._makeOne('secret', include_ip=False) |
| | | helper.auth_tkt.userid = b64encode(b'\xc3\xa9ncoded').strip() |
| | | helper.auth_tkt.user_data = 'userid_type:b64unicode' |
| | |
| | | self.assertEqual(result['timestamp'], 0) |
| | | environ = request.environ |
| | | self.assertEqual(environ['REMOTE_USER_TOKENS'], ()) |
| | | self.assertEqual(environ['REMOTE_USER_DATA'],'userid_type:b64unicode') |
| | | self.assertEqual(environ['AUTH_TYPE'],'cookie') |
| | | self.assertEqual(environ['REMOTE_USER_DATA'], 'userid_type:b64unicode') |
| | | self.assertEqual(environ['AUTH_TYPE'], 'cookie') |
| | | |
| | | def test_identify_bad_cookie(self): |
| | | helper = self._makeOne('secret', include_ip=True) |
| | |
| | | |
| | | def test_identify_cookie_timeout_aged(self): |
| | | import time |
| | | |
| | | helper = self._makeOne('secret', timeout=10) |
| | | now = time.time() |
| | | helper.auth_tkt.timestamp = now - 1 |
| | | helper.now = now + 10 |
| | | helper.auth_tkt.tokens = (text_('a'), ) |
| | | helper.auth_tkt.tokens = (text_('a'),) |
| | | request = self._makeRequest('bogus') |
| | | result = helper.identify(request) |
| | | self.assertFalse(result) |
| | | |
| | | def test_identify_cookie_reissue(self): |
| | | import time |
| | | |
| | | helper = self._makeOne('secret', timeout=10, reissue_time=0) |
| | | now = time.time() |
| | | helper.auth_tkt.timestamp = now |
| | | helper.now = now + 1 |
| | | helper.auth_tkt.tokens = (text_('a'), ) |
| | | helper.auth_tkt.tokens = (text_('a'),) |
| | | request = self._makeRequest('bogus') |
| | | result = helper.identify(request) |
| | | self.assertTrue(result) |
| | |
| | | |
| | | def test_identify_cookie_str_reissue(self): |
| | | import time |
| | | |
| | | helper = self._makeOne('secret', timeout=10, reissue_time='0') |
| | | now = time.time() |
| | | helper.auth_tkt.timestamp = now |
| | | helper.now = now + 1 |
| | | helper.auth_tkt.tokens = (text_('a'), ) |
| | | helper.auth_tkt.tokens = (text_('a'),) |
| | | request = self._makeRequest('bogus') |
| | | result = helper.identify(request) |
| | | self.assertTrue(result) |
| | |
| | | |
| | | def test_identify_cookie_reissue_already_reissued_this_request(self): |
| | | import time |
| | | |
| | | helper = self._makeOne('secret', timeout=10, reissue_time=0) |
| | | now = time.time() |
| | | helper.auth_tkt.timestamp = now |
| | |
| | | |
| | | def test_identify_cookie_reissue_notyet(self): |
| | | import time |
| | | |
| | | helper = self._makeOne('secret', timeout=10, reissue_time=10) |
| | | now = time.time() |
| | | helper.auth_tkt.timestamp = now |
| | |
| | | |
| | | def test_identify_cookie_reissue_revoked_by_forget(self): |
| | | import time |
| | | |
| | | helper = self._makeOne('secret', timeout=10, reissue_time=0) |
| | | now = time.time() |
| | | helper.auth_tkt.timestamp = now |
| | |
| | | |
| | | def test_identify_cookie_reissue_revoked_by_remember(self): |
| | | import time |
| | | |
| | | helper = self._makeOne('secret', timeout=10, reissue_time=0) |
| | | now = time.time() |
| | | helper.auth_tkt.timestamp = now |
| | |
| | | def test_identify_cookie_reissue_with_tokens_default(self): |
| | | # see https://github.com/Pylons/pyramid/issues#issue/108 |
| | | import time |
| | | |
| | | helper = self._makeOne('secret', timeout=10, reissue_time=0) |
| | | auth_tkt = DummyAuthTktModule(tokens=['']) |
| | | helper.auth_tkt = auth_tkt |
| | |
| | | self.assertTrue(result[0][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[1][0], 'Set-Cookie') |
| | | self.assertTrue(result[1][1].endswith( |
| | | '; Domain=localhost; Path=/; SameSite=Lax')) |
| | | self.assertTrue( |
| | | result[1][1].endswith('; Domain=localhost; Path=/; SameSite=Lax') |
| | | ) |
| | | self.assertTrue(result[1][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[2][0], 'Set-Cookie') |
| | | self.assertTrue(result[2][1].endswith( |
| | | '; Domain=.localhost; Path=/; SameSite=Lax')) |
| | | self.assertTrue( |
| | | result[2][1].endswith('; Domain=.localhost; Path=/; SameSite=Lax') |
| | | ) |
| | | self.assertTrue(result[2][1].startswith('auth_tkt=')) |
| | | |
| | | def test_remember_nondefault_samesite(self): |
| | |
| | | self.assertTrue(result[0][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[1][0], 'Set-Cookie') |
| | | self.assertTrue(result[1][1].endswith( |
| | | '; Domain=localhost; Path=/; SameSite=Strict')) |
| | | self.assertTrue( |
| | | result[1][1].endswith( |
| | | '; Domain=localhost; Path=/; SameSite=Strict' |
| | | ) |
| | | ) |
| | | self.assertTrue(result[1][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[2][0], 'Set-Cookie') |
| | | self.assertTrue(result[2][1].endswith( |
| | | '; Domain=.localhost; Path=/; SameSite=Strict')) |
| | | self.assertTrue( |
| | | result[2][1].endswith( |
| | | '; Domain=.localhost; Path=/; SameSite=Strict' |
| | | ) |
| | | ) |
| | | self.assertTrue(result[2][1].startswith('auth_tkt=')) |
| | | |
| | | def test_remember_None_samesite(self): |
| | |
| | | self.assertEqual(len(result), 3) |
| | | |
| | | self.assertEqual(result[0][0], 'Set-Cookie') |
| | | self.assertTrue(result[0][1].endswith('; Path=/')) # no samesite |
| | | self.assertTrue(result[0][1].endswith('; Path=/')) # no samesite |
| | | self.assertTrue(result[0][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[1][0], 'Set-Cookie') |
| | | self.assertTrue(result[1][1].endswith( |
| | | '; Domain=localhost; Path=/')) |
| | | self.assertTrue(result[1][1].endswith('; Domain=localhost; Path=/')) |
| | | self.assertTrue(result[1][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[2][0], 'Set-Cookie') |
| | | self.assertTrue(result[2][1].endswith( |
| | | '; Domain=.localhost; Path=/')) |
| | | self.assertTrue(result[2][1].endswith('; Domain=.localhost; Path=/')) |
| | | self.assertTrue(result[2][1].startswith('auth_tkt=')) |
| | | |
| | | def test_remember_include_ip(self): |
| | |
| | | self.assertTrue(result[0][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[1][0], 'Set-Cookie') |
| | | self.assertTrue(result[1][1].endswith( |
| | | '; Domain=localhost; Path=/; SameSite=Lax')) |
| | | self.assertTrue( |
| | | result[1][1].endswith('; Domain=localhost; Path=/; SameSite=Lax') |
| | | ) |
| | | self.assertTrue(result[1][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[2][0], 'Set-Cookie') |
| | | self.assertTrue(result[2][1].endswith( |
| | | '; Domain=.localhost; Path=/; SameSite=Lax')) |
| | | self.assertTrue( |
| | | result[2][1].endswith('; Domain=.localhost; Path=/; SameSite=Lax') |
| | | ) |
| | | self.assertTrue(result[2][1].startswith('auth_tkt=')) |
| | | |
| | | def test_remember_path(self): |
| | | helper = self._makeOne('secret', include_ip=True, |
| | | path="/cgi-bin/app.cgi/") |
| | | helper = self._makeOne( |
| | | 'secret', include_ip=True, path="/cgi-bin/app.cgi/" |
| | | ) |
| | | request = self._makeRequest() |
| | | result = helper.remember(request, 'other') |
| | | self.assertEqual(len(result), 3) |
| | | |
| | | self.assertEqual(result[0][0], 'Set-Cookie') |
| | | self.assertTrue(result[0][1].endswith( |
| | | '; Path=/cgi-bin/app.cgi/; SameSite=Lax')) |
| | | self.assertTrue( |
| | | result[0][1].endswith('; Path=/cgi-bin/app.cgi/; SameSite=Lax') |
| | | ) |
| | | self.assertTrue(result[0][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[1][0], 'Set-Cookie') |
| | | self.assertTrue(result[1][1].endswith( |
| | | '; Domain=localhost; Path=/cgi-bin/app.cgi/; SameSite=Lax')) |
| | | self.assertTrue( |
| | | result[1][1].endswith( |
| | | '; Domain=localhost; Path=/cgi-bin/app.cgi/; SameSite=Lax' |
| | | ) |
| | | ) |
| | | self.assertTrue(result[1][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[2][0], 'Set-Cookie') |
| | | self.assertTrue(result[2][1].endswith( |
| | | '; Domain=.localhost; Path=/cgi-bin/app.cgi/; SameSite=Lax')) |
| | | self.assertTrue( |
| | | result[2][1].endswith( |
| | | '; Domain=.localhost; Path=/cgi-bin/app.cgi/; SameSite=Lax' |
| | | ) |
| | | ) |
| | | self.assertTrue(result[2][1].startswith('auth_tkt=')) |
| | | |
| | | def test_remember_http_only(self): |
| | |
| | | self.assertTrue(result[0][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[1][0], 'Set-Cookie') |
| | | self.assertTrue(result[1][1].endswith( |
| | | '; Domain=localhost; Path=/; SameSite=Lax')) |
| | | self.assertTrue( |
| | | result[1][1].endswith('; Domain=localhost; Path=/; SameSite=Lax') |
| | | ) |
| | | self.assertTrue(result[1][1].startswith('auth_tkt=')) |
| | | |
| | | def test_remember_parent_domain(self): |
| | |
| | | self.assertEqual(len(result), 1) |
| | | |
| | | self.assertEqual(result[0][0], 'Set-Cookie') |
| | | self.assertTrue(result[0][1].endswith( |
| | | '; Domain=.example.com; Path=/; SameSite=Lax')) |
| | | self.assertTrue( |
| | | result[0][1].endswith( |
| | | '; Domain=.example.com; Path=/; SameSite=Lax' |
| | | ) |
| | | ) |
| | | self.assertTrue(result[0][1].startswith('auth_tkt=')) |
| | | |
| | | def test_remember_parent_domain_supercedes_wild_domain(self): |
| | |
| | | request.domain = 'www.example.com' |
| | | result = helper.remember(request, 'other') |
| | | self.assertEqual(len(result), 1) |
| | | self.assertTrue(result[0][1].endswith( |
| | | '; Domain=.example.com; Path=/; SameSite=Lax')) |
| | | self.assertTrue( |
| | | result[0][1].endswith( |
| | | '; Domain=.example.com; Path=/; SameSite=Lax' |
| | | ) |
| | | ) |
| | | |
| | | def test_remember_explicit_domain(self): |
| | | helper = self._makeOne('secret', domain='pyramid.bazinga') |
| | |
| | | self.assertEqual(len(result), 1) |
| | | |
| | | self.assertEqual(result[0][0], 'Set-Cookie') |
| | | self.assertTrue(result[0][1].endswith( |
| | | '; Domain=pyramid.bazinga; Path=/; SameSite=Lax')) |
| | | self.assertTrue( |
| | | result[0][1].endswith( |
| | | '; Domain=pyramid.bazinga; Path=/; SameSite=Lax' |
| | | ) |
| | | ) |
| | | self.assertTrue(result[0][1].startswith('auth_tkt=')) |
| | | |
| | | def test_remember_domain_supercedes_parent_and_wild_domain(self): |
| | | helper = self._makeOne('secret', domain='pyramid.bazinga', |
| | | parent_domain=True, wild_domain=True) |
| | | helper = self._makeOne( |
| | | 'secret', |
| | | domain='pyramid.bazinga', |
| | | parent_domain=True, |
| | | wild_domain=True, |
| | | ) |
| | | request = self._makeRequest() |
| | | request.domain = 'www.example.com' |
| | | result = helper.remember(request, 'other') |
| | | self.assertEqual(len(result), 1) |
| | | self.assertTrue(result[0][1].endswith( |
| | | '; Domain=pyramid.bazinga; Path=/; SameSite=Lax')) |
| | | self.assertTrue( |
| | | result[0][1].endswith( |
| | | '; Domain=pyramid.bazinga; Path=/; SameSite=Lax' |
| | | ) |
| | | ) |
| | | |
| | | def test_remember_binary_userid(self): |
| | | import base64 |
| | | |
| | | helper = self._makeOne('secret') |
| | | request = self._makeRequest() |
| | | result = helper.remember(request, b'userid') |
| | | values = self._parseHeaders(result) |
| | | self.assertEqual(len(result), 3) |
| | | val = self._cookieValue(values[0]) |
| | | self.assertEqual(val['userid'], |
| | | text_(base64.b64encode(b'userid').strip())) |
| | | self.assertEqual( |
| | | val['userid'], text_(base64.b64encode(b'userid').strip()) |
| | | ) |
| | | self.assertEqual(val['user_data'], 'userid_type:b64str') |
| | | |
| | | def test_remember_int_userid(self): |
| | |
| | | |
| | | def test_remember_long_userid(self): |
| | | from pyramid.compat import long |
| | | |
| | | helper = self._makeOne('secret') |
| | | request = self._makeRequest() |
| | | result = helper.remember(request, long(1)) |
| | |
| | | |
| | | def test_remember_unicode_userid(self): |
| | | import base64 |
| | | |
| | | helper = self._makeOne('secret') |
| | | request = self._makeRequest() |
| | | userid = text_(b'\xc2\xa9', 'utf-8') |
| | |
| | | values = self._parseHeaders(result) |
| | | self.assertEqual(len(result), 3) |
| | | val = self._cookieValue(values[0]) |
| | | self.assertEqual(val['userid'], |
| | | text_(base64.b64encode(userid.encode('utf-8')))) |
| | | self.assertEqual( |
| | | val['userid'], text_(base64.b64encode(userid.encode('utf-8'))) |
| | | ) |
| | | self.assertEqual(val['user_data'], 'userid_type:b64unicode') |
| | | |
| | | def test_remember_insane_userid(self): |
| | |
| | | def test_remember_str_max_age_invalid(self): |
| | | helper = self._makeOne('secret') |
| | | request = self._makeRequest() |
| | | self.assertRaises(ValueError, helper.remember, request, 'userid', max_age='invalid value') |
| | | self.assertRaises( |
| | | ValueError, |
| | | helper.remember, |
| | | request, |
| | | 'userid', |
| | | max_age='invalid value', |
| | | ) |
| | | |
| | | def test_remember_tokens(self): |
| | | helper = self._makeOne('secret') |
| | |
| | | |
| | | self.assertEqual(result[0][0], 'Set-Cookie') |
| | | cookieval = result[0][1] |
| | | self.assertTrue('SameSite=Strict' in |
| | | [x.strip() for x in cookieval.split(';')], cookieval) |
| | | self.assertTrue( |
| | | 'SameSite=Strict' in [x.strip() for x in cookieval.split(';')], |
| | | cookieval, |
| | | ) |
| | | |
| | | self.assertEqual(result[1][0], 'Set-Cookie') |
| | | cookieval = result[1][1] |
| | | self.assertTrue('SameSite=Strict' in |
| | | [x.strip() for x in cookieval.split(';')], cookieval) |
| | | self.assertTrue( |
| | | 'SameSite=Strict' in [x.strip() for x in cookieval.split(';')], |
| | | cookieval, |
| | | ) |
| | | |
| | | self.assertEqual(result[2][0], 'Set-Cookie') |
| | | cookieval = result[2][1] |
| | | self.assertTrue('SameSite=Strict' in |
| | | [x.strip() for x in cookieval.split(';')], cookieval) |
| | | self.assertTrue( |
| | | 'SameSite=Strict' in [x.strip() for x in cookieval.split(';')], |
| | | cookieval, |
| | | ) |
| | | |
| | | def test_remember_samesite_default(self): |
| | | helper = self._makeOne('secret') |
| | |
| | | |
| | | self.assertEqual(result[0][0], 'Set-Cookie') |
| | | cookieval = result[0][1] |
| | | self.assertTrue('SameSite=Lax' in |
| | | [x.strip() for x in cookieval.split(';')], cookieval) |
| | | self.assertTrue( |
| | | 'SameSite=Lax' in [x.strip() for x in cookieval.split(';')], |
| | | cookieval, |
| | | ) |
| | | |
| | | self.assertEqual(result[1][0], 'Set-Cookie') |
| | | cookieval = result[1][1] |
| | | self.assertTrue('SameSite=Lax' in |
| | | [x.strip() for x in cookieval.split(';')], cookieval) |
| | | self.assertTrue( |
| | | 'SameSite=Lax' in [x.strip() for x in cookieval.split(';')], |
| | | cookieval, |
| | | ) |
| | | |
| | | self.assertEqual(result[2][0], 'Set-Cookie') |
| | | cookieval = result[2][1] |
| | | self.assertTrue('SameSite=Lax' in |
| | | [x.strip() for x in cookieval.split(';')], cookieval) |
| | | self.assertTrue( |
| | | 'SameSite=Lax' in [x.strip() for x in cookieval.split(';')], |
| | | cookieval, |
| | | ) |
| | | |
| | | def test_remember_unicode_but_ascii_token(self): |
| | | helper = self._makeOne('secret') |
| | |
| | | helper = self._makeOne('secret') |
| | | request = self._makeRequest() |
| | | la = text_(b'La Pe\xc3\xb1a', 'utf-8') |
| | | self.assertRaises(ValueError, helper.remember, request, 'other', |
| | | tokens=(la,)) |
| | | self.assertRaises( |
| | | ValueError, helper.remember, request, 'other', tokens=(la,) |
| | | ) |
| | | |
| | | def test_remember_invalid_token_format(self): |
| | | helper = self._makeOne('secret') |
| | | request = self._makeRequest() |
| | | self.assertRaises(ValueError, helper.remember, request, 'other', |
| | | tokens=('foo bar',)) |
| | | self.assertRaises(ValueError, helper.remember, request, 'other', |
| | | tokens=('1bar',)) |
| | | self.assertRaises( |
| | | ValueError, helper.remember, request, 'other', tokens=('foo bar',) |
| | | ) |
| | | self.assertRaises( |
| | | ValueError, helper.remember, request, 'other', tokens=('1bar',) |
| | | ) |
| | | |
| | | def test_forget(self): |
| | | helper = self._makeOne('secret') |
| | |
| | | self.assertEqual( |
| | | value, |
| | | 'auth_tkt=; Max-Age=0; Path=/; ' |
| | | 'expires=Wed, 31-Dec-97 23:59:59 GMT; SameSite=Lax' |
| | | ) |
| | | 'expires=Wed, 31-Dec-97 23:59:59 GMT; SameSite=Lax', |
| | | ) |
| | | name, value = headers[1] |
| | | self.assertEqual(name, 'Set-Cookie') |
| | | self.assertEqual( |
| | | value, |
| | | 'auth_tkt=; Domain=localhost; Max-Age=0; Path=/; ' |
| | | 'expires=Wed, 31-Dec-97 23:59:59 GMT; SameSite=Lax' |
| | | ) |
| | | 'expires=Wed, 31-Dec-97 23:59:59 GMT; SameSite=Lax', |
| | | ) |
| | | name, value = headers[2] |
| | | self.assertEqual(name, 'Set-Cookie') |
| | | self.assertEqual( |
| | | value, |
| | | 'auth_tkt=; Domain=.localhost; Max-Age=0; Path=/; ' |
| | | 'expires=Wed, 31-Dec-97 23:59:59 GMT; SameSite=Lax' |
| | | ) |
| | | 'expires=Wed, 31-Dec-97 23:59:59 GMT; SameSite=Lax', |
| | | ) |
| | | |
| | | |
| | | class TestAuthTicket(unittest.TestCase): |
| | | def _makeOne(self, *arg, **kw): |
| | | from pyramid.authentication import AuthTicket |
| | | |
| | | return AuthTicket(*arg, **kw) |
| | | |
| | | def test_ctor_with_tokens(self): |
| | |
| | | self.assertEqual(result, '126fd6224912187ee9ffa80e0b81420c') |
| | | |
| | | def test_digest_sha512(self): |
| | | ticket = self._makeOne('secret', 'userid', '0.0.0.0', |
| | | time=10, hashalg='sha512') |
| | | ticket = self._makeOne( |
| | | 'secret', 'userid', '0.0.0.0', time=10, hashalg='sha512' |
| | | ) |
| | | result = ticket.digest() |
| | | self.assertEqual(result, '74770b2e0d5b1a54c2a466ec567a40f7d7823576aa49'\ |
| | | '3c65fc3445e9b44097f4a80410319ef8cb256a2e60b9'\ |
| | | 'c2002e48a9e33a3e8ee4379352c04ef96d2cb278') |
| | | self.assertEqual( |
| | | result, |
| | | '74770b2e0d5b1a54c2a466ec567a40f7d7823576aa49' |
| | | '3c65fc3445e9b44097f4a80410319ef8cb256a2e60b9' |
| | | 'c2002e48a9e33a3e8ee4379352c04ef96d2cb278', |
| | | ) |
| | | |
| | | def test_cookie_value(self): |
| | | ticket = self._makeOne('secret', 'userid', '0.0.0.0', time=10, |
| | | tokens=('a', 'b')) |
| | | ticket = self._makeOne( |
| | | 'secret', 'userid', '0.0.0.0', time=10, tokens=('a', 'b') |
| | | ) |
| | | result = ticket.cookie_value() |
| | | self.assertEqual(result, |
| | | '66f9cc3e423dc57c91df696cf3d1f0d80000000auserid!a,b!') |
| | | self.assertEqual( |
| | | result, '66f9cc3e423dc57c91df696cf3d1f0d80000000auserid!a,b!' |
| | | ) |
| | | |
| | | def test_ipv4(self): |
| | | ticket = self._makeOne('secret', 'userid', '198.51.100.1', |
| | | time=10, hashalg='sha256') |
| | | ticket = self._makeOne( |
| | | 'secret', 'userid', '198.51.100.1', time=10, hashalg='sha256' |
| | | ) |
| | | result = ticket.cookie_value() |
| | | self.assertEqual(result, 'b3e7156db4f8abde4439c4a6499a0668f9e7ffd7fa27b'\ |
| | | '798400ecdade8d76c530000000auserid!') |
| | | self.assertEqual( |
| | | result, |
| | | 'b3e7156db4f8abde4439c4a6499a0668f9e7ffd7fa27b' |
| | | '798400ecdade8d76c530000000auserid!', |
| | | ) |
| | | |
| | | def test_ipv6(self): |
| | | ticket = self._makeOne('secret', 'userid', '2001:db8::1', |
| | | time=10, hashalg='sha256') |
| | | ticket = self._makeOne( |
| | | 'secret', 'userid', '2001:db8::1', time=10, hashalg='sha256' |
| | | ) |
| | | result = ticket.cookie_value() |
| | | self.assertEqual(result, 'd025b601a0f12ca6d008aa35ff3a22b7d8f3d1c1456c8'\ |
| | | '5becf8760cd7a2fa4910000000auserid!') |
| | | self.assertEqual( |
| | | result, |
| | | 'd025b601a0f12ca6d008aa35ff3a22b7d8f3d1c1456c8' |
| | | '5becf8760cd7a2fa4910000000auserid!', |
| | | ) |
| | | |
| | | |
| | | class TestBadTicket(unittest.TestCase): |
| | | def _makeOne(self, msg, expected=None): |
| | | from pyramid.authentication import BadTicket |
| | | |
| | | return BadTicket(msg, expected) |
| | | |
| | | def test_it(self): |
| | |
| | | self.assertEqual(exc.expected, True) |
| | | self.assertTrue(isinstance(exc, Exception)) |
| | | |
| | | |
| | | class Test_parse_ticket(unittest.TestCase): |
| | | def _callFUT(self, secret, ticket, ip, hashalg='md5'): |
| | | from pyramid.authentication import parse_ticket |
| | | |
| | | return parse_ticket(secret, ticket, ip, hashalg) |
| | | |
| | | def _assertRaisesBadTicket(self, secret, ticket, ip, hashalg='md5'): |
| | | from pyramid.authentication import BadTicket |
| | | self.assertRaises(BadTicket,self._callFUT, secret, ticket, ip, hashalg) |
| | | |
| | | self.assertRaises( |
| | | BadTicket, self._callFUT, secret, ticket, ip, hashalg |
| | | ) |
| | | |
| | | def test_bad_timestamp(self): |
| | | ticket = 'x' * 64 |
| | |
| | | self.assertEqual(result, (10, 'userid', ['a', 'b'], '')) |
| | | |
| | | def test_correct_with_user_data_sha512(self): |
| | | ticket = text_('7d947cdef99bad55f8e3382a8bd089bb9dd0547f7925b7d189adc1' |
| | | '160cab0ec0e6888faa41eba641a18522b26f19109f3ffafb769767' |
| | | 'ba8a26d02aaeae56599a0000000auserid!a,b!') |
| | | ticket = text_( |
| | | '7d947cdef99bad55f8e3382a8bd089bb9dd0547f7925b7d189adc1' |
| | | '160cab0ec0e6888faa41eba641a18522b26f19109f3ffafb769767' |
| | | 'ba8a26d02aaeae56599a0000000auserid!a,b!' |
| | | ) |
| | | result = self._callFUT('secret', ticket, '0.0.0.0', 'sha512') |
| | | self.assertEqual(result, (10, 'userid', ['a', 'b'], '')) |
| | | |
| | | def test_ipv4(self): |
| | | ticket = text_('b3e7156db4f8abde4439c4a6499a0668f9e7ffd7fa27b798400ecd' |
| | | 'ade8d76c530000000auserid!') |
| | | ticket = text_( |
| | | 'b3e7156db4f8abde4439c4a6499a0668f9e7ffd7fa27b798400ecd' |
| | | 'ade8d76c530000000auserid!' |
| | | ) |
| | | result = self._callFUT('secret', ticket, '198.51.100.1', 'sha256') |
| | | self.assertEqual(result, (10, 'userid', [''], '')) |
| | | |
| | | def test_ipv6(self): |
| | | ticket = text_('d025b601a0f12ca6d008aa35ff3a22b7d8f3d1c1456c85becf8760' |
| | | 'cd7a2fa4910000000auserid!') |
| | | ticket = text_( |
| | | 'd025b601a0f12ca6d008aa35ff3a22b7d8f3d1c1456c85becf8760' |
| | | 'cd7a2fa4910000000auserid!' |
| | | ) |
| | | result = self._callFUT('secret', ticket, '2001:db8::1', 'sha256') |
| | | self.assertEqual(result, (10, 'userid', [''], '')) |
| | | |
| | | |
| | | class TestSessionAuthenticationPolicy(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.authentication import SessionAuthenticationPolicy |
| | | |
| | | return SessionAuthenticationPolicy |
| | | |
| | | def _makeOne(self, callback=None, prefix=''): |
| | |
| | | def test_class_implements_IAuthenticationPolicy(self): |
| | | from zope.interface.verify import verifyClass |
| | | from pyramid.interfaces import IAuthenticationPolicy |
| | | |
| | | verifyClass(IAuthenticationPolicy, self._getTargetClass()) |
| | | |
| | | def test_instance_implements_IAuthenticationPolicy(self): |
| | | from zope.interface.verify import verifyObject |
| | | from pyramid.interfaces import IAuthenticationPolicy |
| | | |
| | | verifyObject(IAuthenticationPolicy, self._makeOne()) |
| | | |
| | | def test_unauthenticated_userid_returns_None(self): |
| | |
| | | self.assertEqual(policy.unauthenticated_userid(request), None) |
| | | |
| | | def test_unauthenticated_userid(self): |
| | | request = DummyRequest(session={'userid':'fred'}) |
| | | request = DummyRequest(session={'userid': 'fred'}) |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.unauthenticated_userid(request), 'fred') |
| | | |
| | |
| | | self.assertEqual(policy.authenticated_userid(request), None) |
| | | |
| | | def test_authenticated_userid_callback_returns_None(self): |
| | | request = DummyRequest(session={'userid':'fred'}) |
| | | request = DummyRequest(session={'userid': 'fred'}) |
| | | |
| | | def callback(userid, request): |
| | | return None |
| | | |
| | | policy = self._makeOne(callback) |
| | | self.assertEqual(policy.authenticated_userid(request), None) |
| | | |
| | | def test_authenticated_userid(self): |
| | | request = DummyRequest(session={'userid':'fred'}) |
| | | request = DummyRequest(session={'userid': 'fred'}) |
| | | |
| | | def callback(userid, request): |
| | | return True |
| | | |
| | | policy = self._makeOne(callback) |
| | | self.assertEqual(policy.authenticated_userid(request), 'fred') |
| | | |
| | | def test_effective_principals_no_identity(self): |
| | | from pyramid.security import Everyone |
| | | |
| | | request = DummyRequest() |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.effective_principals(request), [Everyone]) |
| | | |
| | | def test_effective_principals_callback_returns_None(self): |
| | | from pyramid.security import Everyone |
| | | request = DummyRequest(session={'userid':'fred'}) |
| | | |
| | | request = DummyRequest(session={'userid': 'fred'}) |
| | | |
| | | def callback(userid, request): |
| | | return None |
| | | |
| | | policy = self._makeOne(callback) |
| | | self.assertEqual(policy.effective_principals(request), [Everyone]) |
| | | |
| | | def test_effective_principals(self): |
| | | from pyramid.security import Everyone |
| | | from pyramid.security import Authenticated |
| | | request = DummyRequest(session={'userid':'fred'}) |
| | | |
| | | request = DummyRequest(session={'userid': 'fred'}) |
| | | |
| | | def callback(userid, request): |
| | | return ['group.foo'] |
| | | |
| | | policy = self._makeOne(callback) |
| | | self.assertEqual(policy.effective_principals(request), |
| | | [Everyone, Authenticated, 'fred', 'group.foo']) |
| | | self.assertEqual( |
| | | policy.effective_principals(request), |
| | | [Everyone, Authenticated, 'fred', 'group.foo'], |
| | | ) |
| | | |
| | | def test_remember(self): |
| | | request = DummyRequest() |
| | |
| | | self.assertEqual(result, []) |
| | | |
| | | def test_forget(self): |
| | | request = DummyRequest(session={'userid':'fred'}) |
| | | request = DummyRequest(session={'userid': 'fred'}) |
| | | policy = self._makeOne() |
| | | result = policy.forget(request) |
| | | self.assertEqual(request.session.get('userid'), None) |
| | |
| | | self.assertEqual(request.session.get('userid'), None) |
| | | self.assertEqual(result, []) |
| | | |
| | | |
| | | class TestBasicAuthAuthenticationPolicy(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.authentication import BasicAuthAuthenticationPolicy as cls |
| | | |
| | | return cls |
| | | |
| | | def _makeOne(self, check): |
| | |
| | | def test_class_implements_IAuthenticationPolicy(self): |
| | | from zope.interface.verify import verifyClass |
| | | from pyramid.interfaces import IAuthenticationPolicy |
| | | |
| | | verifyClass(IAuthenticationPolicy, self._getTargetClass()) |
| | | |
| | | def test_unauthenticated_userid(self): |
| | | import base64 |
| | | |
| | | request = testing.DummyRequest() |
| | | request.headers['Authorization'] = 'Basic %s' % base64.b64encode( |
| | | bytes_('chrisr:password')).decode('ascii') |
| | | bytes_('chrisr:password') |
| | | ).decode('ascii') |
| | | policy = self._makeOne(None) |
| | | self.assertEqual(policy.unauthenticated_userid(request), 'chrisr') |
| | | |
| | |
| | | |
| | | def test_authenticated_userid(self): |
| | | import base64 |
| | | |
| | | request = testing.DummyRequest() |
| | | request.headers['Authorization'] = 'Basic %s' % base64.b64encode( |
| | | bytes_('chrisr:password')).decode('ascii') |
| | | bytes_('chrisr:password') |
| | | ).decode('ascii') |
| | | |
| | | def check(username, password, request): |
| | | return [] |
| | | |
| | | policy = self._makeOne(check) |
| | | self.assertEqual(policy.authenticated_userid(request), 'chrisr') |
| | | |
| | | def test_authenticated_userid_utf8(self): |
| | | import base64 |
| | | |
| | | request = testing.DummyRequest() |
| | | inputs = (b'm\xc3\xb6rk\xc3\xb6:' |
| | | b'm\xc3\xb6rk\xc3\xb6password').decode('utf-8') |
| | | inputs = ( |
| | | b'm\xc3\xb6rk\xc3\xb6:' b'm\xc3\xb6rk\xc3\xb6password' |
| | | ).decode('utf-8') |
| | | request.headers['Authorization'] = 'Basic %s' % ( |
| | | base64.b64encode(inputs.encode('utf-8')).decode('latin-1')) |
| | | base64.b64encode(inputs.encode('utf-8')).decode('latin-1') |
| | | ) |
| | | |
| | | def check(username, password, request): |
| | | return [] |
| | | |
| | | policy = self._makeOne(check) |
| | | self.assertEqual(policy.authenticated_userid(request), |
| | | b'm\xc3\xb6rk\xc3\xb6'.decode('utf-8')) |
| | | self.assertEqual( |
| | | policy.authenticated_userid(request), |
| | | b'm\xc3\xb6rk\xc3\xb6'.decode('utf-8'), |
| | | ) |
| | | |
| | | def test_authenticated_userid_latin1(self): |
| | | import base64 |
| | | |
| | | request = testing.DummyRequest() |
| | | inputs = (b'm\xc3\xb6rk\xc3\xb6:' |
| | | b'm\xc3\xb6rk\xc3\xb6password').decode('utf-8') |
| | | inputs = ( |
| | | b'm\xc3\xb6rk\xc3\xb6:' b'm\xc3\xb6rk\xc3\xb6password' |
| | | ).decode('utf-8') |
| | | request.headers['Authorization'] = 'Basic %s' % ( |
| | | base64.b64encode(inputs.encode('latin-1')).decode('latin-1')) |
| | | base64.b64encode(inputs.encode('latin-1')).decode('latin-1') |
| | | ) |
| | | |
| | | def check(username, password, request): |
| | | return [] |
| | | |
| | | policy = self._makeOne(check) |
| | | self.assertEqual(policy.authenticated_userid(request), |
| | | b'm\xc3\xb6rk\xc3\xb6'.decode('utf-8')) |
| | | self.assertEqual( |
| | | policy.authenticated_userid(request), |
| | | b'm\xc3\xb6rk\xc3\xb6'.decode('utf-8'), |
| | | ) |
| | | |
| | | def test_unauthenticated_userid_invalid_payload(self): |
| | | import base64 |
| | | |
| | | request = testing.DummyRequest() |
| | | request.headers['Authorization'] = 'Basic %s' % base64.b64encode( |
| | | bytes_('chrisrpassword')).decode('ascii') |
| | | bytes_('chrisrpassword') |
| | | ).decode('ascii') |
| | | policy = self._makeOne(None) |
| | | self.assertEqual(policy.unauthenticated_userid(request), None) |
| | | |
| | |
| | | |
| | | def test_forget(self): |
| | | policy = self._makeOne(None) |
| | | self.assertEqual(policy.forget(None), [ |
| | | ('WWW-Authenticate', 'Basic realm="SomeRealm"')]) |
| | | self.assertEqual( |
| | | policy.forget(None), |
| | | [('WWW-Authenticate', 'Basic realm="SomeRealm"')], |
| | | ) |
| | | |
| | | |
| | | class TestExtractHTTPBasicCredentials(unittest.TestCase): |
| | | def _get_func(self): |
| | | from pyramid.authentication import extract_http_basic_credentials |
| | | |
| | | return extract_http_basic_credentials |
| | | |
| | | def test_no_auth_header(self): |
| | |
| | | |
| | | def test_invalid_payload(self): |
| | | import base64 |
| | | |
| | | request = testing.DummyRequest() |
| | | request.headers['Authorization'] = 'Basic %s' % base64.b64encode( |
| | | bytes_('chrisrpassword')).decode('ascii') |
| | | bytes_('chrisrpassword') |
| | | ).decode('ascii') |
| | | fn = self._get_func() |
| | | self.assertIsNone(fn(request)) |
| | | |
| | | def test_not_a_basic_auth_scheme(self): |
| | | import base64 |
| | | |
| | | request = testing.DummyRequest() |
| | | request.headers['Authorization'] = 'OtherScheme %s' % base64.b64encode( |
| | | bytes_('chrisr:password')).decode('ascii') |
| | | bytes_('chrisr:password') |
| | | ).decode('ascii') |
| | | fn = self._get_func() |
| | | self.assertIsNone(fn(request)) |
| | | |
| | |
| | | |
| | | def test_latin1_payload(self): |
| | | import base64 |
| | | |
| | | request = testing.DummyRequest() |
| | | inputs = (b'm\xc3\xb6rk\xc3\xb6:' |
| | | b'm\xc3\xb6rk\xc3\xb6password').decode('utf-8') |
| | | inputs = ( |
| | | b'm\xc3\xb6rk\xc3\xb6:' b'm\xc3\xb6rk\xc3\xb6password' |
| | | ).decode('utf-8') |
| | | request.headers['Authorization'] = 'Basic %s' % ( |
| | | base64.b64encode(inputs.encode('latin-1')).decode('latin-1')) |
| | | base64.b64encode(inputs.encode('latin-1')).decode('latin-1') |
| | | ) |
| | | fn = self._get_func() |
| | | self.assertEqual(fn(request), ( |
| | | b'm\xc3\xb6rk\xc3\xb6'.decode('utf-8'), |
| | | b'm\xc3\xb6rk\xc3\xb6password'.decode('utf-8') |
| | | )) |
| | | self.assertEqual( |
| | | fn(request), |
| | | ( |
| | | b'm\xc3\xb6rk\xc3\xb6'.decode('utf-8'), |
| | | b'm\xc3\xb6rk\xc3\xb6password'.decode('utf-8'), |
| | | ), |
| | | ) |
| | | |
| | | def test_utf8_payload(self): |
| | | import base64 |
| | | |
| | | request = testing.DummyRequest() |
| | | inputs = (b'm\xc3\xb6rk\xc3\xb6:' |
| | | b'm\xc3\xb6rk\xc3\xb6password').decode('utf-8') |
| | | inputs = ( |
| | | b'm\xc3\xb6rk\xc3\xb6:' b'm\xc3\xb6rk\xc3\xb6password' |
| | | ).decode('utf-8') |
| | | request.headers['Authorization'] = 'Basic %s' % ( |
| | | base64.b64encode(inputs.encode('utf-8')).decode('latin-1')) |
| | | base64.b64encode(inputs.encode('utf-8')).decode('latin-1') |
| | | ) |
| | | fn = self._get_func() |
| | | self.assertEqual(fn(request), ( |
| | | b'm\xc3\xb6rk\xc3\xb6'.decode('utf-8'), |
| | | b'm\xc3\xb6rk\xc3\xb6password'.decode('utf-8') |
| | | )) |
| | | self.assertEqual( |
| | | fn(request), |
| | | ( |
| | | b'm\xc3\xb6rk\xc3\xb6'.decode('utf-8'), |
| | | b'm\xc3\xb6rk\xc3\xb6password'.decode('utf-8'), |
| | | ), |
| | | ) |
| | | |
| | | def test_namedtuple_return(self): |
| | | import base64 |
| | | |
| | | request = testing.DummyRequest() |
| | | request.headers['Authorization'] = 'Basic %s' % base64.b64encode( |
| | | bytes_('chrisr:pass')).decode('ascii') |
| | | bytes_('chrisr:pass') |
| | | ).decode('ascii') |
| | | fn = self._get_func() |
| | | result = fn(request) |
| | | |
| | | self.assertEqual(result.username, 'chrisr') |
| | | self.assertEqual(result.password, 'pass') |
| | | |
| | | |
| | | |
| | | class DummyContext: |
| | | pass |
| | | |
| | | |
| | | class DummyCookies(object): |
| | | def __init__(self, cookie): |
| | |
| | | def get(self, name): |
| | | return self.cookie |
| | | |
| | | |
| | | class DummyRequest: |
| | | domain = 'localhost' |
| | | |
| | | def __init__(self, environ=None, session=None, registry=None, cookie=None): |
| | | self.environ = environ or {} |
| | | self.session = session or {} |
| | |
| | | def add_response_callback(self, callback): |
| | | self.callbacks.append(callback) |
| | | |
| | | |
| | | class DummyWhoPlugin: |
| | | def remember(self, environ, identity): |
| | | return environ, identity |
| | | |
| | | def forget(self, environ, identity): |
| | | return environ, identity |
| | | |
| | | |
| | | class DummyCookieHelper: |
| | | def __init__(self, result): |
| | |
| | | def forget(self, *arg): |
| | | return [] |
| | | |
| | | |
| | | class DummyAuthTktModule(object): |
| | | def __init__(self, timestamp=0, userid='userid', tokens=(), user_data='', |
| | | parse_raise=False, hashalg="md5"): |
| | | def __init__( |
| | | self, |
| | | timestamp=0, |
| | | userid='userid', |
| | | tokens=(), |
| | | user_data='', |
| | | parse_raise=False, |
| | | hashalg="md5", |
| | | ): |
| | | self.timestamp = timestamp |
| | | self.userid = userid |
| | | self.tokens = tokens |
| | | self.user_data = user_data |
| | | self.parse_raise = parse_raise |
| | | self.hashalg = hashalg |
| | | |
| | | def parse_ticket(secret, value, remote_addr, hashalg): |
| | | self.secret = secret |
| | | self.value = value |
| | |
| | | if self.parse_raise: |
| | | raise self.BadTicket() |
| | | return self.timestamp, self.userid, self.tokens, self.user_data |
| | | |
| | | self.parse_ticket = parse_ticket |
| | | |
| | | class AuthTicket(object): |
| | |
| | | |
| | | def cookie_value(self): |
| | | result = { |
| | | 'secret':self.secret, |
| | | 'userid':self.userid, |
| | | 'remote_addr':self.remote_addr |
| | | } |
| | | 'secret': self.secret, |
| | | 'userid': self.userid, |
| | | 'remote_addr': self.remote_addr, |
| | | } |
| | | result.update(self.kw) |
| | | tokens = result.pop('tokens', None) |
| | | if tokens is not None: |
| | |
| | | for k, v in items: |
| | | if isinstance(v, bytes): |
| | | v = text_(v) |
| | | new_items.append((k,v)) |
| | | result = '/'.join(['%s=%s' % (k, v) for k,v in new_items ]) |
| | | new_items.append((k, v)) |
| | | result = '/'.join(['%s=%s' % (k, v) for k, v in new_items]) |
| | | return result |
| | | |
| | | self.AuthTicket = AuthTicket |
| | | |
| | | class BadTicket(Exception): |
| | | pass |
| | | |
| | | |
| | | class DummyResponse: |
| | | def __init__(self): |
| | | self.headerlist = [] |
| | | |
| | |
| | | |
| | | from pyramid.testing import cleanUp |
| | | |
| | | |
| | | class TestACLAuthorizationPolicy(unittest.TestCase): |
| | | def setUp(self): |
| | | cleanUp() |
| | |
| | | |
| | | def _getTargetClass(self): |
| | | from pyramid.authorization import ACLAuthorizationPolicy |
| | | |
| | | return ACLAuthorizationPolicy |
| | | |
| | | def _makeOne(self): |
| | |
| | | def test_class_implements_IAuthorizationPolicy(self): |
| | | from zope.interface.verify import verifyClass |
| | | from pyramid.interfaces import IAuthorizationPolicy |
| | | |
| | | verifyClass(IAuthorizationPolicy, self._getTargetClass()) |
| | | |
| | | def test_instance_implements_IAuthorizationPolicy(self): |
| | | from zope.interface.verify import verifyObject |
| | | from pyramid.interfaces import IAuthorizationPolicy |
| | | |
| | | verifyObject(IAuthorizationPolicy, self._makeOne()) |
| | | |
| | | def test_permits_no_acl(self): |
| | | context = DummyContext() |
| | | policy = self._makeOne() |
| | | self.assertEqual(policy.permits(context, [], 'view'), False) |
| | | |
| | | |
| | | def test_permits(self): |
| | | from pyramid.security import Deny |
| | | from pyramid.security import Allow |
| | |
| | | from pyramid.security import Authenticated |
| | | from pyramid.security import ALL_PERMISSIONS |
| | | from pyramid.security import DENY_ALL |
| | | |
| | | root = DummyContext() |
| | | community = DummyContext(__name__='community', __parent__=root) |
| | | blog = DummyContext(__name__='blog', __parent__=community) |
| | | root.__acl__ = [ |
| | | (Allow, Authenticated, VIEW), |
| | | ] |
| | | root.__acl__ = [(Allow, Authenticated, VIEW)] |
| | | community.__acl__ = [ |
| | | (Allow, 'fred', ALL_PERMISSIONS), |
| | | (Allow, 'wilma', VIEW), |
| | | DENY_ALL, |
| | | ] |
| | | ] |
| | | blog.__acl__ = [ |
| | | (Allow, 'barney', MEMBER_PERMS), |
| | | (Allow, 'wilma', VIEW), |
| | | ] |
| | | ] |
| | | |
| | | policy = self._makeOne() |
| | | |
| | | result = policy.permits(blog, [Everyone, Authenticated, 'wilma'], |
| | | 'view') |
| | | result = policy.permits( |
| | | blog, [Everyone, Authenticated, 'wilma'], 'view' |
| | | ) |
| | | self.assertEqual(result, True) |
| | | self.assertEqual(result.context, blog) |
| | | self.assertEqual(result.ace, (Allow, 'wilma', VIEW)) |
| | | self.assertEqual(result.acl, blog.__acl__) |
| | | |
| | | result = policy.permits(blog, [Everyone, Authenticated, 'wilma'], |
| | | 'delete') |
| | | result = policy.permits( |
| | | blog, [Everyone, Authenticated, 'wilma'], 'delete' |
| | | ) |
| | | self.assertEqual(result, False) |
| | | self.assertEqual(result.context, community) |
| | | self.assertEqual(result.ace, (Deny, Everyone, ALL_PERMISSIONS)) |
| | | self.assertEqual(result.acl, community.__acl__) |
| | | |
| | | result = policy.permits(blog, [Everyone, Authenticated, 'fred'], 'view') |
| | | result = policy.permits( |
| | | blog, [Everyone, Authenticated, 'fred'], 'view' |
| | | ) |
| | | self.assertEqual(result, True) |
| | | self.assertEqual(result.context, community) |
| | | self.assertEqual(result.ace, (Allow, 'fred', ALL_PERMISSIONS)) |
| | | result = policy.permits(blog, [Everyone, Authenticated, 'fred'], |
| | | 'doesntevenexistyet') |
| | | result = policy.permits( |
| | | blog, [Everyone, Authenticated, 'fred'], 'doesntevenexistyet' |
| | | ) |
| | | self.assertEqual(result, True) |
| | | self.assertEqual(result.context, community) |
| | | self.assertEqual(result.ace, (Allow, 'fred', ALL_PERMISSIONS)) |
| | | self.assertEqual(result.acl, community.__acl__) |
| | | |
| | | result = policy.permits(blog, [Everyone, Authenticated, 'barney'], |
| | | 'view') |
| | | result = policy.permits( |
| | | blog, [Everyone, Authenticated, 'barney'], 'view' |
| | | ) |
| | | self.assertEqual(result, True) |
| | | self.assertEqual(result.context, blog) |
| | | self.assertEqual(result.ace, (Allow, 'barney', MEMBER_PERMS)) |
| | | result = policy.permits(blog, [Everyone, Authenticated, 'barney'], |
| | | 'administer') |
| | | result = policy.permits( |
| | | blog, [Everyone, Authenticated, 'barney'], 'administer' |
| | | ) |
| | | self.assertEqual(result, False) |
| | | self.assertEqual(result.context, community) |
| | | self.assertEqual(result.ace, (Deny, Everyone, ALL_PERMISSIONS)) |
| | | self.assertEqual(result.acl, community.__acl__) |
| | | |
| | | result = policy.permits(root, [Everyone, Authenticated, 'someguy'], |
| | | 'view') |
| | | |
| | | result = policy.permits( |
| | | root, [Everyone, Authenticated, 'someguy'], 'view' |
| | | ) |
| | | self.assertEqual(result, True) |
| | | self.assertEqual(result.context, root) |
| | | self.assertEqual(result.ace, (Allow, Authenticated, VIEW)) |
| | | result = policy.permits(blog, |
| | | [Everyone, Authenticated, 'someguy'], 'view') |
| | | result = policy.permits( |
| | | blog, [Everyone, Authenticated, 'someguy'], 'view' |
| | | ) |
| | | self.assertEqual(result, False) |
| | | self.assertEqual(result.context, community) |
| | | self.assertEqual(result.ace, (Deny, Everyone, ALL_PERMISSIONS)) |
| | |
| | | self.assertEqual(result, False) |
| | | self.assertEqual(result.ace, '<default deny>') |
| | | self.assertEqual( |
| | | result.acl, |
| | | '<No ACL found on any object in resource lineage>') |
| | | result.acl, '<No ACL found on any object in resource lineage>' |
| | | ) |
| | | |
| | | def test_permits_string_permissions_in_acl(self): |
| | | from pyramid.security import Allow |
| | | |
| | | root = DummyContext() |
| | | root.__acl__ = [ |
| | | (Allow, 'wilma', 'view_stuff'), |
| | | ] |
| | | root.__acl__ = [(Allow, 'wilma', 'view_stuff')] |
| | | |
| | | policy = self._makeOne() |
| | | |
| | | result = policy.permits(root, ['wilma'], 'view') |
| | | # would be True if matching against 'view_stuff' instead of against |
| | | # ['view_stuff'] |
| | | self.assertEqual(result, False) |
| | | self.assertEqual(result, False) |
| | | |
| | | def test_principals_allowed_by_permission_direct(self): |
| | | from pyramid.security import Allow |
| | | from pyramid.security import DENY_ALL |
| | | |
| | | context = DummyContext() |
| | | acl = [ (Allow, 'chrism', ('read', 'write')), |
| | | DENY_ALL, |
| | | (Allow, 'other', 'read') ] |
| | | acl = [ |
| | | (Allow, 'chrism', ('read', 'write')), |
| | | DENY_ALL, |
| | | (Allow, 'other', 'read'), |
| | | ] |
| | | context.__acl__ = acl |
| | | policy = self._makeOne() |
| | | result = sorted( |
| | | policy.principals_allowed_by_permission(context, 'read')) |
| | | policy.principals_allowed_by_permission(context, 'read') |
| | | ) |
| | | self.assertEqual(result, ['chrism']) |
| | | |
| | | def test_principals_allowed_by_permission_callable_acl(self): |
| | | from pyramid.security import Allow |
| | | from pyramid.security import DENY_ALL |
| | | |
| | | context = DummyContext() |
| | | acl = lambda: [ (Allow, 'chrism', ('read', 'write')), |
| | | DENY_ALL, |
| | | (Allow, 'other', 'read') ] |
| | | acl = lambda: [ |
| | | (Allow, 'chrism', ('read', 'write')), |
| | | DENY_ALL, |
| | | (Allow, 'other', 'read'), |
| | | ] |
| | | context.__acl__ = acl |
| | | policy = self._makeOne() |
| | | result = sorted( |
| | | policy.principals_allowed_by_permission(context, 'read')) |
| | | policy.principals_allowed_by_permission(context, 'read') |
| | | ) |
| | | self.assertEqual(result, ['chrism']) |
| | | |
| | | |
| | | def test_principals_allowed_by_permission_string_permission(self): |
| | | from pyramid.security import Allow |
| | | |
| | | context = DummyContext() |
| | | acl = [ (Allow, 'chrism', 'read_it')] |
| | | acl = [(Allow, 'chrism', 'read_it')] |
| | | context.__acl__ = acl |
| | | policy = self._makeOne() |
| | | result = policy.principals_allowed_by_permission(context, 'read') |
| | | # would be ['chrism'] if 'read' were compared against 'read_it' instead |
| | | # of against ['read_it'] |
| | | self.assertEqual(list(result), []) |
| | | |
| | | |
| | | def test_principals_allowed_by_permission(self): |
| | | from pyramid.security import Allow |
| | | from pyramid.security import Deny |
| | | from pyramid.security import DENY_ALL |
| | | from pyramid.security import ALL_PERMISSIONS |
| | | |
| | | root = DummyContext(__name__='', __parent__=None) |
| | | community = DummyContext(__name__='community', __parent__=root) |
| | | blog = DummyContext(__name__='blog', __parent__=community) |
| | | root.__acl__ = [ (Allow, 'chrism', ('read', 'write')), |
| | | (Allow, 'other', ('read',)), |
| | | (Allow, 'jim', ALL_PERMISSIONS)] |
| | | community.__acl__ = [ (Deny, 'flooz', 'read'), |
| | | (Allow, 'flooz', 'read'), |
| | | (Allow, 'mork', 'read'), |
| | | (Deny, 'jim', 'read'), |
| | | (Allow, 'someguy', 'manage')] |
| | | blog.__acl__ = [ (Allow, 'fred', 'read'), |
| | | DENY_ALL] |
| | | root.__acl__ = [ |
| | | (Allow, 'chrism', ('read', 'write')), |
| | | (Allow, 'other', ('read',)), |
| | | (Allow, 'jim', ALL_PERMISSIONS), |
| | | ] |
| | | community.__acl__ = [ |
| | | (Deny, 'flooz', 'read'), |
| | | (Allow, 'flooz', 'read'), |
| | | (Allow, 'mork', 'read'), |
| | | (Deny, 'jim', 'read'), |
| | | (Allow, 'someguy', 'manage'), |
| | | ] |
| | | blog.__acl__ = [(Allow, 'fred', 'read'), DENY_ALL] |
| | | |
| | | policy = self._makeOne() |
| | | |
| | | |
| | | result = sorted(policy.principals_allowed_by_permission(blog, 'read')) |
| | | self.assertEqual(result, ['fred']) |
| | | result = sorted(policy.principals_allowed_by_permission(community, |
| | | 'read')) |
| | | result = sorted( |
| | | policy.principals_allowed_by_permission(community, 'read') |
| | | ) |
| | | self.assertEqual(result, ['chrism', 'mork', 'other']) |
| | | result = sorted(policy.principals_allowed_by_permission(community, |
| | | 'read')) |
| | | result = sorted( |
| | | policy.principals_allowed_by_permission(community, 'read') |
| | | ) |
| | | result = sorted(policy.principals_allowed_by_permission(root, 'read')) |
| | | self.assertEqual(result, ['chrism', 'jim', 'other']) |
| | | |
| | | def test_principals_allowed_by_permission_no_acls(self): |
| | | context = DummyContext() |
| | | policy = self._makeOne() |
| | | result = sorted(policy.principals_allowed_by_permission(context,'read')) |
| | | result = sorted( |
| | | policy.principals_allowed_by_permission(context, 'read') |
| | | ) |
| | | self.assertEqual(result, []) |
| | | |
| | | def test_principals_allowed_by_permission_deny_not_permission_in_acl(self): |
| | | from pyramid.security import Deny |
| | | from pyramid.security import Everyone |
| | | |
| | | context = DummyContext() |
| | | acl = [ (Deny, Everyone, 'write') ] |
| | | acl = [(Deny, Everyone, 'write')] |
| | | context.__acl__ = acl |
| | | policy = self._makeOne() |
| | | result = sorted( |
| | | policy.principals_allowed_by_permission(context, 'read')) |
| | | policy.principals_allowed_by_permission(context, 'read') |
| | | ) |
| | | self.assertEqual(result, []) |
| | | |
| | | def test_principals_allowed_by_permission_deny_permission_in_acl(self): |
| | | from pyramid.security import Deny |
| | | from pyramid.security import Everyone |
| | | |
| | | context = DummyContext() |
| | | acl = [ (Deny, Everyone, 'read') ] |
| | | acl = [(Deny, Everyone, 'read')] |
| | | context.__acl__ = acl |
| | | policy = self._makeOne() |
| | | result = sorted( |
| | | policy.principals_allowed_by_permission(context, 'read')) |
| | | policy.principals_allowed_by_permission(context, 'read') |
| | | ) |
| | | self.assertEqual(result, []) |
| | | |
| | | def test_callable_acl(self): |
| | | from pyramid.security import Allow |
| | | |
| | | context = DummyContext() |
| | | fn = lambda self: [(Allow, 'bob', 'read')] |
| | | context.__acl__ = fn.__get__(context, context.__class__) |
| | | policy = self._makeOne() |
| | | result = policy.permits(context, ['bob'], 'read') |
| | | self.assertTrue(result) |
| | | |
| | | |
| | | |
| | | class DummyContext: |
| | | def __init__(self, *arg, **kw): |
| | |
| | | MEMBER_PERMS = GUEST_PERMS + (EDIT, CREATE, DELETE) |
| | | MODERATOR_PERMS = MEMBER_PERMS + (MODERATE,) |
| | | ADMINISTRATOR_PERMS = MODERATOR_PERMS + (ADMINISTER,) |
| | | |
| | |
| | | import unittest |
| | | from pyramid.compat import is_unbound_method |
| | | |
| | | |
| | | class TestUnboundMethods(unittest.TestCase): |
| | | def test_old_style_bound(self): |
| | | self.assertFalse(is_unbound_method(OldStyle().run)) |
| | |
| | | self.assertTrue(is_unbound_method(NewStyle.run)) |
| | | |
| | | def test_normal_func_unbound(self): |
| | | def func(): return 'OK' |
| | | def func(): # pragma: no cover |
| | | return 'OK' |
| | | |
| | | self.assertFalse(is_unbound_method(func)) |
| | | |
| | | |
| | | class OldStyle: |
| | | def run(self): return 'OK' |
| | | def run(self): # pragma: no cover |
| | | return 'OK' |
| | | |
| | | |
| | | class NewStyle(object): |
| | | def run(self): return 'OK' |
| | | def run(self): # pragma: no cover |
| | | return 'OK' |
| | |
| | | # package |
| | | |
| | | from functools import partial |
| | | from zope.interface import implementer |
| | | from zope.interface import Interface |
| | | |
| | | |
| | | class IFactory(Interface): |
| | | pass |
| | | |
| | | def dummy_tween_factory(handler, registry): pass |
| | | |
| | | def dummy_tween_factory2(handler, registry): pass |
| | | def dummy_tween_factory(handler, registry): # pragma: no cover |
| | | pass |
| | | |
| | | |
| | | def dummy_tween_factory2(handler, registry): # pragma: no cover |
| | | pass |
| | | |
| | | |
| | | def dummy_include(config): |
| | | config.registry.included = True |
| | | config.action('discrim', None, config.package) |
| | | |
| | | |
| | | def dummy_include2(config): |
| | | config.registry.also_included = True |
| | | config.action('discrim', None, config.package) |
| | | |
| | | |
| | | includeme = dummy_include |
| | | |
| | | |
| | | class DummyContext: |
| | | pass |
| | | |
| | | |
| | | @implementer(IFactory) |
| | | class DummyFactory(object): |
| | | def __call__(self): |
| | | """ """ |
| | | |
| | | |
| | | def dummyfactory(request): |
| | | """ """ |
| | | |
| | | |
| | | class IDummy(Interface): |
| | | pass |
| | | |
| | | |
| | | def dummy_view(request): |
| | | return 'OK' |
| | | |
| | | |
| | | def dummy_extend(config, discrim): |
| | | config.action(discrim, None, config.package) |
| | | |
| | | |
| | | def dummy_extend2(config, discrim): |
| | | config.action(discrim, None, config.registry) |
| | | |
| | | from functools import partial |
| | | |
| | | dummy_partial = partial(dummy_extend, discrim='partial') |
| | | |
| | | |
| | | class DummyCallable(object): |
| | | def __call__(self, config, discrim): |
| | | config.action(discrim, None, config.package) |
| | | dummy_callable = DummyCallable() |
| | | |
| | | |
| | | dummy_callable = DummyCallable() |
| | |
| | | import venusian |
| | | |
| | | |
| | | def foo(wrapped): |
| | | def bar(scanner, name, wrapped): |
| | | scanner.config.a = scanner.a |
| | | |
| | | venusian.attach(wrapped, bar) |
| | | return wrapped |
| | | |
| | | |
| | | @foo |
| | | def hello(): |
| | | pass |
| | | |
| | | hello() # appease coverage |
| | | |
| | | hello() # appease coverage |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.renderers import null_renderer |
| | | |
| | | |
| | | @view_config(renderer=null_renderer) |
| | | def grokked(context, request): |
| | | return 'grokked' |
| | | |
| | | |
| | | @view_config(request_method='POST', renderer=null_renderer) |
| | | def grokked_post(context, request): |
| | | return 'grokked_post' |
| | | |
| | | |
| | | @view_config(name='stacked2', renderer=null_renderer) |
| | | @view_config(name='stacked1', renderer=null_renderer) |
| | | def stacked(context, request): |
| | | return 'stacked' |
| | | |
| | | |
| | | class stacked_class(object): |
| | | def __init__(self, context, request): |
| | |
| | | def __call__(self): |
| | | return 'stacked_class' |
| | | |
| | | stacked_class = view_config(name='stacked_class1', |
| | | renderer=null_renderer)(stacked_class) |
| | | stacked_class = view_config(name='stacked_class2', |
| | | renderer=null_renderer)(stacked_class) |
| | | |
| | | |
| | | stacked_class = view_config(name='stacked_class1', renderer=null_renderer)( |
| | | stacked_class |
| | | ) |
| | | stacked_class = view_config(name='stacked_class2', renderer=null_renderer)( |
| | | stacked_class |
| | | ) |
| | | |
| | | |
| | | class oldstyle_grokked_class: |
| | | def __init__(self, context, request): |
| | | self.context = context |
| | |
| | | |
| | | def __call__(self): |
| | | return 'oldstyle_grokked_class' |
| | | |
| | | oldstyle_grokked_class = view_config(name='oldstyle_grokked_class', |
| | | renderer=null_renderer)( |
| | | oldstyle_grokked_class) |
| | | |
| | | |
| | | oldstyle_grokked_class = view_config( |
| | | name='oldstyle_grokked_class', renderer=null_renderer |
| | | )(oldstyle_grokked_class) |
| | | |
| | | |
| | | class grokked_class(object): |
| | | def __init__(self, context, request): |
| | |
| | | |
| | | def __call__(self): |
| | | return 'grokked_class' |
| | | |
| | | grokked_class = view_config(name='grokked_class', |
| | | renderer=null_renderer)(grokked_class) |
| | | |
| | | |
| | | grokked_class = view_config(name='grokked_class', renderer=null_renderer)( |
| | | grokked_class |
| | | ) |
| | | |
| | | |
| | | class Foo(object): |
| | | def __call__(self, context, request): |
| | | return 'grokked_instance' |
| | | |
| | | |
| | | grokked_instance = Foo() |
| | | grokked_instance = view_config(name='grokked_instance', |
| | | renderer=null_renderer)(grokked_instance) |
| | | grokked_instance = view_config( |
| | | name='grokked_instance', renderer=null_renderer |
| | | )(grokked_instance) |
| | | |
| | | |
| | | class Base(object): |
| | | @view_config(name='basemethod', renderer=null_renderer) |
| | | def basemethod(self): |
| | | """ """ |
| | | |
| | | |
| | | |
| | | class MethodViews(Base): |
| | | def __init__(self, context, request): |
| | | self.context = context |
| | |
| | | def stacked(self): |
| | | return 'stacked_method' |
| | | |
| | | |
| | | # ungrokkable |
| | | |
| | | A = 1 |
| | | B = {} |
| | | |
| | | |
| | | def stuff(): |
| | | """ """ |
| | | |
| | | |
| | | class Whatever(object): |
| | | pass |
| | | |
| | | |
| | | class Whatever2: |
| | | pass |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.renderers import null_renderer |
| | | |
| | | |
| | | @view_config(name='another', renderer=null_renderer) |
| | | def grokked(context, request): |
| | | return 'another_grokked' |
| | | |
| | | |
| | | @view_config(request_method='POST', name='another', renderer=null_renderer) |
| | | def grokked_post(context, request): |
| | | return 'another_grokked_post' |
| | | |
| | | |
| | | @view_config(name='another_stacked2', renderer=null_renderer) |
| | | @view_config(name='another_stacked1', renderer=null_renderer) |
| | | def stacked(context, request): |
| | | return 'another_stacked' |
| | | |
| | | |
| | | class stacked_class(object): |
| | | def __init__(self, context, request): |
| | |
| | | def __call__(self): |
| | | return 'another_stacked_class' |
| | | |
| | | stacked_class = view_config(name='another_stacked_class1', |
| | | renderer=null_renderer)(stacked_class) |
| | | stacked_class = view_config(name='another_stacked_class2', |
| | | renderer=null_renderer)(stacked_class) |
| | | |
| | | stacked_class = view_config( |
| | | name='another_stacked_class1', renderer=null_renderer |
| | | )(stacked_class) |
| | | stacked_class = view_config( |
| | | name='another_stacked_class2', renderer=null_renderer |
| | | )(stacked_class) |
| | | |
| | | |
| | | class oldstyle_grokked_class: |
| | | def __init__(self, context, request): |
| | |
| | | |
| | | def __call__(self): |
| | | return 'another_oldstyle_grokked_class' |
| | | |
| | | oldstyle_grokked_class = view_config(name='another_oldstyle_grokked_class', |
| | | renderer=null_renderer)( |
| | | oldstyle_grokked_class) |
| | | |
| | | |
| | | oldstyle_grokked_class = view_config( |
| | | name='another_oldstyle_grokked_class', renderer=null_renderer |
| | | )(oldstyle_grokked_class) |
| | | |
| | | |
| | | class grokked_class(object): |
| | | def __init__(self, context, request): |
| | |
| | | |
| | | def __call__(self): |
| | | return 'another_grokked_class' |
| | | |
| | | grokked_class = view_config(name='another_grokked_class', |
| | | renderer=null_renderer)(grokked_class) |
| | | |
| | | |
| | | grokked_class = view_config( |
| | | name='another_grokked_class', renderer=null_renderer |
| | | )(grokked_class) |
| | | |
| | | |
| | | class Foo(object): |
| | | def __call__(self, context, request): |
| | | return 'another_grokked_instance' |
| | | |
| | | |
| | | grokked_instance = Foo() |
| | | grokked_instance = view_config(name='another_grokked_instance', |
| | | renderer=null_renderer)( |
| | | grokked_instance) |
| | | grokked_instance = view_config( |
| | | name='another_grokked_instance', renderer=null_renderer |
| | | )(grokked_instance) |
| | | |
| | | # ungrokkable |
| | | |
| | | A = 1 |
| | | B = {} |
| | | |
| | | |
| | | def stuff(): |
| | | """ """ |
| | | |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.renderers import null_renderer |
| | | |
| | | |
| | | @view_config(name='pod_notinit', renderer=null_renderer) |
| | | def subpackage_notinit(context, request): |
| | | return 'pod_notinit' |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.renderers import null_renderer |
| | | |
| | | |
| | | @view_config(name='subpackage_init', renderer=null_renderer) |
| | | def subpackage_init(context, request): |
| | | return 'subpackage_init' |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.renderers import null_renderer |
| | | |
| | | |
| | | @view_config(name='subpackage_notinit', renderer=null_renderer) |
| | | def subpackage_notinit(context, request): |
| | | return 'subpackage_notinit' |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.renderers import null_renderer |
| | | |
| | | |
| | | @view_config(name='subsubpackage_init', renderer=null_renderer) |
| | | def subpackage_init(context, request): |
| | | return 'subsubpackage_init' |
| | |
| | | from pyramid.view import view_config |
| | | |
| | | |
| | | @view_config(renderer='string') |
| | | def abc(request): |
| | | return 'root' |
| | | |
| | | |
| | | def main(): |
| | | from pyramid.config import Configurator |
| | | |
| | | c = Configurator() |
| | | c.scan() |
| | | return c |
| | |
| | | from pyramid.view import view_config |
| | | |
| | | |
| | | @view_config(name='two', renderer='string') |
| | | def two(request): |
| | | return 'two' |
| | | |
| | |
| | | from pyramid.compat import PY2 |
| | | from . import IDummy |
| | | |
| | | |
| | | class AdaptersConfiguratorMixinTests(unittest.TestCase): |
| | | def _makeOne(self, *arg, **kw): |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator(*arg, **kw) |
| | | return config |
| | | |
| | | def test_add_subscriber_defaults(self): |
| | | from zope.interface import implementer |
| | | from zope.interface import Interface |
| | | |
| | | class IEvent(Interface): |
| | | pass |
| | | |
| | | @implementer(IEvent) |
| | | class Event: |
| | | pass |
| | | |
| | | L = [] |
| | | |
| | | def subscriber(event): |
| | | L.append(event) |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_subscriber(subscriber) |
| | | event = Event() |
| | |
| | | def test_add_subscriber_iface_specified(self): |
| | | from zope.interface import implementer |
| | | from zope.interface import Interface |
| | | |
| | | class IEvent(Interface): |
| | | pass |
| | | |
| | | @implementer(IEvent) |
| | | class Event: |
| | | pass |
| | | |
| | | L = [] |
| | | |
| | | def subscriber(event): |
| | | L.append(event) |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_subscriber(subscriber, IEvent) |
| | | event = Event() |
| | |
| | | def test_add_subscriber_dottednames(self): |
| | | import tests.test_config |
| | | from pyramid.interfaces import INewRequest |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_subscriber('tests.test_config', |
| | | 'pyramid.interfaces.INewRequest') |
| | | config.add_subscriber( |
| | | 'tests.test_config', 'pyramid.interfaces.INewRequest' |
| | | ) |
| | | handlers = list(config.registry.registeredHandlers()) |
| | | self.assertEqual(len(handlers), 1) |
| | | handler = handlers[0] |
| | |
| | | def test_add_object_event_subscriber(self): |
| | | from zope.interface import implementer |
| | | from zope.interface import Interface |
| | | |
| | | class IEvent(Interface): |
| | | pass |
| | | |
| | | @implementer(IEvent) |
| | | class Event: |
| | | object = 'foo' |
| | | |
| | | event = Event() |
| | | L = [] |
| | | |
| | | def subscriber(object, event): |
| | | L.append(event) |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_subscriber(subscriber, (Interface, IEvent)) |
| | | config.registry.subscribers((event.object, event), None) |
| | |
| | | def test_add_subscriber_with_specific_type_and_predicates_True(self): |
| | | from zope.interface import implementer |
| | | from zope.interface import Interface |
| | | |
| | | class IEvent(Interface): |
| | | pass |
| | | |
| | | @implementer(IEvent) |
| | | class Event: |
| | | pass |
| | | |
| | | L = [] |
| | | |
| | | def subscriber(event): |
| | | L.append(event) |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | predlist = config.get_predlist('subscriber') |
| | | jam_predicate = predicate_maker('jam') |
| | |
| | | def test_add_subscriber_with_default_type_predicates_True(self): |
| | | from zope.interface import implementer |
| | | from zope.interface import Interface |
| | | |
| | | class IEvent(Interface): |
| | | pass |
| | | |
| | | @implementer(IEvent) |
| | | class Event: |
| | | pass |
| | | |
| | | L = [] |
| | | |
| | | def subscriber(event): |
| | | L.append(event) |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | predlist = config.get_predlist('subscriber') |
| | | jam_predicate = predicate_maker('jam') |
| | |
| | | def test_add_subscriber_with_specific_type_and_predicates_False(self): |
| | | from zope.interface import implementer |
| | | from zope.interface import Interface |
| | | |
| | | class IEvent(Interface): |
| | | pass |
| | | |
| | | @implementer(IEvent) |
| | | class Event: |
| | | pass |
| | | |
| | | L = [] |
| | | def subscriber(event): L.append(event) |
| | | |
| | | def subscriber(event): # pragma: no cover |
| | | L.append(event) |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | predlist = config.get_predlist('subscriber') |
| | | jam_predicate = predicate_maker('jam') |
| | |
| | | def test_add_subscriber_with_default_type_predicates_False(self): |
| | | from zope.interface import implementer |
| | | from zope.interface import Interface |
| | | |
| | | class IEvent(Interface): |
| | | pass |
| | | |
| | | @implementer(IEvent) |
| | | class Event: |
| | | pass |
| | | |
| | | L = [] |
| | | def subscriber(event): L.append(event) |
| | | |
| | | def subscriber(event): # pragma: no cover |
| | | L.append(event) |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | predlist = config.get_predlist('subscriber') |
| | | jam_predicate = predicate_maker('jam') |
| | |
| | | def test_add_subscriber_predicate(self): |
| | | config = self._makeOne() |
| | | L = [] |
| | | def add_predicate(type, name, factory, weighs_less_than=None, |
| | | weighs_more_than=None): |
| | | |
| | | def add_predicate( |
| | | type, name, factory, weighs_less_than=None, weighs_more_than=None |
| | | ): |
| | | self.assertEqual(type, 'subscriber') |
| | | self.assertEqual(name, 'name') |
| | | self.assertEqual(factory, 'factory') |
| | | self.assertEqual(weighs_more_than, 1) |
| | | self.assertEqual(weighs_less_than, 2) |
| | | L.append(1) |
| | | |
| | | config._add_predicate = add_predicate |
| | | config.add_subscriber_predicate('name', 'factory', 1, 2) |
| | | self.assertTrue(L) |
| | | |
| | | |
| | | def test_add_response_adapter(self): |
| | | from pyramid.interfaces import IResponse |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | |
| | | class Adapter(object): |
| | | def __init__(self, other): |
| | | self.other = other |
| | | |
| | | config.add_response_adapter(Adapter, str) |
| | | result = config.registry.queryAdapter('foo', IResponse) |
| | | self.assertTrue(result.other, 'foo') |
| | | |
| | | def test_add_response_adapter_self(self): |
| | | from pyramid.interfaces import IResponse |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | |
| | | class Adapter(object): |
| | | pass |
| | | |
| | | config.add_response_adapter(None, Adapter) |
| | | adapter = Adapter() |
| | | result = config.registry.queryAdapter(adapter, IResponse) |
| | |
| | | |
| | | def test_add_response_adapter_dottednames(self): |
| | | from pyramid.interfaces import IResponse |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | if PY2: |
| | | str_name = '__builtin__.str' |
| | |
| | | |
| | | def test_add_traverser_dotted_names(self): |
| | | from pyramid.interfaces import ITraverser |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_traverser( |
| | | 'tests.test_config.test_adapters.DummyTraverser', |
| | | 'tests.test_config.test_adapters.DummyIface') |
| | | 'tests.test_config.test_adapters.DummyIface', |
| | | ) |
| | | iface = DummyIface() |
| | | traverser = config.registry.getAdapter(iface, ITraverser) |
| | | self.assertEqual(traverser.__class__, DummyTraverser) |
| | |
| | | |
| | | def test_add_traverser_default_iface_means_Interface(self): |
| | | from pyramid.interfaces import ITraverser |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_traverser(DummyTraverser) |
| | | traverser = config.registry.getAdapter(None, ITraverser) |
| | |
| | | |
| | | def test_add_traverser_nondefault_iface(self): |
| | | from pyramid.interfaces import ITraverser |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_traverser(DummyTraverser, DummyIface) |
| | | iface = DummyIface() |
| | | traverser = config.registry.getAdapter(iface, ITraverser) |
| | | self.assertEqual(traverser.__class__, DummyTraverser) |
| | | self.assertEqual(traverser.root, iface) |
| | | |
| | | |
| | | def test_add_traverser_introspectables(self): |
| | | config = self._makeOne() |
| | | config.add_traverser(DummyTraverser, DummyIface) |
| | | actions = config.action_state.actions |
| | | self.assertEqual(len(actions), 1) |
| | | intrs = actions[0]['introspectables'] |
| | | intrs = actions[0]['introspectables'] |
| | | self.assertEqual(len(intrs), 1) |
| | | intr = intrs[0] |
| | | self.assertEqual(intr.type_name, 'traverser') |
| | |
| | | |
| | | def test_add_resource_url_adapter_dotted_names(self): |
| | | from pyramid.interfaces import IResourceURL |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_resource_url_adapter( |
| | | 'tests.test_config.test_adapters.DummyResourceURL', |
| | | 'tests.test_config.test_adapters.DummyIface', |
| | | ) |
| | | ) |
| | | iface = DummyIface() |
| | | adapter = config.registry.getMultiAdapter((iface, iface), |
| | | IResourceURL) |
| | | adapter = config.registry.getMultiAdapter((iface, iface), IResourceURL) |
| | | self.assertEqual(adapter.__class__, DummyResourceURL) |
| | | self.assertEqual(adapter.resource, iface) |
| | | self.assertEqual(adapter.request, iface) |
| | | |
| | | def test_add_resource_url_default_resource_iface_means_Interface(self): |
| | | from pyramid.interfaces import IResourceURL |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_resource_url_adapter(DummyResourceURL) |
| | | iface = DummyIface() |
| | | adapter = config.registry.getMultiAdapter((iface, iface), |
| | | IResourceURL) |
| | | adapter = config.registry.getMultiAdapter((iface, iface), IResourceURL) |
| | | self.assertEqual(adapter.__class__, DummyResourceURL) |
| | | self.assertEqual(adapter.resource, iface) |
| | | self.assertEqual(adapter.request, iface) |
| | |
| | | def test_add_resource_url_nodefault_resource_iface(self): |
| | | from zope.interface import Interface |
| | | from pyramid.interfaces import IResourceURL |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_resource_url_adapter(DummyResourceURL, DummyIface) |
| | | iface = DummyIface() |
| | | adapter = config.registry.getMultiAdapter((iface, iface), |
| | | IResourceURL) |
| | | adapter = config.registry.getMultiAdapter((iface, iface), IResourceURL) |
| | | self.assertEqual(adapter.__class__, DummyResourceURL) |
| | | self.assertEqual(adapter.resource, iface) |
| | | self.assertEqual(adapter.request, iface) |
| | | bad_result = config.registry.queryMultiAdapter( |
| | | (Interface, Interface), |
| | | IResourceURL, |
| | | ) |
| | | (Interface, Interface), IResourceURL |
| | | ) |
| | | self.assertEqual(bad_result, None) |
| | | |
| | | def test_add_resource_url_adapter_introspectables(self): |
| | |
| | | config.add_resource_url_adapter(DummyResourceURL, DummyIface) |
| | | actions = config.action_state.actions |
| | | self.assertEqual(len(actions), 1) |
| | | intrs = actions[0]['introspectables'] |
| | | intrs = actions[0]['introspectables'] |
| | | self.assertEqual(len(intrs), 1) |
| | | intr = intrs[0] |
| | | self.assertEqual(intr.type_name, 'resource url adapter') |
| | | self.assertEqual(intr.discriminator, |
| | | ('resource url adapter', DummyIface)) |
| | | self.assertEqual( |
| | | intr.discriminator, ('resource url adapter', DummyIface) |
| | | ) |
| | | self.assertEqual(intr.category_name, 'resource url adapters') |
| | | self.assertEqual( |
| | | intr.title, |
| | | "resource url adapter for resource iface " |
| | | "<class 'tests.test_config.test_adapters.DummyIface'>" |
| | | ) |
| | | "<class 'tests.test_config.test_adapters.DummyIface'>", |
| | | ) |
| | | self.assertEqual(intr['adapter'], DummyResourceURL) |
| | | self.assertEqual(intr['resource_iface'], DummyIface) |
| | | |
| | | |
| | | class Test_eventonly(unittest.TestCase): |
| | | def _callFUT(self, callee): |
| | | from pyramid.config.adapters import eventonly |
| | | |
| | | return eventonly(callee) |
| | | |
| | | def test_defaults(self): |
| | | def acallable(event, a=1, b=2): pass |
| | | def acallable(event, a=1, b=2): # pragma: no cover |
| | | pass |
| | | |
| | | self.assertTrue(self._callFUT(acallable)) |
| | | |
| | | |
| | | class DummyTraverser(object): |
| | | def __init__(self, root): |
| | | self.root = root |
| | | |
| | | |
| | | class DummyIface(object): |
| | | pass |
| | | |
| | | |
| | | class DummyResourceURL(object): |
| | | def __init__(self, resource, request): |
| | | self.resource = resource |
| | | self.request = request |
| | | |
| | | |
| | | |
| | | def predicate_maker(name): |
| | | class Predicate(object): |
| | | def __init__(self, val, config): |
| | | self.val = val |
| | | |
| | | def phash(self): |
| | | return 'phash' |
| | | |
| | | text = phash |
| | | |
| | | def __call__(self, event): |
| | | return getattr(event, name, None) == self.val |
| | | return Predicate |
| | | |
| | | return Predicate |
| | |
| | | # we use this folder |
| | | here = os.path.dirname(os.path.abspath(__file__)) |
| | | |
| | | |
| | | class TestAssetsConfiguratorMixin(unittest.TestCase): |
| | | def _makeOne(self, *arg, **kw): |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator(*arg, **kw) |
| | | return config |
| | | |
| | | def test_override_asset_samename(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | |
| | | config = self._makeOne() |
| | | self.assertRaises(ConfigurationError, config.override_asset, 'a', 'a') |
| | | |
| | | def test_override_asset_directory_with_file(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | |
| | | config = self._makeOne() |
| | | self.assertRaises(ConfigurationError, config.override_asset, |
| | | 'a:foo/', |
| | | 'tests.test_config.pkgs.asset:foo.pt') |
| | | self.assertRaises( |
| | | ConfigurationError, |
| | | config.override_asset, |
| | | 'a:foo/', |
| | | 'tests.test_config.pkgs.asset:foo.pt', |
| | | ) |
| | | |
| | | def test_override_asset_file_with_directory(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | |
| | | config = self._makeOne() |
| | | self.assertRaises(ConfigurationError, config.override_asset, |
| | | 'a:foo.pt', |
| | | 'tests.test_config.pkgs.asset:templates/') |
| | | self.assertRaises( |
| | | ConfigurationError, |
| | | config.override_asset, |
| | | 'a:foo.pt', |
| | | 'tests.test_config.pkgs.asset:templates/', |
| | | ) |
| | | |
| | | def test_override_asset_file_with_package(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | |
| | | config = self._makeOne() |
| | | self.assertRaises(ConfigurationError, config.override_asset, |
| | | 'a:foo.pt', |
| | | 'tests.test_config.pkgs.asset') |
| | | self.assertRaises( |
| | | ConfigurationError, |
| | | config.override_asset, |
| | | 'a:foo.pt', |
| | | 'tests.test_config.pkgs.asset', |
| | | ) |
| | | |
| | | def test_override_asset_file_with_file(self): |
| | | from pyramid.config.assets import PackageAssetSource |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | override = DummyUnderOverride() |
| | | config.override_asset( |
| | | 'tests.test_config.pkgs.asset:templates/foo.pt', |
| | | 'tests.test_config.pkgs.asset.subpackage:templates/bar.pt', |
| | | _override=override) |
| | | _override=override, |
| | | ) |
| | | from tests.test_config.pkgs import asset |
| | | from tests.test_config.pkgs.asset import subpackage |
| | | |
| | | self.assertEqual(override.package, asset) |
| | | self.assertEqual(override.path, 'templates/foo.pt') |
| | | source = override.source |
| | |
| | | self.assertEqual(source.prefix, 'templates/bar.pt') |
| | | |
| | | resource_name = '' |
| | | expected = os.path.join(here, 'pkgs', 'asset', |
| | | 'subpackage', 'templates', 'bar.pt') |
| | | self.assertEqual(override.source.get_filename(resource_name), |
| | | expected) |
| | | expected = os.path.join( |
| | | here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' |
| | | ) |
| | | self.assertEqual(override.source.get_filename(resource_name), expected) |
| | | |
| | | def test_override_asset_package_with_package(self): |
| | | from pyramid.config.assets import PackageAssetSource |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | override = DummyUnderOverride() |
| | | config.override_asset( |
| | | 'tests.test_config.pkgs.asset', |
| | | 'tests.test_config.pkgs.asset.subpackage', |
| | | _override=override) |
| | | _override=override, |
| | | ) |
| | | from tests.test_config.pkgs import asset |
| | | from tests.test_config.pkgs.asset import subpackage |
| | | |
| | | self.assertEqual(override.package, asset) |
| | | self.assertEqual(override.path, '') |
| | | source = override.source |
| | |
| | | self.assertEqual(source.prefix, '') |
| | | |
| | | resource_name = 'templates/bar.pt' |
| | | expected = os.path.join(here, 'pkgs', 'asset', |
| | | 'subpackage', 'templates', 'bar.pt') |
| | | self.assertEqual(override.source.get_filename(resource_name), |
| | | expected) |
| | | expected = os.path.join( |
| | | here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' |
| | | ) |
| | | self.assertEqual(override.source.get_filename(resource_name), expected) |
| | | |
| | | def test_override_asset_directory_with_directory(self): |
| | | from pyramid.config.assets import PackageAssetSource |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | override = DummyUnderOverride() |
| | | config.override_asset( |
| | | 'tests.test_config.pkgs.asset:templates/', |
| | | 'tests.test_config.pkgs.asset.subpackage:templates/', |
| | | _override=override) |
| | | _override=override, |
| | | ) |
| | | from tests.test_config.pkgs import asset |
| | | from tests.test_config.pkgs.asset import subpackage |
| | | |
| | | self.assertEqual(override.package, asset) |
| | | self.assertEqual(override.path, 'templates/') |
| | | source = override.source |
| | |
| | | self.assertEqual(source.prefix, 'templates/') |
| | | |
| | | resource_name = 'bar.pt' |
| | | expected = os.path.join(here, 'pkgs', 'asset', |
| | | 'subpackage', 'templates', 'bar.pt') |
| | | self.assertEqual(override.source.get_filename(resource_name), |
| | | expected) |
| | | expected = os.path.join( |
| | | here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' |
| | | ) |
| | | self.assertEqual(override.source.get_filename(resource_name), expected) |
| | | |
| | | def test_override_asset_directory_with_package(self): |
| | | from pyramid.config.assets import PackageAssetSource |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | override = DummyUnderOverride() |
| | | config.override_asset( |
| | | 'tests.test_config.pkgs.asset:templates/', |
| | | 'tests.test_config.pkgs.asset.subpackage', |
| | | _override=override) |
| | | _override=override, |
| | | ) |
| | | from tests.test_config.pkgs import asset |
| | | from tests.test_config.pkgs.asset import subpackage |
| | | |
| | | self.assertEqual(override.package, asset) |
| | | self.assertEqual(override.path, 'templates/') |
| | | source = override.source |
| | |
| | | self.assertEqual(source.prefix, '') |
| | | |
| | | resource_name = 'templates/bar.pt' |
| | | expected = os.path.join(here, 'pkgs', 'asset', |
| | | 'subpackage', 'templates', 'bar.pt') |
| | | self.assertEqual(override.source.get_filename(resource_name), |
| | | expected) |
| | | expected = os.path.join( |
| | | here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' |
| | | ) |
| | | self.assertEqual(override.source.get_filename(resource_name), expected) |
| | | |
| | | def test_override_asset_package_with_directory(self): |
| | | from pyramid.config.assets import PackageAssetSource |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | override = DummyUnderOverride() |
| | | config.override_asset( |
| | | 'tests.test_config.pkgs.asset', |
| | | 'tests.test_config.pkgs.asset.subpackage:templates/', |
| | | _override=override) |
| | | _override=override, |
| | | ) |
| | | from tests.test_config.pkgs import asset |
| | | from tests.test_config.pkgs.asset import subpackage |
| | | |
| | | self.assertEqual(override.package, asset) |
| | | self.assertEqual(override.path, '') |
| | | source = override.source |
| | |
| | | self.assertEqual(source.prefix, 'templates/') |
| | | |
| | | resource_name = 'bar.pt' |
| | | expected = os.path.join(here, 'pkgs', 'asset', |
| | | 'subpackage', 'templates', 'bar.pt') |
| | | self.assertEqual(override.source.get_filename(resource_name), |
| | | expected) |
| | | expected = os.path.join( |
| | | here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' |
| | | ) |
| | | self.assertEqual(override.source.get_filename(resource_name), expected) |
| | | |
| | | def test_override_asset_directory_with_absfile(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | |
| | | config = self._makeOne() |
| | | self.assertRaises(ConfigurationError, config.override_asset, |
| | | 'a:foo/', |
| | | os.path.join(here, 'pkgs', 'asset', 'foo.pt')) |
| | | self.assertRaises( |
| | | ConfigurationError, |
| | | config.override_asset, |
| | | 'a:foo/', |
| | | os.path.join(here, 'pkgs', 'asset', 'foo.pt'), |
| | | ) |
| | | |
| | | def test_override_asset_file_with_absdirectory(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | |
| | | config = self._makeOne() |
| | | abspath = os.path.join(here, 'pkgs', 'asset', 'subpackage', 'templates') |
| | | self.assertRaises(ConfigurationError, config.override_asset, |
| | | 'a:foo.pt', |
| | | abspath) |
| | | abspath = os.path.join( |
| | | here, 'pkgs', 'asset', 'subpackage', 'templates' |
| | | ) |
| | | self.assertRaises( |
| | | ConfigurationError, config.override_asset, 'a:foo.pt', abspath |
| | | ) |
| | | |
| | | def test_override_asset_file_with_missing_abspath(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | |
| | | config = self._makeOne() |
| | | self.assertRaises(ConfigurationError, config.override_asset, |
| | | 'a:foo.pt', |
| | | os.path.join(here, 'wont_exist')) |
| | | self.assertRaises( |
| | | ConfigurationError, |
| | | config.override_asset, |
| | | 'a:foo.pt', |
| | | os.path.join(here, 'wont_exist'), |
| | | ) |
| | | |
| | | def test_override_asset_file_with_absfile(self): |
| | | from pyramid.config.assets import FSAssetSource |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | override = DummyUnderOverride() |
| | | abspath = os.path.join(here, 'pkgs', 'asset', 'subpackage', |
| | | 'templates', 'bar.pt') |
| | | abspath = os.path.join( |
| | | here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' |
| | | ) |
| | | config.override_asset( |
| | | 'tests.test_config.pkgs.asset:templates/foo.pt', |
| | | abspath, |
| | | _override=override) |
| | | _override=override, |
| | | ) |
| | | from tests.test_config.pkgs import asset |
| | | |
| | | self.assertEqual(override.package, asset) |
| | | self.assertEqual(override.path, 'templates/foo.pt') |
| | | source = override.source |
| | |
| | | self.assertEqual(source.prefix, abspath) |
| | | |
| | | resource_name = '' |
| | | expected = os.path.join(here, 'pkgs', 'asset', |
| | | 'subpackage', 'templates', 'bar.pt') |
| | | self.assertEqual(override.source.get_filename(resource_name), |
| | | expected) |
| | | expected = os.path.join( |
| | | here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' |
| | | ) |
| | | self.assertEqual(override.source.get_filename(resource_name), expected) |
| | | |
| | | def test_override_asset_directory_with_absdirectory(self): |
| | | from pyramid.config.assets import FSAssetSource |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | override = DummyUnderOverride() |
| | | abspath = os.path.join(here, 'pkgs', 'asset', 'subpackage', 'templates') |
| | | abspath = os.path.join( |
| | | here, 'pkgs', 'asset', 'subpackage', 'templates' |
| | | ) |
| | | config.override_asset( |
| | | 'tests.test_config.pkgs.asset:templates/', |
| | | abspath, |
| | | _override=override) |
| | | _override=override, |
| | | ) |
| | | from tests.test_config.pkgs import asset |
| | | |
| | | self.assertEqual(override.package, asset) |
| | | self.assertEqual(override.path, 'templates/') |
| | | source = override.source |
| | |
| | | self.assertEqual(source.prefix, abspath) |
| | | |
| | | resource_name = 'bar.pt' |
| | | expected = os.path.join(here, 'pkgs', 'asset', |
| | | 'subpackage', 'templates', 'bar.pt') |
| | | self.assertEqual(override.source.get_filename(resource_name), |
| | | expected) |
| | | expected = os.path.join( |
| | | here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' |
| | | ) |
| | | self.assertEqual(override.source.get_filename(resource_name), expected) |
| | | |
| | | def test_override_asset_package_with_absdirectory(self): |
| | | from pyramid.config.assets import FSAssetSource |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | override = DummyUnderOverride() |
| | | abspath = os.path.join(here, 'pkgs', 'asset', 'subpackage', 'templates') |
| | | abspath = os.path.join( |
| | | here, 'pkgs', 'asset', 'subpackage', 'templates' |
| | | ) |
| | | config.override_asset( |
| | | 'tests.test_config.pkgs.asset', |
| | | abspath, |
| | | _override=override) |
| | | 'tests.test_config.pkgs.asset', abspath, _override=override |
| | | ) |
| | | from tests.test_config.pkgs import asset |
| | | |
| | | self.assertEqual(override.package, asset) |
| | | self.assertEqual(override.path, '') |
| | | source = override.source |
| | |
| | | self.assertEqual(source.prefix, abspath) |
| | | |
| | | resource_name = 'bar.pt' |
| | | expected = os.path.join(here, 'pkgs', 'asset', |
| | | 'subpackage', 'templates', 'bar.pt') |
| | | self.assertEqual(override.source.get_filename(resource_name), |
| | | expected) |
| | | expected = os.path.join( |
| | | here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' |
| | | ) |
| | | self.assertEqual(override.source.get_filename(resource_name), expected) |
| | | |
| | | def test__override_not_yet_registered(self): |
| | | from pyramid.interfaces import IPackageOverrides |
| | | |
| | | package = DummyPackage('package') |
| | | source = DummyAssetSource() |
| | | config = self._makeOne() |
| | | config._override(package, 'path', source, |
| | | PackageOverrides=DummyPackageOverrides) |
| | | overrides = config.registry.queryUtility(IPackageOverrides, |
| | | name='package') |
| | | config._override( |
| | | package, 'path', source, PackageOverrides=DummyPackageOverrides |
| | | ) |
| | | overrides = config.registry.queryUtility( |
| | | IPackageOverrides, name='package' |
| | | ) |
| | | self.assertEqual(overrides.inserted, [('path', source)]) |
| | | self.assertEqual(overrides.package, package) |
| | | |
| | | def test__override_already_registered(self): |
| | | from pyramid.interfaces import IPackageOverrides |
| | | |
| | | package = DummyPackage('package') |
| | | source = DummyAssetSource() |
| | | overrides = DummyPackageOverrides(package) |
| | | config = self._makeOne() |
| | | config.registry.registerUtility(overrides, IPackageOverrides, |
| | | name='package') |
| | | config._override(package, 'path', source, |
| | | PackageOverrides=DummyPackageOverrides) |
| | | config.registry.registerUtility( |
| | | overrides, IPackageOverrides, name='package' |
| | | ) |
| | | config._override( |
| | | package, 'path', source, PackageOverrides=DummyPackageOverrides |
| | | ) |
| | | self.assertEqual(overrides.inserted, [('path', source)]) |
| | | self.assertEqual(overrides.package, package) |
| | | |
| | |
| | | |
| | | def _getTargetClass(self): |
| | | from pyramid.config.assets import OverrideProvider |
| | | |
| | | return OverrideProvider |
| | | |
| | | def _makeOne(self, module): |
| | |
| | | def _registerOverrides(self, overrides, name='tests.test_config'): |
| | | from pyramid.interfaces import IPackageOverrides |
| | | from pyramid.threadlocal import get_current_registry |
| | | |
| | | reg = get_current_registry() |
| | | reg.registerUtility(overrides, IPackageOverrides, name=name) |
| | | |
| | | def test_get_resource_filename_no_overrides(self): |
| | | resource_name = 'test_assets.py' |
| | | import tests.test_config |
| | | |
| | | provider = self._makeOne(tests.test_config) |
| | | expected = os.path.join(here, resource_name) |
| | | result = provider.get_resource_filename(None, resource_name) |
| | |
| | | def test_get_resource_stream_no_overrides(self): |
| | | resource_name = 'test_assets.py' |
| | | import tests.test_config |
| | | |
| | | provider = self._makeOne(tests.test_config) |
| | | with provider.get_resource_stream(None, resource_name) as result: |
| | | _assertBody(result.read(), os.path.join(here, resource_name)) |
| | |
| | | def test_get_resource_string_no_overrides(self): |
| | | resource_name = 'test_assets.py' |
| | | import tests.test_config |
| | | |
| | | provider = self._makeOne(tests.test_config) |
| | | result = provider.get_resource_string(None, resource_name) |
| | | _assertBody(result, os.path.join(here, resource_name)) |
| | |
| | | def test_has_resource_no_overrides(self): |
| | | resource_name = 'test_assets.py' |
| | | import tests.test_config |
| | | |
| | | provider = self._makeOne(tests.test_config) |
| | | result = provider.has_resource(resource_name) |
| | | self.assertEqual(result, True) |
| | |
| | | file_resource_name = 'test_assets.py' |
| | | directory_resource_name = 'files' |
| | | import tests.test_config |
| | | |
| | | provider = self._makeOne(tests.test_config) |
| | | result = provider.resource_isdir(file_resource_name) |
| | | self.assertEqual(result, False) |
| | |
| | | def test_resource_listdir_no_overrides(self): |
| | | resource_name = 'files' |
| | | import tests.test_config |
| | | |
| | | provider = self._makeOne(tests.test_config) |
| | | result = provider.resource_listdir(resource_name) |
| | | self.assertTrue(result) |
| | |
| | | self._registerOverrides(overrides) |
| | | resource_name = 'test_assets.py' |
| | | import tests.test_config |
| | | |
| | | provider = self._makeOne(tests.test_config) |
| | | expected = os.path.join(here, resource_name) |
| | | result = provider.get_resource_filename(None, resource_name) |
| | | self.assertEqual(result, expected) |
| | | |
| | | |
| | | def test_get_resource_stream_override_returns_None(self): |
| | | overrides = DummyOverrides(None) |
| | | self._registerOverrides(overrides) |
| | | resource_name = 'test_assets.py' |
| | | import tests.test_config |
| | | |
| | | provider = self._makeOne(tests.test_config) |
| | | with provider.get_resource_stream(None, resource_name) as result: |
| | | _assertBody(result.read(), os.path.join(here, resource_name)) |
| | |
| | | self._registerOverrides(overrides) |
| | | resource_name = 'test_assets.py' |
| | | import tests.test_config |
| | | |
| | | provider = self._makeOne(tests.test_config) |
| | | result = provider.get_resource_string(None, resource_name) |
| | | _assertBody(result, os.path.join(here, resource_name)) |
| | |
| | | self._registerOverrides(overrides) |
| | | resource_name = 'test_assets.py' |
| | | import tests.test_config |
| | | |
| | | provider = self._makeOne(tests.test_config) |
| | | result = provider.has_resource(resource_name) |
| | | self.assertEqual(result, True) |
| | |
| | | self._registerOverrides(overrides) |
| | | resource_name = 'files' |
| | | import tests.test_config |
| | | |
| | | provider = self._makeOne(tests.test_config) |
| | | result = provider.resource_isdir(resource_name) |
| | | self.assertEqual(result, True) |
| | |
| | | self._registerOverrides(overrides) |
| | | resource_name = 'files' |
| | | import tests.test_config |
| | | |
| | | provider = self._makeOne(tests.test_config) |
| | | result = provider.resource_listdir(resource_name) |
| | | self.assertTrue(result) |
| | |
| | | def test_get_resource_filename_override_returns_value(self): |
| | | overrides = DummyOverrides('value') |
| | | import tests.test_config |
| | | |
| | | self._registerOverrides(overrides) |
| | | provider = self._makeOne(tests.test_config) |
| | | result = provider.get_resource_filename(None, 'test_assets.py') |
| | |
| | | |
| | | def test_get_resource_stream_override_returns_value(self): |
| | | from io import BytesIO |
| | | |
| | | overrides = DummyOverrides(BytesIO(b'value')) |
| | | import tests.test_config |
| | | |
| | | self._registerOverrides(overrides) |
| | | provider = self._makeOne(tests.test_config) |
| | | with provider.get_resource_stream(None, 'test_assets.py') as stream: |
| | |
| | | def test_get_resource_string_override_returns_value(self): |
| | | overrides = DummyOverrides('value') |
| | | import tests.test_config |
| | | |
| | | self._registerOverrides(overrides) |
| | | provider = self._makeOne(tests.test_config) |
| | | result = provider.get_resource_string(None, 'test_assets.py') |
| | |
| | | def test_has_resource_override_returns_True(self): |
| | | overrides = DummyOverrides(True) |
| | | import tests.test_config |
| | | |
| | | self._registerOverrides(overrides) |
| | | provider = self._makeOne(tests.test_config) |
| | | result = provider.has_resource('test_assets.py') |
| | |
| | | def test_resource_isdir_override_returns_False(self): |
| | | overrides = DummyOverrides(False) |
| | | import tests.test_config |
| | | |
| | | self._registerOverrides(overrides) |
| | | provider = self._makeOne(tests.test_config) |
| | | result = provider.resource_isdir('files') |
| | |
| | | def test_resource_listdir_override_returns_values(self): |
| | | overrides = DummyOverrides(['a']) |
| | | import tests.test_config |
| | | |
| | | self._registerOverrides(overrides) |
| | | provider = self._makeOne(tests.test_config) |
| | | result = provider.resource_listdir('files') |
| | | self.assertEqual(result, ['a']) |
| | | |
| | | |
| | | class TestPackageOverrides(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.config.assets import PackageOverrides |
| | | |
| | | return PackageOverrides |
| | | |
| | | def _makeOne(self, package=None, pkg_resources=None): |
| | |
| | | def test_class_conforms_to_IPackageOverrides(self): |
| | | from zope.interface.verify import verifyClass |
| | | from pyramid.interfaces import IPackageOverrides |
| | | |
| | | verifyClass(IPackageOverrides, self._getTargetClass()) |
| | | |
| | | def test_instance_conforms_to_IPackageOverrides(self): |
| | | from zope.interface.verify import verifyObject |
| | | from pyramid.interfaces import IPackageOverrides |
| | | |
| | | verifyObject(IPackageOverrides, self._makeOne()) |
| | | |
| | | def test_class_conforms_to_IPEP302Loader(self): |
| | | from zope.interface.verify import verifyClass |
| | | from pyramid.interfaces import IPEP302Loader |
| | | |
| | | verifyClass(IPEP302Loader, self._getTargetClass()) |
| | | |
| | | def test_instance_conforms_to_IPEP302Loader(self): |
| | | from zope.interface.verify import verifyObject |
| | | from pyramid.interfaces import IPEP302Loader |
| | | |
| | | verifyObject(IPEP302Loader, self._makeOne()) |
| | | |
| | | def test_ctor_package_already_has_loader_of_different_type(self): |
| | |
| | | |
| | | def test_ctor_registers_loader_type(self): |
| | | from pyramid.config.assets import OverrideProvider |
| | | |
| | | dummy_pkg_resources = DummyPkgResources() |
| | | package = DummyPackage('package') |
| | | po = self._makeOne(package, dummy_pkg_resources) |
| | | self.assertEqual(dummy_pkg_resources.registered, [(po.__class__, |
| | | OverrideProvider)]) |
| | | self.assertEqual( |
| | | dummy_pkg_resources.registered, [(po.__class__, OverrideProvider)] |
| | | ) |
| | | |
| | | def test_ctor_sets_local_state(self): |
| | | package = DummyPackage('package') |
| | |
| | | |
| | | def test_insert_directory(self): |
| | | from pyramid.config.assets import DirectoryOverride |
| | | |
| | | package = DummyPackage('package') |
| | | po = self._makeOne(package) |
| | | po.overrides = [None] |
| | |
| | | |
| | | def test_insert_file(self): |
| | | from pyramid.config.assets import FileOverride |
| | | |
| | | package = DummyPackage('package') |
| | | po = self._makeOne(package) |
| | | po.overrides = [None] |
| | |
| | | def test_insert_emptystring(self): |
| | | # XXX is this a valid case for a directory? |
| | | from pyramid.config.assets import DirectoryOverride |
| | | |
| | | package = DummyPackage('package') |
| | | po = self._makeOne(package) |
| | | po.overrides = [None] |
| | |
| | | self.assertEqual(override.__class__, DirectoryOverride) |
| | | |
| | | def test_filtered_sources(self): |
| | | overrides = [ DummyOverride(None), DummyOverride('foo')] |
| | | overrides = [DummyOverride(None), DummyOverride('foo')] |
| | | package = DummyPackage('package') |
| | | po = self._makeOne(package) |
| | | po.overrides = overrides |
| | |
| | | |
| | | def test_get_filename(self): |
| | | source = DummyAssetSource(filename='foo.pt') |
| | | overrides = [ DummyOverride(None), DummyOverride((source, ''))] |
| | | overrides = [DummyOverride(None), DummyOverride((source, ''))] |
| | | package = DummyPackage('package') |
| | | po = self._makeOne(package) |
| | | po.overrides = overrides |
| | |
| | | |
| | | def test_get_filename_file_doesnt_exist(self): |
| | | source = DummyAssetSource(filename=None) |
| | | overrides = [DummyOverride(None), DummyOverride((source, 'wont_exist'))] |
| | | overrides = [ |
| | | DummyOverride(None), |
| | | DummyOverride((source, 'wont_exist')), |
| | | ] |
| | | package = DummyPackage('package') |
| | | po = self._makeOne(package) |
| | | po.overrides = overrides |
| | |
| | | po.overrides = overrides |
| | | self.assertEqual(po.get_stream('whatever'), 'a stream?') |
| | | self.assertEqual(source.resource_name, 'foo.pt') |
| | | |
| | | |
| | | def test_get_stream_file_doesnt_exist(self): |
| | | source = DummyAssetSource(stream=None) |
| | | overrides = [DummyOverride(None), DummyOverride((source, 'wont_exist'))] |
| | | overrides = [ |
| | | DummyOverride(None), |
| | | DummyOverride((source, 'wont_exist')), |
| | | ] |
| | | package = DummyPackage('package') |
| | | po = self._makeOne(package) |
| | | po.overrides = overrides |
| | |
| | | po.overrides = overrides |
| | | self.assertEqual(po.get_string('whatever'), 'a string') |
| | | self.assertEqual(source.resource_name, 'foo.pt') |
| | | |
| | | |
| | | def test_get_string_file_doesnt_exist(self): |
| | | source = DummyAssetSource(string=None) |
| | | overrides = [DummyOverride(None), DummyOverride((source, 'wont_exist'))] |
| | | overrides = [ |
| | | DummyOverride(None), |
| | | DummyOverride((source, 'wont_exist')), |
| | | ] |
| | | package = DummyPackage('package') |
| | | po = self._makeOne(package) |
| | | po.overrides = overrides |
| | |
| | | |
| | | def test_has_resource_file_doesnt_exist(self): |
| | | source = DummyAssetSource(exists=None) |
| | | overrides = [DummyOverride(None), DummyOverride((source, 'wont_exist'))] |
| | | overrides = [ |
| | | DummyOverride(None), |
| | | DummyOverride((source, 'wont_exist')), |
| | | ] |
| | | package = DummyPackage('package') |
| | | po = self._makeOne(package) |
| | | po.overrides = overrides |
| | |
| | | |
| | | def test_isdir_doesnt_exist(self): |
| | | source = DummyAssetSource(isdir=None) |
| | | overrides = [DummyOverride(None), DummyOverride((source, 'wont_exist'))] |
| | | overrides = [ |
| | | DummyOverride(None), |
| | | DummyOverride((source, 'wont_exist')), |
| | | ] |
| | | package = DummyPackage('package') |
| | | po = self._makeOne(package) |
| | | po.overrides = overrides |
| | |
| | | |
| | | def test_listdir_doesnt_exist(self): |
| | | source = DummyAssetSource(listdir=None) |
| | | overrides = [DummyOverride(None), DummyOverride((source, 'wont_exist'))] |
| | | overrides = [ |
| | | DummyOverride(None), |
| | | DummyOverride((source, 'wont_exist')), |
| | | ] |
| | | package = DummyPackage('package') |
| | | po = self._makeOne(package) |
| | | po.overrides = overrides |
| | |
| | | |
| | | def test_get_data_pkg_has___loader__(self): |
| | | package = DummyPackage('package') |
| | | loader = package.__loader__ = DummyLoader() |
| | | loader = package.__loader__ = DummyLoader() |
| | | po = self._makeOne(package) |
| | | self.assertEqual(po.get_data('whatever'), b'DEADBEEF') |
| | | self.assertEqual(loader._got_data, 'whatever') |
| | |
| | | |
| | | def test_is_package_pkg_has___loader__(self): |
| | | package = DummyPackage('package') |
| | | loader = package.__loader__ = DummyLoader() |
| | | loader = package.__loader__ = DummyLoader() |
| | | po = self._makeOne(package) |
| | | self.assertTrue(po.is_package('whatever')) |
| | | self.assertEqual(loader._is_package, 'whatever') |
| | |
| | | |
| | | def test_get_code_pkg_has___loader__(self): |
| | | package = DummyPackage('package') |
| | | loader = package.__loader__ = DummyLoader() |
| | | loader = package.__loader__ = DummyLoader() |
| | | po = self._makeOne(package) |
| | | self.assertEqual(po.get_code('whatever'), b'DEADBEEF') |
| | | self.assertEqual(loader._got_code, 'whatever') |
| | |
| | | self.assertEqual(po.get_source('whatever'), 'def foo():\n pass') |
| | | self.assertEqual(loader._got_source, 'whatever') |
| | | |
| | | class AssetSourceIntegrationTests(object): |
| | | |
| | | class AssetSourceIntegrationTests(object): |
| | | def test_get_filename(self): |
| | | source = self._makeOne('') |
| | | self.assertEqual(source.get_filename('test_assets.py'), |
| | | os.path.join(here, 'test_assets.py')) |
| | | self.assertEqual( |
| | | source.get_filename('test_assets.py'), |
| | | os.path.join(here, 'test_assets.py'), |
| | | ) |
| | | |
| | | def test_get_filename_with_prefix(self): |
| | | source = self._makeOne('test_assets.py') |
| | | self.assertEqual(source.get_filename(''), |
| | | os.path.join(here, 'test_assets.py')) |
| | | self.assertEqual( |
| | | source.get_filename(''), os.path.join(here, 'test_assets.py') |
| | | ) |
| | | |
| | | def test_get_filename_file_doesnt_exist(self): |
| | | source = self._makeOne('') |
| | |
| | | |
| | | def test_get_string(self): |
| | | source = self._makeOne('') |
| | | _assertBody(source.get_string('test_assets.py'), |
| | | os.path.join(here, 'test_assets.py')) |
| | | _assertBody( |
| | | source.get_string('test_assets.py'), |
| | | os.path.join(here, 'test_assets.py'), |
| | | ) |
| | | |
| | | def test_get_string_with_prefix(self): |
| | | source = self._makeOne('test_assets.py') |
| | | _assertBody(source.get_string(''), |
| | | os.path.join(here, 'test_assets.py')) |
| | | _assertBody( |
| | | source.get_string(''), os.path.join(here, 'test_assets.py') |
| | | ) |
| | | |
| | | def test_get_string_file_doesnt_exist(self): |
| | | source = self._makeOne('') |
| | |
| | | source = self._makeOne('') |
| | | self.assertEqual(source.listdir('wont_exist'), None) |
| | | |
| | | class TestPackageAssetSource(AssetSourceIntegrationTests, unittest.TestCase): |
| | | |
| | | class TestPackageAssetSource(AssetSourceIntegrationTests, unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.config.assets import PackageAssetSource |
| | | |
| | | return PackageAssetSource |
| | | |
| | | def _makeOne(self, prefix, package='tests.test_config'): |
| | | klass = self._getTargetClass() |
| | | return klass(package, prefix) |
| | | |
| | | |
| | | class TestFSAssetSource(AssetSourceIntegrationTests, unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.config.assets import FSAssetSource |
| | | |
| | | return FSAssetSource |
| | | |
| | | def _makeOne(self, prefix, base_prefix=here): |
| | | klass = self._getTargetClass() |
| | | return klass(os.path.join(base_prefix, prefix)) |
| | | |
| | | |
| | | class TestDirectoryOverride(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.config.assets import DirectoryOverride |
| | | |
| | | return DirectoryOverride |
| | | |
| | | def _makeOne(self, path, source): |
| | |
| | | o = self._makeOne('foo/', source) |
| | | result = o('foo/something.pt') |
| | | self.assertEqual(result, (source, 'something.pt')) |
| | | |
| | | |
| | | def test_it_no_match(self): |
| | | source = DummyAssetSource() |
| | | o = self._makeOne('foo/', source) |
| | | result = o('baz/notfound.pt') |
| | | self.assertEqual(result, None) |
| | | |
| | | |
| | | class TestFileOverride(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.config.assets import FileOverride |
| | | |
| | | return FileOverride |
| | | |
| | | def _makeOne(self, path, source): |
| | |
| | | o = self._makeOne('foo.pt', source) |
| | | result = o('foo.pt') |
| | | self.assertEqual(result, (source, '')) |
| | | |
| | | |
| | | def test_it_no_match(self): |
| | | source = DummyAssetSource() |
| | | o = self._makeOne('foo.pt', source) |
| | | result = o('notfound.pt') |
| | | self.assertEqual(result, None) |
| | | |
| | | |
| | | class DummyOverride: |
| | | def __init__(self, result): |
| | |
| | | |
| | | def __call__(self, resource_name): |
| | | return self.result |
| | | |
| | | |
| | | class DummyOverrides: |
| | | def __init__(self, result): |
| | |
| | | |
| | | listdir = isdir = has_resource = get_stream = get_string = get_filename |
| | | |
| | | |
| | | class DummyPackageOverrides: |
| | | def __init__(self, package): |
| | | self.package = package |
| | |
| | | |
| | | def insert(self, path, source): |
| | | self.inserted.append((path, source)) |
| | | |
| | | |
| | | |
| | | class DummyPkgResources: |
| | | def __init__(self): |
| | | self.registered = [] |
| | |
| | | def register_loader_type(self, typ, inst): |
| | | self.registered.append((typ, inst)) |
| | | |
| | | |
| | | class DummyPackage: |
| | | def __init__(self, name): |
| | | self.__name__ = name |
| | | |
| | | |
| | | class DummyAssetSource: |
| | | def __init__(self, **kw): |
| | |
| | | def listdir(self, resource_name): |
| | | self.resource_name = resource_name |
| | | return self.kw['listdir'] |
| | | |
| | | |
| | | |
| | | class DummyLoader: |
| | | _got_data = _is_package = None |
| | | |
| | | def get_data(self, path): |
| | | self._got_data = path |
| | | return b'DEADBEEF' |
| | | |
| | | def is_package(self, fullname): |
| | | self._is_package = fullname |
| | | return True |
| | | |
| | | def get_code(self, fullname): |
| | | self._got_code = fullname |
| | | return b'DEADBEEF' |
| | | |
| | | def get_source(self, fullname): |
| | | self._got_source = fullname |
| | | return 'def foo():\n pass' |
| | | |
| | | |
| | | class DummyUnderOverride: |
| | | def __call__(self, package, path, source, _info=''): |
| | |
| | | self.path = path |
| | | self.source = source |
| | | |
| | | |
| | | def read_(src): |
| | | with open(src, 'rb') as f: |
| | | contents = f.read() |
| | | return contents |
| | | |
| | | |
| | | def _assertBody(body, filename): |
| | | # strip both \n and \r for windows |
| | |
| | | data = read_(filename) |
| | | data = data.replace(b'\r', b'') |
| | | data = data.replace(b'\n', b'') |
| | | assert(body == data) |
| | | assert body == data |
| | |
| | | |
| | | from . import dummyfactory |
| | | |
| | | |
| | | class TestFactoriesMixin(unittest.TestCase): |
| | | def _makeOne(self, *arg, **kw): |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator(*arg, **kw) |
| | | return config |
| | | |
| | | def test_set_request_factory(self): |
| | | from pyramid.interfaces import IRequestFactory |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | factory = object() |
| | | config.set_request_factory(factory) |
| | |
| | | |
| | | def test_set_request_factory_dottedname(self): |
| | | from pyramid.interfaces import IRequestFactory |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.set_request_factory( |
| | | 'tests.test_config.dummyfactory') |
| | | self.assertEqual(config.registry.getUtility(IRequestFactory), |
| | | dummyfactory) |
| | | config.set_request_factory('tests.test_config.dummyfactory') |
| | | self.assertEqual( |
| | | config.registry.getUtility(IRequestFactory), dummyfactory |
| | | ) |
| | | |
| | | def test_set_response_factory(self): |
| | | from pyramid.interfaces import IResponseFactory |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | factory = lambda r: object() |
| | | config.set_response_factory(factory) |
| | |
| | | |
| | | def test_set_response_factory_dottedname(self): |
| | | from pyramid.interfaces import IResponseFactory |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.set_response_factory( |
| | | 'tests.test_config.dummyfactory') |
| | | self.assertEqual(config.registry.getUtility(IResponseFactory), |
| | | dummyfactory) |
| | | config.set_response_factory('tests.test_config.dummyfactory') |
| | | self.assertEqual( |
| | | config.registry.getUtility(IResponseFactory), dummyfactory |
| | | ) |
| | | |
| | | def test_set_root_factory(self): |
| | | from pyramid.interfaces import IRootFactory |
| | | |
| | | config = self._makeOne() |
| | | config.set_root_factory(dummyfactory) |
| | | self.assertEqual(config.registry.queryUtility(IRootFactory), None) |
| | | config.commit() |
| | | self.assertEqual(config.registry.getUtility(IRootFactory), dummyfactory) |
| | | self.assertEqual( |
| | | config.registry.getUtility(IRootFactory), dummyfactory |
| | | ) |
| | | |
| | | def test_set_root_factory_as_None(self): |
| | | from pyramid.interfaces import IRootFactory |
| | | from pyramid.traversal import DefaultRootFactory |
| | | |
| | | config = self._makeOne() |
| | | config.set_root_factory(None) |
| | | self.assertEqual(config.registry.queryUtility(IRootFactory), None) |
| | | config.commit() |
| | | self.assertEqual(config.registry.getUtility(IRootFactory), |
| | | DefaultRootFactory) |
| | | self.assertEqual( |
| | | config.registry.getUtility(IRootFactory), DefaultRootFactory |
| | | ) |
| | | |
| | | def test_set_root_factory_dottedname(self): |
| | | from pyramid.interfaces import IRootFactory |
| | | |
| | | config = self._makeOne() |
| | | config.set_root_factory('tests.test_config.dummyfactory') |
| | | self.assertEqual(config.registry.queryUtility(IRootFactory), None) |
| | | config.commit() |
| | | self.assertEqual(config.registry.getUtility(IRootFactory), dummyfactory) |
| | | self.assertEqual( |
| | | config.registry.getUtility(IRootFactory), dummyfactory |
| | | ) |
| | | |
| | | def test_set_session_factory(self): |
| | | from pyramid.interfaces import ISessionFactory |
| | | |
| | | config = self._makeOne() |
| | | config.set_session_factory(dummyfactory) |
| | | self.assertEqual(config.registry.queryUtility(ISessionFactory), None) |
| | | config.commit() |
| | | self.assertEqual(config.registry.getUtility(ISessionFactory), |
| | | dummyfactory) |
| | | self.assertEqual( |
| | | config.registry.getUtility(ISessionFactory), dummyfactory |
| | | ) |
| | | |
| | | def test_set_session_factory_dottedname(self): |
| | | from pyramid.interfaces import ISessionFactory |
| | | |
| | | config = self._makeOne() |
| | | config.set_session_factory('tests.test_config.dummyfactory') |
| | | self.assertEqual(config.registry.queryUtility(ISessionFactory), None) |
| | | config.commit() |
| | | self.assertEqual(config.registry.getUtility(ISessionFactory), |
| | | dummyfactory) |
| | | self.assertEqual( |
| | | config.registry.getUtility(ISessionFactory), dummyfactory |
| | | ) |
| | | |
| | | def test_add_request_method_with_callable(self): |
| | | from pyramid.interfaces import IRequestExtensions |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | callable = lambda x: None |
| | | config.add_request_method(callable, name='foo') |
| | |
| | | |
| | | def test_add_request_method_with_unnamed_callable(self): |
| | | from pyramid.interfaces import IRequestExtensions |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | def foo(self): pass |
| | | |
| | | def foo(self): # pragma: no cover |
| | | pass |
| | | |
| | | config.add_request_method(foo) |
| | | exts = config.registry.getUtility(IRequestExtensions) |
| | | self.assertTrue('foo' in exts.methods) |
| | | |
| | | def test_set_multiple_request_methods_conflict(self): |
| | | from pyramid.exceptions import ConfigurationConflictError |
| | | |
| | | config = self._makeOne() |
| | | def foo(self): pass |
| | | def bar(self): pass |
| | | |
| | | def foo(self): # pragma: no cover |
| | | pass |
| | | |
| | | def bar(self): # pragma: no cover |
| | | pass |
| | | |
| | | config.add_request_method(foo, name='bar') |
| | | config.add_request_method(bar, name='bar') |
| | | self.assertRaises(ConfigurationConflictError, config.commit) |
| | | |
| | | def test_add_request_method_with_None_callable(self): |
| | | from pyramid.interfaces import IRequestExtensions |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_request_method(name='foo') |
| | | exts = config.registry.queryUtility(IRequestExtensions) |
| | |
| | | |
| | | def test_add_request_method_with_None_callable_conflict(self): |
| | | from pyramid.exceptions import ConfigurationConflictError |
| | | |
| | | config = self._makeOne() |
| | | def bar(self): pass |
| | | |
| | | def bar(self): # pragma: no cover |
| | | pass |
| | | |
| | | config.add_request_method(name='foo') |
| | | config.add_request_method(bar, name='foo') |
| | | self.assertRaises(ConfigurationConflictError, config.commit) |
| | |
| | | self.assertRaises(AttributeError, config.add_request_method) |
| | | |
| | | def test_add_request_method_with_text_type_name(self): |
| | | from pyramid.interfaces import IRequestExtensions |
| | | from pyramid.compat import text_, PY2 |
| | | from pyramid.exceptions import ConfigurationError |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | def boomshaka(r): pass |
| | | |
| | | def boomshaka(r): # pragma: no cover |
| | | pass |
| | | |
| | | def get_bad_name(): |
| | | if PY2: |
| | |
| | | |
| | | def test_set_execution_policy(self): |
| | | from pyramid.interfaces import IExecutionPolicy |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | def dummy_policy(environ, router): pass |
| | | |
| | | def dummy_policy(environ, router): # pragma: no cover |
| | | pass |
| | | |
| | | config.set_execution_policy(dummy_policy) |
| | | registry = config.registry |
| | | result = registry.queryUtility(IExecutionPolicy) |
| | |
| | | def test_set_execution_policy_to_None(self): |
| | | from pyramid.interfaces import IExecutionPolicy |
| | | from pyramid.router import default_execution_policy |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.set_execution_policy(None) |
| | | registry = config.registry |
| | |
| | | |
| | | here = os.path.dirname(__file__) |
| | | locale = os.path.abspath( |
| | | os.path.join(here, '..', 'pkgs', 'localeapp', 'locale')) |
| | | os.path.join(here, '..', 'pkgs', 'localeapp', 'locale') |
| | | ) |
| | | locale2 = os.path.abspath( |
| | | os.path.join(here, '..', 'pkgs', 'localeapp', 'locale2')) |
| | | os.path.join(here, '..', 'pkgs', 'localeapp', 'locale2') |
| | | ) |
| | | locale3 = os.path.abspath( |
| | | os.path.join(here, '..', 'pkgs', 'localeapp', 'locale3')) |
| | | os.path.join(here, '..', 'pkgs', 'localeapp', 'locale3') |
| | | ) |
| | | |
| | | |
| | | class TestI18NConfiguratorMixin(unittest.TestCase): |
| | | def _makeOne(self, *arg, **kw): |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator(*arg, **kw) |
| | | return config |
| | | |
| | | def test_set_locale_negotiator(self): |
| | | from pyramid.interfaces import ILocaleNegotiator |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | def negotiator(request): pass |
| | | |
| | | def negotiator(request): # pragma: no cover |
| | | pass |
| | | |
| | | config.set_locale_negotiator(negotiator) |
| | | self.assertEqual(config.registry.getUtility(ILocaleNegotiator), |
| | | negotiator) |
| | | self.assertEqual( |
| | | config.registry.getUtility(ILocaleNegotiator), negotiator |
| | | ) |
| | | |
| | | def test_set_locale_negotiator_dottedname(self): |
| | | from pyramid.interfaces import ILocaleNegotiator |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.set_locale_negotiator( |
| | | 'tests.test_config.dummyfactory') |
| | | self.assertEqual(config.registry.getUtility(ILocaleNegotiator), |
| | | dummyfactory) |
| | | config.set_locale_negotiator('tests.test_config.dummyfactory') |
| | | self.assertEqual( |
| | | config.registry.getUtility(ILocaleNegotiator), dummyfactory |
| | | ) |
| | | |
| | | def test_add_translation_dirs_missing_dir(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | |
| | | config = self._makeOne() |
| | | config.add_translation_dirs('/wont/exist/on/my/system') |
| | | self.assertRaises(ConfigurationError, config.commit) |
| | | |
| | | def test_add_translation_dirs_no_specs(self): |
| | | from pyramid.interfaces import ITranslationDirectories |
| | | |
| | | config = self._makeOne() |
| | | config.add_translation_dirs() |
| | | self.assertEqual(config.registry.queryUtility(ITranslationDirectories), |
| | | None) |
| | | self.assertEqual( |
| | | config.registry.queryUtility(ITranslationDirectories), None |
| | | ) |
| | | |
| | | def test_add_translation_dirs_asset_spec(self): |
| | | from pyramid.interfaces import ITranslationDirectories |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_translation_dirs('tests.pkgs.localeapp:locale') |
| | | self.assertEqual(config.registry.getUtility(ITranslationDirectories), |
| | | [locale]) |
| | | self.assertEqual( |
| | | config.registry.getUtility(ITranslationDirectories), [locale] |
| | | ) |
| | | |
| | | def test_add_translation_dirs_asset_spec_existing_translation_dirs(self): |
| | | from pyramid.interfaces import ITranslationDirectories |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | directories = ['abc'] |
| | | config.registry.registerUtility(directories, ITranslationDirectories) |
| | |
| | | |
| | | def test_add_translation_dirs_multiple_specs(self): |
| | | from pyramid.interfaces import ITranslationDirectories |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_translation_dirs('tests.pkgs.localeapp:locale', |
| | | 'tests.pkgs.localeapp:locale2') |
| | | self.assertEqual(config.registry.getUtility(ITranslationDirectories), |
| | | [locale, locale2]) |
| | | config.add_translation_dirs( |
| | | 'tests.pkgs.localeapp:locale', 'tests.pkgs.localeapp:locale2' |
| | | ) |
| | | self.assertEqual( |
| | | config.registry.getUtility(ITranslationDirectories), |
| | | [locale, locale2], |
| | | ) |
| | | |
| | | def test_add_translation_dirs_multiple_specs_multiple_calls(self): |
| | | from pyramid.interfaces import ITranslationDirectories |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_translation_dirs('tests.pkgs.localeapp:locale', |
| | | 'tests.pkgs.localeapp:locale2') |
| | | config.add_translation_dirs( |
| | | 'tests.pkgs.localeapp:locale', 'tests.pkgs.localeapp:locale2' |
| | | ) |
| | | config.add_translation_dirs('tests.pkgs.localeapp:locale3') |
| | | self.assertEqual(config.registry.getUtility(ITranslationDirectories), |
| | | [locale3, locale, locale2]) |
| | | self.assertEqual( |
| | | config.registry.getUtility(ITranslationDirectories), |
| | | [locale3, locale, locale2], |
| | | ) |
| | | |
| | | def test_add_translation_dirs_override_multiple_specs_multiple_calls(self): |
| | | from pyramid.interfaces import ITranslationDirectories |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_translation_dirs('tests.pkgs.localeapp:locale', |
| | | 'tests.pkgs.localeapp:locale2') |
| | | config.add_translation_dirs('tests.pkgs.localeapp:locale3', |
| | | override=True) |
| | | self.assertEqual(config.registry.getUtility(ITranslationDirectories), |
| | | [locale, locale2, locale3]) |
| | | config.add_translation_dirs( |
| | | 'tests.pkgs.localeapp:locale', 'tests.pkgs.localeapp:locale2' |
| | | ) |
| | | config.add_translation_dirs( |
| | | 'tests.pkgs.localeapp:locale3', override=True |
| | | ) |
| | | self.assertEqual( |
| | | config.registry.getUtility(ITranslationDirectories), |
| | | [locale, locale2, locale3], |
| | | ) |
| | | |
| | | def test_add_translation_dirs_invalid_kwargs(self): |
| | | from pyramid.interfaces import ITranslationDirectories |
| | | config = self._makeOne(autocommit=True) |
| | | with self.assertRaises(TypeError): |
| | | config.add_translation_dirs('tests.pkgs.localeapp:locale', |
| | | foo=1) |
| | | config.add_translation_dirs('tests.pkgs.localeapp:locale', foo=1) |
| | | |
| | | def test_add_translation_dirs_abspath(self): |
| | | from pyramid.interfaces import ITranslationDirectories |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_translation_dirs(locale) |
| | | self.assertEqual(config.registry.getUtility(ITranslationDirectories), |
| | | [locale]) |
| | | self.assertEqual( |
| | | config.registry.getUtility(ITranslationDirectories), [locale] |
| | | ) |
| | | |
| | | def test_add_translation_dirs_uses_override_out_of_order(self): |
| | | from pyramid.interfaces import ITranslationDirectories |
| | | |
| | | config = self._makeOne() |
| | | config.add_translation_dirs('tests.pkgs.localeapp:locale') |
| | | config.override_asset('tests.pkgs.localeapp:locale/', |
| | | 'tests.pkgs.localeapp:locale2/') |
| | | config.override_asset( |
| | | 'tests.pkgs.localeapp:locale/', 'tests.pkgs.localeapp:locale2/' |
| | | ) |
| | | config.commit() |
| | | self.assertEqual(config.registry.getUtility(ITranslationDirectories), |
| | | [locale2]) |
| | | self.assertEqual( |
| | | config.registry.getUtility(ITranslationDirectories), [locale2] |
| | | ) |
| | | |
| | | def test_add_translation_dirs_doesnt_use_override_w_autocommit(self): |
| | | from pyramid.interfaces import ITranslationDirectories |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_translation_dirs('tests.pkgs.localeapp:locale') |
| | | config.override_asset('tests.pkgs.localeapp:locale/', |
| | | 'tests.pkgs.localeapp:locale2/') |
| | | self.assertEqual(config.registry.getUtility(ITranslationDirectories), |
| | | [locale]) |
| | | config.override_asset( |
| | | 'tests.pkgs.localeapp:locale/', 'tests.pkgs.localeapp:locale2/' |
| | | ) |
| | | self.assertEqual( |
| | | config.registry.getUtility(ITranslationDirectories), [locale] |
| | | ) |
| | | |
| | | def test_add_translation_dirs_uses_override_w_autocommit(self): |
| | | from pyramid.interfaces import ITranslationDirectories |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.override_asset('tests.pkgs.localeapp:locale/', |
| | | 'tests.pkgs.localeapp:locale2/') |
| | | config.override_asset( |
| | | 'tests.pkgs.localeapp:locale/', 'tests.pkgs.localeapp:locale2/' |
| | | ) |
| | | config.add_translation_dirs('tests.pkgs.localeapp:locale') |
| | | self.assertEqual(config.registry.getUtility(ITranslationDirectories), |
| | | [locale2]) |
| | | self.assertEqual( |
| | | config.registry.getUtility(ITranslationDirectories), [locale2] |
| | | ) |
| | |
| | | import unittest |
| | | |
| | | import os |
| | | import unittest |
| | | from zope.interface import Interface |
| | | from zope.interface import implementer |
| | | |
| | | from pyramid.compat import im_func |
| | | from pyramid.testing import skip_on |
| | |
| | | |
| | | from pyramid.interfaces import IRequest |
| | | |
| | | |
| | | class ConfiguratorTests(unittest.TestCase): |
| | | def _makeOne(self, *arg, **kw): |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator(*arg, **kw) |
| | | return config |
| | | |
| | | def _getViewCallable(self, config, ctx_iface=None, request_iface=None, |
| | | name='', exception_view=False): |
| | | def _getViewCallable( |
| | | self, |
| | | config, |
| | | ctx_iface=None, |
| | | request_iface=None, |
| | | name='', |
| | | exception_view=False, |
| | | ): |
| | | from zope.interface import Interface |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IView |
| | | from pyramid.interfaces import IViewClassifier |
| | | from pyramid.interfaces import IExceptionViewClassifier |
| | | if exception_view: # pragma: no cover |
| | | |
| | | if exception_view: # pragma: no cover |
| | | classifier = IExceptionViewClassifier |
| | | else: |
| | | classifier = IViewClassifier |
| | |
| | | if request_iface is None: |
| | | request_iface = IRequest |
| | | return config.registry.adapters.lookup( |
| | | (classifier, request_iface, ctx_iface), IView, name=name, |
| | | default=None) |
| | | (classifier, request_iface, ctx_iface), |
| | | IView, |
| | | name=name, |
| | | default=None, |
| | | ) |
| | | |
| | | def _registerEventListener(self, config, event_iface=None): |
| | | if event_iface is None: # pragma: no cover |
| | | if event_iface is None: # pragma: no cover |
| | | from zope.interface import Interface |
| | | |
| | | event_iface = Interface |
| | | L = [] |
| | | |
| | | def subscriber(*event): |
| | | L.extend(event) |
| | | |
| | | config.registry.registerHandler(subscriber, (event_iface,)) |
| | | return L |
| | | |
| | |
| | | from pyramid.interfaces import ISettings |
| | | from pyramid.config import Configurator |
| | | from pyramid.interfaces import IRendererFactory |
| | | |
| | | config = Configurator() |
| | | this_pkg = sys.modules['tests.test_config'] |
| | | self.assertTrue(config.registry.getUtility(ISettings)) |
| | |
| | | |
| | | def test_begin(self): |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator() |
| | | manager = DummyThreadLocalManager() |
| | | config.manager = manager |
| | | config.begin() |
| | | self.assertEqual(manager.pushed, |
| | | {'registry':config.registry, 'request':None}) |
| | | self.assertEqual( |
| | | manager.pushed, {'registry': config.registry, 'request': None} |
| | | ) |
| | | self.assertEqual(manager.popped, False) |
| | | |
| | | def test_begin_with_request(self): |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator() |
| | | request = object() |
| | | manager = DummyThreadLocalManager() |
| | | config.manager = manager |
| | | config.begin(request=request) |
| | | self.assertEqual(manager.pushed, |
| | | {'registry':config.registry, 'request':request}) |
| | | self.assertEqual( |
| | | manager.pushed, {'registry': config.registry, 'request': request} |
| | | ) |
| | | self.assertEqual(manager.popped, False) |
| | | |
| | | def test_begin_overrides_request(self): |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator() |
| | | manager = DummyThreadLocalManager() |
| | | req = object() |
| | |
| | | |
| | | def test_begin_propagates_request_for_same_registry(self): |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator() |
| | | manager = DummyThreadLocalManager() |
| | | req = object() |
| | |
| | | |
| | | def test_begin_does_not_propagate_request_for_diff_registry(self): |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator() |
| | | manager = DummyThreadLocalManager() |
| | | req = object() |
| | |
| | | |
| | | def test_end(self): |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator() |
| | | manager = DummyThreadLocalManager() |
| | | pushed = manager.pushed |
| | |
| | | |
| | | def test_context_manager(self): |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator() |
| | | manager = DummyThreadLocalManager() |
| | | config.manager = manager |
| | | view = lambda r: None |
| | | with config as ctx: |
| | | self.assertTrue(config is ctx) |
| | | self.assertEqual(manager.pushed, |
| | | {'registry': config.registry, 'request': None}) |
| | | self.assertEqual( |
| | | manager.pushed, {'registry': config.registry, 'request': None} |
| | | ) |
| | | self.assertFalse(manager.popped) |
| | | config.add_view(view) |
| | | self.assertTrue(manager.popped) |
| | |
| | | def test_ctor_with_package_registry(self): |
| | | import sys |
| | | from pyramid.config import Configurator |
| | | |
| | | pkg = sys.modules['pyramid'] |
| | | config = Configurator(package=pkg) |
| | | self.assertEqual(config.package, pkg) |
| | | |
| | | def test_ctor_noreg_custom_settings(self): |
| | | from pyramid.interfaces import ISettings |
| | | settings = {'reload_templates':True, |
| | | 'mysetting':True} |
| | | |
| | | settings = {'reload_templates': True, 'mysetting': True} |
| | | config = self._makeOne(settings=settings) |
| | | settings = config.registry.getUtility(ISettings) |
| | | self.assertEqual(settings['reload_templates'], True) |
| | |
| | | |
| | | def test_ctor_noreg_debug_logger_None_default(self): |
| | | from pyramid.interfaces import IDebugLogger |
| | | |
| | | config = self._makeOne() |
| | | logger = config.registry.getUtility(IDebugLogger) |
| | | self.assertEqual(logger.name, 'tests.test_config') |
| | | |
| | | def test_ctor_noreg_debug_logger_non_None(self): |
| | | from pyramid.interfaces import IDebugLogger |
| | | |
| | | logger = object() |
| | | config = self._makeOne(debug_logger=logger) |
| | | result = config.registry.getUtility(IDebugLogger) |
| | |
| | | |
| | | def test_ctor_authentication_policy(self): |
| | | from pyramid.interfaces import IAuthenticationPolicy |
| | | |
| | | policy = object() |
| | | config = self._makeOne(authentication_policy=policy) |
| | | config.commit() |
| | |
| | | |
| | | def test_ctor_no_root_factory(self): |
| | | from pyramid.interfaces import IRootFactory |
| | | |
| | | config = self._makeOne() |
| | | self.assertEqual(config.registry.queryUtility(IRootFactory), None) |
| | | config.commit() |
| | |
| | | |
| | | def test_ctor_with_root_factory(self): |
| | | from pyramid.interfaces import IRootFactory |
| | | |
| | | factory = object() |
| | | config = self._makeOne(root_factory=factory) |
| | | self.assertEqual(config.registry.queryUtility(IRootFactory), None) |
| | |
| | | |
| | | def test_ctor_alternate_renderers(self): |
| | | from pyramid.interfaces import IRendererFactory |
| | | |
| | | renderer = object() |
| | | config = self._makeOne(renderers=[('yeah', renderer)]) |
| | | config.commit() |
| | | self.assertEqual(config.registry.getUtility(IRendererFactory, 'yeah'), |
| | | renderer) |
| | | self.assertEqual( |
| | | config.registry.getUtility(IRendererFactory, 'yeah'), renderer |
| | | ) |
| | | |
| | | def test_ctor_default_renderers(self): |
| | | from pyramid.interfaces import IRendererFactory |
| | | from pyramid.renderers import json_renderer_factory |
| | | |
| | | config = self._makeOne() |
| | | self.assertEqual(config.registry.getUtility(IRendererFactory, 'json'), |
| | | json_renderer_factory) |
| | | self.assertEqual( |
| | | config.registry.getUtility(IRendererFactory, 'json'), |
| | | json_renderer_factory, |
| | | ) |
| | | |
| | | def test_ctor_default_permission(self): |
| | | from pyramid.interfaces import IDefaultPermission |
| | | |
| | | config = self._makeOne(default_permission='view') |
| | | config.commit() |
| | | self.assertEqual(config.registry.getUtility(IDefaultPermission), 'view') |
| | | self.assertEqual( |
| | | config.registry.getUtility(IDefaultPermission), 'view' |
| | | ) |
| | | |
| | | def test_ctor_session_factory(self): |
| | | from pyramid.interfaces import ISessionFactory |
| | | |
| | | factory = object() |
| | | config = self._makeOne(session_factory=factory) |
| | | self.assertEqual(config.registry.queryUtility(ISessionFactory), None) |
| | |
| | | |
| | | def test_ctor_default_view_mapper(self): |
| | | from pyramid.interfaces import IViewMapperFactory |
| | | |
| | | mapper = object() |
| | | config = self._makeOne(default_view_mapper=mapper) |
| | | config.commit() |
| | | self.assertEqual(config.registry.getUtility(IViewMapperFactory), |
| | | mapper) |
| | | self.assertEqual( |
| | | config.registry.getUtility(IViewMapperFactory), mapper |
| | | ) |
| | | |
| | | def test_ctor_httpexception_view_default(self): |
| | | from pyramid.interfaces import IExceptionResponse |
| | | from pyramid.httpexceptions import default_exceptionresponse_view |
| | | from pyramid.interfaces import IRequest |
| | | |
| | | config = self._makeOne() |
| | | view = self._getViewCallable(config, |
| | | ctx_iface=IExceptionResponse, |
| | | request_iface=IRequest) |
| | | view = self._getViewCallable( |
| | | config, ctx_iface=IExceptionResponse, request_iface=IRequest |
| | | ) |
| | | self.assertTrue(view.__wraps__ is default_exceptionresponse_view) |
| | | |
| | | def test_ctor_exceptionresponse_view_None(self): |
| | | from pyramid.interfaces import IExceptionResponse |
| | | from pyramid.interfaces import IRequest |
| | | |
| | | config = self._makeOne(exceptionresponse_view=None) |
| | | view = self._getViewCallable(config, |
| | | ctx_iface=IExceptionResponse, |
| | | request_iface=IRequest) |
| | | view = self._getViewCallable( |
| | | config, ctx_iface=IExceptionResponse, request_iface=IRequest |
| | | ) |
| | | self.assertTrue(view is None) |
| | | |
| | | def test_ctor_exceptionresponse_view_custom(self): |
| | | from pyramid.interfaces import IExceptionResponse |
| | | from pyramid.interfaces import IRequest |
| | | def exceptionresponse_view(context, request): pass |
| | | |
| | | def exceptionresponse_view(context, request): # pragma: no cover |
| | | pass |
| | | |
| | | config = self._makeOne(exceptionresponse_view=exceptionresponse_view) |
| | | view = self._getViewCallable(config, |
| | | ctx_iface=IExceptionResponse, |
| | | request_iface=IRequest) |
| | | view = self._getViewCallable( |
| | | config, ctx_iface=IExceptionResponse, request_iface=IRequest |
| | | ) |
| | | self.assertTrue(view.__wraps__ is exceptionresponse_view) |
| | | |
| | | def test_ctor_with_introspection(self): |
| | |
| | | |
| | | def test_ctor_default_webob_response_adapter_registered(self): |
| | | from webob import Response as WebobResponse |
| | | |
| | | response = WebobResponse() |
| | | from pyramid.interfaces import IResponse |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | result = config.registry.queryAdapter(response, IResponse) |
| | | self.assertEqual(result, response) |
| | | |
| | | |
| | | def test_with_package_module(self): |
| | | from . import test_init |
| | | |
| | | config = self._makeOne() |
| | | newconfig = config.with_package(test_init) |
| | | import tests.test_config |
| | | |
| | | self.assertEqual(newconfig.package, tests.test_config) |
| | | |
| | | def test_with_package_package(self): |
| | | from tests import test_config |
| | | |
| | | config = self._makeOne() |
| | | newconfig = config.with_package(test_config) |
| | | self.assertEqual(newconfig.package, test_config) |
| | | |
| | | def test_with_package(self): |
| | | import tests |
| | | |
| | | config = self._makeOne() |
| | | config.basepath = 'basepath' |
| | | config.info = 'info' |
| | |
| | | |
| | | def test_maybe_dotted_string_success(self): |
| | | import tests.test_config |
| | | |
| | | config = self._makeOne() |
| | | result = config.maybe_dotted('tests.test_config') |
| | | self.assertEqual(result, tests.test_config) |
| | |
| | | |
| | | def test_maybe_dotted_notstring_success(self): |
| | | import tests.test_config |
| | | |
| | | config = self._makeOne() |
| | | result = config.maybe_dotted(tests.test_config) |
| | | self.assertEqual(result, tests.test_config) |
| | | |
| | | def test_absolute_asset_spec_already_absolute(self): |
| | | import tests.test_config |
| | | |
| | | config = self._makeOne(package=tests.test_config) |
| | | result = config.absolute_asset_spec('already:absolute') |
| | | self.assertEqual(result, 'already:absolute') |
| | | |
| | | def test_absolute_asset_spec_notastring(self): |
| | | import tests.test_config |
| | | |
| | | config = self._makeOne(package=tests.test_config) |
| | | result = config.absolute_asset_spec(None) |
| | | self.assertEqual(result, None) |
| | | |
| | | def test_absolute_asset_spec_relative(self): |
| | | import tests.test_config |
| | | |
| | | config = self._makeOne(package=tests.test_config) |
| | | result = config.absolute_asset_spec('files') |
| | | self.assertEqual(result, 'tests.test_config:files') |
| | |
| | | def test__fix_registry_queryAdapterOrSelf(self): |
| | | from zope.interface import Interface |
| | | from zope.interface import implementer |
| | | |
| | | class IFoo(Interface): |
| | | pass |
| | | |
| | | @implementer(IFoo) |
| | | class Foo(object): |
| | | pass |
| | | |
| | | class Bar(object): |
| | | pass |
| | | |
| | | adaptation = () |
| | | foo = Foo() |
| | | bar = Bar() |
| | |
| | | self.assertEqual(len(reg.adapters), 1) |
| | | args, kw = reg.adapters[0] |
| | | self.assertEqual(args[0]('abc'), 'abc') |
| | | self.assertEqual(kw, |
| | | {'info': '', 'provided': 'provided', |
| | | 'required': 'required', 'name': 'abc', 'event': True}) |
| | | self.assertEqual( |
| | | kw, |
| | | { |
| | | 'info': '', |
| | | 'provided': 'provided', |
| | | 'required': 'required', |
| | | 'name': 'abc', |
| | | 'event': True, |
| | | }, |
| | | ) |
| | | |
| | | def test__fix_registry_adds__lock(self): |
| | | reg = DummyRegistry() |
| | |
| | | from webob.exc import WSGIHTTPException |
| | | from pyramid.interfaces import IExceptionResponse |
| | | from pyramid.view import default_exceptionresponse_view |
| | | |
| | | reg = DummyRegistry() |
| | | config = self._makeOne(reg) |
| | | views = [] |
| | |
| | | config.add_default_view_predicates = lambda *arg: None |
| | | config._add_tween = lambda *arg, **kw: False |
| | | config.setup_registry() |
| | | self.assertEqual(views[0], ((default_exceptionresponse_view,), |
| | | {'context':IExceptionResponse})) |
| | | self.assertEqual(views[1], ((default_exceptionresponse_view,), |
| | | {'context':WSGIHTTPException})) |
| | | self.assertEqual( |
| | | views[0], |
| | | ( |
| | | (default_exceptionresponse_view,), |
| | | {'context': IExceptionResponse}, |
| | | ), |
| | | ) |
| | | self.assertEqual( |
| | | views[1], |
| | | ( |
| | | (default_exceptionresponse_view,), |
| | | {'context': WSGIHTTPException}, |
| | | ), |
| | | ) |
| | | |
| | | def test_setup_registry_registers_default_view_predicates(self): |
| | | reg = DummyRegistry() |
| | | config = self._makeOne(reg) |
| | | vp_called = [] |
| | | config.add_view = lambda *arg, **kw: None |
| | | config.add_default_view_predicates = lambda *arg: vp_called.append(True) |
| | | config.add_default_view_predicates = lambda *arg: vp_called.append( |
| | | True |
| | | ) |
| | | config._add_tween = lambda *arg, **kw: False |
| | | config.setup_registry() |
| | | self.assertTrue(vp_called) |
| | |
| | | def test_setup_registry_registers_default_webob_iresponse_adapter(self): |
| | | from webob import Response |
| | | from pyramid.interfaces import IResponse |
| | | |
| | | config = self._makeOne() |
| | | config.setup_registry() |
| | | response = Response() |
| | | self.assertTrue( |
| | | config.registry.queryAdapter(response, IResponse) is response) |
| | | config.registry.queryAdapter(response, IResponse) is response |
| | | ) |
| | | |
| | | def test_setup_registry_explicit_notfound_trumps_iexceptionresponse(self): |
| | | from pyramid.renderers import null_renderer |
| | |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from pyramid.registry import Registry |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg, autocommit=True) |
| | | config.setup_registry() # registers IExceptionResponse default view |
| | | config.setup_registry() # registers IExceptionResponse default view |
| | | |
| | | def myview(context, request): |
| | | return 'OK' |
| | | |
| | | config.add_view(myview, context=HTTPNotFound, renderer=null_renderer) |
| | | request = self._makeRequest(config) |
| | | view = self._getViewCallable(config, |
| | | ctx_iface=implementedBy(HTTPNotFound), |
| | | request_iface=IRequest) |
| | | view = self._getViewCallable( |
| | | config, |
| | | ctx_iface=implementedBy(HTTPNotFound), |
| | | request_iface=IRequest, |
| | | ) |
| | | result = view(None, request) |
| | | self.assertEqual(result, 'OK') |
| | | |
| | | def test_setup_registry_custom_settings(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import ISettings |
| | | settings = {'reload_templates':True, |
| | | 'mysetting':True} |
| | | |
| | | settings = {'reload_templates': True, 'mysetting': True} |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | config.setup_registry(settings=settings) |
| | |
| | | def test_setup_registry_debug_logger_None_default(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import IDebugLogger |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | config.setup_registry() |
| | |
| | | def test_setup_registry_debug_logger_non_None(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import IDebugLogger |
| | | |
| | | logger = object() |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | |
| | | def test_setup_registry_debug_logger_name(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import IDebugLogger |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | config.setup_registry(debug_logger='foo') |
| | |
| | | def test_setup_registry_authentication_policy(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import IAuthenticationPolicy |
| | | |
| | | policy = object() |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | |
| | | def test_setup_registry_authentication_policy_dottedname(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import IAuthenticationPolicy |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | config.setup_registry(authentication_policy='tests.test_config') |
| | | config.commit() |
| | | result = reg.getUtility(IAuthenticationPolicy) |
| | | import tests.test_config |
| | | |
| | | self.assertEqual(result, tests.test_config) |
| | | |
| | | def test_setup_registry_authorization_policy_dottedname(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import IAuthorizationPolicy |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | dummy = object() |
| | | config.setup_registry(authentication_policy=dummy, |
| | | authorization_policy='tests.test_config') |
| | | config.setup_registry( |
| | | authentication_policy=dummy, |
| | | authorization_policy='tests.test_config', |
| | | ) |
| | | config.commit() |
| | | result = reg.getUtility(IAuthorizationPolicy) |
| | | import tests.test_config |
| | | |
| | | self.assertEqual(result, tests.test_config) |
| | | |
| | | def test_setup_registry_authorization_policy_only(self): |
| | | from pyramid.registry import Registry |
| | | |
| | | policy = object() |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | |
| | | def test_setup_registry_no_default_root_factory(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import IRootFactory |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | config.setup_registry() |
| | |
| | | def test_setup_registry_dottedname_root_factory(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import IRootFactory |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | import tests.test_config |
| | | |
| | | config.setup_registry(root_factory='tests.test_config') |
| | | self.assertEqual(reg.queryUtility(IRootFactory), None) |
| | | config.commit() |
| | |
| | | def test_setup_registry_locale_negotiator_dottedname(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import ILocaleNegotiator |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | import tests.test_config |
| | | |
| | | config.setup_registry(locale_negotiator='tests.test_config') |
| | | self.assertEqual(reg.queryUtility(ILocaleNegotiator), None) |
| | | config.commit() |
| | |
| | | def test_setup_registry_locale_negotiator(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import ILocaleNegotiator |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | negotiator = object() |
| | |
| | | def test_setup_registry_request_factory(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import IRequestFactory |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | factory = object() |
| | |
| | | def test_setup_registry_response_factory(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import IResponseFactory |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | factory = lambda r: object() |
| | |
| | | def test_setup_registry_request_factory_dottedname(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import IRequestFactory |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | import tests.test_config |
| | | |
| | | config.setup_registry(request_factory='tests.test_config') |
| | | self.assertEqual(reg.queryUtility(IRequestFactory), None) |
| | | config.commit() |
| | |
| | | def test_setup_registry_alternate_renderers(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import IRendererFactory |
| | | |
| | | renderer = object() |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | config.setup_registry(renderers=[('yeah', renderer)]) |
| | | config.commit() |
| | | self.assertEqual(reg.getUtility(IRendererFactory, 'yeah'), |
| | | renderer) |
| | | self.assertEqual(reg.getUtility(IRendererFactory, 'yeah'), renderer) |
| | | |
| | | def test_setup_registry_default_permission(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import IDefaultPermission |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | config.setup_registry(default_permission='view') |
| | |
| | | |
| | | def test_setup_registry_includes(self): |
| | | from pyramid.registry import Registry |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | settings = { |
| | | 'pyramid.includes': |
| | | """tests.test_config.dummy_include |
| | | tests.test_config.dummy_include2""", |
| | | 'pyramid.includes': """tests.test_config.dummy_include |
| | | tests.test_config.dummy_include2""" |
| | | } |
| | | config.setup_registry(settings=settings) |
| | | self.assertTrue(reg.included) |
| | |
| | | |
| | | def test_setup_registry_includes_spaces(self): |
| | | from pyramid.registry import Registry |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | settings = { |
| | | 'pyramid.includes': |
| | | """tests.test_config.dummy_include tests.test_config.dummy_include2""", |
| | | 'pyramid.includes': """tests.test_config.dummy_include tests.\ |
| | | test_config.dummy_include2""" |
| | | } |
| | | config.setup_registry(settings=settings) |
| | | self.assertTrue(reg.included) |
| | |
| | | def test_setup_registry_tweens(self): |
| | | from pyramid.interfaces import ITweens |
| | | from pyramid.registry import Registry |
| | | |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | settings = { |
| | | 'pyramid.tweens': |
| | | 'tests.test_config.dummy_tween_factory' |
| | | } |
| | | settings = {'pyramid.tweens': 'tests.test_config.dummy_tween_factory'} |
| | | config.setup_registry(settings=settings) |
| | | config.commit() |
| | | tweens = config.registry.getUtility(ITweens) |
| | | self.assertEqual( |
| | | tweens.explicit, |
| | | [('tests.test_config.dummy_tween_factory', |
| | | dummy_tween_factory)]) |
| | | [('tests.test_config.dummy_tween_factory', dummy_tween_factory)], |
| | | ) |
| | | |
| | | def test_introspector_decorator(self): |
| | | inst = self._makeOne() |
| | |
| | | import pyramid.config |
| | | from pyramid.router import Router |
| | | from pyramid.interfaces import IApplicationCreated |
| | | |
| | | manager = DummyThreadLocalManager() |
| | | config = self._makeOne() |
| | | subscriber = self._registerEventListener(config, IApplicationCreated) |
| | |
| | | |
| | | def test_include_with_dotted_name(self): |
| | | from tests import test_config |
| | | |
| | | config = self._makeOne() |
| | | config.include('tests.test_config.dummy_include') |
| | | after = config.action_state |
| | |
| | | |
| | | def test_include_with_python_callable(self): |
| | | from tests import test_config |
| | | |
| | | config = self._makeOne() |
| | | config.include(dummy_include) |
| | | after = config.action_state |
| | |
| | | |
| | | def test_include_with_module_defaults_to_includeme(self): |
| | | from tests import test_config |
| | | |
| | | config = self._makeOne() |
| | | config.include('tests.test_config') |
| | | after = config.action_state |
| | |
| | | |
| | | def test_include_with_module_defaults_to_includeme_missing(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | |
| | | config = self._makeOne() |
| | | self.assertRaises(ConfigurationError, config.include, 'tests') |
| | | |
| | | def test_include_with_route_prefix(self): |
| | | root_config = self._makeOne(autocommit=True) |
| | | |
| | | def dummy_subapp(config): |
| | | self.assertEqual(config.route_prefix, 'root') |
| | | |
| | | root_config.include(dummy_subapp, route_prefix='root') |
| | | |
| | | def test_include_with_nested_route_prefix(self): |
| | | root_config = self._makeOne(autocommit=True, route_prefix='root') |
| | | |
| | | def dummy_subapp2(config): |
| | | self.assertEqual(config.route_prefix, 'root/nested') |
| | | |
| | | def dummy_subapp3(config): |
| | | self.assertEqual(config.route_prefix, 'root/nested/nested2') |
| | | config.include(dummy_subapp4) |
| | | |
| | | def dummy_subapp4(config): |
| | | self.assertEqual(config.route_prefix, 'root/nested/nested2') |
| | | |
| | | def dummy_subapp(config): |
| | | self.assertEqual(config.route_prefix, 'root/nested') |
| | | config.include(dummy_subapp2) |
| | |
| | | def test_include_with_missing_source_file(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | import inspect |
| | | |
| | | config = self._makeOne() |
| | | |
| | | class DummyInspect(object): |
| | | def getmodule(self, c): |
| | | return inspect.getmodule(c) |
| | | |
| | | def getsourcefile(self, c): |
| | | return None |
| | | |
| | | config.inspect = DummyInspect() |
| | | try: |
| | | config.include('tests.test_config.dummy_include') |
| | | except ConfigurationError as e: |
| | | self.assertEqual( |
| | | e.args[0], |
| | | e.args[0], |
| | | "No source file for module 'tests.test_config' (.py " |
| | | "file must exist, refusing to use orphan .pyc or .pyo file).") |
| | | else: # pragma: no cover |
| | | "file must exist, refusing to use orphan .pyc or .pyo file).", |
| | | ) |
| | | else: # pragma: no cover |
| | | raise AssertionError |
| | | |
| | | def test_include_constant_root_package(self): |
| | | import tests |
| | | from tests import test_config |
| | | |
| | | config = self._makeOne(root_package=tests) |
| | | results = {} |
| | | |
| | | def include(config): |
| | | results['package'] = config.package |
| | | results['root_package'] = config.root_package |
| | | |
| | | config.include(include) |
| | | self.assertEqual(results['root_package'], tests) |
| | | self.assertEqual(results['package'], test_config) |
| | | |
| | | def test_include_threadlocals_active(self): |
| | | from pyramid.threadlocal import get_current_registry |
| | | from tests import test_config |
| | | |
| | | stack = [] |
| | | |
| | | def include(config): |
| | | stack.append(get_current_registry()) |
| | | |
| | | config = self._makeOne() |
| | | config.include(include) |
| | | self.assertTrue(stack[0] is config.registry) |
| | |
| | | |
| | | def test_action_branching_kw_is_not_None(self): |
| | | config = self._makeOne(autocommit=True) |
| | | self.assertEqual(config.action('discrim', kw={'a':1}), None) |
| | | self.assertEqual(config.action('discrim', kw={'a': 1}), None) |
| | | |
| | | def test_action_autocommit_with_introspectables(self): |
| | | from pyramid.config.util import ActionInfo |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | intr = DummyIntrospectable() |
| | | config.action('discrim', introspectables=(intr,)) |
| | |
| | | intr = DummyIntrospectable() |
| | | config.action('discrim', introspectables=(intr,)) |
| | | self.assertEqual(len(intr.registered), 0) |
| | | |
| | | |
| | | def test_action_branching_nonautocommit_with_config_info(self): |
| | | config = self._makeOne(autocommit=False) |
| | | config.info = 'abc' |
| | | state = DummyActionState() |
| | | state.autocommit = False |
| | | config.action_state = state |
| | | config.action('discrim', kw={'a':1}) |
| | | config.action('discrim', kw={'a': 1}) |
| | | self.assertEqual( |
| | | state.actions, |
| | | [((), |
| | | {'args': (), |
| | | 'callable': None, |
| | | 'discriminator': 'discrim', |
| | | 'includepath': (), |
| | | 'info': 'abc', |
| | | 'introspectables': (), |
| | | 'kw': {'a': 1}, |
| | | 'order': 0})]) |
| | | [ |
| | | ( |
| | | (), |
| | | { |
| | | 'args': (), |
| | | 'callable': None, |
| | | 'discriminator': 'discrim', |
| | | 'includepath': (), |
| | | 'info': 'abc', |
| | | 'introspectables': (), |
| | | 'kw': {'a': 1}, |
| | | 'order': 0, |
| | | }, |
| | | ) |
| | | ], |
| | | ) |
| | | |
| | | def test_action_branching_nonautocommit_without_config_info(self): |
| | | config = self._makeOne(autocommit=False) |
| | |
| | | state = DummyActionState() |
| | | config.action_state = state |
| | | state.autocommit = False |
| | | config.action('discrim', kw={'a':1}) |
| | | config.action('discrim', kw={'a': 1}) |
| | | self.assertEqual( |
| | | state.actions, |
| | | [((), |
| | | {'args': (), |
| | | 'callable': None, |
| | | 'discriminator': 'discrim', |
| | | 'includepath': (), |
| | | 'info': 'z', |
| | | 'introspectables': (), |
| | | 'kw': {'a': 1}, |
| | | 'order': 0})]) |
| | | [ |
| | | ( |
| | | (), |
| | | { |
| | | 'args': (), |
| | | 'callable': None, |
| | | 'discriminator': 'discrim', |
| | | 'includepath': (), |
| | | 'info': 'z', |
| | | 'introspectables': (), |
| | | 'kw': {'a': 1}, |
| | | 'order': 0, |
| | | }, |
| | | ) |
| | | ], |
| | | ) |
| | | |
| | | def test_action_branching_nonautocommit_with_introspectables(self): |
| | | config = self._makeOne(autocommit=False) |
| | |
| | | state.autocommit = False |
| | | intr = DummyIntrospectable() |
| | | config.action('discrim', introspectables=(intr,)) |
| | | self.assertEqual( |
| | | state.actions[0][1]['introspectables'], (intr,)) |
| | | self.assertEqual(state.actions[0][1]['introspectables'], (intr,)) |
| | | |
| | | def test_action_nonautocommit_with_introspectables_introspection_off(self): |
| | | config = self._makeOne(autocommit=False) |
| | |
| | | state.autocommit = False |
| | | intr = DummyIntrospectable() |
| | | config.action('discrim', introspectables=(intr,)) |
| | | self.assertEqual( |
| | | state.actions[0][1]['introspectables'], ()) |
| | | |
| | | self.assertEqual(state.actions[0][1]['introspectables'], ()) |
| | | |
| | | def test_scan_integration(self): |
| | | from zope.interface import alsoProvides |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.view import render_view_to_response |
| | | import tests.test_config.pkgs.scannable as package |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.scan(package) |
| | | |
| | |
| | | result = render_view_to_response(ctx, req, '') |
| | | self.assertEqual(result, 'grokked_post') |
| | | |
| | | result= render_view_to_response(ctx, req, 'grokked_class') |
| | | result = render_view_to_response(ctx, req, 'grokked_class') |
| | | self.assertEqual(result, 'grokked_class') |
| | | |
| | | result= render_view_to_response(ctx, req, 'grokked_instance') |
| | | result = render_view_to_response(ctx, req, 'grokked_instance') |
| | | self.assertEqual(result, 'grokked_instance') |
| | | |
| | | result= render_view_to_response(ctx, req, 'oldstyle_grokked_class') |
| | | result = render_view_to_response(ctx, req, 'oldstyle_grokked_class') |
| | | self.assertEqual(result, 'oldstyle_grokked_class') |
| | | |
| | | req.method = 'GET' |
| | |
| | | result = render_view_to_response(ctx, req, 'another') |
| | | self.assertEqual(result, 'another_grokked_post') |
| | | |
| | | result= render_view_to_response(ctx, req, 'another_grokked_class') |
| | | result = render_view_to_response(ctx, req, 'another_grokked_class') |
| | | self.assertEqual(result, 'another_grokked_class') |
| | | |
| | | result= render_view_to_response(ctx, req, 'another_grokked_instance') |
| | | result = render_view_to_response(ctx, req, 'another_grokked_instance') |
| | | self.assertEqual(result, 'another_grokked_instance') |
| | | |
| | | result= render_view_to_response(ctx, req, |
| | | 'another_oldstyle_grokked_class') |
| | | result = render_view_to_response( |
| | | ctx, req, 'another_oldstyle_grokked_class' |
| | | ) |
| | | self.assertEqual(result, 'another_oldstyle_grokked_class') |
| | | |
| | | result = render_view_to_response(ctx, req, 'stacked1') |
| | |
| | | # assertion may fail there. We don't support Jython at the moment, |
| | | # this is just a note to a future self. |
| | | |
| | | self.assertRaises(TypeError, |
| | | render_view_to_response, ctx, req, 'basemethod') |
| | | self.assertRaises( |
| | | TypeError, render_view_to_response, ctx, req, 'basemethod' |
| | | ) |
| | | |
| | | result = render_view_to_response(ctx, req, 'method1') |
| | | self.assertEqual(result, 'method1') |
| | |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.view import render_view_to_response |
| | | import tests.test_config.pkgs.scannable as package |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.scan(package, |
| | | ignore='tests.test_config.pkgs.scannable.another') |
| | | config.scan(package, ignore='tests.test_config.pkgs.scannable.another') |
| | | |
| | | ctx = DummyContext() |
| | | req = DummyRequest() |
| | |
| | | # ignored |
| | | v = render_view_to_response(ctx, req, 'another_stacked_class2') |
| | | self.assertEqual(v, None) |
| | | |
| | | |
| | | def test_scan_integration_dottedname_package(self): |
| | | from zope.interface import alsoProvides |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.view import render_view_to_response |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | config.scan('tests.test_config.pkgs.scannable') |
| | | |
| | |
| | | # fancy sys.path manipulation here to appease "setup.py test" which |
| | | # fails miserably when it can't import something in the package |
| | | import sys |
| | | |
| | | try: |
| | | here = os.path.dirname(__file__) |
| | | path = os.path.join(here, 'path') |
| | | sys.path.append(path) |
| | | config = self._makeOne(autocommit=True) |
| | | |
| | | class FooException(Exception): |
| | | pass |
| | | |
| | | def onerror(name): |
| | | raise FooException |
| | | self.assertRaises(FooException, config.scan, 'scanerror', |
| | | onerror=onerror) |
| | | |
| | | self.assertRaises( |
| | | FooException, config.scan, 'scanerror', onerror=onerror |
| | | ) |
| | | finally: |
| | | sys.path.remove(path) |
| | | |
| | | def test_scan_integration_conflict(self): |
| | | from tests.test_config.pkgs import selfscan |
| | | from pyramid.config import Configurator |
| | | |
| | | c = Configurator() |
| | | c.scan(selfscan) |
| | | c.scan(selfscan) |
| | | try: |
| | | c.commit() |
| | | except ConfigurationConflictError as why: |
| | | |
| | | def scanconflicts(e): |
| | | conflicts = e._conflicts.values() |
| | | for conflict in conflicts: |
| | | for confinst in conflict: |
| | | yield confinst.src |
| | | |
| | | which = list(scanconflicts(why)) |
| | | self.assertEqual(len(which), 4) |
| | | self.assertTrue("@view_config(renderer='string')" in which) |
| | | self.assertTrue("@view_config(name='two', renderer='string')" in |
| | | which) |
| | | self.assertTrue( |
| | | "@view_config(name='two', renderer='string')" in which |
| | | ) |
| | | |
| | | @skip_on('py3') |
| | | def test_hook_zca(self): |
| | | from zope.component import getSiteManager |
| | | |
| | | def foo(): |
| | | '123' |
| | | |
| | | try: |
| | | config = self._makeOne() |
| | | config.hook_zca() |
| | |
| | | @skip_on('py3') |
| | | def test_unhook_zca(self): |
| | | from zope.component import getSiteManager |
| | | |
| | | def foo(): |
| | | '123' |
| | | |
| | | try: |
| | | getSiteManager.sethook(foo) |
| | | config = self._makeOne() |
| | |
| | | |
| | | def test_commit_conflict_simple(self): |
| | | config = self._makeOne() |
| | | def view1(request): pass |
| | | def view2(request): pass |
| | | |
| | | def view1(request): # pragma: no cover |
| | | pass |
| | | |
| | | def view2(request): # pragma: no cover |
| | | pass |
| | | |
| | | config.add_view(view1) |
| | | config.add_view(view2) |
| | | self.assertRaises(ConfigurationConflictError, config.commit) |
| | | |
| | | def test_commit_conflict_resolved_with_include(self): |
| | | config = self._makeOne() |
| | | def view1(request): pass |
| | | def view2(request): pass |
| | | |
| | | def view1(request): # pragma: no cover |
| | | pass |
| | | |
| | | def view2(request): # pragma: no cover |
| | | pass |
| | | |
| | | def includeme(config): |
| | | config.add_view(view2) |
| | | |
| | | config.add_view(view1) |
| | | config.include(includeme) |
| | | config.commit() |
| | |
| | | |
| | | def test_commit_conflict_with_two_includes(self): |
| | | config = self._makeOne() |
| | | def view1(request): pass |
| | | def view2(request): pass |
| | | |
| | | def view1(request): # pragma: no cover |
| | | pass |
| | | |
| | | def view2(request): # pragma: no cover |
| | | pass |
| | | |
| | | def includeme1(config): |
| | | config.add_view(view1) |
| | | |
| | | def includeme2(config): |
| | | config.add_view(view2) |
| | | |
| | | config.include(includeme1) |
| | | config.include(includeme2) |
| | | try: |
| | |
| | | c1, c2 = _conflictFunctions(why) |
| | | self.assertEqual(c1, 'includeme1') |
| | | self.assertEqual(c2, 'includeme2') |
| | | else: #pragma: no cover |
| | | else: # pragma: no cover |
| | | raise AssertionError |
| | | |
| | | def test_commit_conflict_resolved_with_two_includes_and_local(self): |
| | | config = self._makeOne() |
| | | def view1(request): pass |
| | | def view2(request): pass |
| | | def view3(request): pass |
| | | |
| | | def view1(request): # pragma: no cover |
| | | pass |
| | | |
| | | def view2(request): # pragma: no cover |
| | | pass |
| | | |
| | | def view3(request): # pragma: no cover |
| | | pass |
| | | |
| | | def includeme1(config): |
| | | config.add_view(view1) |
| | | |
| | | def includeme2(config): |
| | | config.add_view(view2) |
| | | |
| | | config.include(includeme1) |
| | | config.include(includeme2) |
| | | config.add_view(view3) |
| | |
| | | |
| | | def test_autocommit_no_conflicts(self): |
| | | from pyramid.renderers import null_renderer |
| | | |
| | | config = self._makeOne(autocommit=True) |
| | | def view1(request): pass |
| | | def view2(request): pass |
| | | def view3(request): pass |
| | | |
| | | def view1(request): # pragma: no cover |
| | | pass |
| | | |
| | | def view2(request): # pragma: no cover |
| | | pass |
| | | |
| | | def view3(request): # pragma: no cover |
| | | pass |
| | | |
| | | config.add_view(view1, renderer=null_renderer) |
| | | config.add_view(view2, renderer=null_renderer) |
| | | config.add_view(view3, renderer=null_renderer) |
| | |
| | | |
| | | def test_conflict_set_notfound_view(self): |
| | | config = self._makeOne() |
| | | def view1(request): pass |
| | | def view2(request): pass |
| | | |
| | | def view1(request): # pragma: no cover |
| | | pass |
| | | |
| | | def view2(request): # pragma: no cover |
| | | pass |
| | | |
| | | config.set_notfound_view(view1) |
| | | config.set_notfound_view(view2) |
| | | try: |
| | |
| | | c1, c2 = _conflictFunctions(why) |
| | | self.assertEqual(c1, 'test_conflict_set_notfound_view') |
| | | self.assertEqual(c2, 'test_conflict_set_notfound_view') |
| | | else: # pragma: no cover |
| | | else: # pragma: no cover |
| | | raise AssertionError |
| | | |
| | | def test_conflict_set_forbidden_view(self): |
| | | config = self._makeOne() |
| | | def view1(request): pass |
| | | def view2(request): pass |
| | | |
| | | def view1(request): # pragma: no cover |
| | | pass |
| | | |
| | | def view2(request): # pragma: no cover |
| | | pass |
| | | |
| | | config.set_forbidden_view(view1) |
| | | config.set_forbidden_view(view2) |
| | | try: |
| | |
| | | c1, c2 = _conflictFunctions(why) |
| | | self.assertEqual(c1, 'test_conflict_set_forbidden_view') |
| | | self.assertEqual(c2, 'test_conflict_set_forbidden_view') |
| | | else: # pragma: no cover |
| | | else: # pragma: no cover |
| | | raise AssertionError |
| | | |
| | | def test___getattr__missing_when_directives_exist(self): |
| | |
| | | |
| | | def test___getattr__matches(self): |
| | | config = self._makeOne() |
| | | def foo(config): pass |
| | | directives = {'foo':(foo, True)} |
| | | |
| | | def foo(config): # pragma: no cover |
| | | pass |
| | | |
| | | directives = {'foo': (foo, True)} |
| | | config.registry._directives = directives |
| | | foo_meth = config.foo |
| | | self.assertTrue(getattr(foo_meth, im_func).__docobj__ is foo) |
| | | |
| | | def test___getattr__matches_no_action_wrap(self): |
| | | config = self._makeOne() |
| | | def foo(config): pass |
| | | directives = {'foo':(foo, False)} |
| | | |
| | | def foo(config): # pragma: no cover |
| | | pass |
| | | |
| | | directives = {'foo': (foo, False)} |
| | | config.registry._directives = directives |
| | | foo_meth = config.foo |
| | | self.assertTrue(getattr(foo_meth, im_func) is foo) |
| | | |
| | | class TestConfigurator_add_directive(unittest.TestCase): |
| | | |
| | | class TestConfigurator_add_directive(unittest.TestCase): |
| | | def setUp(self): |
| | | from pyramid.config import Configurator |
| | | |
| | | self.config = Configurator() |
| | | |
| | | def test_extend_with_dotted_name(self): |
| | | from tests import test_config |
| | | |
| | | config = self.config |
| | | config.add_directive( |
| | | 'dummy_extend', 'tests.test_config.dummy_extend') |
| | | config.add_directive('dummy_extend', 'tests.test_config.dummy_extend') |
| | | self.assertTrue(hasattr(config, 'dummy_extend')) |
| | | config.dummy_extend('discrim') |
| | | after = config.action_state |
| | |
| | | |
| | | def test_add_directive_with_partial(self): |
| | | from tests import test_config |
| | | |
| | | config = self.config |
| | | config.add_directive( |
| | | 'dummy_partial', 'tests.test_config.dummy_partial') |
| | | 'dummy_partial', 'tests.test_config.dummy_partial' |
| | | ) |
| | | self.assertTrue(hasattr(config, 'dummy_partial')) |
| | | config.dummy_partial() |
| | | after = config.action_state |
| | |
| | | |
| | | def test_add_directive_with_custom_callable(self): |
| | | from tests import test_config |
| | | |
| | | config = self.config |
| | | config.add_directive( |
| | | 'dummy_callable', 'tests.test_config.dummy_callable') |
| | | 'dummy_callable', 'tests.test_config.dummy_callable' |
| | | ) |
| | | self.assertTrue(hasattr(config, 'dummy_callable')) |
| | | config.dummy_callable('discrim') |
| | | after = config.action_state |
| | |
| | | |
| | | def test_extend_with_python_callable(self): |
| | | from tests import test_config |
| | | |
| | | config = self.config |
| | | config.add_directive( |
| | | 'dummy_extend', dummy_extend) |
| | | config.add_directive('dummy_extend', dummy_extend) |
| | | self.assertTrue(hasattr(config, 'dummy_extend')) |
| | | config.dummy_extend('discrim') |
| | | after = config.action_state |
| | |
| | | |
| | | def test_extend_same_name_doesnt_conflict(self): |
| | | config = self.config |
| | | config.add_directive( |
| | | 'dummy_extend', dummy_extend) |
| | | config.add_directive( |
| | | 'dummy_extend', dummy_extend2) |
| | | config.add_directive('dummy_extend', dummy_extend) |
| | | config.add_directive('dummy_extend', dummy_extend2) |
| | | self.assertTrue(hasattr(config, 'dummy_extend')) |
| | | config.dummy_extend('discrim') |
| | | after = config.action_state |
| | |
| | | |
| | | def test_extend_action_method_successful(self): |
| | | config = self.config |
| | | config.add_directive( |
| | | 'dummy_extend', dummy_extend) |
| | | config.add_directive('dummy_extend', dummy_extend) |
| | | config.dummy_extend('discrim') |
| | | config.dummy_extend('discrim') |
| | | self.assertRaises(ConfigurationConflictError, config.commit) |
| | |
| | | self.assertEqual(action['callable'], None) |
| | | self.assertEqual(action['args'], config2.package) |
| | | |
| | | |
| | | class TestConfigurator__add_predicate(unittest.TestCase): |
| | | def _makeOne(self): |
| | | from pyramid.config import Configurator |
| | | |
| | | return Configurator() |
| | | |
| | | def test_factory_as_object(self): |
| | | config = self._makeOne() |
| | | |
| | | def _fakeAction(discriminator, callable=None, args=(), kw=None, |
| | | order=0, introspectables=(), **extra): |
| | | def _fakeAction( |
| | | discriminator, |
| | | callable=None, |
| | | args=(), |
| | | kw=None, |
| | | order=0, |
| | | introspectables=(), |
| | | **extra |
| | | ): |
| | | self.assertEqual(len(introspectables), 1) |
| | | self.assertEqual(introspectables[0]['name'], 'testing') |
| | | self.assertEqual(introspectables[0]['factory'], DummyPredicate) |
| | |
| | | def test_factory_as_dotted_name(self): |
| | | config = self._makeOne() |
| | | |
| | | def _fakeAction(discriminator, callable=None, args=(), |
| | | kw=None, order=0, introspectables=(), **extra): |
| | | def _fakeAction( |
| | | discriminator, |
| | | callable=None, |
| | | args=(), |
| | | kw=None, |
| | | order=0, |
| | | introspectables=(), |
| | | **extra |
| | | ): |
| | | self.assertEqual(len(introspectables), 1) |
| | | self.assertEqual(introspectables[0]['name'], 'testing') |
| | | self.assertEqual(introspectables[0]['factory'], DummyPredicate) |
| | | |
| | | config.action = _fakeAction |
| | | config._add_predicate( |
| | | 'route', |
| | | 'testing', |
| | | 'tests.test_config.test_init.DummyPredicate' |
| | | ) |
| | | |
| | | 'route', 'testing', 'tests.test_config.test_init.DummyPredicate' |
| | | ) |
| | | |
| | | |
| | | class TestActionState(unittest.TestCase): |
| | | def _makeOne(self): |
| | | from pyramid.config import ActionState |
| | | |
| | | return ActionState() |
| | | |
| | | |
| | | def test_it(self): |
| | | c = self._makeOne() |
| | | self.assertEqual(c.actions, []) |
| | | |
| | | def test_action_simple(self): |
| | | from . import dummyfactory as f |
| | | |
| | | c = self._makeOne() |
| | | c.actions = [] |
| | | c.action(1, f, (1,), {'x':1}) |
| | | c.action(1, f, (1,), {'x': 1}) |
| | | self.assertEqual( |
| | | c.actions, |
| | | [{'args': (1,), |
| | | 'callable': f, |
| | | 'discriminator': 1, |
| | | 'includepath': (), |
| | | 'info': None, |
| | | 'introspectables': (), |
| | | 'kw': {'x': 1}, |
| | | 'order': 0}]) |
| | | [ |
| | | { |
| | | 'args': (1,), |
| | | 'callable': f, |
| | | 'discriminator': 1, |
| | | 'includepath': (), |
| | | 'info': None, |
| | | 'introspectables': (), |
| | | 'kw': {'x': 1}, |
| | | 'order': 0, |
| | | } |
| | | ], |
| | | ) |
| | | c.action(None) |
| | | self.assertEqual( |
| | | c.actions, |
| | | [{'args': (1,), |
| | | 'callable': f, |
| | | 'discriminator': 1, |
| | | 'includepath': (), |
| | | 'info': None, |
| | | 'introspectables': (), |
| | | 'kw': {'x': 1}, |
| | | 'order': 0}, |
| | | |
| | | {'args': (), |
| | | 'callable': None, |
| | | 'discriminator': None, |
| | | 'includepath': (), |
| | | 'info': None, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'order': 0},]) |
| | | [ |
| | | { |
| | | 'args': (1,), |
| | | 'callable': f, |
| | | 'discriminator': 1, |
| | | 'includepath': (), |
| | | 'info': None, |
| | | 'introspectables': (), |
| | | 'kw': {'x': 1}, |
| | | 'order': 0, |
| | | }, |
| | | { |
| | | 'args': (), |
| | | 'callable': None, |
| | | 'discriminator': None, |
| | | 'includepath': (), |
| | | 'info': None, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'order': 0, |
| | | }, |
| | | ], |
| | | ) |
| | | |
| | | def test_action_with_includepath(self): |
| | | c = self._makeOne() |
| | |
| | | c.action(None, includepath=('abc',)) |
| | | self.assertEqual( |
| | | c.actions, |
| | | [{'args': (), |
| | | 'callable': None, |
| | | 'discriminator': None, |
| | | 'includepath': ('abc',), |
| | | 'info': None, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'order': 0}]) |
| | | [ |
| | | { |
| | | 'args': (), |
| | | 'callable': None, |
| | | 'discriminator': None, |
| | | 'includepath': ('abc',), |
| | | 'info': None, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'order': 0, |
| | | } |
| | | ], |
| | | ) |
| | | |
| | | def test_action_with_info(self): |
| | | c = self._makeOne() |
| | | c.action(None, info='abc') |
| | | self.assertEqual( |
| | | c.actions, |
| | | [{'args': (), |
| | | 'callable': None, |
| | | 'discriminator': None, |
| | | 'includepath': (), |
| | | 'info': 'abc', |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'order': 0}]) |
| | | [ |
| | | { |
| | | 'args': (), |
| | | 'callable': None, |
| | | 'discriminator': None, |
| | | 'includepath': (), |
| | | 'info': 'abc', |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'order': 0, |
| | | } |
| | | ], |
| | | ) |
| | | |
| | | def test_action_with_includepath_and_info(self): |
| | | c = self._makeOne() |
| | | c.action(None, includepath=('spec',), info='bleh') |
| | | self.assertEqual( |
| | | c.actions, |
| | | [{'args': (), |
| | | 'callable': None, |
| | | 'discriminator': None, |
| | | 'includepath': ('spec',), |
| | | 'info': 'bleh', |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'order': 0}]) |
| | | [ |
| | | { |
| | | 'args': (), |
| | | 'callable': None, |
| | | 'discriminator': None, |
| | | 'includepath': ('spec',), |
| | | 'info': 'bleh', |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'order': 0, |
| | | } |
| | | ], |
| | | ) |
| | | |
| | | def test_action_with_order(self): |
| | | c = self._makeOne() |
| | |
| | | c.action(None, order=99999) |
| | | self.assertEqual( |
| | | c.actions, |
| | | [{'args': (), |
| | | 'callable': None, |
| | | 'discriminator': None, |
| | | 'includepath': (), |
| | | 'info': None, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'order': 99999}]) |
| | | [ |
| | | { |
| | | 'args': (), |
| | | 'callable': None, |
| | | 'discriminator': None, |
| | | 'includepath': (), |
| | | 'info': None, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'order': 99999, |
| | | } |
| | | ], |
| | | ) |
| | | |
| | | def test_action_with_introspectables(self): |
| | | c = self._makeOne() |
| | |
| | | c.action(None, introspectables=(intr,)) |
| | | self.assertEqual( |
| | | c.actions, |
| | | [{'args': (), |
| | | 'callable': None, |
| | | 'discriminator': None, |
| | | 'includepath': (), |
| | | 'info': None, |
| | | 'introspectables': (intr,), |
| | | 'kw': {}, |
| | | 'order': 0}]) |
| | | [ |
| | | { |
| | | 'args': (), |
| | | 'callable': None, |
| | | 'discriminator': None, |
| | | 'includepath': (), |
| | | 'info': None, |
| | | 'introspectables': (intr,), |
| | | 'kw': {}, |
| | | 'order': 0, |
| | | } |
| | | ], |
| | | ) |
| | | |
| | | def test_processSpec(self): |
| | | c = self._makeOne() |
| | |
| | | |
| | | def test_execute_actions_tuples(self): |
| | | output = [] |
| | | |
| | | def f(*a, **k): |
| | | output.append((a, k)) |
| | | |
| | | c = self._makeOne() |
| | | c.actions = [ |
| | | (1, f, (1,)), |
| | | (1, f, (11,), {}, ('x', )), |
| | | (1, f, (11,), {}, ('x',)), |
| | | (2, f, (2,)), |
| | | (None, None), |
| | | ] |
| | | ] |
| | | c.execute_actions() |
| | | self.assertEqual(output, [((1,), {}), ((2,), {})]) |
| | | self.assertEqual(output, [((1,), {}), ((2,), {})]) |
| | | |
| | | def test_execute_actions_dicts(self): |
| | | output = [] |
| | | |
| | | def f(*a, **k): |
| | | output.append((a, k)) |
| | | |
| | | c = self._makeOne() |
| | | c.actions = [ |
| | | {'discriminator':1, 'callable':f, 'args':(1,), 'kw':{}, |
| | | 'order':0, 'includepath':(), 'info':None, |
| | | 'introspectables':()}, |
| | | {'discriminator':1, 'callable':f, 'args':(11,), 'kw':{}, |
| | | 'includepath':('x',), 'order': 0, 'info':None, |
| | | 'introspectables':()}, |
| | | {'discriminator':2, 'callable':f, 'args':(2,), 'kw':{}, |
| | | 'order':0, 'includepath':(), 'info':None, |
| | | 'introspectables':()}, |
| | | {'discriminator':None, 'callable':None, 'args':(), 'kw':{}, |
| | | 'order':0, 'includepath':(), 'info':None, |
| | | 'introspectables':()}, |
| | | ] |
| | | { |
| | | 'discriminator': 1, |
| | | 'callable': f, |
| | | 'args': (1,), |
| | | 'kw': {}, |
| | | 'order': 0, |
| | | 'includepath': (), |
| | | 'info': None, |
| | | 'introspectables': (), |
| | | }, |
| | | { |
| | | 'discriminator': 1, |
| | | 'callable': f, |
| | | 'args': (11,), |
| | | 'kw': {}, |
| | | 'includepath': ('x',), |
| | | 'order': 0, |
| | | 'info': None, |
| | | 'introspectables': (), |
| | | }, |
| | | { |
| | | 'discriminator': 2, |
| | | 'callable': f, |
| | | 'args': (2,), |
| | | 'kw': {}, |
| | | 'order': 0, |
| | | 'includepath': (), |
| | | 'info': None, |
| | | 'introspectables': (), |
| | | }, |
| | | { |
| | | 'discriminator': None, |
| | | 'callable': None, |
| | | 'args': (), |
| | | 'kw': {}, |
| | | 'order': 0, |
| | | 'includepath': (), |
| | | 'info': None, |
| | | 'introspectables': (), |
| | | }, |
| | | ] |
| | | c.execute_actions() |
| | | self.assertEqual(output, [((1,), {}), ((2,), {})]) |
| | | self.assertEqual(output, [((1,), {}), ((2,), {})]) |
| | | |
| | | def test_execute_actions_with_introspectables(self): |
| | | output = [] |
| | | |
| | | def f(*a, **k): |
| | | output.append((a, k)) |
| | | |
| | | c = self._makeOne() |
| | | intr = DummyIntrospectable() |
| | | c.actions = [ |
| | | {'discriminator':1, 'callable':f, 'args':(1,), 'kw':{}, |
| | | 'order':0, 'includepath':(), 'info':None, |
| | | 'introspectables':(intr,)}, |
| | | ] |
| | | { |
| | | 'discriminator': 1, |
| | | 'callable': f, |
| | | 'args': (1,), |
| | | 'kw': {}, |
| | | 'order': 0, |
| | | 'includepath': (), |
| | | 'info': None, |
| | | 'introspectables': (intr,), |
| | | } |
| | | ] |
| | | introspector = object() |
| | | c.execute_actions(introspector=introspector) |
| | | self.assertEqual(output, [((1,), {})]) |
| | | self.assertEqual(output, [((1,), {})]) |
| | | self.assertEqual(intr.registered, [(introspector, None)]) |
| | | |
| | | def test_execute_actions_with_introspectable_no_callable(self): |
| | | c = self._makeOne() |
| | | intr = DummyIntrospectable() |
| | | c.actions = [ |
| | | {'discriminator':1, 'callable':None, 'args':(1,), 'kw':{}, |
| | | 'order':0, 'includepath':(), 'info':None, |
| | | 'introspectables':(intr,)}, |
| | | ] |
| | | { |
| | | 'discriminator': 1, |
| | | 'callable': None, |
| | | 'args': (1,), |
| | | 'kw': {}, |
| | | 'order': 0, |
| | | 'includepath': (), |
| | | 'info': None, |
| | | 'introspectables': (intr,), |
| | | } |
| | | ] |
| | | introspector = object() |
| | | c.execute_actions(introspector=introspector) |
| | | self.assertEqual(intr.registered, [(introspector, None)]) |
| | | |
| | | def test_execute_actions_error(self): |
| | | output = [] |
| | | |
| | | def f(*a, **k): |
| | | output.append(('f', a, k)) |
| | | |
| | | def bad(): |
| | | raise NotImplementedError |
| | | |
| | | c = self._makeOne() |
| | | c.actions = [ |
| | | (1, f, (1,)), |
| | | (1, f, (11,), {}, ('x', )), |
| | | (1, f, (11,), {}, ('x',)), |
| | | (2, f, (2,)), |
| | | (3, bad, (), {}, (), 'oops') |
| | | ] |
| | | (3, bad, (), {}, (), 'oops'), |
| | | ] |
| | | self.assertRaises(ConfigurationExecutionError, c.execute_actions) |
| | | self.assertEqual(output, [('f', (1,), {}), ('f', (2,), {})]) |
| | | |
| | | def test_reentrant_action(self): |
| | | output = [] |
| | | c = self._makeOne() |
| | | |
| | | def f(*a, **k): |
| | | output.append(('f', a, k)) |
| | | c.actions.append((3, g, (8,), {})) |
| | | |
| | | def g(*a, **k): |
| | | output.append(('g', a, k)) |
| | | c.actions = [ |
| | | (1, f, (1,)), |
| | | ] |
| | | |
| | | c.actions = [(1, f, (1,))] |
| | | c.execute_actions() |
| | | self.assertEqual(output, [('f', (1,), {}), ('g', (8,), {})]) |
| | | |
| | | def test_reentrant_action_with_deferred_discriminator(self): |
| | | # see https://github.com/Pylons/pyramid/issues/2697 |
| | | from pyramid.registry import Deferred |
| | | |
| | | output = [] |
| | | c = self._makeOne() |
| | | |
| | | def f(*a, **k): |
| | | output.append(('f', a, k)) |
| | | c.actions.append((4, g, (4,), {}, (), None, 2)) |
| | | |
| | | def g(*a, **k): |
| | | output.append(('g', a, k)) |
| | | |
| | | def h(*a, **k): |
| | | output.append(('h', a, k)) |
| | | |
| | | def discrim(): |
| | | self.assertEqual(output, [('f', (1,), {}), ('g', (2,), {})]) |
| | | return 3 |
| | | |
| | | d = Deferred(discrim) |
| | | c.actions = [ |
| | | (d, h, (3,), {}, (), None, 1), # order 1 |
| | | (1, f, (1,)), # order 0 |
| | | (2, g, (2,)), # order 0 |
| | | (d, h, (3,), {}, (), None, 1), # order 1 |
| | | (1, f, (1,)), # order 0 |
| | | (2, g, (2,)), # order 0 |
| | | ] |
| | | c.execute_actions() |
| | | self.assertEqual(output, [ |
| | | ('f', (1,), {}), ('g', (2,), {}), ('h', (3,), {}), ('g', (4,), {})]) |
| | | self.assertEqual( |
| | | output, |
| | | [ |
| | | ('f', (1,), {}), |
| | | ('g', (2,), {}), |
| | | ('h', (3,), {}), |
| | | ('g', (4,), {}), |
| | | ], |
| | | ) |
| | | |
| | | def test_reentrant_action_error(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | |
| | | c = self._makeOne() |
| | | |
| | | def f(*a, **k): |
| | | c.actions.append((3, g, (8,), {}, (), None, -1)) |
| | | def g(*a, **k): pass |
| | | c.actions = [ |
| | | (1, f, (1,)), |
| | | ] |
| | | |
| | | def g(*a, **k): # pragma: no cover |
| | | pass |
| | | |
| | | c.actions = [(1, f, (1,))] |
| | | self.assertRaises(ConfigurationError, c.execute_actions) |
| | | |
| | | def test_reentrant_action_without_clear(self): |
| | | c = self._makeOne() |
| | | |
| | | def f(*a, **k): |
| | | c.actions.append((3, g, (8,))) |
| | | def g(*a, **k): pass |
| | | c.actions = [ |
| | | (1, f, (1,)), |
| | | ] |
| | | |
| | | def g(*a, **k): |
| | | pass |
| | | |
| | | c.actions = [(1, f, (1,))] |
| | | c.execute_actions(clear=False) |
| | | self.assertEqual(c.actions, [ |
| | | (1, f, (1,)), |
| | | (3, g, (8,)), |
| | | ]) |
| | | self.assertEqual(c.actions, [(1, f, (1,)), (3, g, (8,))]) |
| | | |
| | | def test_executing_conflicting_action_across_orders(self): |
| | | from pyramid.exceptions import ConfigurationConflictError |
| | | |
| | | c = self._makeOne() |
| | | def f(*a, **k): pass |
| | | def g(*a, **k): pass |
| | | c.actions = [ |
| | | (1, f, (1,), {}, (), None, -1), |
| | | (1, g, (2,)), |
| | | ] |
| | | |
| | | def f(*a, **k): |
| | | pass |
| | | |
| | | def g(*a, **k): # pragma: no cover |
| | | pass |
| | | |
| | | c.actions = [(1, f, (1,), {}, (), None, -1), (1, g, (2,))] |
| | | self.assertRaises(ConfigurationConflictError, c.execute_actions) |
| | | |
| | | def test_executing_conflicting_action_across_reentrant_orders(self): |
| | | from pyramid.exceptions import ConfigurationConflictError |
| | | |
| | | c = self._makeOne() |
| | | |
| | | def f(*a, **k): |
| | | c.actions.append((1, g, (8,))) |
| | | def g(*a, **k): pass |
| | | c.actions = [ |
| | | (1, f, (1,), {}, (), None, -1), |
| | | ] |
| | | |
| | | def g(*a, **k): # pragma: no cover |
| | | pass |
| | | |
| | | c.actions = [(1, f, (1,), {}, (), None, -1)] |
| | | self.assertRaises(ConfigurationConflictError, c.execute_actions) |
| | | |
| | | |
| | | class Test_reentrant_action_functional(unittest.TestCase): |
| | | def _makeConfigurator(self, *arg, **kw): |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator(*arg, **kw) |
| | | return config |
| | | |
| | | def test_functional(self): |
| | | def add_auto_route(config, name, view): |
| | | def register(): |
| | | config.add_view(route_name=name, view=view) |
| | | config.add_route(name, '/' + name) |
| | | config.action( |
| | | ('auto route', name), register, order=-30 |
| | | ) |
| | | def register(): |
| | | config.add_view(route_name=name, view=view) |
| | | config.add_route(name, '/' + name) |
| | | |
| | | config.action(('auto route', name), register, order=-30) |
| | | |
| | | config = self._makeConfigurator() |
| | | config.add_directive('add_auto_route', add_auto_route) |
| | | def my_view(request): return request.response |
| | | |
| | | def my_view(request): # pragma: no cover |
| | | return request.response |
| | | |
| | | config.add_auto_route('foo', my_view) |
| | | config.commit() |
| | | from pyramid.interfaces import IRoutesMapper |
| | | |
| | | mapper = config.registry.getUtility(IRoutesMapper) |
| | | routes = mapper.get_routes() |
| | | route = routes[0] |
| | |
| | | def test_deferred_discriminator(self): |
| | | # see https://github.com/Pylons/pyramid/issues/2697 |
| | | from pyramid.config import PHASE0_CONFIG |
| | | |
| | | config = self._makeConfigurator() |
| | | def deriver(view, info): return view |
| | | |
| | | def deriver(view, info): |
| | | return view |
| | | |
| | | deriver.options = ('foo',) |
| | | config.add_view_deriver(deriver, 'foo_view') |
| | | # add_view uses a deferred discriminator and will fail if executed |
| | | # prior to add_view_deriver executing its action |
| | | config.add_view(lambda r: r.response, name='', foo=1) |
| | | |
| | | def dummy_action(): |
| | | # trigger a re-entrant action |
| | | config.action(None, lambda: None) |
| | | |
| | | config.action(None, dummy_action, order=PHASE0_CONFIG) |
| | | config.commit() |
| | | |
| | | |
| | | class Test_resolveConflicts(unittest.TestCase): |
| | | def _callFUT(self, actions): |
| | | from pyramid.config import resolveConflicts |
| | | |
| | | return resolveConflicts(actions) |
| | | |
| | | def test_it_success_tuples(self): |
| | | from . import dummyfactory as f |
| | | result = self._callFUT([ |
| | | (None, f), |
| | | (1, f, (1,), {}, (), 'first'), |
| | | (1, f, (2,), {}, ('x',), 'second'), |
| | | (1, f, (3,), {}, ('y',), 'third'), |
| | | (4, f, (4,), {}, ('y',), 'should be last', 99999), |
| | | (3, f, (3,), {}, ('y',)), |
| | | (None, f, (5,), {}, ('y',)), |
| | | ]) |
| | | |
| | | result = self._callFUT( |
| | | [ |
| | | (None, f), |
| | | (1, f, (1,), {}, (), 'first'), |
| | | (1, f, (2,), {}, ('x',), 'second'), |
| | | (1, f, (3,), {}, ('y',), 'third'), |
| | | (4, f, (4,), {}, ('y',), 'should be last', 99999), |
| | | (3, f, (3,), {}, ('y',)), |
| | | (None, f, (5,), {}, ('y',)), |
| | | ] |
| | | ) |
| | | result = list(result) |
| | | self.assertEqual( |
| | | result, |
| | | [{'info': None, |
| | | 'args': (), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': None, |
| | | 'includepath': (), |
| | | 'order': 0}, |
| | | |
| | | {'info': 'first', |
| | | 'args': (1,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 1, |
| | | 'includepath': (), |
| | | 'order': 0}, |
| | | |
| | | {'info': None, |
| | | 'args': (3,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 3, |
| | | 'includepath': ('y',), |
| | | 'order': 0}, |
| | | |
| | | {'info': None, |
| | | 'args': (5,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': None, |
| | | 'includepath': ('y',), |
| | | 'order': 0}, |
| | | |
| | | {'info': 'should be last', |
| | | 'args': (4,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 4, |
| | | 'includepath': ('y',), |
| | | 'order': 99999} |
| | | ] |
| | | ) |
| | | [ |
| | | { |
| | | 'info': None, |
| | | 'args': (), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': None, |
| | | 'includepath': (), |
| | | 'order': 0, |
| | | }, |
| | | { |
| | | 'info': 'first', |
| | | 'args': (1,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 1, |
| | | 'includepath': (), |
| | | 'order': 0, |
| | | }, |
| | | { |
| | | 'info': None, |
| | | 'args': (3,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 3, |
| | | 'includepath': ('y',), |
| | | 'order': 0, |
| | | }, |
| | | { |
| | | 'info': None, |
| | | 'args': (5,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': None, |
| | | 'includepath': ('y',), |
| | | 'order': 0, |
| | | }, |
| | | { |
| | | 'info': 'should be last', |
| | | 'args': (4,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 4, |
| | | 'includepath': ('y',), |
| | | 'order': 99999, |
| | | }, |
| | | ], |
| | | ) |
| | | |
| | | def test_it_success_dicts(self): |
| | | from . import dummyfactory as f |
| | | result = self._callFUT([ |
| | | (None, f), |
| | | (1, f, (1,), {}, (), 'first'), |
| | | (1, f, (2,), {}, ('x',), 'second'), |
| | | (1, f, (3,), {}, ('y',), 'third'), |
| | | (4, f, (4,), {}, ('y',), 'should be last', 99999), |
| | | (3, f, (3,), {}, ('y',)), |
| | | (None, f, (5,), {}, ('y',)), |
| | | ]) |
| | | |
| | | result = self._callFUT( |
| | | [ |
| | | (None, f), |
| | | (1, f, (1,), {}, (), 'first'), |
| | | (1, f, (2,), {}, ('x',), 'second'), |
| | | (1, f, (3,), {}, ('y',), 'third'), |
| | | (4, f, (4,), {}, ('y',), 'should be last', 99999), |
| | | (3, f, (3,), {}, ('y',)), |
| | | (None, f, (5,), {}, ('y',)), |
| | | ] |
| | | ) |
| | | result = list(result) |
| | | self.assertEqual( |
| | | result, |
| | | [{'info': None, |
| | | 'args': (), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': None, |
| | | 'includepath': (), |
| | | 'order': 0}, |
| | | |
| | | {'info': 'first', |
| | | 'args': (1,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 1, |
| | | 'includepath': (), |
| | | 'order': 0}, |
| | | |
| | | {'info': None, |
| | | 'args': (3,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 3, |
| | | 'includepath': ('y',), |
| | | 'order': 0}, |
| | | |
| | | {'info': None, |
| | | 'args': (5,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': None, |
| | | 'includepath': ('y',), |
| | | 'order': 0}, |
| | | |
| | | {'info': 'should be last', |
| | | 'args': (4,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 4, |
| | | 'includepath': ('y',), |
| | | 'order': 99999} |
| | | ] |
| | | ) |
| | | [ |
| | | { |
| | | 'info': None, |
| | | 'args': (), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': None, |
| | | 'includepath': (), |
| | | 'order': 0, |
| | | }, |
| | | { |
| | | 'info': 'first', |
| | | 'args': (1,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 1, |
| | | 'includepath': (), |
| | | 'order': 0, |
| | | }, |
| | | { |
| | | 'info': None, |
| | | 'args': (3,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 3, |
| | | 'includepath': ('y',), |
| | | 'order': 0, |
| | | }, |
| | | { |
| | | 'info': None, |
| | | 'args': (5,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': None, |
| | | 'includepath': ('y',), |
| | | 'order': 0, |
| | | }, |
| | | { |
| | | 'info': 'should be last', |
| | | 'args': (4,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 4, |
| | | 'includepath': ('y',), |
| | | 'order': 99999, |
| | | }, |
| | | ], |
| | | ) |
| | | |
| | | def test_it_conflict(self): |
| | | from . import dummyfactory as f |
| | | result = self._callFUT([ |
| | | (None, f), |
| | | (1, f, (2,), {}, ('x',), 'eek'), # will conflict |
| | | (1, f, (3,), {}, ('y',), 'ack'), # will conflict |
| | | (4, f, (4,), {}, ('y',)), |
| | | (3, f, (3,), {}, ('y',)), |
| | | (None, f, (5,), {}, ('y',)), |
| | | ]) |
| | | |
| | | result = self._callFUT( |
| | | [ |
| | | (None, f), |
| | | (1, f, (2,), {}, ('x',), 'eek'), # will conflict |
| | | (1, f, (3,), {}, ('y',), 'ack'), # will conflict |
| | | (4, f, (4,), {}, ('y',)), |
| | | (3, f, (3,), {}, ('y',)), |
| | | (None, f, (5,), {}, ('y',)), |
| | | ] |
| | | ) |
| | | self.assertRaises(ConfigurationConflictError, list, result) |
| | | |
| | | def test_it_with_actions_grouped_by_order(self): |
| | | from . import dummyfactory as f |
| | | result = self._callFUT([ |
| | | (None, f), # X |
| | | (1, f, (1,), {}, (), 'third', 10), # X |
| | | (1, f, (2,), {}, ('x',), 'fourth', 10), |
| | | (1, f, (3,), {}, ('y',), 'fifth', 10), |
| | | (2, f, (1,), {}, (), 'sixth', 10), # X |
| | | (3, f, (1,), {}, (), 'seventh', 10), # X |
| | | (5, f, (4,), {}, ('y',), 'eighth', 99999), # X |
| | | (4, f, (3,), {}, (), 'first', 5), # X |
| | | (4, f, (5,), {}, ('y',), 'second', 5), |
| | | ]) |
| | | |
| | | result = self._callFUT( |
| | | [ |
| | | (None, f), # X |
| | | (1, f, (1,), {}, (), 'third', 10), # X |
| | | (1, f, (2,), {}, ('x',), 'fourth', 10), |
| | | (1, f, (3,), {}, ('y',), 'fifth', 10), |
| | | (2, f, (1,), {}, (), 'sixth', 10), # X |
| | | (3, f, (1,), {}, (), 'seventh', 10), # X |
| | | (5, f, (4,), {}, ('y',), 'eighth', 99999), # X |
| | | (4, f, (3,), {}, (), 'first', 5), # X |
| | | (4, f, (5,), {}, ('y',), 'second', 5), |
| | | ] |
| | | ) |
| | | result = list(result) |
| | | self.assertEqual(len(result), 6) |
| | | # resolved actions should be grouped by (order, i) |
| | | self.assertEqual( |
| | | result, |
| | | [{'info': None, |
| | | 'args': (), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': None, |
| | | 'includepath': (), |
| | | 'order': 0}, |
| | | |
| | | {'info': 'first', |
| | | 'args': (3,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 4, |
| | | 'includepath': (), |
| | | 'order': 5}, |
| | | |
| | | {'info': 'third', |
| | | 'args': (1,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 1, |
| | | 'includepath': (), |
| | | 'order': 10}, |
| | | |
| | | {'info': 'sixth', |
| | | 'args': (1,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 2, |
| | | 'includepath': (), |
| | | 'order': 10}, |
| | | |
| | | {'info': 'seventh', |
| | | 'args': (1,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 3, |
| | | 'includepath': (), |
| | | 'order': 10}, |
| | | |
| | | {'info': 'eighth', |
| | | 'args': (4,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 5, |
| | | 'includepath': ('y',), |
| | | 'order': 99999} |
| | | ] |
| | | ) |
| | | [ |
| | | { |
| | | 'info': None, |
| | | 'args': (), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': None, |
| | | 'includepath': (), |
| | | 'order': 0, |
| | | }, |
| | | { |
| | | 'info': 'first', |
| | | 'args': (3,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 4, |
| | | 'includepath': (), |
| | | 'order': 5, |
| | | }, |
| | | { |
| | | 'info': 'third', |
| | | 'args': (1,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 1, |
| | | 'includepath': (), |
| | | 'order': 10, |
| | | }, |
| | | { |
| | | 'info': 'sixth', |
| | | 'args': (1,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 2, |
| | | 'includepath': (), |
| | | 'order': 10, |
| | | }, |
| | | { |
| | | 'info': 'seventh', |
| | | 'args': (1,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 3, |
| | | 'includepath': (), |
| | | 'order': 10, |
| | | }, |
| | | { |
| | | 'info': 'eighth', |
| | | 'args': (4,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 5, |
| | | 'includepath': ('y',), |
| | | 'order': 99999, |
| | | }, |
| | | ], |
| | | ) |
| | | |
| | | def test_override_success_across_orders(self): |
| | | from . import dummyfactory as f |
| | | result = self._callFUT([ |
| | | (1, f, (2,), {}, ('x',), 'eek', 0), |
| | | (1, f, (3,), {}, ('x', 'y'), 'ack', 10), |
| | | ]) |
| | | |
| | | result = self._callFUT( |
| | | [ |
| | | (1, f, (2,), {}, ('x',), 'eek', 0), |
| | | (1, f, (3,), {}, ('x', 'y'), 'ack', 10), |
| | | ] |
| | | ) |
| | | result = list(result) |
| | | self.assertEqual(result, [ |
| | | {'info': 'eek', |
| | | 'args': (2,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 1, |
| | | 'includepath': ('x',), |
| | | 'order': 0}, |
| | | ]) |
| | | self.assertEqual( |
| | | result, |
| | | [ |
| | | { |
| | | 'info': 'eek', |
| | | 'args': (2,), |
| | | 'callable': f, |
| | | 'introspectables': (), |
| | | 'kw': {}, |
| | | 'discriminator': 1, |
| | | 'includepath': ('x',), |
| | | 'order': 0, |
| | | } |
| | | ], |
| | | ) |
| | | |
| | | def test_conflicts_across_orders(self): |
| | | from . import dummyfactory as f |
| | | result = self._callFUT([ |
| | | (1, f, (2,), {}, ('x', 'y'), 'eek', 0), |
| | | (1, f, (3,), {}, ('x'), 'ack', 10), |
| | | ]) |
| | | |
| | | result = self._callFUT( |
| | | [ |
| | | (1, f, (2,), {}, ('x', 'y'), 'eek', 0), |
| | | (1, f, (3,), {}, ('x'), 'ack', 10), |
| | | ] |
| | | ) |
| | | self.assertRaises(ConfigurationConflictError, list, result) |
| | | |
| | | |
| | | class TestGlobalRegistriesIntegration(unittest.TestCase): |
| | | def setUp(self): |
| | | from pyramid.config import global_registries |
| | | |
| | | global_registries.empty() |
| | | |
| | | tearDown = setUp |
| | | |
| | | def _makeConfigurator(self, *arg, **kw): |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator(*arg, **kw) |
| | | return config |
| | | |
| | | def test_global_registries_empty(self): |
| | | from pyramid.config import global_registries |
| | | |
| | | self.assertEqual(global_registries.last, None) |
| | | |
| | | def test_global_registries(self): |
| | | from pyramid.config import global_registries |
| | | |
| | | config1 = self._makeConfigurator() |
| | | config1.make_wsgi_app() |
| | | self.assertEqual(global_registries.last, config1.registry) |
| | | config2 = self._makeConfigurator() |
| | | config2.make_wsgi_app() |
| | | self.assertEqual(global_registries.last, config2.registry) |
| | | self.assertEqual(list(global_registries), |
| | | [config1.registry, config2.registry]) |
| | | self.assertEqual( |
| | | list(global_registries), [config1.registry, config2.registry] |
| | | ) |
| | | global_registries.remove(config2.registry) |
| | | self.assertEqual(global_registries.last, config1.registry) |
| | | |
| | | |
| | | class DummyRequest: |
| | | subpath = () |
| | | matchdict = None |
| | | request_iface = IRequest |
| | | |
| | | def __init__(self, environ=None): |
| | | if environ is None: |
| | | environ = {} |
| | |
| | | self.params = {} |
| | | self.cookies = {} |
| | | |
| | | |
| | | class DummyThreadLocalManager(object): |
| | | def __init__(self): |
| | | self.pushed = {'registry': None, 'request': None} |
| | | self.popped = False |
| | | |
| | | def push(self, d): |
| | | self.pushed = d |
| | | |
| | | def get(self): |
| | | return self.pushed |
| | | |
| | | def pop(self): |
| | | self.popped = True |
| | | |
| | | from zope.interface import implementer |
| | | |
| | | @implementer(IDummy) |
| | | class DummyEvent: |
| | | pass |
| | | |
| | | |
| | | class DummyRegistry(object): |
| | | def __init__(self, adaptation=None, util=None): |
| | |
| | | self.adapters = [] |
| | | self.adaptation = adaptation |
| | | self.util = util |
| | | |
| | | def subscribers(self, events, name): |
| | | self.events = events |
| | | return events |
| | | |
| | | def registerUtility(self, *arg, **kw): |
| | | self.utilities.append((arg, kw)) |
| | | |
| | | def registerAdapter(self, *arg, **kw): |
| | | self.adapters.append((arg, kw)) |
| | | |
| | | def queryAdapter(self, *arg, **kw): |
| | | return self.adaptation |
| | | |
| | | def queryUtility(self, *arg, **kw): |
| | | return self.util |
| | | |
| | | from zope.interface import Interface |
| | | |
| | | class IOther(Interface): |
| | | pass |
| | | |
| | | |
| | | def _conflictFunctions(e): |
| | | conflicts = e._conflicts.values() |
| | |
| | | for confinst in conflict: |
| | | yield confinst.function |
| | | |
| | | |
| | | class DummyActionState(object): |
| | | autocommit = False |
| | | info = '' |
| | | |
| | | def __init__(self): |
| | | self.actions = [] |
| | | |
| | | def action(self, *arg, **kw): |
| | | self.actions.append((arg, kw)) |
| | | |
| | | |
| | | class DummyIntrospectable(object): |
| | | def __init__(self): |
| | | self.registered = [] |
| | | |
| | | def register(self, introspector, action_info): |
| | | self.registered.append((introspector, action_info)) |
| | | |
| | | |
| | | |
| | | class DummyPredicate(object): |
| | | pass |
tests/test_config/test_rendering.py
tests/test_config/test_routes.py
tests/test_config/test_security.py
tests/test_config/test_settings.py
tests/test_config/test_testing.py
tests/test_config/test_tweens.py
tests/test_config/test_util.py
tests/test_config/test_views.py
tests/test_csrf.py
tests/test_decorator.py
tests/test_docs.py
tests/test_encode.py
tests/test_events.py
tests/test_exceptions.py
tests/test_httpexceptions.py
tests/test_i18n.py
tests/test_integration.py
tests/test_location.py
tests/test_paster.py
tests/test_path.py
tests/test_predicates.py
tests/test_registry.py
tests/test_renderers.py
tests/test_request.py
tests/test_response.py
tests/test_router.py
tests/test_scaffolds/test_copydir.py
tests/test_scaffolds/test_init.py
tests/test_scaffolds/test_template.py
tests/test_scripting.py
tests/test_scripts/dummy.py
tests/test_scripts/test_common.py
tests/test_scripts/test_pcreate.py
tests/test_scripts/test_pdistreport.py
tests/test_scripts/test_prequest.py
tests/test_scripts/test_proutes.py
tests/test_scripts/test_pserve.py
tests/test_scripts/test_pshell.py
tests/test_scripts/test_ptweens.py
tests/test_scripts/test_pviews.py
tests/test_security.py
tests/test_session.py
tests/test_settings.py
tests/test_static.py
tests/test_testing.py
tests/test_threadlocal.py
tests/test_traversal.py
tests/test_tweens.py
tests/test_url.py
tests/test_urldispatch.py
tests/test_util.py
tests/test_view.py
tests/test_viewderivers.py
tests/test_wsgi.py
tox.ini |