Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DM-32801: Add sphinx docs build action #109

Merged
merged 6 commits into from
Dec 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/build_docs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: docs

on:
push:
branches:
- main
pull_request:

jobs:
build_sphinx_docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.8

- name: Update pip/wheel infrastructure
run: |
python -m pip install --upgrade pip
pip install wheel

- name: Install dependencies
run: |
pip install -r requirements.txt

- name: Build and install
run: pip install -v .

- name: Install documenteer
run: pip install 'documenteer[pipelines]<0.7'

- name: Build documentation
working-directory: ./doc
run: package-docs build
24 changes: 24 additions & 0 deletions .github/workflows/docstyle.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: lint docstrings

on:
push:
branches:
- main
pull_request:

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.8

- name: Install
run: pip install pydocstyle

- name: Run linter
run: pydocstyle python/lsst/
1 change: 1 addition & 0 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
html_title = project
html_short_title = project
doxylink = {}
exclude_patterns = ["changes/*"]
1 change: 1 addition & 0 deletions python/lsst/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#
# Use of this source code is governed by a 3-clause BSD-style
# license that can be found in the LICENSE file.
"""Top-level LSST package definition."""

import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
1 change: 1 addition & 0 deletions python/lsst/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#
# Use of this source code is governed by a 3-clause BSD-style
# license that can be found in the LICENSE file.
"""General LSST Utilities."""

from .get_caller_name import *
from .doImport import *
Expand Down
1 change: 1 addition & 0 deletions python/lsst/utils/_forwarded.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@

@deprecated(reason=_REASON, version=_VERSION_REMOVED, category=FutureWarning)
def demangleType(type_name: str) -> str:
"""Demangle a C++ type string."""
import lsst.cpputils
return lsst.cpputils.demangleType(type_name)
1 change: 1 addition & 0 deletions python/lsst/utils/backtrace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#
# Use of this source code is governed by a 3-clause BSD-style
# license that can be found in the LICENSE file.
"""Temporary forwarding of backtrace to cpputils package."""

__all__ = ["isEnabled"]

Expand Down
5 changes: 2 additions & 3 deletions python/lsst/utils/inheritDoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@


def inheritDoc(klass: Type) -> Callable:
"""Extends existing documentation for a method that exists in another
"""Extend existing documentation for a method that exists in another
class and extend it with any additional documentation defined.

This decorator takes a class from which to draw documentation from as an
Expand All @@ -34,8 +34,7 @@ class and extend it with any additional documentation defined.
Intermediate decorator used in the documentation process.
"""
def tmpDecorator(method: Type) -> Callable:
"""Decorator to update the documentation from a class with the same
method.
"""Update the documentation from a class with the same method.
"""
methodName = method.__name__
if not hasattr(klass, methodName):
Expand Down
23 changes: 10 additions & 13 deletions python/lsst/utils/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@


def trace_set_at(name: str, number: int) -> None:
"""Adjusts logging level to display messages with the trace number being
"""Adjust logging level to display messages with the trace number being
less than or equal to the provided value.

Parameters
Expand All @@ -51,16 +51,8 @@ def trace_set_at(name: str, number: int) -> None:
number : `int`
The trace number threshold for display.

Notes
-----
Loggers ``TRACE0.`` to ``TRACE5.`` are set. All loggers above
the specified threshold are set to ``INFO`` and those below the threshold
are set to ``DEBUG``. The expectation is that ``TRACE`` loggers only
issue ``DEBUG`` log messages.

Examples
--------

.. code-block:: python

lsst.utils.logging.trace_set_at("lsst.afw", 3)
Expand All @@ -70,6 +62,11 @@ def trace_set_at(name: str, number: int) -> None:

Notes
-----
Loggers ``TRACE0.`` to ``TRACE5.`` are set. All loggers above
the specified threshold are set to ``INFO`` and those below the threshold
are set to ``DEBUG``. The expectation is that ``TRACE`` loggers only
issue ``DEBUG`` log messages.

If ``lsst.log`` is installed, this function will also call
`lsst.log.utils.traceSetAt` to ensure that non-Python loggers are
also configured correctly.
Expand All @@ -85,14 +82,14 @@ def trace_set_at(name: str, number: int) -> None:


class _F:
"""
Format, supporting `str.format()` syntax.
"""Format, supporting `str.format()` syntax.

Notes
-----
This follows the recommendation from
https://docs.python.org/3/howto/logging-cookbook.html#using-custom-message-objects
"""

def __init__(self, fmt: str, /, *args: Any, **kwargs: Any):
self.fmt = fmt
self.args = args
Expand Down Expand Up @@ -135,7 +132,7 @@ class LsstLogAdapter(LoggerAdapter):

@contextmanager
def temporary_log_level(self, level: Union[int, str]) -> Generator:
"""A context manager that temporarily sets the level of this logger.
"""Temporarily set the level of this logger.

Parameters
----------
Expand All @@ -151,7 +148,7 @@ def temporary_log_level(self, level: Union[int, str]) -> Generator:

@property
def level(self) -> int:
"""Current level of this logger (``int``)."""
"""Return current level of this logger (``int``)."""
return self.logger.level

def getChild(self, name: str) -> LsstLogAdapter:
Expand Down
49 changes: 27 additions & 22 deletions python/lsst/utils/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ def sort_tests(tests) -> unittest.TestSuite:
A combined `~unittest.TestSuite` with
`~lsst.utils.tests.MemoryTestCase` at the end.
"""

suite = unittest.TestSuite()
memtests = []
for test_suite in tests:
Expand Down Expand Up @@ -157,20 +156,22 @@ class ExecutablesTestCase(unittest.TestCase):
must subclass this class in their own test file and invoke
the create_executable_tests() class method to register the tests.
"""

TESTS_DISCOVERED = -1

@classmethod
def setUpClass(cls) -> None:
"""Abort testing if automated test creation was enabled and
no tests were found."""

no tests were found.
"""
if cls.TESTS_DISCOVERED == 0:
raise RuntimeError("No executables discovered.")

def testSanity(self) -> None:
"""This test exists to ensure that there is at least one test to be
"""Ensure that there is at least one test to be
executed. This allows the test runner to trigger the class set up
machinery to test whether there are some executables to test."""
machinery to test whether there are some executables to test.
"""
pass

def assertExecutable(self, executable: str, root_dir: Optional[str] = None,
Expand Down Expand Up @@ -198,7 +199,6 @@ def assertExecutable(self, executable: str, root_dir: Optional[str] = None,
AssertionError
The executable did not return 0 exit status.
"""

if root_dir is not None and not os.path.isabs(executable):
executable = os.path.join(root_dir, executable)

Expand Down Expand Up @@ -287,7 +287,6 @@ def create_executable_tests(cls, ref_file: str, executables: Optional[Sequence[s
--------
>>> cls.create_executable_tests(__file__)
"""

# Get the search directory from the reference file
ref_dir = os.path.abspath(os.path.dirname(ref_file))

Expand Down Expand Up @@ -329,7 +328,6 @@ def getTempFilePath(ext: str, expectOutput: bool = True) -> Iterator[str]:

Parameters
----------

ext : `str`
File name extension, e.g. ``.fits``.
expectOutput : `bool`, optional
Expand All @@ -339,13 +337,13 @@ def getTempFilePath(ext: str, expectOutput: bool = True) -> Iterator[str]:

Returns
-------
`str`
path : `str`
Path for a temporary file. The path is a combination of the caller's
file path and the name of the top-level function

Notes
-----
::
Examples
--------
.. code-block:: python

# file tests/testFoo.py
import unittest
Expand Down Expand Up @@ -423,15 +421,15 @@ class TestCase(unittest.TestCase):


def inTestCase(func: Callable) -> Callable:
"""A decorator to add a free function to our custom TestCase class, while
"""Add a free function to our custom TestCase class, while
also making it available as a free function.
"""
setattr(TestCase, func.__name__, func)
return func


def debugger(*exceptions):
"""Decorator to enter the debugger when there's an uncaught exception
"""Enter the debugger when there's an uncaught exception

To use, just slap a ``@debugger()`` on your function.

Expand Down Expand Up @@ -823,7 +821,7 @@ def decorator(cls: Type) -> None:


def methodParameters(**settings: Sequence[Any]) -> Callable:
"""Method decorator for unit tests
"""Iterate over supplied settings to create subtests automatically.

This decorator iterates over the supplied settings, using
``TestCase.subTest`` to communicate the values in the event of a failure.
Expand All @@ -836,13 +834,15 @@ def methodParameters(**settings: Sequence[Any]) -> Callable:

Examples
--------
::
.. code-block:: python

@methodParameters(foo=[1, 2], bar=[3, 4])
def testSomething(self, foo, bar):
...

will run::
will run:

.. code-block:: python

testSomething(foo=1, bar=3)
testSomething(foo=2, bar=4)
Expand Down Expand Up @@ -872,12 +872,15 @@ def _cartesianProduct(settings: Mapping[str, Sequence[Any]]) -> Mapping[str, Seq
Parameter combinations covering the cartesian product (all possible
combinations) of the input parameters.

Example
-------
Examples
--------
.. code-block:: python

cartesianProduct({"foo": [1, 2], "bar": ["black", "white"]})

returns:
will return:

.. code-block:: python

{"foo": [1, 1, 2, 2], "bar": ["black", "white", "black", "white"]}
"""
Expand All @@ -902,14 +905,16 @@ def classParametersProduct(**settings: Sequence[Any]) -> Callable:

Examples
--------
::
.. code-block:: python

@classParametersProduct(foo=[1, 2], bar=[3, 4])
class MyTestCase(unittest.TestCase):
...

will generate four classes, as if you wrote::

.. code-block:: python

class MyTestCase_1_3(unittest.TestCase):
foo = 1
bar = 3
Expand All @@ -936,7 +941,7 @@ class MyTestCase_2_4(unittest.TestCase):


def methodParametersProduct(**settings: Sequence[Any]) -> Callable:
"""Method decorator for unit tests
"""Iterate over cartesian product creating sub tests.

This decorator iterates over the cartesian product of the supplied
settings, using `~unittest.TestCase.subTest` to communicate the values in
Expand Down
2 changes: 1 addition & 1 deletion python/lsst/utils/timer.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ def logInfo(obj: Any, prefix: str, logLevel: int = logging.DEBUG,
def timeMethod(_func: Optional[Any] = None, *, metadata: Optional[MutableMapping] = None,
logger: Optional[logging.Logger] = None,
logLevel: int = logging.DEBUG) -> Callable:
"""Decorator to measure duration of a method.
"""Measure duration of a method.

Parameters
----------
Expand Down
7 changes: 7 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ lsst.utils = py.typed

[pydocstyle]
convention = numpy
# Our coding style does not require docstrings for magic methods (D105)
# Our docstyle documents __init__ at the class level (D107)
# We allow methods to inherit docstrings and this is not compatible with D102.
# Docstring at the very first line is not required
# D200, D205 and D400 all complain if the first sentence of the docstring does
# not fit on one line.
add-ignore = D107, D105, D102, D100, D200, D205, D400

# The ignore list for flake8 itself when run on the command line is distinct
# from the ignore list used by the pytest-flake8 plugin. This provides more
Expand Down
1 change: 1 addition & 0 deletions ups/utils.table
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ setupRequired(cpputils)
setupRequired(sconsUtils)

envPrepend(PYTHONPATH, ${PRODUCT_DIR}/python)
envPrepend(MYPYPATH, ${PRODUCT_DIR}/python)