| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 5b5a079 commit 7b9c818
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,7 +5,7 @@ | |||
| 5 | 5 | from coreapi.document import Document, Link, Field | |
| 6 | 6 | from coreapi.exceptions import ParseError | |
| 7 | 7 | from openapi_codec.utils import _get_string, _get_dict, _get_list, _get_bool, get_strings, get_dicts | |
| 8 | - from openapi_codec.converters import DocumentToOpenAPIConverter | ||
| 8 | + from openapi_codec.converters import generate_swagger_object | ||
| 9 | 9 | ||
| 10 | 10 | ||
| 11 | 11 | __version__ = "0.0.3" | |
@@ -142,5 +142,5 @@ def load(self, bytes, base_url=None): | |||
| 142 | 142 | return doc | |
| 143 | 143 | ||
| 144 | 144 | def dump(self, document, **kwargs): | |
| 145 | - converter = DocumentToOpenAPIConverter(document) | ||
| 146 | - return force_bytes(json.dumps(converter.convert())) | ||
| 145 | + data = generate_swagger_object(document) | ||
| 146 | + return force_bytes(json.dumps(data)) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,93 +1,82 @@ | |||
| 1 | 1 | from coreapi.compat import urlparse | |
| 2 | 2 | ||
| 3 | 3 | ||
| 4 | - class DocumentToOpenAPIConverter(object): | ||
| 5 | - def __init__(self, document): | ||
| 6 | - self.document = document | ||
| 7 | - | ||
| 8 | - def convert(self): | ||
| 9 | - return self._generate_swagger_object() | ||
| 10 | - | ||
| 11 | - def _generate_swagger_object(self): | ||
| 12 | - """ | ||
| 13 | - Generates root of the Swagger spec. | ||
| 14 | - """ | ||
| 15 | - parsed_url = urlparse.urlparse(self.document.url) | ||
| 16 | - | ||
| 17 | - return { | ||
| 18 | - 'swagger': '2.0', | ||
| 19 | - 'info': self._get_info_object(), | ||
| 20 | - 'paths': self._get_paths_object(), | ||
| 21 | - 'host': parsed_url.netloc, | ||
| 4 | + def generate_swagger_object(document): | ||
| 5 | + """ | ||
| 6 | + Generates root of the Swagger spec. | ||
| 7 | + """ | ||
| 8 | + parsed_url = urlparse.urlparse(document.url) | ||
| 9 | + | ||
| 10 | + return { | ||
| 11 | + 'swagger': '2.0', | ||
| 12 | + 'info': _get_info_object(document), | ||
| 13 | + 'paths': _get_paths_object(document), | ||
| 14 | + 'host': parsed_url.netloc, | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + def _get_info_object(document): | ||
| 19 | + return { | ||
| 20 | + 'title': document.title, | ||
| 21 | + 'version': '' # Required by the spec | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + def _get_paths_object(document): | ||
| 26 | + paths = {} | ||
| 27 | + for tag, object_ in document.data.items(): | ||
| 28 | + if not hasattr(object_, 'links'): | ||
| 29 | + continue | ||
| 30 | + | ||
| 31 | + for link in object_.links.values(): | ||
| 32 | + if link.url not in paths: | ||
| 33 | + paths[link.url] = {} | ||
| 34 | + | ||
| 35 | + operation = _get_operation(tag, link) | ||
| 36 | + paths[link.url].update({link.action: operation}) | ||
| 37 | + | ||
| 38 | + return paths | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + def _get_operation(tag, link): | ||
| 42 | + return { | ||
| 43 | + 'tags': [tag], | ||
| 44 | + 'description': link.description, | ||
| 45 | + 'responses': _get_responses(link), | ||
| 46 | + 'parameters': _get_parameters(link.fields) | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + def _get_parameters(fields): | ||
| 51 | + """ | ||
| 52 | + Generates Swagger Parameter Item object. | ||
| 53 | + """ | ||
| 54 | + return [ | ||
| 55 | + { | ||
| 56 | + 'name': field.name, | ||
| 57 | + 'required': field.required, | ||
| 58 | + 'in': _convert_location_to_in(field), | ||
| 59 | + 'description': field.description, | ||
| 60 | + 'type': 'string' | ||
| 22 | 61 | } | |
| 23 | - | ||
| 24 | - def _get_info_object(self): | ||
| 25 | - return { | ||
| 26 | - 'title': self.document.title, | ||
| 27 | - 'version': '' # Required by the spec | ||
| 28 | - } | ||
| 29 | - | ||
| 30 | - def _get_paths_object(self): | ||
| 31 | - paths = {} | ||
| 32 | - for tag, object_ in self.document.data.items(): | ||
| 33 | - if not hasattr(object_, 'links'): | ||
| 34 | - continue | ||
| 35 | - | ||
| 36 | - for link in object_.links.values(): | ||
| 37 | - if link.url not in paths: | ||
| 38 | - paths[link.url] = {} | ||
| 39 | - | ||
| 40 | - operation = self._get_operation(tag, link) | ||
| 41 | - paths[link.url].update({link.action: operation}) | ||
| 42 | - | ||
| 43 | - return paths | ||
| 44 | - | ||
| 45 | - @classmethod | ||
| 46 | - def _get_operation(cls, tag, link): | ||
| 47 | - return { | ||
| 48 | - 'tags': [tag], | ||
| 49 | - 'description': link.description, | ||
| 50 | - 'responses': cls._get_responses(link.action), | ||
| 51 | - 'parameters': cls._get_parameters(link.fields) | ||
| 52 | - } | ||
| 53 | - | ||
| 54 | - @classmethod | ||
| 55 | - def _get_parameters(cls, fields): | ||
| 56 | - """ | ||
| 57 | - Generates Swagger Parameter Item object. | ||
| 58 | - """ | ||
| 59 | - return [ | ||
| 60 | - { | ||
| 61 | - 'name': field.name, | ||
| 62 | - 'required': field.required, | ||
| 63 | - 'in': cls._convert_location_to_in(field.location), | ||
| 64 | - 'description': field.description, | ||
| 65 | - 'type': 'string' | ||
| 66 | - } | ||
| 67 | - for field in fields | ||
| 68 | - ] | ||
| 69 | - | ||
| 70 | - @classmethod | ||
| 71 | - def _convert_location_to_in(cls, location): | ||
| 72 | - """ | ||
| 73 | - Translates the CoreAPI field `location` into the Swagger `in`. | ||
| 74 | - The values are all the same with the exception of form -> formData. | ||
| 75 | - """ | ||
| 76 | - if location == 'form': | ||
| 77 | - return 'formData' | ||
| 78 | - | ||
| 79 | - return location | ||
| 80 | - | ||
| 81 | - @classmethod | ||
| 82 | - def _get_responses(cls, action): | ||
| 83 | - """ | ||
| 84 | - Returns minimally acceptable responses object based | ||
| 85 | - on action / method type. | ||
| 86 | - """ | ||
| 87 | - template = {'description': ''} | ||
| 88 | - if action == 'post': | ||
| 89 | - return {'201': template} | ||
| 90 | - if action == 'delete': | ||
| 91 | - return {'204': template} | ||
| 92 | - | ||
| 93 | - return {'200': template} | ||
| 62 | + for field in fields | ||
| 63 | + ] | ||
| 64 | + | ||
| 65 | + | ||
| 66 | + def _convert_location_to_in(field): | ||
| 67 | + if field.location == 'form': | ||
| 68 | + return 'formData' | ||
| 69 | + return field.location | ||
| 70 | + | ||
| 71 | + | ||
| 72 | + def _get_responses(link): | ||
| 73 | + """ | ||
| 74 | + Returns minimally acceptable responses object based | ||
| 75 | + on action / method type. | ||
| 76 | + """ | ||
| 77 | + template = {'description': ''} | ||
| 78 | + if link.action == 'post': | ||
| 79 | + return {'201': template} | ||
| 80 | + if link.action == 'delete': | ||
| 81 | + return {'204': template} | ||
| 82 | + return {'200': template} | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,30 +1,35 @@ | |||
| 1 | - import uuid | ||
| 2 | - | ||
| 3 | 1 | import coreapi | |
| 4 | - from openapi_codec.converters import DocumentToOpenAPIConverter | ||
| 5 | - | ||
| 6 | - from .compat import mock, TestCase | ||
| 2 | + from openapi_codec.converters import generate_swagger_object, _get_parameters | ||
| 3 | + from unittest import TestCase | ||
| 7 | 4 | ||
| 8 | 5 | ||
| 9 | - class TestGetInfoObject(TestCase): | ||
| 6 | + class TestBasicInfo(TestCase): | ||
| 10 | 7 | def setUp(self): | |
| 11 | 8 | self.document = coreapi.Document(title='Example API') | |
| 12 | - converter = DocumentToOpenAPIConverter(self.document) | ||
| 13 | - self.sut = converter._get_info_object() | ||
| 9 | + self.swagger = generate_swagger_object(self.document) | ||
| 14 | 10 | ||
| 15 | - def test_title(self): | ||
| 16 | - self.assertDictContainsSubset({'title': self.document.title}, self.sut) | ||
| 11 | + def test_info(self): | ||
| 12 | + self.assertIn('info', self.swagger) | ||
| 13 | + expected = { | ||
| 14 | + 'title': self.document.title, | ||
| 15 | + 'version': '' | ||
| 16 | + } | ||
| 17 | + self.assertEquals(self.swagger['info'], expected) | ||
| 17 | 18 | ||
| 18 | - def test_version(self): | ||
| 19 | - """ | ||
| 20 | - Ensures that the version is provided since it is a required field. | ||
| 21 | - """ | ||
| 22 | - self.assertDictContainsSubset({'version': ''}, self.sut) | ||
| 19 | + def test_swagger_version(self): | ||
| 20 | + self.assertIn('swagger', self.swagger) | ||
| 21 | + expected = '2.0' | ||
| 22 | + self.assertEquals(self.swagger['swagger'], expected) | ||
| 23 | 23 | ||
| 24 | + def test_host(self): | ||
| 25 | + self.assertIn('host', self.swagger) | ||
| 26 | + expected = '' | ||
| 27 | + self.assertEquals(self.swagger['host'], expected) | ||
| 24 | 28 | ||
| 25 | - class TestGetPathsObject(TestCase): | ||
| 29 | + | ||
| 30 | + class TestPaths(TestCase): | ||
| 26 | 31 | def setUp(self): | |
| 27 | - self.path = '/users' | ||
| 32 | + self.path = '/users/' | ||
| 28 | 33 | self.document = coreapi.Document( | |
| 29 | 34 | content={ | |
| 30 | 35 | 'users': { | |
@@ -39,79 +44,54 @@ def setUp(self): | |||
| 39 | 44 | } | |
| 40 | 45 | } | |
| 41 | 46 | ) | |
| 42 | - self.sut = DocumentToOpenAPIConverter(self.document) \ | ||
| 43 | - ._get_paths_object() | ||
| 44 | - | ||
| 45 | - def test_url_is_converted_to_key(self): | ||
| 46 | - self.assertIn(self.path, self.sut) | ||
| 47 | - | ||
| 48 | - def test_actions_are_converted_to_keys_under_url(self): | ||
| 49 | - expected = [ | ||
| 50 | - link.action for link in self.document.data['users'].values() | ||
| 51 | - ] | ||
| 52 | - self.assertCountEqual(expected, self.sut[self.path].keys()) | ||
| 47 | + self.swagger = generate_swagger_object(self.document) | ||
| 48 | + | ||
| 49 | + def test_paths(self): | ||
| 50 | + self.assertIn('paths', self.swagger) | ||
| 51 | + self.assertIn(self.path, self.swagger['paths']) | ||
| 52 | + self.assertIn('get', self.swagger['paths'][self.path]) | ||
| 53 | + self.assertIn('post', self.swagger['paths'][self.path]) | ||
| 54 | + expected = { | ||
| 55 | + 'responses': { | ||
| 56 | + '200': { | ||
| 57 | + 'description': '' | ||
| 58 | + } | ||
| 59 | + }, | ||
| 60 | + 'parameters': [], | ||
| 61 | + 'description': '', | ||
| 62 | + 'tags': ['users'] | ||
| 63 | + } | ||
| 64 | + self.assertEquals(self.swagger['paths'][self.path]['get'], expected) | ||
| 65 | + expected = { | ||
| 66 | + 'responses': { | ||
| 67 | + '201': { | ||
| 68 | + 'description': '' | ||
| 69 | + } | ||
| 70 | + }, | ||
| 71 | + 'parameters': [], | ||
| 72 | + 'description': '', | ||
| 73 | + 'tags': ['users'] | ||
| 74 | + } | ||
| 75 | + self.assertEquals(self.swagger['paths'][self.path]['post'], expected) | ||
| 53 | 76 | ||
| 54 | 77 | ||
| 55 | - class TestGetParameters(TestCase): | ||
| 78 | + class TestParameters(TestCase): | ||
| 56 | 79 | def setUp(self): | |
| 57 | 80 | self.field = coreapi.Field( | |
| 58 | 81 | name='email', | |
| 59 | - required='true', | ||
| 82 | + required=True, | ||
| 60 | 83 | location='query', | |
| 61 | 84 | description='A valid email address.' | |
| 62 | 85 | ) | |
| 63 | - patcher = mock.patch.object( | ||
| 64 | - DocumentToOpenAPIConverter, | ||
| 65 | - '_convert_location_to_in' | ||
| 66 | - ) | ||
| 67 | - self.location_mock = patcher.start() | ||
| 68 | - self.addCleanup(patcher.stop) | ||
| 69 | - | ||
| 70 | - self.sut = DocumentToOpenAPIConverter \ | ||
| 71 | - ._get_parameters([self.field])[0] | ||
| 86 | + self.swagger = _get_parameters([self.field]) | ||
| 72 | 87 | ||
| 73 | 88 | def test_expected_fields(self): | |
| 74 | - self.assertDictContainsSubset( | ||
| 75 | - { | ||
| 76 | - 'name': self.field.name, | ||
| 77 | - 'required': self.field.required, | ||
| 78 | - 'in': self.location_mock.return_value, | ||
| 79 | - 'description': self.field.description, | ||
| 80 | - 'type': 'string' # Everything is a string for now. | ||
| 81 | - }, | ||
| 82 | - self.sut | ||
| 83 | - ) | ||
| 84 | - | ||
| 85 | - | ||
| 86 | - class TestConvertLocationToIn(TestCase): | ||
| 87 | - def setUp(self): | ||
| 88 | - self.sut = DocumentToOpenAPIConverter._convert_location_to_in | ||
| 89 | - | ||
| 90 | - def test_form_is_converted_to_formdata(self): | ||
| 91 | - self.assertEqual('formData', self.sut('form')) | ||
| 92 | - | ||
| 93 | - def test_random_string_is_returned_as_is(self): | ||
| 94 | - """ | ||
| 95 | - Asserts that any input (other than form) is returned as-is, | ||
| 96 | - since the Swagger Parameter object `in` property maps 1:1 with | ||
| 97 | - the Field.location property, | ||
| 98 | - """ | ||
| 99 | - expected = str(uuid.uuid4()) | ||
| 100 | - self.assertEqual(expected, self.sut(expected)) | ||
| 101 | - | ||
| 102 | - | ||
| 103 | - class TestGetResponses(TestCase): | ||
| 104 | - def setUp(self): | ||
| 105 | - self.sut = DocumentToOpenAPIConverter._get_responses | ||
| 106 | - | ||
| 107 | - def test_post(self): | ||
| 108 | - self.assertDictEqual({'201': {'description': ''}}, self.sut('post')) | ||
| 109 | - | ||
| 110 | - def test_delete(self): | ||
| 111 | - self.assertDictEqual({'201': {'description': ''}}, self.sut('post')) | ||
| 112 | - | ||
| 113 | - def test_default(self): | ||
| 114 | - self.assertDictEqual( | ||
| 115 | - {'200': {'description': ''}}, | ||
| 116 | - self.sut(uuid.uuid4()) | ||
| 117 | - ) | ||
| 89 | + self.assertEquals(len(self.swagger), 1) | ||
| 90 | + expected = { | ||
| 91 | + 'name': self.field.name, | ||
| 92 | + 'required': self.field.required, | ||
| 93 | + 'in': 'query', | ||
| 94 | + 'description': self.field.description, | ||
| 95 | + 'type': 'string' # Everything is a string for now. | ||
| 96 | + } | ||
| 97 | + self.assertEquals(self.swagger[0], expected) | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments