Skip to content

Commit

Permalink
Merge pull request #124 from scipp/type-alias-formatter
Browse files Browse the repository at this point in the history
Use custom typehint formatter
  • Loading branch information
jl-wynen authored Jan 12, 2024
2 parents bba4103 + 96b2a70 commit 0b94d03
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 1 deletion.
82 changes: 82 additions & 0 deletions template/docs/_typehints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import sphinx
from typing import Optional, Any, NewType

_typehint_aliases = {
'scipp._scipp.core.DataArray': 'scipp.DataArray',
'scipp._scipp.core.Dataset': 'scipp.Dataset',
'scipp._scipp.core.DType': 'scipp.DType',
'scipp._scipp.core.Unit': 'scipp.Unit',
'scipp._scipp.core.Variable': 'scipp.Variable',
'scipp.core.data_group.DataGroup': 'scipp.DataGroup',
}


def typehints_formatter_for(package: str) -> callable:
def typehints_formatter(annotation, config: sphinx.config.Config) -> Optional[str]:
"""Format typehints with improved NewType handling."""
_ = config
if _is_new_type(annotation):
return _format_new_type(annotation, package)
if _is_type_alias_type(annotation):
return _format_type_alias_type(annotation, package)
return None

return typehints_formatter


def _is_new_type(annotation: Any) -> bool:
# TODO Switch to isinstance(key, NewType) once our minimum is Python 3.10
# Note that we cannot pass mypy in Python<3.10 since NewType is not a type.
return hasattr(annotation, '__supertype__')


def _format_new_type(annotation: NewType, package: str) -> str:
return (
f'{_internal_link(annotation, "class", package)}'
f' ({_link(annotation.__supertype__, "class")})'
)


def _is_type_alias_type(annotation) -> bool:
try:
from typing import TypeAliasType

return isinstance(annotation, TypeAliasType)
except ImportError:
return False # pre python 3.12


def _format_type_alias_type(annotation: Any, package: str) -> str:
alias = _internal_link(annotation, "class", package, annotation.__type_params__)
value = _link(annotation.__value__, "class", _get_type_args(annotation.__value__))
return f'{alias} ({value})'


def _get_type_args(ty: type) -> tuple[type, ...]:
if (args := getattr(ty, '__args__', None)) is not None:
return args # e.g. list[int]
return ty.__type_params__


def _internal_link(
annotation: Any,
kind: str,
package: str,
type_params: Optional[tuple[type, ...]] = None,
) -> str:
target = f'{annotation.__module__}.{annotation.__name__}'
label = f'{annotation.__module__.removeprefix(package+".")}.{annotation.__name__}'
if type_params:
label += f'[{", ".join(ty.__name__ for ty in type_params)}]'
return f':{kind}:`{label} <{target}>`'


def _link(ty: type, kind: str, type_params: Optional[tuple[type, ...]] = None) -> str:
if ty.__module__ == 'builtins':
target = ty.__name__
else:
target = f'{ty.__module__}.{ty.__name__}'
label = _typehint_aliases.get(target, target)
if type_params:
label += f'[{", ".join(ty.__name__ for ty in type_params)}]'
return f':{kind}:`{label} <{target}>`'
6 changes: 5 additions & 1 deletion template/docs/conf.py.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import sys

sys.path.insert(0, os.path.abspath('.'))

from _typehints import typehints_formatter_for # noqa: E402

# General information about the project.
project = u'{{prettyname}}'
copyright = u'{{year}} Scipp contributors'
Expand Down Expand Up @@ -54,6 +56,7 @@ autodoc_type_aliases = {
intersphinx_mapping = {
'python': ('https://docs.python.org/3', None),
'numpy': ('https://numpy.org/doc/stable/', None),
'scipp': ('https://scipp.github.io/', None),
}

# autodocs includes everything, even irrelevant API internals. autosummary
Expand All @@ -72,6 +75,7 @@ napoleon_type_aliases = {
}
typehints_defaults = 'comma'
typehints_use_rtype = False
typehints_formatter = typehints_formatter_for('{% if namespace_package %}{{namespace_package}}.{% endif %}{{ projectname.removeprefix(namespace_package) }}')

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
Expand Down Expand Up @@ -134,7 +138,7 @@ html_theme_options = {
"external_links": [
{% for link in related_projects.replace(' ', '').split(',')|sort -%}
{"name": "{{ link }}", "url": "https://scipp.github.io{% if link == 'Scipp' %}{% else %}/{{ link|lower }}{% endif %}"},
{% endfor %}],
{% endfor %}],
"icon_links": [
{
"name": "GitHub",
Expand Down

0 comments on commit 0b94d03

Please sign in to comment.