Skip to content

Commit d92d785

Browse files
committed
STDIO spec support
1 parent 827b49c commit d92d785

File tree

4 files changed

+89
-21
lines changed

4 files changed

+89
-21
lines changed

openapi_spec_validator/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from openapi_spec_validator.shortcuts import (
33
validate_spec_factory, validate_spec_url_factory,
44
)
5-
from openapi_spec_validator.handlers import UrlHandler
5+
from openapi_spec_validator.handlers import UrlHandler, FileObjectHandler
66
from openapi_spec_validator.schemas import get_openapi_schema
77
from openapi_spec_validator.factories import JSONSpecValidatorFactory
88
from openapi_spec_validator.validators import SpecValidator
@@ -19,8 +19,10 @@
1919
'validate_v2_spec_url', 'validate_v3_spec_url', 'validate_spec_url',
2020
]
2121

22+
file_object_handler = FileObjectHandler()
23+
all_urls_handler = UrlHandler('http', 'https', 'file')
2224
default_handlers = {
23-
'<all_urls>': UrlHandler('http', 'https', 'file'),
25+
'<all_urls>': all_urls_handler,
2426
'http': UrlHandler('http'),
2527
'https': UrlHandler('https'),
2628
'file': UrlHandler('file'),

openapi_spec_validator/__main__.py

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
import pathlib2 as pathlib
88
import sys
99

10-
11-
from openapi_spec_validator import validate_spec_url, validate_v2_spec_url
10+
from openapi_spec_validator import (
11+
openapi_v2_spec_validator, openapi_v3_spec_validator, all_urls_handler,
12+
file_object_handler,
13+
)
1214
from openapi_spec_validator.exceptions import ValidationError
1315

1416
logger = logging.getLogger(__name__)
@@ -18,6 +20,19 @@
1820
)
1921

2022

23+
def read_from_stdin(filename):
24+
return file_object_handler(sys.stdin), ''
25+
26+
27+
def read_from_filename(filename):
28+
if not os.path.isfile(filename):
29+
raise SystemError("No such file {0}".format(filename))
30+
31+
filename = os.path.abspath(filename)
32+
uri = pathlib.Path(filename).as_uri()
33+
return all_urls_handler(uri), uri
34+
35+
2136
def main(args=None):
2237
parser = argparse.ArgumentParser()
2338
parser.add_argument('filename', help="Absolute or relative path to file")
@@ -29,21 +44,34 @@ def main(args=None):
2944
default='3.0.0'
3045
)
3146
args = parser.parse_args(args)
32-
filename = args.filename
33-
filename = os.path.abspath(filename)
47+
48+
# choose source
49+
reader = read_from_filename
50+
if args.filename == '-':
51+
reader = read_from_stdin
52+
53+
# read source
54+
try:
55+
spec, spec_url = reader(args.filename)
56+
except Exception as exc:
57+
print(exc)
58+
sys.exit(1)
59+
3460
# choose the validator
35-
if args.schema == '2.0':
36-
validate_url = validate_v2_spec_url
37-
elif args.schema == '3.0.0':
38-
validate_url = validate_spec_url
61+
validators = {
62+
'2.0': openapi_v2_spec_validator,
63+
'3.0.0': openapi_v3_spec_validator,
64+
}
65+
validator = validators[args.schema]
66+
3967
# validate
4068
try:
41-
validate_url(pathlib.Path(filename).as_uri())
42-
except ValidationError as e:
43-
print(e)
69+
validator.validate(spec, spec_url=spec_url)
70+
except ValidationError as exc:
71+
print(exc)
4472
sys.exit(1)
45-
except Exception as e:
46-
print(e)
73+
except Exception as exc:
74+
print(exc)
4775
sys.exit(2)
4876
else:
4977
print('OK')

openapi_spec_validator/handlers.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,30 @@
88
from openapi_spec_validator.loaders import ExtendedSafeLoader
99

1010

11-
class UrlHandler:
12-
"""OpenAPI spec validator URL scheme handler."""
11+
class FileObjectHandler(object):
12+
"""OpenAPI spec validator file-like object handler."""
1313

14-
def __init__(self, *allowed_schemes, **options):
15-
self.allowed_schemes = allowed_schemes
14+
def __init__(self, **options):
1615
self.options = options
1716

1817
@property
1918
def loader(self):
2019
return self.options.get('loader', ExtendedSafeLoader)
2120

21+
def __call__(self, f):
22+
return load(f, self.loader)
23+
24+
25+
class UrlHandler(FileObjectHandler):
26+
"""OpenAPI spec validator URL scheme handler."""
27+
28+
def __init__(self, *allowed_schemes, **options):
29+
super(UrlHandler, self).__init__(**options)
30+
self.allowed_schemes = allowed_schemes
31+
2232
def __call__(self, url, timeout=1):
2333
assert urlparse(url).scheme in self.allowed_schemes
2434

25-
with contextlib.closing(urlopen(url, timeout=timeout)) as fh:
26-
return load(fh, self.loader)
35+
f = urlopen(url, timeout=timeout)
36+
with contextlib.closing(f) as fh:
37+
return super(UrlHandler, self).__call__(fh)

tests/integration/test_main.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import mock
2+
13
import pytest
4+
from six import StringIO
25

36
from openapi_spec_validator.__main__ import main
47

@@ -39,8 +42,32 @@ def test_validation_error():
3942
main(testargs)
4043

4144

45+
@mock.patch(
46+
'openapi_spec_validator.__main__.openapi_v3_spec_validator.validate',
47+
side_effect=Exception,
48+
)
49+
def test_unknown_error(m_validate):
50+
"""SystemExit on running with unknown error."""
51+
testargs = ['--schema', '3.0.0',
52+
'./tests/integration/data/v2.0/petstore.yaml']
53+
with pytest.raises(SystemExit):
54+
main(testargs)
55+
56+
4257
def test_nonexisting_file():
4358
"""Calling with non-existing file should sys.exit."""
4459
testargs = ['i_dont_exist.yaml']
4560
with pytest.raises(SystemExit):
4661
main(testargs)
62+
63+
64+
def test_schema_stdin():
65+
"""Test schema from STDIN"""
66+
spes_path = './tests/integration/data/v3.0/petstore.yaml'
67+
with open(spes_path, 'r') as spec_file:
68+
spec_lines = spec_file.readlines()
69+
spec_io = StringIO("".join(spec_lines))
70+
71+
testargs = ['-']
72+
with mock.patch('openapi_spec_validator.__main__.sys.stdin', spec_io):
73+
main(testargs)

0 commit comments

Comments
 (0)