diff --git a/.cruft.json b/.cruft.json index f2f3b97..e13da47 100644 --- a/.cruft.json +++ b/.cruft.json @@ -1,6 +1,6 @@ { "template": "https://github.com/scverse/cookiecutter-scverse", - "commit": "8148f720e622a82345bfc18b74b2bd288d12f7d5", + "commit": "28f47a97470826ca5000df24fd272e0d32d1c6fa", "context": { "cookiecutter": { "project_name": "infercnvpy", @@ -11,10 +11,13 @@ "github_user": "grst", "project_repo": "https://github.com/icbi-lab/infercnvpy", "license": "BSD 3-Clause License", - "_copy_without_render": [".github/workflows/**.yaml"], + "_copy_without_render": [ + ".github/workflows/**.yaml", + "docs/_templates/autosummary/**.rst" + ], "_template": "https://github.com/scverse/cookiecutter-scverse" } }, "directory": null, - "checkout": "v0.0.2" + "checkout": "v0.0.3" } diff --git a/.flake8 b/.flake8 index 8d014c6..5535753 100644 --- a/.flake8 +++ b/.flake8 @@ -10,32 +10,28 @@ ignore = E501 # whitespace before : -> black does not adhere to PEP8 E203 + # line break before binary operator -> black does not adhere to PEP8 + W503 # missing whitespace after ,', ';', or ':' -> black does not adhere to PEP8 E231 # continuation line over-indented for hanging indent -> black does not adhere to PEP8 E126 - # E266 too many leading '#' for block comment -> this is fine for indicating sections + # too many leading '#' for block comment -> this is fine for indicating sections E262 # Do not assign a lambda expression, use a def -> lambda expression assignments are convenient E731 - # allow I, O, l as variable names -> I is the identity matrix, i, j, k, l is reasonable indexing notation + # allow I, O, l as variable names -> I is the identity matrix E741 # Missing docstring in public package D104 - # ... imported but unused - F401 # Missing docstring in public module D100 # Missing docstring in __init__ D107 - # Do not perform function calls in argument defaults. + # Errors from function calls in argument defaults. These are fine when the result is immutable. B008 - # line break before binary operator - W503 # Missing docstring in magic method D105 - # whitespace before ':' - E203 # format string does contain unindexed parameters P101 # first line should end with a period [Bug: doesn't work with single-line docstrings] @@ -58,6 +54,8 @@ rst-roles = class, func, ref, + cite:p, + cite:t, rst-directives = envvar, exception, diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..9dfd4ac --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,89 @@ +name: Bug report +description: Report something that is broken or incorrect +labels: bug +body: + - type: markdown + attributes: + value: | + **Note**: Please read [this guide](https://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports) + detailing how to provide the necessary information for us to reproduce your bug. In brief: + * Please provide exact steps how to reproduce the bug in a clean Python environment. + * In case it's not clear what's causing this bug, please provide the data or the data generation procecure. + * Sometimes it is not possible to share the data but usually it is possible to replicate problems on publicly + available datasets or to share a subset of your data. + + - type: textarea + id: report + attributes: + label: Report + description: A clear and concise description of what the bug is. + validations: + required: true + + - type: textarea + id: versions + attributes: + label: Version information + description: | + Please paste below the output of + + ```python + import session_info + session_info.show(html=False, dependencies=True) + ``` + placeholder: | + ----- + anndata 0.8.0rc2.dev27+ge524389 + session_info 1.0.0 + ----- + asttokens NA + awkward 1.8.0 + backcall 0.2.0 + cython_runtime NA + dateutil 2.8.2 + debugpy 1.6.0 + decorator 5.1.1 + entrypoints 0.4 + executing 0.8.3 + h5py 3.7.0 + ipykernel 6.15.0 + jedi 0.18.1 + mpl_toolkits NA + natsort 8.1.0 + numpy 1.22.4 + packaging 21.3 + pandas 1.4.2 + parso 0.8.3 + pexpect 4.8.0 + pickleshare 0.7.5 + pkg_resources NA + prompt_toolkit 3.0.29 + psutil 5.9.1 + ptyprocess 0.7.0 + pure_eval 0.2.2 + pydev_ipython NA + pydevconsole NA + pydevd 2.8.0 + pydevd_file_utils NA + pydevd_plugins NA + pydevd_tracing NA + pygments 2.12.0 + pytz 2022.1 + scipy 1.8.1 + setuptools 62.5.0 + setuptools_scm NA + six 1.16.0 + stack_data 0.3.0 + tornado 6.1 + traitlets 5.3.0 + wcwidth 0.2.5 + zmq 23.1.0 + ----- + IPython 8.4.0 + jupyter_client 7.3.4 + jupyter_core 4.10.0 + ----- + Python 3.9.13 | packaged by conda-forge | (main, May 27 2022, 16:58:50) [GCC 10.3.0] + Linux-5.18.6-arch1-1-x86_64-with-glibc2.35 + ----- + Session information updated at 2022-07-07 17:55 diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..5cad625 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Scverse Community Forum + url: https://discourse.scverse.org/ + about: If you have questions about “How to do X”, please ask them here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..26123f3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,11 @@ +name: Feature request +description: Propose a new feature for infercnvpy +labels: enhancement +body: + - type: textarea + id: description + attributes: + label: Description of feature + description: Please describe your suggestion for a new feature. It might help to describe a problem or use case, plus any alternatives that you have considered. + validations: + required: true diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 170325e..9e5d5fa 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -6,6 +6,7 @@ build: python: "3.10" sphinx: configuration: docs/conf.py + # disable this for more lenient docs builds fail_on_warning: true python: install: diff --git a/README.md b/README.md index dbacf35..3f6776e 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Please refer to the [documentation][link-docs]. In particular, the ## Installation You need to have Python 3.8 or newer installed on your system. If you don't have -Python installed, we recommend installing [Miniconda](https://docs.conda.io/en/latest/miniconda.html). +Python installed, we recommend installing [Mambaforge](https://github.com/conda-forge/miniforge#mambaforge). There are several alternative options to install infercnvpy: diff --git a/docs/_templates/autosummary/class.rst b/docs/_templates/autosummary/class.rst new file mode 100644 index 0000000..49f45ed --- /dev/null +++ b/docs/_templates/autosummary/class.rst @@ -0,0 +1,65 @@ +{{ fullname | escape | underline}} + +.. currentmodule:: {{ module }} + +.. add toctree option to make autodoc generate the pages + +.. autoclass:: {{ objname }} + +{% block attributes %} +{% if attributes %} +Attributes table +~~~~~~~~~~~~~~~~~~ + +.. autosummary:: +{% for item in attributes %} + ~{{ fullname }}.{{ item }} +{%- endfor %} +{% endif %} +{% endblock %} + +{% block methods %} +{% if methods %} +Methods table +~~~~~~~~~~~~~ + +.. autosummary:: +{% for item in methods %} + {%- if item != '__init__' %} + ~{{ fullname }}.{{ item }} + {%- endif -%} +{%- endfor %} +{% endif %} +{% endblock %} + +{% block attributes_documentation %} +{% if attributes %} +Attributes +~~~~~~~~~~~ + +{% for item in attributes %} +{{ item }} +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autoattribute:: {{ [objname, item] | join(".") }} +{%- endfor %} + +{% endif %} +{% endblock %} + +{% block methods_documentation %} +{% if methods %} +Methods +~~~~~~~ + +{% for item in methods %} +{%- if item != '__init__' %} +{{ item }} +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automethod:: {{ [objname, item] | join(".") }} +{%- endif -%} +{%- endfor %} + +{% endif %} +{% endblock %} diff --git a/docs/conf.py b/docs/conf.py index 2dcaf96..a693321 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,10 +17,11 @@ # -- Project information ----------------------------------------------------- info = metadata("infercnvpy") -project = info["Name"] +project_name = info["Name"] author = info["Author"] copyright = f"{datetime.now():%Y}, {author}." version = info["Version"] +repository_url = "https://github.com/" + "grst" + "/" + project_name # The full version, including alpha/beta/rc tags release = info["Version"] @@ -33,7 +34,7 @@ html_context = { "display_github": True, # Integrate GitHub "github_user": "icbi-lab", # Username - "github_repo": project, # Repo name + "github_repo": project_name, # Repo name "github_version": "main", # Version "conf_py_path": "/docs/", # Path in the checkout to the docs root } @@ -43,15 +44,14 @@ # Add any Sphinx extension module names here, as strings. # They can be extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ - "myst_parser", + "myst_nb", + "sphinx_copybutton", "sphinx.ext.autodoc", "sphinx.ext.intersphinx", "sphinx.ext.autosummary", "sphinx.ext.napoleon", "sphinxcontrib.bibtex", "sphinx_autodoc_typehints", - "scanpydoc.definition_list_typed_field", - "nbsphinx", "sphinx.ext.mathjax", *[p.stem for p in (HERE / "extensions").glob("*.py")], ] @@ -65,6 +65,25 @@ napoleon_use_rtype = True # having a separate entry generally helps readability napoleon_use_param = True myst_heading_anchors = 3 # create anchors for h1-h3 +myst_enable_extensions = [ + "amsmath", + "colon_fence", + "deflist", + "dollarmath", + "html_image", + "html_admonition", +] +myst_url_schemes = ("http", "https", "mailto") +nb_output_stderr = "remove" +nb_execution_mode = "off" +nb_merge_streams = True +typehints_defaults = "braces" + +source_suffix = { + ".rst": "restructuredtext", + ".ipynb": "myst-nb", + ".myst": "myst-nb", +} intersphinx_mapping = { "scanpy": ("https://scanpy.readthedocs.io/en/stable/", None), @@ -95,10 +114,16 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = "furo" +html_theme = "sphinx_book_theme" html_static_path = ["_static"] +html_title = project_name + +html_theme_options = { + "repository_url": repository_url, + "use_repository_button": True, +} -pygments_style = "sphinx" +pygments_style = "default" nitpick_ignore = [ # If building the documentation fails because of a missing link that is outside your control, diff --git a/docs/developer_docs.md b/docs/developer_docs.md index 3854bd5..4d1c9f1 100644 --- a/docs/developer_docs.md +++ b/docs/developer_docs.md @@ -20,6 +20,7 @@ On the RTD dashboard choose "Import a Project" and follow the instructions to ad that break the documentation. To do so, got to `Admin -> Advanced Settings`, check the `Build pull requests for this projects` option, and click `Save`. For more information, please refer to the [official RTD documentation](https://docs.readthedocs.io/en/stable/pull-requests.html). +- If you find the RTD builds are failing, you can disable the `fail_on_warning` option in `.readthedocs.yaml`. ### Coverage tests with _Codecov_ @@ -92,6 +93,8 @@ The following pre-commit checks are for errors and inconsistencies: - **check-case-conflict**: check files that would conflict with case-insensitive file systems. - [pyupgrade](https://github.com/asottile/pyupgrade): upgrade syntax for newer versions of the language. +- **forbid-to-commit**: Make sure that `*.rej` files cannot be commited. These files are created by the + [automated template sync](#automated-template-sync) if there's a merge conflict and need to be addressed manually. #### Notes on pre-commit checks @@ -240,6 +243,32 @@ in the root of the repository. Continuous integration will automatically run the [scanpy-test-docs]: https://scanpy.readthedocs.io/en/latest/dev/testing.html#writing-tests +### Automated template sync + +Automated template sync is enabled by default. This means that every night, a GitHub action runs [cruft][] to check +if a new version of the `scverse-cookiecutter` template got released. If there are any new changes, a pull request +proposing these changes is created automatically. This helps keeping the repository up-to-date with the latest +coding standards. + +It may happen that a template sync results in a merge conflict. If this is the case a `*.ref` file with the +diff is created. You need to manually address these changes and remove the `.rej` file when you are done. +The pull request can only be merged after all `*.rej` files have been removed. + +:::{tip} +The following hints may be useful to work with the template sync: + +- GitHub automatically disables scheduled actions if there has been not activity to the repository for 60 days. + You can re-enable or manually trigger the sync by navigating to `Actions` -> `Sync Template` in your GitHub repository. +- If you want to ignore certain files from the template update, you can add them to the `[tool.cruft]` section in the + `pyproject.toml` file in the root of your repository. More details are described in the + [cruft documentation][cruft-update-project]. +- To disable the sync entirely, simply remove the file `.github/workflows/sync.yaml`. + +::: + +[cruft]: https://cruft.github.io/cruft/ +[cruft-update-project]: https://cruft.github.io/cruft/#updating-a-project + ### Making a release #### Updating the version number @@ -289,15 +318,15 @@ Please write documentation for your package. This project uses [sphinx][] with t - the [myst][] extension allows to write documentation in markdown/Markedly Structured Text - [Numpy-style docstrings][numpydoc] (through the [napoloen][numpydoc-napoleon] extension). -- Jupyter notebooks as tutorials through [nbsphinx][] (See [Tutorials with nbsphinx](#tutorials-with-nbsphinx-and-jupyter-notebooks)) +- Jupyter notebooks as tutorials through [myst-nb][] (See [Tutorials with myst-nb](#tutorials-with-myst-nb-and-jupyter-notebooks)) - [Sphinx autodoc typehints][], to automatically reference annotated input and output types See the [scanpy developer docs](https://scanpy.readthedocs.io/en/latest/dev/documentation.html) for more information on how to write documentation. -### Tutorials with nbsphinx and jupyter notebooks +### Tutorials with myst-nb and jupyter notebooks -The documentation is set-up to render jupyter notebooks stored in the `docs/notebooks` directory using [nbsphinx][]. +The documentation is set-up to render jupyter notebooks stored in the `docs/notebooks` directory using [myst-nb][]. Currently, only notebooks in `.ipynb` format are supported that will be included with both their input and output cells. It is your reponsibility to update and re-run the notebook whenever necessary. @@ -305,8 +334,6 @@ If you are interested in automatically running notebooks as part of the continuo out [this feature request](https://github.com/scverse/cookiecutter-scverse/issues/40) in the `cookiecutter-scverse` repository. -[nbsphinx]: https://github.com/spatialaudio/nbsphinx - #### Hints - If you refer to objects from other packages, please add an entry to `intersphinx_mapping` in `docs/conf.py`. Only @@ -329,7 +356,7 @@ open _build/html/index.html [codecov docs]: https://docs.codecov.com/docs [pre-commit.ci]: https://pre-commit.ci/ [readthedocs.org]: https://readthedocs.org/ -[nbshpinx]: https://github.com/spatialaudio/nbsphinx +[myst-nb]: https://myst-nb.readthedocs.io/en/latest/ [jupytext]: https://jupytext.readthedocs.io/en/latest/ [pre-commit]: https://pre-commit.com/ [anndata]: https://github.com/scverse/anndata diff --git a/docs/extensions/.gitkeep b/docs/extensions/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/docs/extensions/typed_returns.py b/docs/extensions/typed_returns.py new file mode 100644 index 0000000..9447813 --- /dev/null +++ b/docs/extensions/typed_returns.py @@ -0,0 +1,29 @@ +# code from https://github.com/theislab/scanpy/blob/master/docs/extensions/typed_returns.py +# with some minor adjustment +import re + +from sphinx.application import Sphinx +from sphinx.ext.napoleon import NumpyDocstring + + +def _process_return(lines): + for line in lines: + m = re.fullmatch(r"(?P\w+)\s+:\s+(?P[\w.]+)", line) + if m: + # Once this is in scanpydoc, we can use the fancy hover stuff + yield f'-{m["param"]} (:class:`~{m["type"]}`)' + else: + yield line + + +def _parse_returns_section(self, section): + lines_raw = list(_process_return(self._dedent(self._consume_to_next_section()))) + lines = self._format_block(":returns: ", lines_raw) + if lines and lines[-1]: + lines.append("") + return lines + + +def setup(app: Sphinx): + """Set app.""" + NumpyDocstring._parse_returns_section = _parse_returns_section diff --git a/pyproject.toml b/pyproject.toml index 989f683..cf25e77 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,9 @@ dependencies = [ 'gtfparse>=1.2.1', 'pycairo>=1.20; sys_platform == "win32"', 'leidenalg', - 'pyreadr' + 'pyreadr', + # for debug logging (referenced from the issue template) + "session-info", ] [project.optional-dependencies] @@ -43,16 +45,15 @@ dev = [ ] doc = [ "sphinx>=4.2", - "furo", - "myst-parser", + "sphinx-book-theme>=0.3.3", + "myst-nb", "sphinxcontrib-bibtex>=1.0.0", - "scanpydoc[typehints]>=0.7.4", + "sphinx-autodoc-typehints", # for tutorial - 'nbsphinx>=0.6.0,!=0.8.8', # https://github.com/spatialaudio/nbsphinx/issues/620, should be patched in >=0.8.9 - 'jupytext', + "ipykernel", + "sphinx-copybutton", 'pycairo', 'jupyter_client', - 'ipykernel', ] test = [ "pytest", @@ -108,3 +109,15 @@ exclude = ''' [tool.jupytext] formats = "ipynb,md" + +[tool.cruft] +skip = [ + "tests", + "src/**/__init__.py", + "src/**/basic.py", + "docs/api.md", + "docs/changelog.md", + "docs/references.bib", + "docs/references.md", + "docs/notebooks/example.ipynb" +]