Skip to content

Commit

Permalink
cleaned documentation creation
Browse files Browse the repository at this point in the history
Now a bit more clear, no annotation in sig
but only in parameters list.

This makes it more compatible with numpy's way
of writing documentation.

It also becomes less obscure for docstrings
with many parameters.

Signed-off-by: Nick Papior <[email protected]>
  • Loading branch information
zerothi committed Jan 6, 2025
1 parent 866a97b commit 6330cdb
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 50 deletions.
5 changes: 5 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,8 @@ repos:
rev: ebf0b5e44d67f8beaa1cd13a0d0393ea04c6058d
hooks:
- id: validate-cff
#Validate the numpydoc string, we use numpydoc for parsing
#- repo: https://github.com/numpy/numpydoc
# rev: v1.8.0
# hooks:
# - id: numpydoc-validation
145 changes: 111 additions & 34 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#
# All configuration values have a default; values that are commented out
# serve to show the default.

""" sisl documentation """
from __future__ import annotations

import inspect
Expand Down Expand Up @@ -114,21 +114,10 @@
]


napoleon_google_docstring = False
napoleon_numpy_docstring = True
napoleon_use_param = False
napoleon_use_rtype = False
napoleon_use_ivar = False
napoleon_preprocess_types = True
# Using attr_annotations = True ensures that
# autodoc_type_aliases is in effect.
# Then there is no need to use napoleon_type_aliases.
napoleon_attr_annotations = True


# The default is MathJax 3.
# In case we want to revert to 2.7.7, then use the below link:
# mathjax_path = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS-MML_HTMLorMML"
# If numpydoc is available, then let sphinx report warnings
numpydoc_validation_checks = {"all", "EX01", "SA01", "ES01"}


# Add any paths that contain templates here, relative to this directory.
Expand Down Expand Up @@ -233,15 +222,26 @@
"inherited-members": True,
"show-inheritance": True,
}

# How to show the class signature
# mixed: signature with class name
# separated: signature as method
autodoc_class_signature = "separated"

# alphabetical | groupwise | bysource
# How automodule + autoclass orders content.
# Right now, the current way sisl documents things
# is basically groupwise. So lets be explicit
autodoc_member_order = "groupwise"

# Show type-hints in both the signature
# and in the variable list
autodoc_typehints = "signature"
# Do not evaluate things that are defaulted in arguments.
# Show them *as-is*.
autodoc_preserve_defaults = True

# Show type-hints in only the discription, in this way the
# signature is readable and the argument order can easily
# be inferred.
autodoc_typehints = "description"

# typehints only shows the minimal class, instead
# of full module paths
Expand All @@ -250,24 +250,20 @@
# autodoc will likely get a rewrite. Until then..
autodoc_typehints_format = "short"

# Do not evaluate things that are defaulted in arguments.
# Show them *as-is*.
autodoc_preserve_defaults = True

# Automatically create the autodoc_type_aliases
# This is handy for commonly used terminologies.
# It currently puts everything into a `<>` which
# is sub-optimal (i.e. one cannot do "`umpy.ndarray` or `any`")
# Perhaps just a small tweak and it works.
autodoc_type_aliases = {
# general terms
"array-like": "numpy.ndarray",
"array_like": "numpy.ndarray",
"int-like": "int or numpy.ndarray",
"float-like": "float or numpy.ndarray",
"array-like": "~numpy.ndarray",
"array_like": "~numpy.ndarray",
"int-like": "int or ~numpy.ndarray",
"float-like": "float or ~numpy.ndarray",
"sequence": "sequence",
"np.ndarray": "numpy.ndarray",
"ndarray": "numpy.ndarray",
"np.ndarray": "~numpy.ndarray",
"ndarray": "~numpy.ndarray",
}
_type_aliases_skip = set()

Expand All @@ -276,23 +272,29 @@ def has_under(name: str):
return name.startswith("_")


def has_no_under(name: str):
return not has_under(name)
# Retrive all typings
try:
from numpy.typing import __all__ as numpy_types
except ImportError:
numpy_types = []
try:
from sisl.typing import __all__ as sisl_types
except ImportError:
sisl_types = []


for name in filter(has_no_under, dir(np.typing)):
for name in numpy_types:
if name in _type_aliases_skip:
continue
autodoc_type_aliases[f"npt.{name}"] = f"numpy.typing.{name}"
autodoc_type_aliases[f"npt.{name}"] = f"~numpy.typing.{name}"


for name in filter(has_no_under, dir(sisl.typing)):
for name in sisl_types:
if name in _type_aliases_skip:
continue

# sisl typing should be last, in this way we ensure
# that sisl typing is always preferred
autodoc_type_aliases[name] = f"sisl.typing.{name}"
autodoc_type_aliases[name] = f"~sisl.typing.{name}"


# List of patterns, relative to source directory, that match files and
Expand Down Expand Up @@ -901,7 +903,82 @@ def get_items(self, *args, **kwargs):
return items


def _setup_autodoc(app):
"""Patch and fix autodoc so we get the correct formatting of the environment"""
from sphinx.ext import autodoc, autosummary
from sphinx.locale import _
from sphinx.util import typing

# These subsequent class and methods originate from mpi4py
# which is released under BSD-3 clause.
# All credits must go to mpi4py developers for their contribution!
def istypealias(obj, name):
if isinstance(obj, type):
return name != getattr(obj, "__name__", None)
return obj in (typing.Any,)

def istypevar(obj):
return isinstance(obj, typing.TypeVar)

class TypeDocumenter(autodoc.DataDocumenter):
objtype = "type"
directivetype = "data"
priority = autodoc.ClassDocumenter.priority + 1

@classmethod
def can_document_member(cls, member, membername, _isattr, parent):
return (
isinstance(parent, autodoc.ModuleDocumenter)
and parent.name == "sisl.typing"
and (istypevar(member) or istypealias(member, membername))
)

def add_directive_header(self, sig):
if istypevar(self.object):
obj = self.object
if not self.options.annotation:
self.options.annotation = f' = TypeVar("{obj.__name__}")'
super().add_directive_header(sig)

def update_content(self, more_content):
obj = self.object
if istypevar(obj):
if obj.__covariant__:
kind = _("Covariant")
elif obj.__contravariant__:
kind = _("Contravariant")
else:
kind = _("Invariant")
content = f"{kind} :class:`~typing.TypeVar`."
more_content.append(content, "")
more_content.append("", "")
if istypealias(obj, self.name):
content = _("alias of %s") % typing.restify(obj)
more_content.append(content, "")
more_content.append("", "")
super().update_content(more_content)

def get_doc(self, *args, **kwargs):
obj = self.object
if istypevar(obj):
if obj.__doc__ == typing.TypeVar.__doc__:
return []
return super().get_doc(*args, **kwargs)

# Ensure the data-type gets parsed as a role.
# This will make the Type definitions print like a class
# which gives more space than the simpler table with very
# limited entry-space.
from sphinx.domains.python import PythonDomain

PythonDomain.object_types["data"].roles += ("class",)

app.add_autodocumenter(TypeDocumenter)


def setup(app):
# Setup autodoc skipping
_setup_autodoc(app)

app.connect("autodoc-skip-member", sisl_skip)
app.add_directive("autosummary", RemovePrefixAutosummary, override=True)
7 changes: 7 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -331,3 +331,10 @@ extend-exclude = """
| .*/\\..*
)
"""


[tool.numpydoc_validation]
checks = ["all", "EX01", "SA01", "ES01"]
exclude = [
'^conf\.',
]
11 changes: 6 additions & 5 deletions src/sisl/_core/_ufuncs_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,7 @@ def repeat(geometry: Geometry, reps: int, axis: CellAxis) -> Geometry:
[1.5 1. 0. ]]
In functional form:
>>> repeat(geom, 2, axis=0)
See Also
Expand Down Expand Up @@ -1122,7 +1123,7 @@ def rotate(
atoms will be rotated.
rad :
if ``True`` the angle is provided in radians (rather than degrees)
what : {'xyz', 'abc', 'abc+xyz', <or combinations of "xyzabc">}
what :
which coordinate subject should be rotated,
if any of ``abc`` is in this string the corresponding cell vector will be rotated
if any of ``xyz`` is in this string the corresponding coordinates will be rotated
Expand Down Expand Up @@ -1381,7 +1382,7 @@ def append(
axis :
Cell direction to which the `other` geometry should be
appended.
offset : {'none', 'min', (3,)}
offset :
By default appending two structures will simply use the coordinates,
as is.
With 'min', the routine will shift both the structures along the cell
Expand Down Expand Up @@ -1450,7 +1451,7 @@ def prepend(
"""Prepend two structures along `axis`
This will automatically add the ``geometry.cell[axis,:]`` to all atomic
coordiates in the `other` structure before appending.
coordinates in the `other` structure before appending.
The basic algorithm is this:
Expand All @@ -1470,7 +1471,7 @@ def prepend(
axis :
Cell direction to which the `other` geometry should be
prepended
offset : {'none', 'min', (3,)}
offset :
By default appending two structures will simply use the coordinates,
as is.
With 'min', the routine will shift both the structures along the cell
Expand Down Expand Up @@ -1600,7 +1601,7 @@ def scale(
scale :
the scale factor for the new geometry (lattice vectors, coordinates
and the atomic radii are scaled).
what: {"abc", "xyz"}
what :
``abc``
Is applied on the corresponding lattice vector and the fractional coordinates.
Expand Down
8 changes: 4 additions & 4 deletions src/sisl/_core/_ufuncs_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def copy(grid: Grid, dtype=None) -> Grid:
def write(grid: Grid, sile: SileLike, *args, **kwargs) -> None:
"""Writes grid to the `sile` using `sile.write_grid`
parameters
Parameters
----------
sile :
a `Sile` object which will be used to write the grid
Expand Down Expand Up @@ -71,12 +71,12 @@ def apply(grid: Grid, function_, *args, **kwargs):
some measurement). In that case, you will get the result instead of a `Grid`.
Parameters
-----------
function_: str or function
----------
function_ : str or function
for a string the full module path to the function should be given.
The function that will be called should have the grid as the first argument in its
interface.
*args and **kwargs:
*args and **kwargs :
arguments that go directly to the function call
Notes
Expand Down
Loading

0 comments on commit 6330cdb

Please sign in to comment.