Python 3.8 support

pull/199/head
Ashley Whetter 5 years ago committed by Ashley Whetter
parent f8b6a6151c
commit fc1d78f758

@ -10,6 +10,8 @@ Features
^^^^^^^^
* `#151 <https://github.com/readthedocs/sphinx-autoapi/issues/151>`: (Python) Added the ``autoapi_python_use_implicit_namespaces`` option to allow
AutoAPI to search for implicit namespace packages.
* Added support for Sphinx 2.2 and 2.3.
* Added support for Python 3.8.
Bug Fixes
^^^^^^^^^

@ -367,12 +367,21 @@ def get_module_all(node):
return all_
def _is_ellipsis(node):
if sys.version_info < (3, 8):
return isinstance(node, astroid.Ellipsis)
return isinstance(node, astroid.Const) and node.value == Ellipsis
def merge_annotations(annotations, comment_annotations):
for ann, comment_ann in _zip_longest(annotations, comment_annotations):
if not ann or isinstance(ann, astroid.Ellipsis):
if ann and not _is_ellipsis(ann):
yield ann
elif comment_ann and not _is_ellipsis(comment_ann):
yield comment_ann
else:
yield ann
yield None
def _format_args(args, defaults=None, annotations=None):
@ -409,7 +418,7 @@ def _format_args(args, defaults=None, annotations=None):
return ", ".join(values)
def format_args(args_node):
def format_args(args_node): # pylint: disable=too-many-branches,too-many-statements
result = []
positional_only_defaults = []
positional_or_keyword_defaults = args_node.defaults
@ -422,7 +431,17 @@ def format_args(args_node):
plain_annotations = getattr(args_node, "annotations", ()) or ()
func_comment_annotations = getattr(args_node.parent, "type_comment_args", ()) or ()
comment_annotations = getattr(args_node, "type_comment_args", ()) or ()
comment_annotations = getattr(args_node, "type_comment_args", []) or []
if hasattr(args_node, "type_comment_posonlyargs"):
comment_annotations = args_node.type_comment_posonlyargs + comment_annotations
else:
# astroid used to not expose type comments of positional only arguments,
# so pad the comments with the number of positional only arguments.
comment_annotations = (
[None] * len(getattr(args_node, "posonlyargs", ()))
) + comment_annotations
if hasattr(args_node, "type_comment_kwonlyargs"):
comment_annotations += args_node.type_comment_kwonlyargs
annotations = list(
merge_annotations(
plain_annotations,
@ -432,18 +451,33 @@ def format_args(args_node):
annotation_offset = 0
if getattr(args_node, "posonlyargs", None):
result.append(_format_args(args_node.posonlyargs, positional_only_defaults))
posonlyargs_annotations = args_node.posonlyargs_annotations
if not any(args_node.posonlyargs_annotations):
num_args = len(args_node.posonlyargs)
posonlyargs_annotations = annotations[
annotation_offset : annotation_offset + num_args
]
result.append(
_format_args(
args_node.posonlyargs, positional_only_defaults, posonlyargs_annotations
)
)
result.append("/")
if not any(args_node.posonlyargs_annotations):
annotation_offset += num_args
if args_node.args:
annotation_offset = len(args_node.args)
num_args = len(args_node.args)
result.append(
_format_args(
args_node.args,
positional_or_keyword_defaults,
annotations[:annotation_offset],
annotations[annotation_offset : annotation_offset + num_args],
)
)
annotation_offset += num_args
if args_node.vararg:
vararg_result = "*{}".format(args_node.vararg)
@ -462,14 +496,22 @@ def format_args(args_node):
if not args_node.vararg:
result.append("*")
kwonlyargs_annotations = args_node.kwonlyargs_annotations
if not any(args_node.kwonlyargs_annotations):
num_args = len(args_node.kwonlyargs)
kwonlyargs_annotations = annotations[
annotation_offset : annotation_offset + num_args
]
result.append(
_format_args(
args_node.kwonlyargs,
args_node.kw_defaults,
args_node.kwonlyargs_annotations,
args_node.kwonlyargs, args_node.kw_defaults, kwonlyargs_annotations,
)
)
if not any(args_node.kwonlyargs_annotations):
annotation_offset += num_args
if args_node.kwarg:
kwarg_result = "**{}".format(args_node.kwarg)
if getattr(args_node, "kwargannotation", None):

@ -42,5 +42,6 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
],
)

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = u"pyexample"
copyright = u"2015, readthedocs"
author = u"readthedocs"
version = "0.1"
release = "0.1"
language = None
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
html_static_path = ["_static"]
htmlhelp_basename = "pyexampledoc"
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
autoapi_type = "python"
autoapi_dirs = ["example"]
autoapi_file_pattern = "*.py"

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
"""Example module
This is a description
"""
from typing import Optional
def f_simple(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)
def f_comment(a, b, /, c, d, *, e, f):
# type: (int, int, Optional[int], Optional[int], float, float) -> None
print(a, b, c, d, e, f)
def f_annotation(a: int, b: int, /, c: Optional[int], d: Optional[int], *, e: float, f: float) -> None:
print(a, b, c, d, e, f)
def f_arg_comment(
a, # type: int
b, # type: int
/,
c, # type: Optional[int]
d, # type: Optional[int]
*,
e, # type: float
f, # type: float
):
# type: (...) -> None
print(a, b, c, d, e, f)
def f_no_cd(a: int, b: int, /, *, e: float, f: float):
print(a, b, e, f)

@ -0,0 +1,26 @@
.. pyexample documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pyexample's documentation!
=====================================
.. toctree::
autoapi/index
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

@ -210,6 +210,34 @@ class TestAnnotationCommentsModule(object):
assert "global_a :A" in example_file
@pytest.mark.skipif(
sys.version_info < (3, 8), reason="Positional only arguments need Python >=3.8"
)
class TestPositionalOnlyArgumentsModule(object):
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder("py38positionalparams")
def test_integration(self):
example_path = "_build/text/autoapi/example/index.txt"
with io.open(example_path, encoding="utf8") as example_handle:
example_file = example_handle.read()
assert "f_simple(a, b, /, c, d, *, e, f)" in example_file
assert (
"f_comment(a: int, b: int, /, c: Optional[int], d: Optional[int], *, e: float, f: float)"
in example_file
)
assert (
"f_annotation(a: int, b: int, /, c: Optional[int], d: Optional[int], *, e: float, f: float)"
in example_file
)
# Requires unreleased astroid >2.4
# assert "f_arg_comment(a: int, b: int, /, c: Optional[int], d: Optional[int], *, e: float, f: float)" in example_file
assert "f_no_cd(a: int, b: int, /, *, e: float, f: float)" in example_file
def test_napoleon_integration_loaded(builder):
confoverrides = {
"extensions": ["autoapi.extension", "sphinx.ext.autodoc", "sphinx.ext.napoleon"]

@ -1,6 +1,6 @@
[tox]
envlist =
py{27,34,35,36,37}-sphinx{16,17,18},py{35,36,37}-sphinx{20,21}
py{27,34,35,36,37}-sphinx{16,17,18},py{35,36,37,38}-sphinx{20,21,22,23}
formatting
lint
docs
@ -12,6 +12,7 @@ python =
3.5: py35
3.6: py36
3.7: py37
3.8: py38
[testenv]
setenv =
@ -27,6 +28,8 @@ deps = -r{toxinidir}/requirements.txt
sphinx18: Sphinx<1.9
sphinx20: Sphinx<2.1
sphinx21: Sphinx<2.2
sphinx22: Sphinx<2.3
sphinx23: Sphinx<2.4
commands =
py.test {posargs}
@ -47,7 +50,7 @@ commands =
[testenv:docs]
deps =
Sphinx>=2.1,<2.2
Sphinx~=2.3.0
sphinx_rtd_theme
changedir = {toxinidir}/docs
commands =

Loading…
Cancel
Save