-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from dave-shawley/setuptools-task
Add a setuptools task
- Loading branch information
Showing
7 changed files
with
582 additions
and
244 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
from distutils import cmd, log | ||
import os.path | ||
|
||
from sphinx import application | ||
|
||
|
||
class BuildSwagger(cmd.Command): | ||
description = 'Build a swagger definition from Sphinx docs' | ||
user_options = [ | ||
('config-dir=', 'c', 'configuration directory'), | ||
('output-file=', 'o', 'output file name'), | ||
('ignore-distinfo', 'u', 'ignore distribution metadata'), | ||
] | ||
boolean_options = ['ignore-distinfo'] | ||
|
||
def initialize_options(self): | ||
self.config_dir = None | ||
self.output_file = None | ||
self.ignore_distinfo = False | ||
|
||
def finalize_options(self): | ||
if self.config_dir is None: | ||
self.config_dir = 'docs' | ||
self.ensure_dirname('config_dir') | ||
if self.config_dir is None: | ||
self.config_dir = os.curdir | ||
self.warning('Using {} as configuration directory', | ||
self.source_dir) | ||
self.config_dir = os.path.abspath(self.config_dir) | ||
|
||
if self.output_file is not None: | ||
self.output_file = os.path.abspath(self.output_file) | ||
|
||
def run(self): | ||
build_cmd = self.get_finalized_command('build') | ||
build_dir = os.path.join(os.path.abspath(build_cmd.build_base), | ||
'swagger') | ||
self.mkpath(build_dir) | ||
doctree_dir = os.path.join(build_dir, 'doctrees') | ||
self.mkpath(doctree_dir) | ||
|
||
overrides = {} | ||
if self.output_file is not None: | ||
overrides['swagger_file'] = self.output_file | ||
|
||
if not self.ignore_distinfo: | ||
if self.distribution.get_description(): | ||
overrides['swagger_description'] = \ | ||
self.distribution.get_description() | ||
if self.distribution.get_license(): | ||
overrides['swagger_license.name'] = \ | ||
self.distribution.get_license() | ||
if self.distribution.get_version(): | ||
overrides['version'] = self.distribution.get_version() | ||
|
||
app = application.Sphinx( | ||
self.config_dir, self.config_dir, build_dir, doctree_dir, | ||
'swagger', confoverrides=overrides) | ||
app.build() | ||
|
||
def warning(self, msg, *args): | ||
self.announce(msg.format(*args), level=log.WARNING) | ||
|
||
def info(self, msg, *args): | ||
self.announce(msg.format(*args), level=log.INFO) | ||
|
||
def debug(self, msg, *args): | ||
self.announce(msg.format(*args), level=log.DEBUG) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
try: | ||
import http.client as http_client | ||
except ImportError: | ||
import httplib as http_client | ||
|
||
|
||
class SwaggerDocument(object): | ||
|
||
def __init__(self): | ||
super(SwaggerDocument, self).__init__() | ||
self._paths = {} | ||
|
||
def get_document(self, config): | ||
""" | ||
:param sphinx.config.Config config: project level configuration | ||
:return: the swagger document as a :class:`dict` | ||
:rtype: dict | ||
""" | ||
info = {'title': config.project, | ||
'description': config.swagger_description, | ||
'license': config.swagger_license, | ||
'version': config.version} | ||
if not info['description'] and hasattr(config, 'html_theme_options'): | ||
info['description'] = config.html_theme_options.get('description') | ||
|
||
return {'swagger': '2.0', | ||
'info': info, | ||
'host': 'localhost:80', | ||
'basePath': '/', | ||
'paths': self._paths} | ||
|
||
def add_endpoint(self, endpoint, debug_info=None): | ||
""" | ||
Add a swagger endpoint document. | ||
:param SwaggerEndpoint endpoint: the endpoint to add | ||
:param dict debug_info: optional debug information to include | ||
in the swagger definition | ||
""" | ||
path_info = self._paths.setdefault(endpoint.uri_template, {}) | ||
if endpoint.method in path_info: | ||
pass # already gots this ... good this isn't | ||
path_info[endpoint.method] = endpoint.generate_swagger() | ||
if debug_info: | ||
path_info[endpoint.method]['x-debug-info'] = debug_info | ||
|
||
|
||
class SwaggerEndpoint(object): | ||
|
||
def __init__(self): | ||
self.method = None | ||
self.uri_template = None | ||
self.summary = '' | ||
self.description = '' | ||
self.parameters = [] | ||
self.responses = {} | ||
self.default_response_schema = None | ||
self.response_headers = None | ||
|
||
def set_default_response_structure(self, properties, is_array=False): | ||
schema = {'type': 'object', 'properties': {}, 'required': []} | ||
for prop in properties: | ||
name = prop.pop('name') | ||
schema['properties'][name] = prop.copy() | ||
schema['required'].append(name) | ||
if is_array: | ||
schema = {'type': 'array', 'items': schema} | ||
self.default_response_schema = schema | ||
|
||
def add_request_headers(self, headers): | ||
for name, description in headers.items(): | ||
self.parameters.append({ | ||
'name': name, | ||
'description': description, | ||
'in': 'header', | ||
'type': 'string', | ||
}) | ||
|
||
def add_response_headers(self, headers): | ||
self.response_headers = { | ||
name: {'description': description, 'type': 'string'} | ||
for name, description in headers.items() | ||
} | ||
|
||
def add_response_codes(self, status_dict): | ||
for code, info in status_dict.items(): | ||
swagger_rsp = self.responses.setdefault(code, {}) | ||
if not info['reason']: | ||
try: | ||
code = int(code) | ||
info['reason'] = http_client.responses[code] | ||
except (KeyError, TypeError, ValueError): | ||
info['reason'] = 'Unknown' | ||
|
||
tokens = info['description'].split(maxsplit=2) | ||
if tokens: | ||
tokens[0] = tokens[0].title() | ||
swagger_rsp['description'] = '{}\n\n{}'.format( | ||
info['reason'], ' '.join(tokens)).strip() | ||
|
||
def generate_swagger(self): | ||
swagger = {'summary': self.summary, 'description': self.description} | ||
if self.parameters: | ||
swagger['parameters'] = self.parameters | ||
|
||
if self.responses: | ||
swagger['responses'] = self.responses | ||
else: # swagger requires at least one response | ||
swagger['responses'] = {'default': {'description': ''}} | ||
|
||
# Figure out where to put the response schema and response | ||
# header details. This is probably going to change in the | ||
# future since it is `hinky' at best. | ||
default_code = 'default' | ||
status_codes = sorted(int(code) | ||
for code in swagger['responses'] | ||
if code.isdigit()) | ||
for code in status_codes: | ||
if 200 <= code < 400: | ||
default_code = str(code) | ||
break | ||
|
||
if default_code in swagger['responses']: | ||
if self.default_response_schema: | ||
swagger['responses'][default_code]['schema'] = \ | ||
self.default_response_schema | ||
if self.response_headers: | ||
swagger['responses'][default_code]['headers'] = \ | ||
self.response_headers | ||
|
||
return swagger |
Oops, something went wrong.