Python 3.8 support
This commit is contained in:
parent
f8b6a6151c
commit
fc1d78f758
8 changed files with 172 additions and 12 deletions
|
|
@ -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):
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -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',
|
||||
],
|
||||
)
|
||||
|
|
|
|||
21
tests/python/py38positionalparams/conf.py
Normal file
21
tests/python/py38positionalparams/conf.py
Normal file
|
|
@ -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"
|
||||
37
tests/python/py38positionalparams/example/example.py
Normal file
37
tests/python/py38positionalparams/example/example.py
Normal file
|
|
@ -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)
|
||||
26
tests/python/py38positionalparams/index.rst
Normal file
26
tests/python/py38positionalparams/index.rst
Normal file
|
|
@ -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"]
|
||||
|
|
|
|||
7
tox.ini
7
tox.ini
|
|
@ -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…
Reference in a new issue