Hello community, here is the log from the commit of package python-sphinxcontrib-httpdomain for openSUSE:Factory checked in at 2016-08-09 22:14:40 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-sphinxcontrib-httpdomain (Old) and /work/SRC/openSUSE:Factory/.python-sphinxcontrib-httpdomain.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-sphinxcontrib-httpdomain" Changes: -------- --- /work/SRC/openSUSE:Factory/python-sphinxcontrib-httpdomain/python-sphinxcontrib-httpdomain.changes 2014-09-17 17:27:29.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.python-sphinxcontrib-httpdomain.new/python-sphinxcontrib-httpdomain.changes 2016-08-09 22:14:41.000000000 +0200 @@ -1,0 +2,17 @@ +Wed Jul 27 10:55:41 UTC 2016 - buschman...@opensuse.org + +- update to version 1.4.0 + * Added 429 Too Many Requests as a valid http:statuscode. + [pull request #81 by DDBReloaded] + * Became to not resolve references if they can’t be resolved. + [pull request #87 by Ken Robbins] + * Became to preserve endpoint ordering when :endpoints: option is + given. [pull request #88 by Dan Callaghan] + * Added status codes for WebDAV. [pull request #92 by Ewen + Cheslack-Postava] + * Added CORS headers. [pull request #96 by Tomi Pieviläinen] + * Now sphinxcontrib.autohttp.flask supports multiple paths for + endpoints using same HTTP method. [pull request #97 by Christian + Felder] + +------------------------------------------------------------------- Old: ---- sphinxcontrib-httpdomain-1.3.0.tar.gz New: ---- sphinxcontrib-httpdomain-1.4.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-sphinxcontrib-httpdomain.spec ++++++ --- /var/tmp/diff_new_pack.2YT70Y/_old 2016-08-09 22:14:42.000000000 +0200 +++ /var/tmp/diff_new_pack.2YT70Y/_new 2016-08-09 22:14:42.000000000 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-sphinxcontrib-httpdomain # -# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: python-sphinxcontrib-httpdomain -Version: 1.3.0 +Version: 1.4.0 Release: 0 Summary: Sphinx domain for HTTP APIs License: BSD-2-Clause ++++++ sphinxcontrib-httpdomain-1.3.0.tar.gz -> sphinxcontrib-httpdomain-1.4.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sphinxcontrib-httpdomain-1.3.0/PKG-INFO new/sphinxcontrib-httpdomain-1.4.0/PKG-INFO --- old/sphinxcontrib-httpdomain-1.3.0/PKG-INFO 2014-07-30 18:41:23.000000000 +0200 +++ new/sphinxcontrib-httpdomain-1.4.0/PKG-INFO 2015-08-13 16:15:20.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: sphinxcontrib-httpdomain -Version: 1.3.0 +Version: 1.4.0 Summary: Sphinx domain for HTTP APIs Home-page: http://bitbucket.org/birkenfeld/sphinx-contrib Author: Hong Minhee diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sphinxcontrib-httpdomain-1.3.0/setup.cfg new/sphinxcontrib-httpdomain-1.4.0/setup.cfg --- old/sphinxcontrib-httpdomain-1.3.0/setup.cfg 2014-07-30 18:41:23.000000000 +0200 +++ new/sphinxcontrib-httpdomain-1.4.0/setup.cfg 2015-08-13 16:15:20.000000000 +0200 @@ -9,7 +9,7 @@ upload_dir = build/sphinx/html [egg_info] -tag_svn_revision = 0 tag_build = tag_date = 0 +tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sphinxcontrib-httpdomain-1.3.0/setup.py new/sphinxcontrib-httpdomain-1.4.0/setup.py --- old/sphinxcontrib-httpdomain-1.3.0/setup.py 2014-07-30 18:33:26.000000000 +0200 +++ new/sphinxcontrib-httpdomain-1.4.0/setup.py 2015-08-13 16:10:47.000000000 +0200 @@ -18,7 +18,7 @@ setup( name='sphinxcontrib-httpdomain', - version='1.3.0', + version='1.4.0', url='http://bitbucket.org/birkenfeld/sphinx-contrib', download_url='http://pypi.python.org/pypi/sphinxcontrib-httpdomain', license='BSD', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sphinxcontrib-httpdomain-1.3.0/sphinxcontrib/autohttp/common.py new/sphinxcontrib-httpdomain-1.4.0/sphinxcontrib/autohttp/common.py --- old/sphinxcontrib-httpdomain-1.3.0/sphinxcontrib/autohttp/common.py 2014-07-30 18:33:17.000000000 +0200 +++ new/sphinxcontrib-httpdomain-1.4.0/sphinxcontrib/autohttp/common.py 2015-08-13 16:06:35.000000000 +0200 @@ -27,7 +27,9 @@ if isinstance(content, six.string_types): content = content.splitlines() yield '' - yield '.. http:{method}:: {path}'.format(**locals()) + paths = [path] if isinstance(path, six.string_types) else path + for path in paths: + yield '.. http:{method}:: {path}'.format(**locals()) yield '' for line in content: yield ' ' + line diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sphinxcontrib-httpdomain-1.3.0/sphinxcontrib/autohttp/flask.py new/sphinxcontrib-httpdomain-1.4.0/sphinxcontrib/autohttp/flask.py --- old/sphinxcontrib-httpdomain-1.3.0/sphinxcontrib/autohttp/flask.py 2014-07-30 18:33:17.000000000 +0200 +++ new/sphinxcontrib-httpdomain-1.4.0/sphinxcontrib/autohttp/flask.py 2015-08-13 16:06:35.000000000 +0200 @@ -11,6 +11,7 @@ """ import re +import itertools import six from docutils import nodes @@ -43,12 +44,23 @@ return buf.getvalue() -def get_routes(app): - for rule in app.url_map.iter_rules(): - methods = rule.methods.difference(['OPTIONS', 'HEAD']) - for method in methods: +def get_routes(app, endpoint=None): + endpoints = [] + for rule in app.url_map.iter_rules(endpoint): + if rule.endpoint not in endpoints: + endpoints.append(rule.endpoint) + for endpoint in endpoints: + methodrules = {} + for rule in app.url_map.iter_rules(endpoint): + methods = rule.methods.difference(['OPTIONS', 'HEAD']) path = translate_werkzeug_rule(rule.rule) - yield method, path, rule.endpoint + for method in methods: + if method in methodrules: + methodrules[method].append(path) + else: + methodrules[method] = [path] + for method, paths in methodrules.items(): + yield method, paths, endpoint class AutoflaskDirective(Directive): @@ -67,7 +79,7 @@ endpoints = self.options.get('endpoints', None) if not endpoints: return None - return frozenset(re.split(r'\s*,\s*', endpoints)) + return re.split(r'\s*,\s*', endpoints) @property def undoc_endpoints(self): @@ -92,7 +104,12 @@ def make_rst(self): app = import_object(self.arguments[0]) - for method, path, endpoint in get_routes(app): + if self.endpoints: + routes = itertools.chain(*[get_routes(app, endpoint) + for endpoint in self.endpoints]) + else: + routes = get_routes(app) + for method, paths, endpoint in routes: try: blueprint, _, endpoint_internal = endpoint.rpartition('.') if self.blueprints and blueprint not in self.blueprints: @@ -102,8 +119,6 @@ except ValueError: pass # endpoint is not within a blueprint - if self.endpoints and endpoint not in self.endpoints: - continue if endpoint in self.undoc_endpoints: continue try: @@ -111,7 +126,7 @@ except AttributeError: static_url_path = app.static_path # Flask 0.6 or under if ('undoc-static' in self.options and endpoint == 'static' and - path == static_url_path + '/(path:filename)'): + static_url_path + '/(path:filename)' in paths): continue view = app.view_functions[endpoint] docstring = view.__doc__ or '' @@ -126,7 +141,7 @@ if not docstring and 'include-empty-docstring' not in self.options: continue docstring = prepare_docstring(docstring) - for line in http_directive(method, path, docstring): + for line in http_directive(method, paths, docstring): yield line def run(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sphinxcontrib-httpdomain-1.3.0/sphinxcontrib/httpdomain.py new/sphinxcontrib-httpdomain-1.4.0/sphinxcontrib/httpdomain.py --- old/sphinxcontrib-httpdomain-1.3.0/sphinxcontrib/httpdomain.py 2014-07-30 18:33:17.000000000 +0200 +++ new/sphinxcontrib-httpdomain-1.4.0/sphinxcontrib/httpdomain.py 2015-08-13 15:44:55.000000000 +0200 @@ -12,7 +12,6 @@ import re from docutils import nodes -from docutils.parsers.rst.roles import set_classes from pygments.lexer import RegexLexer, bygroups from pygments.lexers import get_lexer_by_name @@ -65,6 +64,14 @@ super(EventSourceRef, self).__init__(url, section, '') +class CORSRef(DocRef): + """Represents a reference to W3 Cross-Origin Resource Sharing recommendation.""" + + def __init__(self, name, type): + url = 'http://www.w3.org/TR/cors/' + super(CORSRef, self).__init__(url, name, '-' + type) + + #: Mapping from lowercase HTTP method name to :class:`DocRef` object which #: maintains the URL which points to the section of the RFC which defines that #: HTTP method. @@ -118,6 +125,7 @@ 'If-Unmodified-Since': RFC2616Ref(14.28), 'Last-Event-ID': EventSourceRef('last-event-id'), 'Last-Modified': RFC2616Ref(14.29), + 'Link': IETFRef(5988, '5'), 'Location': RFC2616Ref(14.30), 'Max-Forwards': RFC2616Ref(14.31), 'Pragma': RFC2616Ref(14.32), @@ -136,7 +144,24 @@ 'Vary': RFC2616Ref(14.44), 'Via': RFC2616Ref(14.45), 'Warning': RFC2616Ref(14.46), - 'WWW-Authenticate': RFC2616Ref(14.47) + 'WWW-Authenticate': RFC2616Ref(14.47), + 'Access-Control-Allow-Origin': CORSRef('access-control-allow-origin', + 'response-header'), + 'Access-Control-Allow-Credentials': CORSRef('access-control-allow-credentials', + 'response-header'), + 'Access-Control-Expose-Headers': CORSRef('access-control-expose-headers', + 'response-header'), + 'Access-Control-Max-Age': CORSRef('access-control-max-age', + 'response-header'), + 'Access-Control-Allow-Methods': CORSRef('access-control-allow-methods', + 'response-header'), + 'Access-Control-Allow-Headers': CORSRef('access-control-allow-headers', + 'response-header'), + 'Origin': CORSRef('origin', 'request-header'), + 'Access-Control-Request-Method': CORSRef('access-control-request-method', + 'response-header'), + 'Access-Control-Request-Headers': CORSRef('access-control-request-headers', + 'response-header'), } @@ -183,6 +208,7 @@ 423: 'Locked', 424: 'Failed Dependency', 426: 'Upgrade Required', + 429: 'Too Many Requests', 449: 'Retry With', # proprietary MS extension 500: 'Internal Server Error', 501: 'Not Implemented', @@ -194,6 +220,8 @@ 510: 'Not Extended' } +WEBDAV_STATUS_CODES = [207, 422, 423, 424, 507] + http_sig_param_re = re.compile(r'\((?:(?P<type>[^:)]+):)?(?P<name>[\w_]+)\)', re.VERBOSE) @@ -244,10 +272,10 @@ GroupedField('formparameter', label='Form Parameters', names=('formparameter', 'formparam', 'fparam', 'form')), GroupedField('requestheader', label='Request Headers', - rolename='mailheader', + rolename='header', names=('<header', 'reqheader', 'requestheader')), GroupedField('responseheader', label='Response Headers', - rolename='mailheader', + rolename='header', names=('>header', 'resheader', 'responseheader')), GroupedField('statuscode', label='Status Codes', rolename='statuscode', @@ -359,92 +387,6 @@ method = 'any' -def http_statuscode_role(name, rawtext, text, lineno, inliner, - options=None, content=None): - if options is None: - options = {} - if content is None: - content = [] - if text.isdigit(): - code = int(text) - try: - status = HTTP_STATUS_CODES[code] - except KeyError: - msg = inliner.reporter.error('%d is invalid HTTP status code' - % code, lineno=lineno) - prb = inliner.problematic(rawtext, rawtext, msg) - return [prb], [msg] - else: - try: - code, status = re.split(r'\s', text.strip(), 1) - code = int(code) - except ValueError: - msg = inliner.reporter.error( - 'HTTP status code must be an integer (e.g. `200`) or ' - 'start with an integer (e.g. `200 OK`); %r is invalid' % - text, - line=lineno - ) - prb = inliner.problematic(rawtext, rawtext, msg) - return [prb], [msg] - nodes.reference(rawtext) - if code == 226: - url = 'http://www.ietf.org/rfc/rfc3229.txt' - elif code == 418: - url = 'http://www.ietf.org/rfc/rfc2324.txt' - elif code == 449: - url = 'http://msdn.microsoft.com/en-us/library/dd891478(v=prot.10).aspx' - elif code in HTTP_STATUS_CODES: - url = 'http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html' \ - '#sec10.' + ('%d.%d' % (code // 100, 1 + code % 100)) - else: - url = '' - set_classes(options) - node = nodes.reference(rawtext, '%d %s' % (code, status), - refuri=url, **options) - return [node], [] - - -def http_method_role(name, rawtext, text, lineno, inliner, - options=None, content=None): - if options is None: - options = {} - if content is None: - content = [] - method = str(text).lower() - if method not in METHOD_REFS: - msg = inliner.reporter.error('%s is not valid HTTP method' % method, - lineno=lineno) - prb = inliner.problematic(rawtext, rawtext, msg) - return [prb], [msg] - url = str(METHOD_REFS[method]) - if not url: - return [nodes.emphasis(text, text)], [] - node = nodes.reference(rawtext, method.upper(), refuri=url, **options) - return [node], [] - - -def http_header_role(name, rawtext, text, lineno, inliner, - options=None, content=None): - if options is None: - options = {} - if content is None: - content = [] - header = str(text) - if header not in HEADER_REFS: - header = header.title() - if header not in HEADER_REFS: - if header.startswith('X-'): # skip custom headers - return [nodes.strong(header, header)], [] - msg = inliner.reporter.error('%s is not unknown HTTP header' % header, - lineno=lineno) - prb = inliner.problematic(rawtext, rawtext, msg) - return [prb], [msg] - url = str(HEADER_REFS[header]) - node = nodes.reference(rawtext, header, refuri=url, **options) - return [node], [] - - class HTTPXRefRole(XRefRole): def __init__(self, method, **kwargs): @@ -452,13 +394,128 @@ self.method = method def process_link(self, env, refnode, has_explicit_title, title, target): - if not target.startswith('/'): - pass if not has_explicit_title: title = self.method.upper() + ' ' + title return title, target +class HTTPXRefMethodRole(XRefRole): + + def result_nodes(self, document, env, node, is_ref): + method = node[0][0].lower() + rawsource = node[0].rawsource + config = env.domains['http'].env.config + if method not in METHOD_REFS: + if not config['http_strict_mode']: + return [nodes.emphasis(method, method)], [] + reporter = document.reporter + msg = reporter.error('%s is not valid HTTP method' % method, + line=node.line) + prb = nodes.problematic(method, method) + return [prb], [msg] + url = str(METHOD_REFS[method]) + if not url: + return [nodes.emphasis(method, method)], [] + node = nodes.reference(rawsource, method.upper(), refuri=url) + return [node], [] + + +class HTTPXRefStatusRole(XRefRole): + + def result_nodes(self, document, env, node, is_ref): + def get_code_status(text): + if text.isdigit(): + code = int(text) + return code, HTTP_STATUS_CODES.get(code) + else: + try: + code, status = re.split(r'\s', text.strip(), 1) + code = int(code) + except ValueError: + return None, None + known_status = HTTP_STATUS_CODES.get(code) + if known_status is None: + return code, None + elif known_status.lower() != status.lower(): + return code, None + else: + return code, status + + def report_unknown_code(): + if not config['http_strict_mode']: + return [nodes.emphasis(text, text)], [] + reporter = document.reporter + msg = reporter.error('%d is unknown HTTP status code' % code, + line=node.line) + prb = nodes.problematic(text, text) + return [prb], [msg] + + def report_invalid_code(): + if not config['http_strict_mode']: + return [nodes.emphasis(text, text)], [] + reporter = document.reporter + msg = reporter.error( + 'HTTP status code must be an integer (e.g. `200`) or ' + 'start with an integer (e.g. `200 OK`); %r is invalid' % + text, + line=node.line + ) + prb = nodes.problematic(text, text) + return [prb], [msg] + + text = node[0][0] + rawsource = node[0].rawsource + config = env.domains['http'].env.config + + code, status = get_code_status(text) + if code is None: + return report_invalid_code() + elif status is None: + return report_unknown_code() + elif code == 226: + url = 'http://www.ietf.org/rfc/rfc3229.txt' + elif code == 418: + url = 'http://www.ietf.org/rfc/rfc2324.txt' + elif code == 429: + url = 'http://tools.ietf.org/html/rfc6585#section-4' + elif code == 449: + url = 'http://msdn.microsoft.com/en-us/library/dd891478(v=prot.10).aspx' + elif code in WEBDAV_STATUS_CODES: + url = 'http://tools.ietf.org/html/rfc4918#section-11.%d' % (WEBDAV_STATUS_CODES.index(code) + 1) + elif code in HTTP_STATUS_CODES: + url = 'http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html' \ + '#sec10.' + ('%d.%d' % (code // 100, 1 + code % 100)) + else: + url = '' + node = nodes.reference(rawsource, '%d %s' % (code, status), refuri=url) + return [node], [] + + +class HTTPXRefHeaderRole(XRefRole): + + def result_nodes(self, document, env, node, is_ref): + header = node[0][0] + rawsource = node[0].rawsource + config = env.domains['http'].env.config + if header not in HEADER_REFS: + _header = '-'.join(map(lambda i: i.title(), header.split('-'))) + if _header not in HEADER_REFS: + if not config['http_strict_mode']: + return [nodes.emphasis(header, header)], [] + _header = _header.lower() + if any([_header.startswith(prefix.lower()) + for prefix in config['http_headers_ignore_prefixes']]): + return [nodes.emphasis(header, header)], [] + reporter = document.reporter + msg = reporter.error('%s is not unknown HTTP header' % header, + line=node.line) + prb = nodes.problematic(header, header) + return [prb], [msg] + url = str(HEADER_REFS[header]) + node = nodes.reference(rawsource, header, refuri=url) + return [node], [] + + class HTTPIndex(Index): name = 'routingtable' @@ -552,9 +609,9 @@ 'connect': HTTPXRefRole('connect'), 'copy': HTTPXRefRole('copy'), 'any': HTTPXRefRole('any'), - 'statuscode': http_statuscode_role, - 'method': http_method_role, - 'header': http_header_role + 'statuscode': HTTPXRefStatusRole(), + 'method': HTTPXRefMethodRole(), + 'header': HTTPXRefHeaderRole() } initial_data = { @@ -589,12 +646,18 @@ info = self.data[str(typ)][target] except KeyError: text = contnode.rawsource - if typ == 'statuscode': - return http_statuscode_role(None, text, text, None, None)[0][0] - elif typ == 'mailheader': - return http_header_role(None, text, text, None, None)[0][0] - else: - return nodes.emphasis(text, text) + role = self.roles.get(typ) + if role is None: + return None + resnode = role.result_nodes(env.get_doctree(fromdocname), + env, node, None)[0][0] + if isinstance(resnode, addnodes.pending_xref): + text = node[0][0] + reporter = env.get_doctree(fromdocname).reporter + reporter.warning('Cannot resolve reference to %r' % text, + line=node.line) + return None + return resnode else: anchor = http_resource_anchor(typ, target) title = typ.upper() + ' ' + target @@ -682,3 +745,5 @@ app.add_config_value('http_index_ignore_prefixes', [], None) app.add_config_value('http_index_shortname', 'routing table', True) app.add_config_value('http_index_localname', 'HTTP Routing Table', True) + app.add_config_value('http_strict_mode', True, None) + app.add_config_value('http_headers_ignore_prefixes', ['X-'], None) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sphinxcontrib-httpdomain-1.3.0/sphinxcontrib_httpdomain.egg-info/PKG-INFO new/sphinxcontrib-httpdomain-1.4.0/sphinxcontrib_httpdomain.egg-info/PKG-INFO --- old/sphinxcontrib-httpdomain-1.3.0/sphinxcontrib_httpdomain.egg-info/PKG-INFO 2014-07-30 18:41:22.000000000 +0200 +++ new/sphinxcontrib-httpdomain-1.4.0/sphinxcontrib_httpdomain.egg-info/PKG-INFO 2015-08-13 16:15:19.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: sphinxcontrib-httpdomain -Version: 1.3.0 +Version: 1.4.0 Summary: Sphinx domain for HTTP APIs Home-page: http://bitbucket.org/birkenfeld/sphinx-contrib Author: Hong Minhee diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sphinxcontrib-httpdomain-1.3.0/sphinxcontrib_httpdomain.egg-info/requires.txt new/sphinxcontrib-httpdomain-1.4.0/sphinxcontrib_httpdomain.egg-info/requires.txt --- old/sphinxcontrib-httpdomain-1.3.0/sphinxcontrib_httpdomain.egg-info/requires.txt 2014-07-30 18:41:22.000000000 +0200 +++ new/sphinxcontrib-httpdomain-1.4.0/sphinxcontrib_httpdomain.egg-info/requires.txt 2015-08-13 16:15:19.000000000 +0200 @@ -1,2 +1,2 @@ Sphinx >= 1.0 -six \ No newline at end of file +six