Repository: striglia/pyramid_swagger
Pull request #237 (2019-05-05 23:04:08)

Fix tests and make pyramid-swagger compatible with jsonschema>3
The goal of this CR is to fix tests that are red from ever (roughly 6 months).
The failures were caused by:
 * pre-commit updates (flake8 version was not pinned)
 * release of jsonschema>3 (the library was using private internals which have changed)



Patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 55f712d..635c93c 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,19 +1,32 @@
--   repo: git://github.com/pre-commit/pre-commit-hooks
-    sha: v0.7.1
+repos:
+-   repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v2.2.1
     hooks:
-    -   id: autopep8-wrapper
-        args:
-        - -i
-        - --ignore=E501
     -   id: check-json
     -   id: check-yaml
     -   id: debug-statements
     -   id: end-of-file-fixer
     -   id: fix-encoding-pragma
-    -   id: flake8
     -   id: name-tests-test
     -   id: trailing-whitespace
--   repo: git://github.com/asottile/reorder_python_imports
-    sha: v0.3.2
+-   repo: https://github.com/pre-commit/mirrors-autopep8
+    rev: v1.4.4
+    hooks:
+    -   id: autopep8
+        args:
+        - -i
+        - --ignore=E309,E501
+-   repo: https://gitlab.com/pycqa/flake8.git
+    rev: 3.7.6
+    hooks:
+    -   id: flake8
+        args:
+        - --ignore=W503
+        exclude: ^docs
+-   repo: https://github.com/asottile/reorder_python_imports
+    rev: v1.4.0
     hooks:
     -   id: reorder-python-imports
+        args:
+        - --add-import
+        - from __future__ import absolute_import
diff --git a/.travis.yml b/.travis.yml
index 907bdb5..85690b8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,11 +2,14 @@ sudo: false
 language: python
 matrix:
     include:
-    - env: TOXENV=py27
+    - python: "2.7"
+      env: TOXENV=py27
     - python: "3.5"
       env: TOXENV=py35
-    - env: TOXENV=py27-pyramid15
-    - env: TOXENV=docs
+    - python: "2.7"
+      env: TOXENV=py27-pyramid15
+    - python: "3.6"
+      env: TOXENV=docs
 install: pip install tox coveralls
 script: tox
 after_success: coveralls
diff --git a/README.rst b/README.rst
index 6232ff1..6102703 100644
--- a/README.rst
+++ b/README.rst
@@ -12,7 +12,7 @@
 :Current coverage on master:
     .. image:: https://coveralls.io/repos/striglia/pyramid_swagger/badge.png
         :target: https://coveralls.io/r/striglia/pyramid_swagger
-:Persistent chat for questions: 
+:Persistent chat for questions:
     .. image:: https://badges.gitter.im/Join%20Chat.svg
         :alt: Join the chat at https://gitter.im/striglia/pyramid_swagger
         :target: https://gitter.im/striglia/pyramid_swagger?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
diff --git a/docs/conf.py b/docs/conf.py
index 639cc11..f8a82f5 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -10,6 +10,8 @@
 #
 # All configuration values have a default; values that are commented out
 # serve to show the default.
+from __future__ import absolute_import
+
 import os
 
 
diff --git a/pyramid_swagger/__init__.py b/pyramid_swagger/__init__.py
index 8ea4c67..25ea1fb 100644
--- a/pyramid_swagger/__init__.py
+++ b/pyramid_swagger/__init__.py
@@ -2,16 +2,18 @@
 """
 Import this module to add the validation tween to your pyramid app.
 """
+from __future__ import absolute_import
+
 import pyramid
 
-from .api import build_swagger_20_swagger_schema_views
-from .api import register_api_doc_endpoints
-from .ingest import get_swagger_schema
-from .ingest import get_swagger_spec
-from .renderer import PyramidSwaggerRendererFactory
-from .tween import get_swagger_versions
-from .tween import SWAGGER_12
-from .tween import SWAGGER_20
+from pyramid_swagger.api import build_swagger_20_swagger_schema_views
+from pyramid_swagger.api import register_api_doc_endpoints
+from pyramid_swagger.ingest import get_swagger_schema
+from pyramid_swagger.ingest import get_swagger_spec
+from pyramid_swagger.renderer import PyramidSwaggerRendererFactory
+from pyramid_swagger.tween import get_swagger_versions
+from pyramid_swagger.tween import SWAGGER_12
+from pyramid_swagger.tween import SWAGGER_20
 
 
 def includeme(config):
diff --git a/pyramid_swagger/api.py b/pyramid_swagger/api.py
index 1920804..46c554a 100644
--- a/pyramid_swagger/api.py
+++ b/pyramid_swagger/api.py
@@ -2,6 +2,8 @@
 """
 Module for automatically serving /api-docs* via Pyramid.
 """
+from __future__ import absolute_import
+
 import copy
 import os.path
 
diff --git a/pyramid_swagger/exceptions.py b/pyramid_swagger/exceptions.py
index 3497c95..dfd8c6e 100644
--- a/pyramid_swagger/exceptions.py
+++ b/pyramid_swagger/exceptions.py
@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import sys
 
 import six
diff --git a/pyramid_swagger/ingest.py b/pyramid_swagger/ingest.py
index 289f591..d6129d3 100644
--- a/pyramid_swagger/ingest.py
+++ b/pyramid_swagger/ingest.py
@@ -1,4 +1,5 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
 from __future__ import unicode_literals
 
 import glob
@@ -12,11 +13,11 @@ from six import iteritems
 from six.moves.urllib import parse as urlparse
 from six.moves.urllib.request import pathname2url
 
-from .api import build_swagger_12_endpoints
-from .load_schema import load_schema
-from .model import SwaggerSchema
-from .spec import API_DOCS_FILENAME
-from .spec import validate_swagger_schema
+from pyramid_swagger.api import build_swagger_12_endpoints
+from pyramid_swagger.load_schema import load_schema
+from pyramid_swagger.model import SwaggerSchema
+from pyramid_swagger.spec import API_DOCS_FILENAME
+from pyramid_swagger.spec import validate_swagger_schema
 
 
 # Prefix of configs that will be passed to the underlying bravado-core instance
diff --git a/pyramid_swagger/load_schema.py b/pyramid_swagger/load_schema.py
index 5f1f07b..7a18ba3 100644
--- a/pyramid_swagger/load_schema.py
+++ b/pyramid_swagger/load_schema.py
@@ -3,12 +3,12 @@
 Module to load swagger specs and build efficient data structures for querying
 them during request validation.
 """
+from __future__ import absolute_import
 from __future__ import unicode_literals
 
 from collections import namedtuple
 
 import simplejson
-from jsonschema import _validators
 from jsonschema import RefResolver
 from jsonschema import validators
 from jsonschema.exceptions import ValidationError
@@ -25,6 +25,12 @@ EXTENDED_TYPES = {
 }
 
 
+_draft3_type_validator = Draft3Validator.VALIDATORS['type']
+_draft4_type_validator = Draft4Validator.VALIDATORS['type']
+_draft4_required_validator = Draft4Validator.VALIDATORS['required']
+_ref_validator = Draft4Validator.VALIDATORS['$ref']
+
+
 def build_param_schema(schema, param_type):
     """Turn a swagger endpoint schema into an equivalent one to validate our
     request.
@@ -85,8 +91,10 @@ def ignore(_validator, *args):
 
 def build_swagger_type_validator(models):
     def swagger_type_validator(validator, ref, instance, schema):
-        func = _validators.ref if ref in models else _validators.type_draft4
-        return func(validator, ref, instance, schema)
+        if ref in models:
+            return _ref_validator(validator, ref, instance, schema)
+        else:
+            return _draft4_type_validator(validator, ref, instance, schema)
 
     return swagger_type_validator
 
@@ -97,7 +105,7 @@ def type_validator(validator, types, instance, schema):
     """
     if schema.get('type') == 'File':
         return []
-    return _validators.type_draft3(validator, types, instance, schema)
+    return _draft3_type_validator(validator, types, instance, schema)
 
 
 def required_validator(validator, req, instance, schema):
@@ -108,7 +116,7 @@ def required_validator(validator, req, instance, schema):
         if req is True and not instance:
             return [ValidationError("%s is required" % schema['name'])]
         return []
-    return _validators.required_draft4(validator, req, instance, schema)
+    return _draft4_required_validator(validator, req, instance, schema)
 
 
 def get_body_validator(models):
@@ -228,10 +236,7 @@ class RequestMatcher(object):
         :param request: a :class:`pyramid.request.Request`
         :returns: True if this matcher matches the request, False otherwise
         """
-        return (
-            partial_path_match(request.path_info, self.path) and
-            request.method == self.method
-        )
+        return partial_path_match(request.path_info, self.path) and request.method == self.method
 
 
 def extract_response_body_schema(operation, schema_models):
diff --git a/pyramid_swagger/model.py b/pyramid_swagger/model.py
index 10a2d5e..d6781b9 100644
--- a/pyramid_swagger/model.py
+++ b/pyramid_swagger/model.py
@@ -3,6 +3,8 @@
 The core model we use to represent the entire ingested swagger schema for this
 service.
 """
+from __future__ import absolute_import
+
 import re
 from collections import namedtuple
 
diff --git a/pyramid_swagger/renderer.py b/pyramid_swagger/renderer.py
index 7866be9..b83b019 100644
--- a/pyramid_swagger/renderer.py
+++ b/pyramid_swagger/renderer.py
@@ -2,6 +2,8 @@
 """
 This model contains the main factory of renderers to use while dealing with Swagger 2.0 endpoints.
 """
+from __future__ import absolute_import
+
 from functools import partial
 
 from bravado_core.exception import MatchingResponseNotFound
diff --git a/pyramid_swagger/spec.py b/pyramid_swagger/spec.py
index abdf0da..a52b863 100644
--- a/pyramid_swagger/spec.py
+++ b/pyramid_swagger/spec.py
@@ -2,6 +2,8 @@
 """
 Methods to help validate a given JSON document against the Swagger Spec.
 """
+from __future__ import absolute_import
+
 import os
 
 import swagger_spec_validator
@@ -9,7 +11,7 @@ from jsonschema.exceptions import ValidationError
 from six.moves.urllib import parse as urlparse
 from six.moves.urllib.request import pathname2url
 
-from .exceptions import wrap_exception
+from pyramid_swagger.exceptions import wrap_exception
 
 API_DOCS_FILENAME = 'api_docs.json'
 
diff --git a/pyramid_swagger/tween.py b/pyramid_swagger/tween.py
index 15dc07e..a07a46a 100644
--- a/pyramid_swagger/tween.py
+++ b/pyramid_swagger/tween.py
@@ -1,4 +1,5 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
 from __future__ import unicode_literals
 
 import functools
@@ -90,7 +91,7 @@ def _get_validation_context(registry):
 
     if validation_context_path:
         m = re.match(
-            '(?P<module_path>.*)\.(?P<contextmanager_name>.*)',
+            r'(?P<module_path>.*)\.(?P<contextmanager_name>.*)',
             validation_context_path,
         )
         module_path = m.group('module_path')
@@ -124,14 +125,13 @@ def get_swagger_objects(settings, route_info, registry):
     schema12 = registry.settings['pyramid_swagger.schema12']
     schema20 = registry.settings['pyramid_swagger.schema20']
 
-    fallback_to_swagger12_route = (
-        SWAGGER_20 in enabled_swagger_versions and
-        SWAGGER_12 in enabled_swagger_versions and
-        settings.prefer_20_routes and
-        route_info.get('route') and
-        route_info['route'].name not in settings.prefer_20_routes
-    )
-    if fallback_to_swagger12_route:
+    if (
+        SWAGGER_20 in enabled_swagger_versions
+        and SWAGGER_12 in enabled_swagger_versions
+        and settings.prefer_20_routes
+        and route_info.get('route')
+        and route_info['route'].name not in settings.prefer_20_routes
+    ):
         return settings.swagger12_handler, schema12
 
     if SWAGGER_20 in enabled_swagger_versions:
@@ -452,10 +452,10 @@ def should_exclude_request(settings, request, route_info):
         settings.validate_path
     ))
     return (
-        disable_all_validation or
-        should_exclude_path(settings.exclude_paths, request.path_info) or
-        should_exclude_route(settings.exclude_routes, route_info) or
-        is_swagger_documentation_route(route_info)
+        disable_all_validation
+        or should_exclude_path(settings.exclude_paths, request.path_info)
+        or should_exclude_route(settings.exclude_routes, route_info)
+        or is_swagger_documentation_route(route_info)
     )
 
 
@@ -465,10 +465,7 @@ def should_exclude_path(exclude_path_regexes, path):
 
 
 def should_exclude_route(excluded_routes, route_info):
-    return (
-        route_info.get('route') and
-        route_info['route'].name in excluded_routes
-    )
+    return route_info.get('route') and route_info['route'].name in excluded_routes
 
 
 def validation_error(exc_class):
diff --git a/setup.cfg b/setup.cfg
index 528f01c..e9ab705 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -3,4 +3,3 @@ description-file = README.rst
 
 [wheel]
 universal = True
-
diff --git a/setup.py b/setup.py
index d48c8d9..38bb420 100644
--- a/setup.py
+++ b/setup.py
@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import io
 import os
 
diff --git a/tox.ini b/tox.ini
index b9047b6..9943d18 100644
--- a/tox.ini
+++ b/tox.ini
@@ -12,9 +12,8 @@ commands =
     py27: pre-commit run --all-files
 
 [flake8]
-exclude = .tox,*.egg,docs/conf.py
-# E501: line too long
-ignore = E501
+exclude = .svn,CVS,.bzr,.hg,.git,__pycache__,.tox,*.egg,docs/conf.py
+max_line_length = 120
 
 [testenv:docs]
 deps =


Test patch:
diff --git a/tests/acceptance/api_test.py b/tests/acceptance/api_test.py
index 7266b43..fbbd2d1 100644
--- a/tests/acceptance/api_test.py
+++ b/tests/acceptance/api_test.py
@@ -1,8 +1,10 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import pytest
 from webtest import TestApp as App
 
-from .app import main
+from tests.acceptance.app import main
 
 
 @pytest.fixture
diff --git a/tests/acceptance/app/__init__.py b/tests/acceptance/app/__init__.py
index 83eb091..b12780f 100644
--- a/tests/acceptance/app/__init__.py
+++ b/tests/acceptance/app/__init__.py
@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import datetime
 
 import six
diff --git a/tests/acceptance/config_ini_test.py b/tests/acceptance/config_ini_test.py
index 648329c..8f6ef07 100644
--- a/tests/acceptance/config_ini_test.py
+++ b/tests/acceptance/config_ini_test.py
@@ -1,13 +1,15 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import os.path
 
 import pytest
 from pyramid.paster import get_appsettings
 from webtest import TestApp as App
 
-from .app import main
 from pyramid_swagger.tween import get_swagger_versions
 from pyramid_swagger.tween import load_settings
+from tests.acceptance.app import main
 
 
 @pytest.fixture
diff --git a/tests/acceptance/format_test.py b/tests/acceptance/format_test.py
index 51beb6e..e339a5d 100644
--- a/tests/acceptance/format_test.py
+++ b/tests/acceptance/format_test.py
@@ -1,11 +1,13 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import base64
 
 import pytest
 from webtest import TestApp as App
 
-from .app import main
 from pyramid_swagger.tween import SwaggerFormat
+from tests.acceptance.app import main
 
 
 @pytest.fixture
diff --git a/tests/acceptance/invalid_file_test.py b/tests/acceptance/invalid_file_test.py
index 8fe08c5..ff84427 100644
--- a/tests/acceptance/invalid_file_test.py
+++ b/tests/acceptance/invalid_file_test.py
@@ -1,11 +1,13 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import base64
 
 import pytest
 from webtest import TestApp as App
 
-from .app import main
 from pyramid_swagger.tween import SwaggerFormat
+from tests.acceptance.app import main
 
 
 @pytest.fixture
diff --git a/tests/acceptance/prefer_20_routes_test.py b/tests/acceptance/prefer_20_routes_test.py
index 9b0748b..eff6220 100644
--- a/tests/acceptance/prefer_20_routes_test.py
+++ b/tests/acceptance/prefer_20_routes_test.py
@@ -1,8 +1,10 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import pytest
 from webtest import TestApp as App
 
-from .app import main
+from tests.acceptance.app import main
 
 
 @pytest.fixture
diff --git a/tests/acceptance/recursive_app_test.py b/tests/acceptance/recursive_app_test.py
index 00f856c..5d17431 100644
--- a/tests/acceptance/recursive_app_test.py
+++ b/tests/acceptance/recursive_app_test.py
@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import json
 
 import pytest
@@ -6,7 +8,7 @@ import yaml
 from six import BytesIO
 from webtest import TestApp as App
 
-from .app import main
+from tests.acceptance.app import main
 
 
 DESERIALIZERS = {
diff --git a/tests/acceptance/relative_ref_test.py b/tests/acceptance/relative_ref_test.py
index 57cc13c..5d9b31f 100644
--- a/tests/acceptance/relative_ref_test.py
+++ b/tests/acceptance/relative_ref_test.py
@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import json
 import os.path
 import re
@@ -9,7 +11,7 @@ import yaml
 from six import BytesIO
 from webtest import TestApp as App
 
-from .app import main
+from tests.acceptance.app import main
 
 
 DESERIALIZERS = {
@@ -151,7 +153,7 @@ def test_dereferenced_swagger_schema_retrieval(schema_format, test_app_deref):
     actual_dict = deserializer(response)
 
     # pattern for references outside the current file
-    ref_pattern = re.compile('("\$ref": "[^#][^"]*")')
+    ref_pattern = re.compile(r'("\$ref": "[^#][^"]*")')
     assert ref_pattern.findall(json.dumps(actual_dict)) == []
 
     if sys.platform != 'win32':
diff --git a/tests/acceptance/request_test.py b/tests/acceptance/request_test.py
index b4aa874..b9ad376 100644
--- a/tests/acceptance/request_test.py
+++ b/tests/acceptance/request_test.py
@@ -1,38 +1,45 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import datetime
 from contextlib import contextmanager
 
 import pytest
 import simplejson
-from _pytest.fixtures import FixtureRequest
-from mock import Mock
 from pyramid.httpexceptions import exception_response
 from webtest.utils import NoDefault
 
 from pyramid_swagger import exceptions
 
 
-# Parameterize pyramid_swagger.swagger_versions
-@pytest.fixture(
-    params=[['1.2'], ['2.0'], ['1.2', '2.0']],
-    ids=['1.2', '2.0', '1.2-2.0'],
-)
-def test_app(request, **overrides):
+def build_test_app(swagger_versions, **overrides):
     """Fixture for setting up a test test_app with particular settings."""
-    from .app import main
+    from tests.acceptance.app import main
     from webtest import TestApp as App
     settings = dict({
         'pyramid_swagger.schema_directory': 'tests/sample_schemas/good_app/',
         'pyramid_swagger.enable_request_validation': True,
         'pyramid_swagger.enable_response_validation': False,
         'pyramid_swagger.enable_swagger_spec_validation': False,
-        'pyramid_swagger.swagger_versions': request.param},
+        'pyramid_swagger.swagger_versions': swagger_versions},
         **overrides
     )
 
     return App(main({}, **settings))
 
 
+# Parameterize pyramid_swagger.swagger_versions
+@pytest.fixture(
+    params=[['1.2'], ['2.0'], ['1.2', '2.0']],
+    ids=['1.2', '2.0', '1.2-2.0'],
+)
+def test_app(request):
+    """Fixture for setting up a test test_app with particular settings."""
+    return build_test_app(
+        swagger_versions=request.param,
+    )
+
+
 @contextmanager
 def validation_context(request, response=None):
     try:
@@ -164,8 +171,8 @@ def test_404_if_path_not_in_swagger(test_app):
 
 
 def test_200_skip_validation_with_excluded_path():
-    app = test_app(
-        request=Mock(spec=FixtureRequest, param=['2.0']),
+    app = build_test_app(
+        swagger_versions=['2.0'],
         **{'pyramid_swagger.exclude_paths': [r'^/undefined/path']}
     )
     assert app.get('/undefined/path').status_code == 200
@@ -277,8 +284,8 @@ def test_200_skip_validation_when_disabled():
         'pyramid_swagger.enable_request_validation': False,
         'skip_swagger_data_assert': True,
     }
-    app = test_app(
-        request=Mock(spec=FixtureRequest, param=['2.0']),
+    app = build_test_app(
+        swagger_versions=['2.0'],
         **overrides
     )
     response = app.get('/get_with_non_string_query_args', params={})
@@ -286,16 +293,16 @@ def test_200_skip_validation_when_disabled():
 
 
 def test_path_validation_context():
-    app = test_app(
-        request=Mock(spec=FixtureRequest, param=['2.0']),
+    app = build_test_app(
+        swagger_versions=['2.0'],
         **{'pyramid_swagger.validation_context_path': validation_ctx_path}
     )
     assert app.get('/does_not_exist').status_code == 206
 
 
 def test_request_validation_context():
-    app = test_app(
-        request=Mock(spec=FixtureRequest, param=['2.0']),
+    app = build_test_app(
+        swagger_versions=['2.0'],
         **{'pyramid_swagger.validation_context_path': validation_ctx_path})
     response = app.get('/get_with_non_string_query_args', params={})
     assert response.status_code == 206
diff --git a/tests/acceptance/response20_test.py b/tests/acceptance/response20_test.py
index 7143218..bf2f44c 100644
--- a/tests/acceptance/response20_test.py
+++ b/tests/acceptance/response20_test.py
@@ -5,19 +5,20 @@
 # Based on request_test.py (Swagger 1.2 tests). Differences made it hard for
 # a single codebase to exercise both Swagger 1.2 and 2.0 responses.
 #
+from __future__ import absolute_import
+
 import pytest
 import simplejson
-from _pytest.fixtures import FixtureRequest
 from mock import Mock
 from mock import patch
 from pyramid.interfaces import IRoutesMapper
 from pyramid.response import Response
 from webtest.app import AppError
 
-from .request_test import test_app
 from pyramid_swagger.exceptions import ResponseValidationError
 from pyramid_swagger.ingest import get_swagger_spec
 from pyramid_swagger.tween import validation_tween_factory
+from tests.acceptance.request_test import build_test_app
 from tests.acceptance.response_test import CustomResponseValidationException
 from tests.acceptance.response_test import EnhancedDummyRequest
 from tests.acceptance.response_test import get_registry
@@ -199,11 +200,12 @@ def test_200_for_good_validated_array_response():
 
 
 def test_200_for_normal_response_validation():
-    assert test_app(
-        request=Mock(spec=FixtureRequest, param=['2.0']),
-        **{'pyramid_swagger.enable_response_validation': True}) \
-        .post_json('/sample', {'foo': 'test', 'bar': 'test'}) \
-        .status_code == 200
+    assert build_test_app(
+        swagger_versions=['2.0'],
+        **{'pyramid_swagger.enable_response_validation': True}
+    ).post_json(
+        '/sample', {'foo': 'test', 'bar': 'test'},
+    ).status_code == 200
 
 
 def test_app_error_if_path_not_in_spec_and_path_validation_disabled():
@@ -212,10 +214,10 @@ def test_app_error_if_path_not_in_spec_and_path_validation_disabled():
     HTTPNotFound exception.
     """
     with pytest.raises(AppError):
-        assert test_app(
-            request=Mock(spec=FixtureRequest, param=['2.0']),
-            **{'pyramid_swagger.enable_path_validation': False}) \
-            .get('/this/path/doesnt/exist')
+        assert build_test_app(
+            swagger_versions=['2.0'],
+            **{'pyramid_swagger.enable_path_validation': False}
+        ).get('/this/path/doesnt/exist')
 
 
 def test_response_validation_context():
diff --git a/tests/acceptance/response_test.py b/tests/acceptance/response_test.py
index 568c1f1..d231bbc 100644
--- a/tests/acceptance/response_test.py
+++ b/tests/acceptance/response_test.py
@@ -1,12 +1,12 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 from contextlib import contextmanager
 
 import mock
 import pyramid.testing
 import pytest
 import simplejson
-from _pytest.fixtures import FixtureRequest
-from mock import Mock
 from pyramid.config import Configurator
 from pyramid.interfaces import IRoutesMapper
 from pyramid.registry import Registry
@@ -15,13 +15,12 @@ from pyramid.urldispatch import RoutesMapper
 from webob.multidict import MultiDict
 from webtest import AppError
 
-import pyramid_swagger
 import pyramid_swagger.tween
-from .request_test import test_app
 from pyramid_swagger.exceptions import ResponseValidationError
 from pyramid_swagger.ingest import compile_swagger_schema
 from pyramid_swagger.ingest import get_resource_listing
 from pyramid_swagger.tween import validation_tween_factory
+from tests.acceptance.request_test import build_test_app
 
 
 class CustomResponseValidationException(Exception):
@@ -202,8 +201,8 @@ def test_200_for_good_validated_array_response():
 
 
 def test_200_for_normal_response_validation():
-    app = test_app(
-        request=Mock(spec=FixtureRequest, param=['1.2']),
+    app = build_test_app(
+        swagger_versions=['1.2'],
         **{'pyramid_swagger.enable_response_validation': True}
     )
     response = app.post_json('/sample', {'foo': 'test', 'bar': 'test'})
@@ -212,8 +211,8 @@ def test_200_for_normal_response_validation():
 
 def test_200_skip_validation_for_excluded_path():
     # FIXME(#64): This test is broken and doesn't check anything.
-    app = test_app(
-        request=Mock(spec=FixtureRequest, param=['1.2']),
+    app = build_test_app(
+        swagger_versions=['1.2'],
         **{'pyramid_swagger.exclude_paths': [r'^/sample/?']}
     )
     response = app.get(
@@ -229,16 +228,16 @@ def test_app_error_if_path_not_in_spec_and_path_validation_disabled():
     HTTPNotFound exception.
     """
     with pytest.raises(AppError):
-        app = test_app(
-            request=Mock(spec=FixtureRequest, param=['1.2']),
+        app = build_test_app(
+            swagger_versions=['1.2'],
             **{'pyramid_swagger.enable_path_validation': False}
         )
         assert app.get('/this/path/doesnt/exist')
 
 
 def test_error_handling_for_12():
-    app = test_app(
-        request=Mock(spec=FixtureRequest, param=['1.2']),
+    app = build_test_app(
+        swagger_versions=['1.2'],
         **{'pyramid_swagger.enable_response_validation': True}
     )
     # Should throw 400 and not 500 (500 is thrown by pyramid_swagger when
diff --git a/tests/acceptance/yaml_test.py b/tests/acceptance/yaml_test.py
index 75c3000..2a5d88a 100644
--- a/tests/acceptance/yaml_test.py
+++ b/tests/acceptance/yaml_test.py
@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import base64
 import copy
 import json
@@ -10,8 +12,8 @@ from bravado_core.schema import is_list_like
 from six import iterkeys
 from webtest import TestApp as App
 
-from .app import main
 from pyramid_swagger.tween import SwaggerFormat
+from tests.acceptance.app import main
 
 
 @pytest.fixture
diff --git a/tests/api_test.py b/tests/api_test.py
index d3d477b..2a9cd52 100644
--- a/tests/api_test.py
+++ b/tests/api_test.py
@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import os
 
 import mock
diff --git a/tests/conftest.py b/tests/conftest.py
index 1bce71d..0f71917 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import os
 
 import pytest
diff --git a/tests/includeme_test.py b/tests/includeme_test.py
index 1cd5388..b1699c4 100644
--- a/tests/includeme_test.py
+++ b/tests/includeme_test.py
@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import mock
 import pytest
 from bravado_core.spec import Spec
diff --git a/tests/ingest_test.py b/tests/ingest_test.py
index a394062..cd05de2 100644
--- a/tests/ingest_test.py
+++ b/tests/ingest_test.py
@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import os.path
 
 import mock
@@ -140,7 +142,9 @@ def bravado_core_configs(bravado_core_formats):
 
 
 @mock.patch('pyramid_swagger.ingest.warnings')
-def test_create_bravado_core_config_non_empty_deprecated_configs(mock_warnings, bravado_core_formats, bravado_core_configs):
+def test_create_bravado_core_config_non_empty_deprecated_configs(
+    mock_warnings, bravado_core_formats, bravado_core_configs,
+):
     pyramid_swagger_config = {
         'pyramid_swagger.enable_request_validation': True,
         'pyramid_swagger.enable_response_validation': False,
@@ -153,8 +157,9 @@ def test_create_bravado_core_config_non_empty_deprecated_configs(mock_warnings,
     bravado_core_config = create_bravado_core_config(pyramid_swagger_config)
 
     assert bravado_core_configs == bravado_core_config
-    # NOTE: the assertion is detailed and not defined by a constant because PYRAMID_SWAGGER_TO_BRAVADO_CORE_CONFIGS_MAPPING
-    # usage is deprecated and will eventually be removed in future versions
+    # NOTE: the assertion is detailed and not defined by a constant because
+    # PYRAMID_SWAGGER_TO_BRAVADO_CORE_CONFIGS_MAPPING usage is deprecated
+    # and will eventually be removed in future versions
     mock_warnings.warn.assert_called_once_with(
         message='Configs '
                 'pyramid_swagger.enable_request_validation, pyramid_swagger.enable_response_validation, '
diff --git a/tests/load_schema_test.py b/tests/load_schema_test.py
index 1cb660b..012bc30 100644
--- a/tests/load_schema_test.py
+++ b/tests/load_schema_test.py
@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import mock
 import pytest
 
@@ -43,9 +45,8 @@ def test_type_validator_skips_File():
     assert len(errors) == 0
 
 
-@mock.patch('pyramid_swagger.load_schema._validators.type_draft3')
-def test_type_validator_calls_draft3_type_validator_when_not_File(
-        mock_type_draft3):
+@mock.patch('pyramid_swagger.load_schema._draft3_type_validator')
+def test_type_validator_calls_draft3_type_validator_when_not_File(mock_type_draft3):
     schema = {'paramType': 'form', 'type': 'number'}
     list(load_schema.type_validator(None, "number", 99, schema))
     assert mock_type_draft3.call_count == 1
diff --git a/tests/model_test.py b/tests/model_test.py
index 25df64c..f3a23ca 100644
--- a/tests/model_test.py
+++ b/tests/model_test.py
@@ -2,6 +2,8 @@
 """
 Unit tests for the SwaggerSchema class.
 """
+from __future__ import absolute_import
+
 import mock
 import pytest
 
diff --git a/tests/renderer_test.py b/tests/renderer_test.py
index 5262cf1..1071bd6 100644
--- a/tests/renderer_test.py
+++ b/tests/renderer_test.py
@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import datetime
 import json
 
@@ -185,7 +187,10 @@ class TestPyramidSwaggerRendererFactoryIntegrationTest(object):
             [{'date': datetime.date.today()}, '{"date": "' + datetime.date.today().isoformat() + '"}'],
         ],
     )
-    def test_no_errors(self, spy_get_response_spec, spy_marshal_schema_object, swagger_spec, mock_request, view_response, expected_rendered_value):
+    def test_no_errors(
+        self, spy_get_response_spec, spy_marshal_schema_object,
+        swagger_spec, mock_request, view_response, expected_rendered_value,
+    ):
         system = {'request': mock_request}
         renderer = self.renderer_factory(info=self.info)
         rendered_value = renderer(view_response, system)
@@ -211,7 +216,10 @@ class TestPyramidSwaggerRendererFactoryIntegrationTest(object):
             [{'date': datetime.date.today()}, True],
         ],
     )
-    def test_response_spec_not_found(self, spy_get_response_spec, spy_marshal_schema_object, mock_request, view_response, expect_exernal_renderer_exception):
+    def test_response_spec_not_found(
+        self, spy_get_response_spec, spy_marshal_schema_object,
+        mock_request, view_response, expect_exernal_renderer_exception,
+    ):
         mock_request.response.status_code = 400
         system = {'request': mock_request}
         renderer = self.renderer_factory(info=self.info)
@@ -233,7 +241,9 @@ class TestPyramidSwaggerRendererFactoryIntegrationTest(object):
         assert not spy_marshal_schema_object.called
         assert rendered_value == expected_rendered_value
 
-    def test_marshaling_raise_exception(self, spy_get_response_spec, spy_marshal_schema_object, swagger_spec, mock_request):
+    def test_marshaling_raise_exception(
+        self, spy_get_response_spec, spy_marshal_schema_object, swagger_spec, mock_request,
+    ):
         system = {'request': mock_request}
         value_to_renderer = {'date': datetime.date.today().isoformat()}
 
diff --git a/tests/spec_test.py b/tests/spec_test.py
index 3b233fb..1bf89c5 100644
--- a/tests/spec_test.py
+++ b/tests/spec_test.py
@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import os
 
 import pytest
diff --git a/tests/tween_test.py b/tests/tween_test.py
index 150b221..ff582fd 100644
--- a/tests/tween_test.py
+++ b/tests/tween_test.py
@@ -1,5 +1,7 @@
 # -*- coding: utf-8 -*-
 """Unit tests for tweens.py"""
+from __future__ import absolute_import
+
 import re
 
 import mock