diff --git a/.codecov.yaml b/.codecov.yaml index bd2cef3..8fe09b7 100644 --- a/.codecov.yaml +++ b/.codecov.yaml @@ -4,3 +4,8 @@ coverage: project: default: threshold: 0.2% + +codecov: + require_ci_to_pass: false + notify: + wait_for_ci: true diff --git a/.codespellrc b/.codespellrc new file mode 100644 index 0000000..042a14e --- /dev/null +++ b/.codespellrc @@ -0,0 +1,13 @@ +[codespell] +skip = *.asdf,*.fits,*.fts,*.header,*.json,*.xsh,*cache*,*egg*,*extern*,.git,.idea,.tox,_build,*truncated,*.svg,.asv_env,.history +ignore-words-list = + alog, + nd, + nin, + observ, + ot, + te, + upto, + afile, + precessed, + precess diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..6b793fa --- /dev/null +++ b/.coveragerc @@ -0,0 +1,30 @@ +[run] +omit = + radiospectra/conftest.py + radiospectra/*setup_package* + radiospectra/extern/* + radiospectra/version* + */radiospectra/conftest.py + */radiospectra/*setup_package* + */radiospectra/extern/* + */radiospectra/version* + +[report] +exclude_lines = + # Have to re-enable the standard pragma + pragma: no cover + # Don't complain about packages we have installed + except ImportError + # Don't complain if tests don't hit assertions + raise AssertionError + raise NotImplementedError + # Don't complain about script hooks + def main(.*): + # Ignore branches that don't pertain to this version of Python + pragma: py{ignore_python_version} + # Don't complain about IPython completion helper + def _ipython_key_completions_ + # typing.TYPE_CHECKING is False at runtime + if TYPE_CHECKING: + # Ignore typing overloads + @overload diff --git a/.cruft.json b/.cruft.json new file mode 100644 index 0000000..713057a --- /dev/null +++ b/.cruft.json @@ -0,0 +1,31 @@ +{ + "template": "https://github.com/sunpy/package-template", + "commit": "ed1ad671639f78312b042a76075ea7e9073ab804", + "checkout": null, + "context": { + "cookiecutter": { + "package_name": "radiospectra", + "module_name": "radiospectra", + "short_description": "Provide support for some type of radio spectra in solar physics.", + "author_name": "The SunPy Community", + "author_email": "sunpy@googlegroups.com", + "project_url": "https://sunpy.org", + "license": "BSD 2-Clause", + "minimum_python_version": "3.10", + "use_compiled_extensions": "n", + "enable_dynamic_dev_versions": "y", + "include_example_code": "n", + "include_cruft_update_github_workflow": "y", + "_sphinx_theme": "alabaster", + "_parent_project": "", + "_install_requires": "", + "_copy_without_render": [ + "docs/_templates", + "docs/_static", + ".github/workflows/sub_package_update.yml" + ], + "_template": "https://github.com/sunpy/package-template" + } + }, + "directory": null +} diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..38db7b3 --- /dev/null +++ b/.flake8 @@ -0,0 +1,27 @@ +[flake8] +ignore = + # missing-whitespace-around-operator + E225 + # missing-whitespace-around-arithmetic-operator + E226 + # line-too-long + E501 + # unused-import + F401 + # undefined-local-with-import-star + F403 + # redefined-while-unused + F811 + # Line break occurred before a binary operator + W503, + # Line break occurred after a binary operator + W504 +max-line-length = 110 +exclude = + .git + __pycache__ + docs/conf.py + build + radiospectra/__init__.py +rst-directives = + plot diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e99ac15..aa4c852 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,21 +28,38 @@ jobs: toxdeps: tox-pypi-filter envs: | - linux: py312 + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + sdist_verify: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + - run: python -m pip install -U --user build + - run: python -m build . --sdist + - run: python -m pip install -U --user twine + - run: python -m twine check dist/* test: - needs: [core] + needs: [core, sdist_verify] uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@main with: submodules: false coverage: codecov toxdeps: tox-pypi-filter + posargs: -n auto envs: | - - macos: py311 - - windows: py310 + - windows: py311 + - macos: py310 - linux: py310-oldestdeps + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} docs: - needs: [test] + needs: [core] uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@main with: default_python: '3.12' @@ -56,6 +73,23 @@ jobs: envs: | - linux: build_docs + cron: + if: | + github.event_name == 'workflow_dispatch' || ( + github.event_name == 'pull_request' && + contains(github.event.pull_request.labels.*.name, 'Run cron CI') + ) + uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@main + with: + default_python: '3.12' + submodules: false + coverage: codecov + toxdeps: tox-pypi-filter + envs: | + - linux: py311-devdeps + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + online: if: "!startsWith(github.event.ref, 'refs/tags/v')" needs: [test] @@ -69,9 +103,10 @@ jobs: - linux: py312-devdeps publish: - # Build wheels when pushing to any branch except main - # publish.yml will only publish if tagged ^v.* + # Build wheels on PRs only when labelled. Releases will only be published if tagged ^v.* + # see https://github-actions-workflows.openastronomy.org/en/latest/publish.html#upload-to-pypi if: | + github.event_name != 'pull_request' || ( github.event_name != 'pull_request' && ( github.ref_name != 'main' || @@ -81,12 +116,12 @@ jobs: github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'Run publish') ) - needs: [test] + needs: [test, docs] uses: OpenAstronomy/github-actions-workflows/.github/workflows/publish_pure_python.yml@main with: - python-version: "3.12" - test_extras: 'dev' - test_command: 'pytest -p no:warnings --doctest-rst -m "not mpl_image_compare" --pyargs radiospectra' + python-version: '3.12' + test_extras: 'tests' + test_command: 'pytest -p no:warnings --doctest-rst --pyargs radiospectra' submodules: false secrets: pypi_token: ${{ secrets.pypi_token }} diff --git a/.github/workflows/sub_package_update.yml b/.github/workflows/sub_package_update.yml new file mode 100644 index 0000000..7455847 --- /dev/null +++ b/.github/workflows/sub_package_update.yml @@ -0,0 +1,79 @@ +# This template is taken from the cruft example code, for further information please see: +# https://cruft.github.io/cruft/#automating-updates-with-github-actions +name: Automatic Update from package template +permissions: + contents: write + pull-requests: write + +on: + # Allow manual runs through the web UI + workflow_dispatch: + schedule: + # ┌───────── minute (0 - 59) + # │ ┌───────── hour (0 - 23) + # │ │ ┌───────── day of the month (1 - 31) + # │ │ │ ┌───────── month (1 - 12 or JAN-DEC) + # │ │ │ │ ┌───────── day of the week (0 - 6 or SUN-SAT) + - cron: '0 7 * * 1' # Every Monday at 7am UTC + +jobs: + update: + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + include: + - add-paths: . + body: apply the changes to this repo. + branch: cruft/update + commit-message: "Automatic package template update" + title: Updates from the package template + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install Cruft + run: python -m pip install git+https://github.com/Cadair/cruft@patch-p1 + + - name: Check if update is available + continue-on-error: false + id: check + run: | + CHANGES=0 + if [ -f .cruft.json ]; then + if ! cruft check; then + CHANGES=1 + fi + else + echo "No .cruft.json file" + fi + + echo "has_changes=$CHANGES" >> "$GITHUB_OUTPUT" + + - name: Run update if available + if: steps.check.outputs.has_changes == '1' + run: | + git config --global user.email "${{ github.actor }}@users.noreply.github.com" + git config --global user.name "${{ github.actor }}" + + cruft update --skip-apply-ask --refresh-private-variables + git restore --staged . + + - name: Create pull request + if: steps.check.outputs.has_changes == '1' + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + add-paths: ${{ matrix.add-paths }} + commit-message: ${{ matrix.commit-message }} + branch: ${{ matrix.branch }} + delete-branch: true + branch-suffix: timestamp + title: ${{ matrix.title }} + body: | + This is an autogenerated PR, which will ${{ matrix.body }}. + [Cruft](https://cruft.github.io/cruft/) has detected updates from the Package Template diff --git a/.gitignore b/.gitignore index 09047e2..822a1c4 100644 --- a/.gitignore +++ b/.gitignore @@ -24,11 +24,12 @@ parts/ sdist/ var/ wheels/ +share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST - +radiospectra/_version.py # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. @@ -42,15 +43,17 @@ pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ +.nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover +*.py,cover .hypothesis/ .pytest_cache/ -junit/ +cover/ # Translations *.mo @@ -60,6 +63,7 @@ junit/ *.log local_settings.py db.sqlite3 +db.sqlite3-journal # Flask stuff: instance/ @@ -70,18 +74,47 @@ instance/ # Sphinx documentation docs/_build/ +# automodapi +docs/api +docs/sg_execution_times.rst # PyBuilder +.pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints -# pyenv -.python-version +# IPython +profile_default/ +ipython_config.py -# celery beat schedule file +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff celerybeat-schedule +celerybeat.pid # SageMath parsed files *.sage.py @@ -95,10 +128,6 @@ ENV/ env.bak/ venv.bak/ -# Spyder project settings -.spyderproject -.spyproject - # Rope project settings .ropeproject @@ -108,8 +137,22 @@ venv.bak/ # mypy .mypy_cache/ -### https://raw.github.com/github/gitignore/master/Global/OSX.gitignore +# Pyre type checker +.pyre/ + +# IDE +# PyCharm +.idea + +# Spyder project settings +.spyderproject +.spyproject +### VScode: https://raw.githubusercontent.com/github/gitignore/master/Global/VisualStudioCode.gitignore +.vscode/* +.vs/* + +### https://raw.github.com/github/gitignore/master/Global/OSX.gitignore .DS_Store .AppleDouble .LSOverride @@ -117,7 +160,6 @@ venv.bak/ # Icon must ends with two \r. Icon - # Thumbnails ._* @@ -126,7 +168,6 @@ Icon .Trashes ### Linux: https://raw.githubusercontent.com/github/gitignore/master/Global/Linux.gitignore - *~ # temporary files which can be created if a process still has a handle open of a deleted file @@ -141,7 +182,8 @@ Icon # .nfs files are created when an open file is removed but is still being accessed .nfs* -### MacOS: https://raw.githubusercontent.com/github/gitignore/master/Global/macOS.gitignore +# pytype static type analyzer +.pytype/ # General .DS_Store @@ -197,27 +239,12 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk -### VScode: https://raw.githubusercontent.com/github/gitignore/master/Global/VisualStudioCode.gitignore -.vscode/* -.vs/* - -### Extra Python Items and radiospectra Specific -.hypothesis -.pytest_cache -radiospectra/_compiler.c -radiospectra/cython_version.py -docs/_build -docs/generated -docs/api/ +### Extra Python Items and SunPy Specific docs/whatsnew/latest_changelog.txt -examples/**/*.asdf examples/**/*.csv figure_test_images* tags -radiospectra/_version.py - -### Pycharm(?) -.idea +baseline # Release script .github_cache @@ -226,3 +253,10 @@ radiospectra/_version.py .history *.orig .tmp +node_modules/ +package-lock.json +package.json +.prettierrc + +# Log files generated by 'vagrant up' +*.log diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 0000000..3db949c --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,16 @@ +[settings] +balanced_wrapping = true +skip = + docs/conf.py + radiospectra/__init__.py +default_section = THIRDPARTY +include_trailing_comma = true +known_astropy = astropy, asdf +known_sunpy = sunpy +known_first_party = radiospectra +length_sort = false +length_sort_sections = stdlib +line_length = 110 +multi_line_output = 3 +no_lines_before = LOCALFOLDER +sections = STDLIB, THIRDPARTY, ASTROPY, SUNPY, FIRSTPARTY, LOCALFOLDER diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7c56f19..64ced18 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,33 +1,35 @@ repos: - - repo: https://github.com/PyCQA/autoflake - rev: v2.3.1 + # This should be before any formatting hooks like isort + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: "v0.6.9" + hooks: + - id: ruff + args: ["--fix"] + - repo: https://github.com/PyCQA/isort + rev: 5.13.2 hooks: - - id: autoflake - args: ['--in-place', '--remove-all-unused-imports', '--remove-unused-variable'] - exclude: ".*(.fits|.fts|.fit|.txt|tca.*|extern.*|.rst|.md|__init__.py|docs/conf.py)$" - - repo: https://github.com/psf/black - rev: 24.4.2 - hooks: - - id: black - exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" - - repo: https://github.com/PyCQA/isort - rev: 5.13.2 - hooks: - id: isort - exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 - hooks: + exclude: ".*(.fits|.fts|.fit|.header|.txt|tca.*|extern.*|radiospectra/extern)$" + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: - id: check-ast - id: check-case-conflict - id: trailing-whitespace - exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" - - id: mixed-line-ending - exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" - - id: end-of-file-fixer - exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" + exclude: ".*(.fits|.fts|.fit|.header|.txt)$" - id: check-yaml - id: debug-statements + - id: check-added-large-files + args: ["--enforce-all", "--maxkb=1054"] + - id: end-of-file-fixer + exclude: ".*(.fits|.fts|.fit|.header|.txt|tca.*|.json)$|^CITATION.rst$" + - id: mixed-line-ending + exclude: ".*(.fits|.fts|.fit|.header|.txt|tca.*)$" + - repo: https://github.com/codespell-project/codespell + rev: v2.3.0 + hooks: + - id: codespell + args: [ "--write-changes" ] ci: autofix_prs: false autoupdate_schedule: "quarterly" diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..3d9312d --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,29 @@ +version: 2 + +build: + os: ubuntu-lts-latest + tools: + python: "mambaforge-latest" + jobs: + post_checkout: + - git fetch --unshallow || true + pre_install: + - git update-index --assume-unchanged .rtd-environment.yml docs/conf.py + +conda: + environment: .rtd-environment.yml + +sphinx: + builder: html + configuration: docs/conf.py + fail_on_warning: false + +formats: + - htmlzip + +python: + install: + - method: pip + extra_requirements: + - docs + path: . diff --git a/.rtd-environment.yml b/.rtd-environment.yml new file mode 100644 index 0000000..11dcaa3 --- /dev/null +++ b/.rtd-environment.yml @@ -0,0 +1,7 @@ +name: radiospectra +channels: + - conda-forge +dependencies: + - python=3.12 + - pip + - graphviz!=2.42.*,!=2.43.* diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 0000000..269c162 --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,37 @@ +target-version = "py310" +line-length = 110 +exclude = [ + ".git,", + "__pycache__", + "build", + "radiospectra/version.py", +] + +[lint] +select = ["E", "F", "W", "UP", "PT"] +extend-ignore = [ + # pycodestyle (E, W) + "E501", # LineTooLong # TODO! fix + # pytest (PT) + "PT001", # Always use pytest.fixture() + "PT004", # Fixtures which don't return anything should have leading _ + "PT007", # Parametrize should be lists of tuples # TODO! fix + "PT011", # Too broad exception assert # TODO! fix + "PT023", # Always use () on pytest decorators +] + +[lint.per-file-ignores] +# Part of configuration, not a package. +"setup.py" = ["INP001"] +"conftest.py" = ["INP001"] +"docs/conf.py" = [ + "E402" # Module imports not at top of file +] +"docs/*.py" = [ + "INP001", # Implicit-namespace-package. The examples are not a package. +] +"__init__.py" = ["E402", "F401", "F403"] +"test_*.py" = ["B011", "D", "E402", "PGH001", "S101"] + +[lint.pydocstyle] +convention = "numpy" diff --git a/MANIFEST.in b/MANIFEST.in index 4d9de8b..5ea013a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1,11 @@ +# Exclude specific files +# All files which are tracked by git and not explicitly excluded here are included by setuptools_scm +# Prune folders +prune build +prune docs/_build +prune docs/api +global-exclude *.pyc *.o + +# This subpackage is only used in development checkouts +# and should not be included in built tarballs prune radiospectra/_dev diff --git a/README.rst b/README.rst index 75ea082..db482ee 100644 --- a/README.rst +++ b/README.rst @@ -43,11 +43,49 @@ For more information or to ask questions about ``radiospectra`` or any other Sun - `SunPy Chat`_ - `SunPy mailing list `__ + +License +======= + +This project is Copyright (c) The SunPy Community and licensed under +the terms of the BSD 2-Clause license. This package is based upon +the `Openastronomy packaging guide `_ +which is licensed under the BSD 3-clause licence. See the licenses folder for +more information. + + + Contributing ============ -If you would like to get involved, start by joining the `SunPy Chat`_ and check out our `Newcomers' guide `__. -This will walk you through getting set up for contributing. +We love contributions! radiospectra is open source, +built on open source, and we'd love to have you hang out in our community. + +**Imposter syndrome disclaimer**: We want your help. No, really. + +There may be a little voice inside your head that is telling you that you're not +ready to be an open source contributor; that your skills aren't nearly good +enough to contribute. What could you possibly offer a project like this one? + +We assure you - the little voice in your head is wrong. If you can write code at +all, you can contribute code to open source. Contributing to open source +projects is a fantastic way to advance one's coding skills. Writing perfect code +isn't the measure of a good developer (that would disqualify all of us!); it's +trying to create something, making mistakes, and learning from those +mistakes. That's how we all improve, and we are happy to help others learn. + +Being an open source contributor doesn't just mean writing code, either. You can +help out by writing documentation, tests, or even giving feedback about the +project (and yes - that includes giving feedback about the contribution +process). Some of these contributions may be the most valuable to the project as +a whole, because you're coming to the project with fresh eyes, so you can see +the errors and assumptions that seasoned contributors have glossed over. + +Note: This disclaimer was originally written by +`Adrienne Lowe `_ for a +`PyCon talk `_, and was adapted by +radiospectra based on its use in the README file for the +`MetPy project `_. Code of Conduct =============== diff --git a/docs/conf.py b/docs/conf.py index c8e909c..fcfa935 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,14 +1,13 @@ -""" -Configuration file for the Sphinx documentation builder. - -isort:skip_file -""" +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config # flake8: NOQA: E402 # -- stdlib imports ------------------------------------------------------------ import os -import sys import datetime from packaging.version import Version @@ -23,53 +22,33 @@ os.environ["LC_ALL"] = "C" os.environ["HIDE_PARFIVE_PROGESS"] = "True" -# -- Non stdlib imports -------------------------------------------------------- + +# -- Project information ----------------------------------------------------- +# The full version, including alpha/beta/rc tags from radiospectra import __version__ # NOQA -# -- Project information ------------------------------------------------------- +_version = Version(__version__) +version = release = str(_version) +# Avoid "post" appearing in version string in rendered docs +if _version.is_postrelease: + version = release = _version.base_version +# Avoid long githashes in rendered Sphinx docs +elif _version.is_devrelease: + version = release = f"{_version.base_version}.dev{_version.dev}" +is_development = _version.is_devrelease +is_release = not(_version.is_prerelease or _version.is_devrelease) + project = "radiospectra" author = "The SunPy Community" -copyright = "{}, {}".format(datetime.datetime.now().year, author) +copyright = f"{datetime.datetime.now().year}, {author}" # noqa: A001 -# The full version, including alpha/beta/rc tags -release = __version__ -radiospectra_version = Version(__version__) -is_release = not (radiospectra_version.is_prerelease or radiospectra_version.is_devrelease) - -# For the linkcheck -linkcheck_ignore = [ - r"https://doi.org/\d+", - r"https://element.io/\d+", - r"https://github.com/\d+", - r"https://docs.sunpy.org/\d+", -] -linkcheck_anchors = False - -# This is added to the end of RST files - a good place to put substitutions to -# be used globally. -rst_epilog = """ -.. SunPy -.. _SunPy: https://sunpy.org -.. _`SunPy mailing list`: https://groups.google.com/group/sunpy -.. _`SunPy dev mailing list`: https://groups.google.com/group/sunpy-dev -""" - -# -- General configuration ----------------------------------------------------- - -# Suppress warnings about overriding directives as we overload some of the -# doctest extensions. -suppress_warnings = [ - "app.add_directive", -] +# -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# extensions coming with Sphinx (named "sphinx.ext.*") or your custom # ones. extensions = [ "matplotlib.sphinxext.plot_directive", - "sphinx_automodapi.automodapi", - "sphinx_automodapi.smart_resolver", - "sphinx_changelog", "sphinx.ext.autodoc", "sphinx.ext.coverage", "sphinx.ext.doctest", @@ -79,20 +58,17 @@ "sphinx.ext.napoleon", "sphinx.ext.todo", "sphinx.ext.viewcode", + "sphinx_automodapi.automodapi", + "sphinx_automodapi.smart_resolver", ] # Add any paths that contain templates here, relative to this directory. -# templates_path = ['_templates'] +# templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. html_extra_path = ["robots.txt"] - exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The suffix(es) of source filenames. @@ -102,51 +78,15 @@ # The master toctree document. master_doc = "index" -# The reST default role (used for this markup: `text`) to use for all -# documents. Set to the "smart" one. -default_role = "obj" - -# Disable having a separate return type row -napoleon_use_rtype = False +# Treat everything in single ` as a Python reference. +default_role = "py:obj" -# Disable google style docstrings -napoleon_google_docstring = False - -# -- Options for intersphinx extension ----------------------------------------- +# -- Options for intersphinx extension --------------------------------------- # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = { - "python": ( - "https://docs.python.org/3/", - (None, "http://www.astropy.org/astropy-data/intersphinx/python3.inv"), - ), - "numpy": ( - "https://numpy.org/doc/stable/", - (None, "http://www.astropy.org/astropy-data/intersphinx/numpy.inv"), - ), - "scipy": ( - "https://docs.scipy.org/doc/scipy/reference/", - (None, "http://www.astropy.org/astropy-data/intersphinx/scipy.inv"), - ), - "matplotlib": ( - "https://matplotlib.org/", - (None, "http://www.astropy.org/astropy-data/intersphinx/matplotlib.inv"), - ), - "sunpy": ( - "https://sunpy.org/", - (None, "https://docs.sunpy.org/en/stable/"), - ), - "astropy": ("https://docs.astropy.org/en/stable/", None), - "sqlalchemy": ("https://docs.sqlalchemy.org/en/latest/", None), - "pandas": ("https://pandas.pydata.org/pandas-docs/stable/", None), - "skimage": ("https://scikit-image.org/docs/stable/", None), - "drms": ("https://docs.sunpy.org/projects/drms/en/stable/", None), - "parfive": ("https://parfive.readthedocs.io/en/stable/", None), - "reproject": ("https://reproject.readthedocs.io/en/stable/", None), - "aiapy": ("https://aiapy.readthedocs.io/en/stable/", None), -} - -# -- Options for HTML output --------------------------------------------------- +intersphinx_mapping = {"python": ("https://docs.python.org/", None)} + +# -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. @@ -155,7 +95,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = ['_static'] +# html_static_path = ["_static"] # Render inheritance diagrams in SVG graphviz_output_format = "svg" @@ -168,3 +108,14 @@ "-Gfontsize=10", "-Gfontname=Helvetica Neue, Helvetica, Arial, sans-serif", ] + +# By default, when rendering docstrings for classes, sphinx.ext.autodoc will +# make docs with the class-level docstring and the class-method docstrings, +# but not the __init__ docstring, which often contains the parameters to +# class constructors across the scientific Python ecosystem. The option below +# will append the __init__ docstring to the class-level docstring when rendering +# the docs. For more options, see: +# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autoclass_content +autoclass_content = "both" + +# -- Other options ---------------------------------------------------------- diff --git a/docs/index.rst b/docs/index.rst index 8b8ae22..1899900 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -48,6 +48,7 @@ When you are interacting with the SunPy community you are asked to follow our `C .. toctree:: :maxdepth: 2 + :caption: Contents: overview code_ref/index diff --git a/docs/make.bat b/docs/make.bat index 922152e..2119f51 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -1,35 +1,35 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/licenses/LICENSE.rst b/licenses/LICENSE.rst new file mode 100644 index 0000000..8fcd399 --- /dev/null +++ b/licenses/LICENSE.rst @@ -0,0 +1,22 @@ +Copyright (c) 2024, The SunPy Community + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/TEMPLATE_LICENSE.rst b/licenses/TEMPLATE_LICENSE.rst index f29177b..544a2db 100644 --- a/licenses/TEMPLATE_LICENSE.rst +++ b/licenses/TEMPLATE_LICENSE.rst @@ -1,10 +1,10 @@ -This project is based upon the Astropy package template -(https://github.com/astropy/package-template/) which is licenced under the terms +This project is based upon the OpenAstronomy package template +(https://github.com/OpenAstronomy/package-template/) which is licensed under the terms of the following licence. --- -Copyright (c) 2018, Astropy Developers +Copyright (c) 2018, OpenAstronomy Developers All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/pyproject.toml b/pyproject.toml index c7698f1..9ca294d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,60 @@ [build-system] requires = [ - "setuptools>=56,!=61.0.0", + "setuptools>=62.1", "setuptools_scm[toml]>=6.2", "wheel", ] -build-backend = 'setuptools.build_meta' +build-backend = "setuptools.build_meta" + +[project] +name = "radiospectra" +description = "Provide support for some type of radio spectra in solar physics." +requires-python = ">=3.10" +readme = { file = "README.rst", content-type = "text/x-rst" } +license = { file = "licenses/LICENSE.rst" } +authors = [ + { name = "The SunPy Community", email = "sunpy@googlegroups.com" }, +] +dependencies = [ + "sunpy[net]>=6.0.0", + "numpy>1.24", + "matplotlib>=3.7", + "scipy>=1.10", + "cdflib>=0.3.20" +] +dynamic = ["version"] + +[project.optional-dependencies] +tests = [ + "pytest", + "pytest-astropy", + "pytest-doctestplus", + "pytest-cov", + "pytest-xdist", + "sunpy-soar", +] +docs = [ + "sphinx", + "sphinx-automodapi", + "sphinx-changelog", + "sphinx-gallery", + "sunpy-sphinx-theme", + "packaging", + +] +[project.urls] +repository = "https://sunpy.org" + +[tool.setuptools] +zip-safe = false +include-package-data = true + +[tool.setuptools.packages.find] +include = ["radiospectra*"] +exclude = ["radiospectra._dev*"] + +[tool.setuptools_scm] +write_to = "radiospectra/_version.py" [tool.black] line-length = 120 diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..e02cb4f --- /dev/null +++ b/pytest.ini @@ -0,0 +1,45 @@ +[pytest] +minversion = 7.0 +testpaths = + radiospectra + docs +norecursedirs = + .tox + build + docs/_build + docs/generated + *.egg-info + examples + radiospectra/_dev + .history + radiospectra/extern +doctest_plus = enabled +doctest_optionflags = + NORMALIZE_WHITESPACE + FLOAT_CMP + ELLIPSIS +text_file_format = rst +addopts = + --doctest-rst + -p no:unraisableexception + -p no:threadexception +filterwarnings = + # A list of warnings to ignore follows. If you add to this list, you MUST + error + # + # A list of warnings to ignore follows. If you add to this list, you MUST + # add a comment or ideally a link to an issue that explains why the warning + # is being ignored + # + # + # This is due to dependencies building with a numpy version different from + # the local installed numpy version, but should be fine + # See https://github.com/numpy/numpy/issues/15748#issuecomment-598584838 + ignore:numpy.ufunc size changed:RuntimeWarning + ignore:numpy.ndarray size changed:RuntimeWarning + # Zeep + ignore:'cgi' is deprecated:DeprecationWarning + # Issue with pytest-cov injecting --rsync arg https://github.com/pytest-dev/pytest-xdist/issues/825 + # https://github.com/pytest-dev/pytest-cov/issues/557 + ignore:The --rsyncdir command line argument and rsyncdirs config variable are deprecated.:DeprecationWarning + ignore:File may have been truncated.* diff --git a/radiospectra/__init__.py b/radiospectra/__init__.py index 84ebce5..d4ced70 100644 --- a/radiospectra/__init__.py +++ b/radiospectra/__init__.py @@ -1,14 +1,3 @@ -""" -================ -``radiospectra`` -================ - -An open-source Python library for radio spectra in solar physics. - -* Homepage: https://sunpy.org -* Documentation: https://docs.radiospectra.org/en/stable/ -* Source code: https://github.com/sunpy/radiospectra -""" from .version import version as __version__ diff --git a/radiospectra/_dev/__init__.py b/radiospectra/_dev/__init__.py index f1bff50..e38b3a8 100644 --- a/radiospectra/_dev/__init__.py +++ b/radiospectra/_dev/__init__.py @@ -1,5 +1,6 @@ """ -This package contains utilities that are only used when developing radiospectra in a copy of the source repository. - -These files are not installed, and should not be assumed to exist at runtime. +This package contains utilities that are only used when developing in a +copy of the source repository. +These files are not installed, and should not be assumed to exist at +runtime. """ diff --git a/radiospectra/_dev/scm_version.py b/radiospectra/_dev/scm_version.py index b8913a9..1bcf0dd 100644 --- a/radiospectra/_dev/scm_version.py +++ b/radiospectra/_dev/scm_version.py @@ -5,8 +5,8 @@ try: from setuptools_scm import get_version - version = get_version(root=os.path.join("..", ".."), relative_to=__file__) + version = get_version(root=os.path.join('..', '..'), relative_to=__file__) except ImportError: - raise ImportError("setuptools_scm not installed") + raise except Exception as e: - raise ValueError(f"setuptools_scm broken with {e}") + raise ValueError('setuptools_scm can not determine version.') from e diff --git a/radiospectra/data/README.rst b/radiospectra/data/README.rst new file mode 100644 index 0000000..382f6e7 --- /dev/null +++ b/radiospectra/data/README.rst @@ -0,0 +1,6 @@ +Data directory +============== + +This directory contains data files included with the package source +code distribution. Note that this is intended only for relatively small files +- large files should be externally hosted and downloaded as needed. diff --git a/radiospectra/tests/__init__.py b/radiospectra/tests/__init__.py index e69de29..92ea707 100644 --- a/radiospectra/tests/__init__.py +++ b/radiospectra/tests/__init__.py @@ -0,0 +1,3 @@ +""" +This module contains package tests. +""" diff --git a/radiospectra/version.py b/radiospectra/version.py index bf0f914..515c2f0 100644 --- a/radiospectra/version.py +++ b/radiospectra/version.py @@ -1,5 +1,5 @@ # NOTE: First try _dev.scm_version if it exists and setuptools_scm is installed -# This file is not included in sunpy wheels/tarballs, so otherwise it will +# This file is not included in wheels/tarballs, so otherwise it will # fall back on the generated _version module. try: try: @@ -9,30 +9,9 @@ except Exception: import warnings - warnings.warn(f'could not determine {__name__.split(".")[0]} package version; this indicates a broken installation') + warnings.warn( + f'could not determine {__name__.split(".")[0]} package version; this indicates a broken installation' + ) del warnings - version = "0.0.0" - - -# We use LooseVersion to define major, minor, micro, but ignore any suffixes. -def split_version(version): - pieces = [0, 0, 0] - - try: - from distutils.version import LooseVersion - - for j, piece in enumerate(LooseVersion(version).version[:3]): - pieces[j] = int(piece) - - except Exception: - pass - - return pieces - - -major, minor, bugfix = split_version(version) - -del split_version # clean up namespace. - -release = "dev" not in version + version = '0.0.0' diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 46e22c8..0000000 --- a/setup.cfg +++ /dev/null @@ -1,150 +0,0 @@ -[metadata] -name = radiospectra -provides = radiospectra -description = Provide support for some type of radio spectra in solar physics -long_description = file: README.rst -long_description_content_type = text/x-rst -author = The SunPy Community -author_email = sunpy@googlegroups.com -license = BSD 2-Clause -license_files = LICENSE.rst -url = https://sunpy.org -edit_on_github = True -github_project = sunpy/radiospectra -platform = any -keywords = solar physics, solar, science, sun, wcs, coordinates, radio, spectra -classifiers = - Development Status :: 3 - Alpha - Intended Audience :: Science/Research - License :: OSI Approved :: BSD License - Natural Language :: English - Operating System :: OS Independent - Programming Language :: Python - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3.11 - Programming Language :: Python :: 3.12 - Topic :: Scientific/Engineering :: Physics - -[options] -zip_safe = False -python_requires = >=3.10 -packages = find: -include_package_data = True -setup_requires = - setuptools_scm -install_requires = - sunpy[net]>=6.0.0 - numpy - matplotlib - scipy - cdflib>=0.3.20 - -[options.packages.find] -exclude = radiospectra._dev - -[options.extras_require] -tests = - pytest-astropy - pytest-doctestplus - sunpy-soar -docs = - sphinx-automodapi - sphinx-changelog - sphinx-gallery - sphinx - sunpy-sphinx-theme - -[options.package_data] -radiospectra = data/* - -[tool:pytest] -testpaths = "radiospectra" "docs" -norecursedirs = ".tox" "build" "docs[\/]_build" "docs[\/]generated" "*.egg-info" "examples" ".jupyter" ".history" "tools" "radiospectra[\/]_dev" -doctest_plus = enabled -doctest_optionflags = NORMALIZE_WHITESPACE FLOAT_CMP ELLIPSIS -addopts = --doctest-rst --doctest-ignore-import-errors -p no:unraisableexception -p no:threadexception -markers = - remote_data: marks this test function as needing remote data. - online: marks this test function as needing online connectivity. -remote_data_strict = True -# Pin junit behaviour; we might want to update this to xunit2 at some point -junit_family=xunit1 -filterwarnings = - error - # - # A list of warnings to ignore follows. If you add to this list, you MUST - # add a comment or ideally a link to an issue that explains why the warning - # is being ignored - # - # - # This is due to dependencies building with a numpy version different from - # the local installed numpy version, but should be fine - # See https://github.com/numpy/numpy/issues/15748#issuecomment-598584838 - ignore:numpy.ufunc size changed:RuntimeWarning - ignore:numpy.ndarray size changed:RuntimeWarning - # Zeep - ignore:'cgi' is deprecated:DeprecationWarning - # Issue with pytest-cov injecting --rsync arg https://github.com/pytest-dev/pytest-xdist/issues/825 - # https://github.com/pytest-dev/pytest-cov/issues/557 - ignore:The --rsyncdir command line argument and rsyncdirs config variable are deprecated.:DeprecationWarning - ignore:File may have been truncated.* - -[pycodestyle] -max_line_length = 100 - -[flake8] -max-line-length = 100 -exclude = - .git, - __pycache__, - docs/conf.py, - build, -rst-directives = - plot - -[isort] -balanced_wrapping = True -skip=docs/conf.py -default_section = THIRDPARTY -include_trailing_comma = True -known_astropy = astropy, asdf, sunpy -length_sort = False -length_sort_sections=stdlib -line_length = 110 -multi_line_output = 3 -no_lines_before = LOCALFOLDER -sections = STDLIB, THIRDPARTY, ASTROPY, FIRSTPARTY, LOCALFOLDER - -[coverage:run] -omit = - radiospectra/_sunpy_init* - radiospectra/conftest.py - radiospectra/*setup_package* - radiospectra/tests/* - radiospectra/*/tests/* - radiospectra/extern/* - radiospectra/version* - */radiospectra/_sunpy_init* - */radiospectra/conftest.py - */radiospectra/*setup_package* - */radiospectra/tests/* - */radiospectra/*/tests/* - */radiospectra/extern/* - */radiospectra/version* - -[coverage:report] -exclude_lines = - # Have to re-enable the standard pragma - pragma: no cover - # Don't complain about packages we have installed - except ImportError - # Don't complain if tests don't hit assertions - raise AssertionError - raise NotImplementedError - # Don't complain about script hooks - def main\(.*\): - # Ignore branches that don't pertain to this version of Python - pragma: py{ignore_python_version} - # Don't complain about IPython completion helper - def _ipython_key_completions_ diff --git a/setup.py b/setup.py index ee9f057..c823345 100755 --- a/setup.py +++ b/setup.py @@ -1,30 +1,4 @@ #!/usr/bin/env python -from setuptools import setup # isort:skip -import os -from itertools import chain +from setuptools import setup -try: - # Recommended for setuptools 61.0.0+ - # (though may disappear in the future) - from setuptools.config.setupcfg import read_configuration -except ImportError: - from setuptools.config import read_configuration - -################################################################################ -# Programmatically generate some extras combos. -################################################################################ -extras = read_configuration("setup.cfg")["options"]["extras_require"] - -# Dev is everything -extras["dev"] = list(chain(*extras.values())) - -# All is everything but tests and docs -exclude_keys = ("tests", "docs", "dev") -ex_extras = dict(filter(lambda i: i[0] not in exclude_keys, extras.items())) -# Concatenate all the values together for 'all' -extras["all"] = list(chain.from_iterable(ex_extras.values())) - -setup( - extras_require=extras, - use_scm_version={"write_to": os.path.join("radiospectra", "_version.py")}, -) +setup() diff --git a/tox.ini b/tox.ini index 243cb2f..3787b80 100644 --- a/tox.ini +++ b/tox.ini @@ -1,51 +1,72 @@ [tox] -minversion = 4.0.0 +min_version = 4.0 +requires = + tox-pypi-filter>=0.14 envlist = - py{310,311,312}{,-oldestdeps,-devdeps,-online} - build_docs + py{310,311,312} + py312-devdeps + py310-oldestdeps codestyle -requires = - tox-pypi-filter + build_docs [testenv] pypi_filter = https://raw.githubusercontent.com/sunpy/sunpy/main/.test_package_pins.txt -changedir = .tmp/{envname} +# Run the tests in a temporary directory to make sure that we don't import +# the package from the source tree +change_dir = .tmp/{envname} description = run tests - devdeps: with the latest developer version of key dependencies oldestdeps: with the oldest supported version of key dependencies - online: that require remote data -setenv = + devdeps: with the latest developer version of key dependencies +pass_env = + # A variable to tell tests we are on a CI system + CI + # Custom compiler locations (such as ccache) + CC + # Location of locales (needed by sphinx on some systems) + LOCALE_ARCHIVE + # If the user has set a LC override we should follow it + LC_ALL +set_env = MPLBACKEND = agg COLUMNS = 180 PARFIVE_HIDE_PROGRESS = True - PYTEST_COMMAND = pytest -vvv -s -ra --pyargs radiospectra --cov-report=xml --cov=radiospectra --cov-config={toxinidir}/setup.cfg {toxinidir}/docs devdeps,build_docs,online: HOME = {envtmpdir} SUNPY_SAMPLEDIR = {env:SUNPY_SAMPLEDIR:{toxinidir}/.tox/{envname}/sample_data/} devdeps: PIP_EXTRA_INDEX_URL = https://pypi.anaconda.org/astropy/simple https://pypi.anaconda.org/scientific-python-nightly-wheels/simple deps = + # For packages which publish nightly wheels this will pull the latest nightly + devdeps: numpy>=0.0.dev0 devdeps: git+https://github.com/sunpy/sunpy devdeps: matplotlib>=0.0.dev0 devdeps: scipy>=0.0.dev0 - oldestdeps: sunpy<5.1 + # Packages without nightly wheels will be built from source like this + # devdeps: git+https://github.com/ndcube/ndcube + oldestdeps: minimum_dependencies online: pytest-rerunfailures online: pytest-timeout +# The following indicates which extras_require will be installed extras = all tests +commands_pre = + oldestdeps: minimum_dependencies radiospectra --filename requirements-min.txt + oldestdeps: pip install -r requirements-min.txt + pip freeze --all --no-input commands = + # To amend the pytest command for different factors you can add a line + # which starts with a factor like `online: --remote-data=any \` + # If you have no factors which require different commands this is all you need: !online-!hypothesis-!figure: {env:PYTEST_COMMAND} {posargs} - online: {env:PYTEST_COMMAND} --reruns 2 --timeout=180 --remote-data=any {posargs} - -[testenv:build_docs] -changedir = docs -description = Invoke sphinx-build to build the HTML docs -extras = - all - docs -commands = - sphinx-build --color -W --keep-going -b html -d _build/.doctrees . _build/html {posargs} - python -c 'import pathlib; print("Documentation available under file://\{0\}".format(pathlib.Path(r"{toxinidir}") / "docs" / "_build" / "index.html"))' + pytest \ + -vvv \ + -r fEs \ + --pyargs radiospectra \ + --cov-report=xml \ + --cov=radiospectra \ + --cov-config={toxinidir}/.coveragerc \ + {toxinidir}/docs \ + {posargs} [testenv:codestyle] pypi_filter = @@ -55,4 +76,13 @@ deps = pre-commit commands = pre-commit install-hooks - pre-commit run --verbose --all-files --show-diff-on-failure + pre-commit run --color always --all-files --show-diff-on-failure + +[testenv:build_docs] +description = invoke sphinx-build to build the HTML docs +change_dir = + docs +extras = + docs +commands = + sphinx-build -j auto --color -W --keep-going -b html -d _build/.doctrees . _build/html {posargs}