mirror of
https://github.com/instaloader/instaloader.git
synced 2024-08-17 20:29:38 +02:00
doc: Fix links to Instaloader classes
This commit is contained in:
parent
147cd1a580
commit
7edc69454d
@ -25,6 +25,8 @@ import sphinx_bootstrap_theme
|
|||||||
|
|
||||||
sys.path.insert(0, os.path.abspath('..'))
|
sys.path.insert(0, os.path.abspath('..'))
|
||||||
|
|
||||||
|
import docs.sphinx_autodoc_typehints as sphinx_autodoc_typehints
|
||||||
|
|
||||||
# -- General configuration ------------------------------------------------
|
# -- General configuration ------------------------------------------------
|
||||||
|
|
||||||
# If your documentation needs a minimal Sphinx version, state it here.
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
@ -36,7 +38,6 @@ sys.path.insert(0, os.path.abspath('..'))
|
|||||||
# ones.
|
# ones.
|
||||||
extensions = [
|
extensions = [
|
||||||
'sphinx.ext.autodoc',
|
'sphinx.ext.autodoc',
|
||||||
'sphinx_autodoc_typehints',
|
|
||||||
'sphinx.ext.githubpages',
|
'sphinx.ext.githubpages',
|
||||||
'sphinx.ext.intersphinx'
|
'sphinx.ext.intersphinx'
|
||||||
]
|
]
|
||||||
@ -371,3 +372,5 @@ html_context = {'current_release': current_release, 'current_release_date': curr
|
|||||||
|
|
||||||
def setup(app):
|
def setup(app):
|
||||||
app.add_stylesheet("style.css")
|
app.add_stylesheet("style.css")
|
||||||
|
app.connect('autodoc-process-signature', sphinx_autodoc_typehints.process_signature)
|
||||||
|
app.connect('autodoc-process-docstring', sphinx_autodoc_typehints.process_docstring)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
requests
|
requests
|
||||||
sphinx
|
sphinx
|
||||||
sphinx-autodoc-typehints
|
|
||||||
sphinx-bootstrap-theme
|
sphinx-bootstrap-theme
|
||||||
|
228
docs/sphinx_autodoc_typehints.py
Normal file
228
docs/sphinx_autodoc_typehints.py
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
# sphinx_autodoc_typehints from Mar 18 2018.
|
||||||
|
# https://github.com/agronholm/sphinx-autodoc-typehints
|
||||||
|
# (slightly modified to fix class links, maybe related to agronholm/sphinx-autodoc-typehints#38)
|
||||||
|
#
|
||||||
|
# This is the MIT license: http://www.opensource.org/licenses/mit-license.php
|
||||||
|
#
|
||||||
|
# Copyright (c) Alex Grönholm
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
# software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
# without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
# publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
# to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
# substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
# DEALINGS IN THE SOFTWARE.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
import inspect
|
||||||
|
from typing import get_type_hints, TypeVar, Any, AnyStr, Generic, Union
|
||||||
|
|
||||||
|
from sphinx.util.inspect import getargspec
|
||||||
|
from sphinx.ext.autodoc import formatargspec
|
||||||
|
|
||||||
|
try:
|
||||||
|
from inspect import unwrap
|
||||||
|
except ImportError:
|
||||||
|
def unwrap(func, *, stop=None):
|
||||||
|
"""This is the inspect.unwrap() method copied from Python 3.5's standard library."""
|
||||||
|
if stop is None:
|
||||||
|
def _is_wrapper(f):
|
||||||
|
return hasattr(f, '__wrapped__')
|
||||||
|
else:
|
||||||
|
def _is_wrapper(f):
|
||||||
|
return hasattr(f, '__wrapped__') and not stop(f)
|
||||||
|
f = func # remember the original func for error reporting
|
||||||
|
memo = {id(f)} # Memoise by id to tolerate non-hashable objects
|
||||||
|
while _is_wrapper(func):
|
||||||
|
func = func.__wrapped__
|
||||||
|
id_func = id(func)
|
||||||
|
if id_func in memo:
|
||||||
|
raise ValueError('wrapper loop when unwrapping {!r}'.format(f))
|
||||||
|
memo.add(id_func)
|
||||||
|
return func
|
||||||
|
|
||||||
|
|
||||||
|
def format_annotation(annotation):
|
||||||
|
if inspect.isclass(annotation) and annotation.__module__ == 'builtins':
|
||||||
|
if annotation.__qualname__ == 'NoneType':
|
||||||
|
return '``None``'
|
||||||
|
else:
|
||||||
|
return ':py:class:`{}`'.format(annotation.__qualname__)
|
||||||
|
|
||||||
|
annotation_cls = annotation if inspect.isclass(annotation) else type(annotation)
|
||||||
|
class_name = None
|
||||||
|
if annotation_cls.__module__ == 'typing':
|
||||||
|
params = None
|
||||||
|
prefix = ':py:class:'
|
||||||
|
module = 'typing'
|
||||||
|
extra = ''
|
||||||
|
|
||||||
|
if inspect.isclass(getattr(annotation, '__origin__', None)):
|
||||||
|
annotation_cls = annotation.__origin__
|
||||||
|
try:
|
||||||
|
if Generic in annotation_cls.mro():
|
||||||
|
module = annotation_cls.__module__
|
||||||
|
except TypeError:
|
||||||
|
pass # annotation_cls was either the "type" object or typing.Type
|
||||||
|
|
||||||
|
if annotation is Any:
|
||||||
|
return ':py:data:`~typing.Any`'
|
||||||
|
elif annotation is AnyStr:
|
||||||
|
return ':py:data:`~typing.AnyStr`'
|
||||||
|
elif isinstance(annotation, TypeVar):
|
||||||
|
return '\\%r' % annotation
|
||||||
|
elif (annotation is Union or getattr(annotation, '__origin__', None) is Union or
|
||||||
|
hasattr(annotation, '__union_params__')):
|
||||||
|
prefix = ':py:data:'
|
||||||
|
class_name = 'Union'
|
||||||
|
if hasattr(annotation, '__union_params__'):
|
||||||
|
params = annotation.__union_params__
|
||||||
|
elif hasattr(annotation, '__args__'):
|
||||||
|
params = annotation.__args__
|
||||||
|
|
||||||
|
if params and len(params) == 2 and (hasattr(params[1], '__qualname__') and
|
||||||
|
params[1].__qualname__ == 'NoneType'):
|
||||||
|
class_name = 'Optional'
|
||||||
|
params = (params[0],)
|
||||||
|
elif annotation_cls.__qualname__ == 'Tuple' and hasattr(annotation, '__tuple_params__'):
|
||||||
|
params = annotation.__tuple_params__
|
||||||
|
if annotation.__tuple_use_ellipsis__:
|
||||||
|
params += (Ellipsis,)
|
||||||
|
elif annotation_cls.__qualname__ == 'Callable':
|
||||||
|
prefix = ':py:data:'
|
||||||
|
arg_annotations = result_annotation = None
|
||||||
|
if hasattr(annotation, '__result__'):
|
||||||
|
arg_annotations = annotation.__args__
|
||||||
|
result_annotation = annotation.__result__
|
||||||
|
elif getattr(annotation, '__args__', None):
|
||||||
|
arg_annotations = annotation.__args__[:-1]
|
||||||
|
result_annotation = annotation.__args__[-1]
|
||||||
|
|
||||||
|
if arg_annotations in (Ellipsis, (Ellipsis,)):
|
||||||
|
params = [Ellipsis, result_annotation]
|
||||||
|
elif arg_annotations is not None:
|
||||||
|
params = [
|
||||||
|
'\\[{}]'.format(
|
||||||
|
', '.join(format_annotation(param) for param in arg_annotations)),
|
||||||
|
result_annotation
|
||||||
|
]
|
||||||
|
elif hasattr(annotation, 'type_var'):
|
||||||
|
# Type alias
|
||||||
|
class_name = annotation.name
|
||||||
|
params = (annotation.type_var,)
|
||||||
|
elif getattr(annotation, '__args__', None) is not None:
|
||||||
|
params = annotation.__args__
|
||||||
|
elif hasattr(annotation, '__parameters__'):
|
||||||
|
params = annotation.__parameters__
|
||||||
|
|
||||||
|
if params:
|
||||||
|
extra = '\\[{}]'.format(', '.join(format_annotation(param) for param in params))
|
||||||
|
|
||||||
|
if not class_name:
|
||||||
|
class_name = annotation_cls.__qualname__.title()
|
||||||
|
|
||||||
|
return '{}`~{}.{}`{}'.format(prefix, module, class_name, extra)
|
||||||
|
elif annotation is Ellipsis:
|
||||||
|
return '...'
|
||||||
|
elif inspect.isclass(annotation) or inspect.isclass(getattr(annotation, '__origin__', None)):
|
||||||
|
if not inspect.isclass(annotation):
|
||||||
|
annotation_cls = annotation.__origin__
|
||||||
|
|
||||||
|
extra = ''
|
||||||
|
if Generic in annotation_cls.mro():
|
||||||
|
params = (getattr(annotation, '__parameters__', None) or
|
||||||
|
getattr(annotation, '__args__', None))
|
||||||
|
extra = '\\[{}]'.format(', '.join(format_annotation(param) for param in params))
|
||||||
|
|
||||||
|
module = annotation.__module__.split('.')[0] # hack to 'fix' class linking for Instaloader project
|
||||||
|
return ':py:class:`~{}.{}`{}'.format(module, annotation_cls.__qualname__,
|
||||||
|
extra)
|
||||||
|
|
||||||
|
return str(annotation)
|
||||||
|
|
||||||
|
|
||||||
|
def process_signature(app, what: str, name: str, obj, options, signature, return_annotation):
|
||||||
|
if not callable(obj):
|
||||||
|
return
|
||||||
|
|
||||||
|
if what in ('class', 'exception'):
|
||||||
|
obj = getattr(obj, '__init__', getattr(obj, '__new__', None))
|
||||||
|
|
||||||
|
if not getattr(obj, '__annotations__', None):
|
||||||
|
return
|
||||||
|
|
||||||
|
obj = unwrap(obj)
|
||||||
|
try:
|
||||||
|
argspec = getargspec(obj)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return
|
||||||
|
|
||||||
|
if argspec.args:
|
||||||
|
if what in ('class', 'exception'):
|
||||||
|
del argspec.args[0]
|
||||||
|
elif what == 'method':
|
||||||
|
outer = inspect.getmodule(obj)
|
||||||
|
for clsname in obj.__qualname__.split('.')[:-1]:
|
||||||
|
outer = getattr(outer, clsname)
|
||||||
|
method_object = outer.__dict__[obj.__name__]
|
||||||
|
if not isinstance(method_object, (classmethod, staticmethod)):
|
||||||
|
del argspec.args[0]
|
||||||
|
|
||||||
|
return formatargspec(obj, *argspec[:-1]), None
|
||||||
|
|
||||||
|
|
||||||
|
def process_docstring(app, what, name, obj, options, lines):
|
||||||
|
if isinstance(obj, property):
|
||||||
|
obj = obj.fget
|
||||||
|
|
||||||
|
if callable(obj):
|
||||||
|
if what in ('class', 'exception'):
|
||||||
|
obj = getattr(obj, '__init__')
|
||||||
|
|
||||||
|
obj = unwrap(obj)
|
||||||
|
try:
|
||||||
|
type_hints = get_type_hints(obj)
|
||||||
|
except (AttributeError, TypeError):
|
||||||
|
# Introspecting a slot wrapper will raise TypeError
|
||||||
|
return
|
||||||
|
|
||||||
|
for argname, annotation in type_hints.items():
|
||||||
|
formatted_annotation = format_annotation(annotation)
|
||||||
|
|
||||||
|
if argname == 'return':
|
||||||
|
if what in ('class', 'exception'):
|
||||||
|
# Don't add return type None from __init__()
|
||||||
|
continue
|
||||||
|
|
||||||
|
insert_index = len(lines)
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if line.startswith(':rtype:'):
|
||||||
|
insert_index = None
|
||||||
|
break
|
||||||
|
elif line.startswith(':return:') or line.startswith(':returns:'):
|
||||||
|
insert_index = i
|
||||||
|
|
||||||
|
if insert_index is not None:
|
||||||
|
if insert_index == len(lines):
|
||||||
|
# Ensure that :rtype: doesn't get joined with a paragraph of text, which
|
||||||
|
# prevents it being interpreted.
|
||||||
|
lines.append('')
|
||||||
|
insert_index += 1
|
||||||
|
|
||||||
|
lines.insert(insert_index, ':rtype: {}'.format(formatted_annotation))
|
||||||
|
else:
|
||||||
|
searchfor = ':param {}:'.format(argname)
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if line.startswith(searchfor):
|
||||||
|
lines.insert(i, ':type {}: {}'.format(argname, formatted_annotation))
|
||||||
|
break
|
Loading…
Reference in New Issue
Block a user