diff --git a/.github/workflows/build_docs.yaml b/.github/workflows/build_docs.yaml index becaadf8..a11e8622 100644 --- a/.github/workflows/build_docs.yaml +++ b/.github/workflows/build_docs.yaml @@ -18,7 +18,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v6 with: - python-version: "3.11" + python-version: "3.13" cache: "pip" cache-dependency-path: "setup.cfg" @@ -32,7 +32,7 @@ jobs: uv pip install --system wheel - name: Install documenteer - run: uv pip install --system 'documenteer[pipelines]==0.8.2' sphinx-automodapi==0.19 sphinx-prompt==1.6.0 + run: uv pip install --system -r doc/requirements.txt - name: Install dependencies run: | diff --git a/.gitignore b/.gitignore index 62947084..d98d1392 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ config.log *.so *.cfgc *.pyc +doc/api doc/html doc/xml doc/*.tag diff --git a/doc/conf.py b/doc/conf.py index b0c73752..f24c3c7a 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -2,28 +2,8 @@ This configuration only affects single-package Sphinx documenation builds. """ +# ruff: noqa: F403, F405 -from documenteer.conf.pipelinespkg import * # noqa: F403, import * +from documenteer.conf.guide import * -project = "utils" -html_theme_options["logotext"] = project # noqa: F405, unknown name -html_title = project -html_short_title = project -doxylink = {} -exclude_patterns = ["changes/*"] -nitpick_ignore_regex = [ - ("py:.*", r"lsst\..*"), # Ignore warnings from links to other lsst packages. - ("py:.*", "cProfile.Profile"), # Link does not resolve to py3 docs. - ("py:class", "a set-like.*"), # collections.abc.Mapping inheritance. - ("py:class", "a shallow copy.*"), # collections.abc.Mapping inheritance. - ("py:class", r"None\. .*"), # collections.abc.Mapping inheritance. - ("py:class", "an object providing.*"), # collections.abc.Mapping inheritance. -] -nitpick_ignore = [ - ("py:class", "module"), # Sphinx has problems with types.ModuleType. - ("py:obj", "logging.DEBUG"), # Python 3 constant can not be found. - ("py:class", "unittest.case.TestCase"), # Sphinx can not see TestCase. - ("py:obj", "deprecated.sphinx.deprecated"), # No intersphinx for deprecated package. - ("py:class", "LsstLoggers"), # Sphinx does not understand type aliases - ("py:obj", "structlog"), # structlog does not have intersphinx mapping. -] +exclude_patterns.append("changes/*") diff --git a/doc/documenteer.toml b/doc/documenteer.toml new file mode 100644 index 00000000..c9575cc6 --- /dev/null +++ b/doc/documenteer.toml @@ -0,0 +1,32 @@ +[project] +title = "lsst-utils" + +[project.python] +package = "lsst-utils" + +[build] +clean = true + +[sphinx] +nitpick_ignore = [ + ["py:class", "module"], # Sphinx has problems with types.ModuleType. + ["py:obj", "logging.DEBUG"], # Python 3 constant can not be found. + ["py:class", "unittest.case.TestCase"], # Sphinx can not see TestCase. + ["py:obj", "deprecated.sphinx.deprecated"], # No intersphinx for deprecated package. + ["py:class", "LsstLoggers"], # Sphinx does not understand type aliases + ["py:obj", "structlog"], # structlog does not have intersphinx mapping. + ["py:class", "array-like"], + ["py:class", "scalar"], +] +nitpick_ignore_regex = [ + ['py:.*', 'lsst\..*'], # Ignore warnings from links to other lsst packages. + ['py:.*', 'cProfile.Profile'], # Link does not resolve to py3 docs. + ['py:class', 'a set-like.*'], # collections.abc.Mapping inheritance. + ['py:class', 'a shallow copy.*'], # collections.abc.Mapping inheritance. + ['py:class', 'None\. .*'], # collections.abc.Mapping inheritance. + ['py:class', 'an object providing.*'], # collections.abc.Mapping inheritance. +] + +[sphinx.intersphinx.projects] +astropy = "https://docs.astropy.org/en/stable" +python = "https://docs.python.org/3" diff --git a/doc/requirements.txt b/doc/requirements.txt new file mode 100644 index 00000000..997ebc3e --- /dev/null +++ b/doc/requirements.txt @@ -0,0 +1,2 @@ +documenteer[guide] > 2.0, <3.0 +lsst-sphinxutils @ git+https://github.com/lsst/sphinxutils@main diff --git a/pyproject.toml b/pyproject.toml index f3e09f7c..b02da4bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,7 @@ dependencies = [ dynamic = ["version"] [project.urls] "Homepage" = "https://github.com/lsst/utils" +"Source" = "https://github.com/lsst/utils" [project.optional-dependencies] test = [ "pytest >= 3.2", diff --git a/python/lsst/utils/deprecated.py b/python/lsst/utils/deprecated.py index e123e566..79e67fd4 100644 --- a/python/lsst/utils/deprecated.py +++ b/python/lsst/utils/deprecated.py @@ -35,11 +35,11 @@ def deprecate_pybind11(obj: Any, reason: str, version: str, category: type[Warni Parameters ---------- - obj : function, method, or class + obj : `~collections.abc.Callable` The function, method, or class to deprecate. reason : `str` Reason for deprecation, passed to `~deprecated.sphinx.deprecated`. - version : 'str' + version : `str` Next major version in which the interface will be deprecated, passed to `~deprecated.sphinx.deprecated`. category : `Warning` @@ -47,7 +47,7 @@ def deprecate_pybind11(obj: Any, reason: str, version: str, category: type[Warni Returns ------- - obj : function, method, or class + obj : `~collections.abc.Callable` Wrapped function, method, or class. Examples @@ -88,7 +88,7 @@ def suppress_deprecations(category: type[Warning] = FutureWarning) -> Iterator[N Parameters ---------- - category : `Warning` or subclass + category : `Warning` The category of warning to suppress. """ with warnings.catch_warnings(): diff --git a/python/lsst/utils/inheritDoc.py b/python/lsst/utils/inheritDoc.py index 70ec3bf0..8e4a5cee 100644 --- a/python/lsst/utils/inheritDoc.py +++ b/python/lsst/utils/inheritDoc.py @@ -28,12 +28,12 @@ class and extend it with any additional documentation defined. Parameters ---------- - klass : object + klass : `type` The class to inherit documentation from. Returns ------- - decorator : callable + decorator : `~collections.abc.Callable` Intermediate decorator used in the documentation process. Notes diff --git a/python/lsst/utils/iteration.py b/python/lsst/utils/iteration.py index c0e824fc..180b7aec 100644 --- a/python/lsst/utils/iteration.py +++ b/python/lsst/utils/iteration.py @@ -26,10 +26,10 @@ def chunk_iterable(data: Iterable[Any], chunk_size: int = 1_000) -> Iterator[tup Parameters ---------- - data : iterable of anything + data : `~collections.abc.Iterable` [ `typing.Any` ] of anything The iterable to be chunked. Can be a mapping, in which case the keys are returned in chunks. - chunk_size : int, optional + chunk_size : `int`, optional The largest chunk to return. Can be smaller and depends on the number of elements in the iterator. Defaults to 1_000. @@ -58,7 +58,7 @@ def ensure_iterable(a: Any) -> Iterable[Any]: Parameters ---------- - a : iterable or `str` or not iterable + a : `~collections.abc.Iterable` or `str` or not iterable Argument to be converted to an iterable. Returns @@ -115,18 +115,19 @@ def _extract_numeric_suffix(s: str) -> tuple[str, int | None]: Returns the prefix and the numeric suffix as an integer, if present. For example: - 'node1' -> ('node', 1) - 'node' -> ('node', None) - 'node123abc' -> ('node123abc', None) + + 'node1' -> ('node', 1) + 'node' -> ('node', None) + 'node123abc' -> ('node123abc', None) Parameters ---------- - s : str + s : `str` The string to extract the numeric suffix from. Returns ------- - suffix : str + suffix : `str` The numeric suffix of the string, if any. """ index = len(s) @@ -151,13 +152,13 @@ def _add_pair_to_name(val_name: list[str], val0: int | str, val1: int | str, str Parameters ---------- - val_name : List[str] + val_name : `list` [ `str` ] The list to append the formatted string to. - val0 : [int, str] + val0 : `int` or `str` The starting value of the sequence. - val1 : [int, str] + val1 : `int` or `str` The ending value of the sequence. - stride : int, optional + stride : `int`, optional The stride or difference between consecutive numbers in the sequence. Defaults to 1. """ @@ -195,12 +196,12 @@ def _is_list_of_ints(values: list[int | str]) -> TypeGuard[list[int]]: Parameters ---------- - values : List[int, str]: + values : `list` [`int` or `str`]: The list of values to check. Returns ------- - is_ints : bool + is_ints : `bool` True if all values are integers, False otherwise. """ return all(isinstance(v, int) for v in values) @@ -217,31 +218,33 @@ def sequence_to_string(values: list[int | str]) -> str: strings with common prefixes are handled to produce a concise representation. - >>> getNameOfSet([1, 2, 3, 5, 7, 8, 9]) - '1..3^5^7..9' - >>> getNameOfSet(["node1", "node2", "node3"]) - 'node1..node3' - >>> getNameOfSet([10, 20, 30, 40]) - '10..40:10' - Parameters ---------- - values : list[int, str]: + values : `list` [ `int` or `str` ] A list of items to be compacted. Must all be of the same type. Returns ------- - sequence_as_string : str + sequence_as_string : `str` A compact string representation of the input list. Notes ----- - - The function handles both integers and strings. - - For strings with common prefixes, only the differing suffixes are - considered. - - The stride is determined as the minimum difference between - consecutive numbers. - - Strings without common prefixes are listed individually. + - The function handles both integers and strings. + - For strings with common prefixes, only the differing suffixes are + considered. + - The stride is determined as the minimum difference between + consecutive numbers. + - Strings without common prefixes are listed individually. + + Examples + -------- + >>> getNameOfSet([1, 2, 3, 5, 7, 8, 9]) + '1..3^5^7..9' + >>> getNameOfSet(["node1", "node2", "node3"]) + 'node1..node3' + >>> getNameOfSet([10, 20, 30, 40]) + '10..40:10' """ if not values: return "" diff --git a/python/lsst/utils/logging.py b/python/lsst/utils/logging.py index a8b03830..49c13195 100644 --- a/python/lsst/utils/logging.py +++ b/python/lsst/utils/logging.py @@ -273,7 +273,7 @@ def verbose(self, fmt: str, *args: Any, **kwargs: Any) -> None: *args : `~typing.Any` Parameters references by log message. **kwargs : `~typing.Any` - Parameters forwarded to `log`. + Parameters forwarded to underlying logger. """ # There is no other way to achieve this other than a special logger # method. @@ -294,7 +294,7 @@ def trace(self, fmt: str, *args: Any, **kwargs: Any) -> None: *args : `~typing.Any` Parameters references by log message. **kwargs : `~typing.Any` - Parameters forwarded to `log`. + Parameters forwarded to underlying logger. """ # There is no other way to achieve this other than a special logger # method. diff --git a/python/lsst/utils/timer.py b/python/lsst/utils/timer.py index 6421c2fa..d7134beb 100644 --- a/python/lsst/utils/timer.py +++ b/python/lsst/utils/timer.py @@ -165,7 +165,7 @@ def logInfo( Name prefix, the resulting entries are ``CpuTime``, etc.. For example `timeMethod` uses ``prefix = Start`` when the method begins and ``prefix = End`` when the method ends. - logLevel : optional + logLevel : `int`, optional Log level (a `logging` level constant, such as `logging.DEBUG`). metadata : `collections.abc.MutableMapping`, optional Metadata object to write entries to, overriding ``obj.metadata``. @@ -399,7 +399,7 @@ def time_this( Prefix to use to prepend to the supplied logger to create a new logger to use instead. No prefix is used if the value is set to `None`. Defaults to "timer". - args : iterable of any + args : `~collections.abc.Iterable` [ `typing.Any` ] Additional parameters passed to the log command that should be written to ``msg``. kwargs : `dict`, optional diff --git a/python/lsst/utils/wrappers.py b/python/lsst/utils/wrappers.py index dd15feb7..d0cd58ea 100644 --- a/python/lsst/utils/wrappers.py +++ b/python/lsst/utils/wrappers.py @@ -186,7 +186,7 @@ class TemplateMeta(type): classes with multiple template parameters) are good choices. Alternate type keys for existing classes can be added by calling ``alias``, but only after a subclass already been registered with a "primary" type key. For - example:: + example: .. code-block:: python @@ -210,7 +210,7 @@ class Image(metaclass=TemplateMeta): This allows user code to construct objects directly using ``Image``, as long as an extra ``dtype`` keyword argument is passed that matches one of - the type keys:: + the type keys: .. code-block:: python @@ -233,7 +233,7 @@ class Image(metaclass=TemplateMeta): As an aid for those writing the Python wrappers for C++ classes, ``TemplateMeta`` also provides a way to add pure-Python methods and other attributes to the wrapped template classes. To add a ``sum`` method to - all registered types, for example, we can just do:: + all registered types, for example, we can just do: .. code-block:: python @@ -259,7 +259,7 @@ def sum(self): Finally, abstract base classes that use ``TemplateMeta`` define a dict- like interface for accessing their registered subclasses, providing - something like the C++ syntax for templates:: + something like the C++ syntax for templates: .. code-block:: python diff --git a/ups/utils.table b/ups/utils.table index da9e3363..145034f5 100644 --- a/ups/utils.table +++ b/ups/utils.table @@ -2,4 +2,8 @@ # deprecation period. setupRequired(sconsUtils) +# Add this for convenience in testing documentation builds, even if the +# utils code does not yet use it directly during code builds. +setupRequired(sphinxutils) + envPrepend(PYTHONPATH, ${PRODUCT_DIR}/python)