diff --git a/connexion/json_schema.py b/connexion/json_schema.py index 2e7500501..ec1832342 100644 --- a/connexion/json_schema.py +++ b/connexion/json_schema.py @@ -2,21 +2,70 @@ Module containing all code related to json schema validation. """ +import contextlib +import io +import os import typing as t +import urllib.parse +import urllib.request from collections.abc import Mapping from copy import deepcopy +import requests +import yaml from jsonschema import Draft4Validator, RefResolver from jsonschema.exceptions import RefResolutionError, ValidationError # noqa from jsonschema.validators import extend -from openapi_spec_validator.handlers import UrlHandler from .utils import deep_get + +class ExtendedSafeLoader(yaml.SafeLoader): + """Extends the yaml SafeLoader to coerce all keys to string so the result is valid json.""" + + def __init__(self, stream): + self.original_construct_mapping = self.construct_mapping + self.construct_mapping = self.extended_construct_mapping + super().__init__(stream) + + def extended_construct_mapping(self, node, deep=False): + data = self.original_construct_mapping(node, deep) + return {str(key): data[key] for key in data} + + +class FileHandler: + """Handler to resolve file refs.""" + + def __call__(self, uri): + filepath = self._uri_to_path(uri) + with open(filepath) as fh: + return yaml.load(fh, ExtendedSafeLoader) + + @staticmethod + def _uri_to_path(uri): + parsed = urllib.parse.urlparse(uri) + host = "{0}{0}{mnt}{0}".format(os.path.sep, mnt=parsed.netloc) + return os.path.abspath( + os.path.join(host, urllib.request.url2pathname(parsed.path)) + ) + + +class URLHandler: + """Handler to resolve url refs.""" + + def __call__(self, uri): + response = requests.get(uri) + response.raise_for_status() + + data = io.StringIO(response.text) + with contextlib.closing(data) as fh: + return yaml.load(fh, ExtendedSafeLoader) + + default_handlers = { - 'http': UrlHandler('http'), - 'https': UrlHandler('https'), - 'file': UrlHandler('file'), + 'http': URLHandler(), + 'https': URLHandler(), + 'file': FileHandler(), } diff --git a/setup.py b/setup.py index c5d174922..c85f017d0 100755 --- a/setup.py +++ b/setup.py @@ -25,7 +25,6 @@ def read_version(package): 'PyYAML>=5.1,<6', 'requests>=2.9.1,<3', 'inflection>=0.3.1,<0.6', - 'openapi-spec-validator>=0.2.4,<0.4', 'werkzeug>=1.0,<3', ] diff --git a/tests/api/test_bootstrap.py b/tests/api/test_bootstrap.py index da22d56e2..4ad3b4586 100644 --- a/tests/api/test_bootstrap.py +++ b/tests/api/test_bootstrap.py @@ -7,7 +7,7 @@ from connexion import App from connexion.exceptions import InvalidSpecification from connexion.http_facts import METHODS -from openapi_spec_validator.loaders import ExtendedSafeLoader +from connexion.json_schema import ExtendedSafeLoader from conftest import TEST_FOLDER, build_app_from_fixture