From 3b6369eeaefcec81524adb901cb8471ed67ecedc Mon Sep 17 00:00:00 2001
From: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 19 Oct 2022 10:36:58 +0000
Subject: [PATCH 1/2] Update instance repo from cookiecutter template
---
.flake8 | 2 +
.github/ISSUE_TEMPLATE/bug_report.yml | 89 +++++++++++++++++++
.github/ISSUE_TEMPLATE/config.yml | 5 ++
.github/ISSUE_TEMPLATE/feature_request.yml | 11 +++
.pre-commit-config.yaml | 6 +-
.readthedocs.yaml | 1 +
docs/_templates/autosummary/class.rst | 65 ++++++++++++++
docs/api.md | 1 +
docs/conf.py | 40 +++++++--
docs/developer_docs.md | 11 ++-
docs/extensions/.gitkeep | 0
docs/extensions/typed_returns.py | 29 ++++++
pyproject.toml | 16 ++--
.../pl/__init__.py | 2 +-
src/cookiecutter_scverse_instance/pl/basic.py | 40 ++++++++-
src/cookiecutter_scverse_instance/pp/basic.py | 12 ++-
src/cookiecutter_scverse_instance/tl/basic.py | 12 ++-
17 files changed, 315 insertions(+), 27 deletions(-)
create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml
create mode 100644 .github/ISSUE_TEMPLATE/config.yml
create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml
create mode 100644 docs/_templates/autosummary/class.rst
delete mode 100644 docs/extensions/.gitkeep
create mode 100644 docs/extensions/typed_returns.py
diff --git a/.flake8 b/.flake8
index 53a4353..10cfc5a 100644
--- a/.flake8
+++ b/.flake8
@@ -46,6 +46,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..4830371
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,11 @@
+name: Feature request
+description: Propose a new feature for cookiecutter-scverse-instance
+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/.pre-commit-config.yaml b/.pre-commit-config.yaml
index d567446..47705fc 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -11,7 +11,7 @@ repos:
hooks:
- id: black
- repo: https://github.com/pre-commit/mirrors-prettier
- rev: v3.0.0-alpha.1
+ rev: v3.0.0-alpha.2
hooks:
- id: prettier
- repo: https://github.com/asottile/blacken-docs
@@ -44,7 +44,7 @@ repos:
- id: trailing-whitespace
- id: check-case-conflict
- repo: https://github.com/myint/autoflake
- rev: v1.7.1
+ rev: v1.7.6
hooks:
- id: autoflake
args:
@@ -64,7 +64,7 @@ repos:
- flake8-bugbear
- flake8-blind-except
- repo: https://github.com/asottile/pyupgrade
- rev: v3.0.0
+ rev: v3.1.0
hooks:
- id: pyupgrade
args: [--py3-plus, --py38-plus, --keep-runtime-typing]
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/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/api.md b/docs/api.md
index f6d84db..7c1ad45 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -34,4 +34,5 @@
:toctree: generated
pl.basic_plot
+ pl.BasicClass
```
diff --git a/docs/conf.py b/docs/conf.py
index b2f3dbd..c7c77c5 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -17,10 +17,11 @@
# -- Project information -----------------------------------------------------
info = metadata("cookiecutter-scverse-instance")
-project = info["Name"]
+project_name = info["Name"]
author = info["Author"]
copyright = f"{datetime.now():%Y}, {author}."
version = info["Version"]
+repository_url = "https://github.com/" + "scverse" + "/" + 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": "scverse", # 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,13 +65,31 @@
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 = {
"anndata": ("https://anndata.readthedocs.io/en/stable/", None),
"numpy": ("https://numpy.org/doc/stable/", None),
}
-nbsphinx_execute = "never"
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
@@ -84,10 +102,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 d6f79eb..8634d7e 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_
@@ -289,15 +290,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 +306,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 +328,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 72f08cf..b64f849 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -19,7 +19,11 @@ maintainers = [
urls.Documentation = "https://cookiecutter-scverse-instance.readthedocs.io/"
urls.Source = "https://github.com/scverse/cookiecutter-scverse-instance"
urls.Home-page = "https://github.com/scverse/cookiecutter-scverse-instance"
-dependencies = ["anndata"]
+dependencies = [
+ "anndata",
+ # for debug logging (referenced from the issue template)
+ "session-info"
+]
[project.optional-dependencies]
dev = [
@@ -29,13 +33,13 @@ dev = [
]
doc = [
"sphinx>=4",
- "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 notebooks
- "nbsphinx",
- "ipykernel"
+ "ipykernel",
+ "sphinx-copybutton",
]
test = [
"pytest",
diff --git a/src/cookiecutter_scverse_instance/pl/__init__.py b/src/cookiecutter_scverse_instance/pl/__init__.py
index a9cd20a..c2315dd 100644
--- a/src/cookiecutter_scverse_instance/pl/__init__.py
+++ b/src/cookiecutter_scverse_instance/pl/__init__.py
@@ -1 +1 @@
-from .basic import basic_plot
+from .basic import BasicClass, basic_plot
diff --git a/src/cookiecutter_scverse_instance/pl/basic.py b/src/cookiecutter_scverse_instance/pl/basic.py
index 71b3627..431582b 100644
--- a/src/cookiecutter_scverse_instance/pl/basic.py
+++ b/src/cookiecutter_scverse_instance/pl/basic.py
@@ -2,6 +2,44 @@
def basic_plot(adata: AnnData) -> int:
- """Generate a basic plot for an AnnData object."""
+ """Generate a basic plot for an AnnData object.
+
+ Parameters
+ ----------
+ adata
+ The AnnData object to preprocess.
+
+ Returns
+ -------
+ Some integer value.
+ """
print("Import matplotlib and implement a plotting function here.")
return 0
+
+
+class BasicClass:
+ """A basic class.
+
+ Parameters
+ ----------
+ adata
+ The AnnData object to preprocess.
+ """
+
+ def __init__(self, adata: AnnData):
+ print("Implement a class here.")
+
+ def my_method(self, param: int) -> int:
+ """A basic method.
+
+ Parameters
+ ----------
+ param
+ A parameter.
+
+ Returns
+ -------
+ Some integer value.
+ """
+ print("Implement a method here.")
+ return 0
diff --git a/src/cookiecutter_scverse_instance/pp/basic.py b/src/cookiecutter_scverse_instance/pp/basic.py
index 936f119..5ff1d41 100644
--- a/src/cookiecutter_scverse_instance/pp/basic.py
+++ b/src/cookiecutter_scverse_instance/pp/basic.py
@@ -2,6 +2,16 @@
def basic_preproc(adata: AnnData) -> int:
- """Run a basic preprocessing on the AnnData object."""
+ """Run a basic preprocessing on the AnnData :cite:p:`Wolf2018` object.
+
+ Parameters
+ ----------
+ adata
+ The AnnData object to preprocess.
+
+ Returns
+ -------
+ Some integer value.
+ """
print("Implement a preprocessing function here.")
return 0
diff --git a/src/cookiecutter_scverse_instance/tl/basic.py b/src/cookiecutter_scverse_instance/tl/basic.py
index 4e3387c..d215ade 100644
--- a/src/cookiecutter_scverse_instance/tl/basic.py
+++ b/src/cookiecutter_scverse_instance/tl/basic.py
@@ -2,6 +2,16 @@
def basic_tool(adata: AnnData) -> int:
- """Run a tool on the AnnData object."""
+ """Run a tool on the AnnData object.
+
+ Parameters
+ ----------
+ adata
+ The AnnData object to preprocess.
+
+ Returns
+ -------
+ Some integer value.
+ """
print("Implement a tool to run on the AnnData object.")
return 0
From 239efdb5219d73d6cfa19217737e80c3ad8262ea Mon Sep 17 00:00:00 2001
From: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 19 Oct 2022 13:19:55 +0000
Subject: [PATCH 2/2] Update instance repo from cookiecutter template
---
.github/workflows/sync.yaml | 46 +++++++++++++++++++++++++++++++++++++
.pre-commit-config.yaml | 9 ++++++++
README.md | 2 +-
docs/developer_docs.md | 28 ++++++++++++++++++++++
pyproject.toml | 12 ++++++++++
5 files changed, 96 insertions(+), 1 deletion(-)
create mode 100644 .github/workflows/sync.yaml
diff --git a/.github/workflows/sync.yaml b/.github/workflows/sync.yaml
new file mode 100644
index 0000000..5219499
--- /dev/null
+++ b/.github/workflows/sync.yaml
@@ -0,0 +1,46 @@
+name: Sync Template
+
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: "0 2 * * *" # every night at 2:00 UTC
+
+jobs:
+ sync:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Python 3.10
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.10"
+ - name: Install dependencies
+ # for now, pin cookiecutter version, due to https://github.com/cruft/cruft/issues/166
+ run: python -m pip install --upgrade cruft "cookiecutter<2" pre-commit toml
+ - name: Find Latest Tag
+ uses: oprypin/find-latest-tag@v1.1.0
+ id: get-latest-tag
+ with:
+ repository: scverse/cookiecutter-scverse
+ releases-only: false
+ sort-tags: true
+ regex: '^v\d+\.\d+\.\d+$' # vX.X.X
+ - name: Sync
+ run: |
+ cruft update --checkout ${{ steps.get-latest-tag.outputs.tag }} --skip-apply-ask --project-dir .
+ - name: Create Pull Request
+ uses: peter-evans/create-pull-request@v4
+ with:
+ commit-message: Automated template update from cookiecutter-scverse
+ branch: template-update
+ title: Automated template update from cookiecutter-scverse
+ body: |
+ A new version of the [scverse cookiecutter template](https://github.com/scverse/cookiecutter-scverse/releases)
+ got released. This PR adds all new changes to your repository and helps to to stay in sync with
+ the latest best-practice template maintained by the scverse team.
+
+ **If a merge conflict arised, a `.rej` file with the rejected patch is generated. You'll need to
+ manually merge these changes.**
+
+ For more information about the template sync, please refer to the
+ [template documentation](https://cookiecutter-scverse-instance.readthedocs.io/en/latest/developer_docs.html#automated-template-sync).
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 47705fc..aed6150 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -68,3 +68,12 @@ repos:
hooks:
- id: pyupgrade
args: [--py3-plus, --py38-plus, --keep-runtime-typing]
+ - repo: local
+ hooks:
+ - id: forbid-to-commit
+ name: Don't commit rej files
+ entry: |
+ Cannot commit .rej files. These indicate merge conflicts that arise during automated template updates.
+ Fix the merge conflicts manually and remove the .rej files.
+ language: fail
+ files: '.*\.rej$'
diff --git a/README.md b/README.md
index ea21fd5..22fd6cd 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,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 cookiecutter-scverse-instance:
diff --git a/docs/developer_docs.md b/docs/developer_docs.md
index 8634d7e..c95a9a6 100644
--- a/docs/developer_docs.md
+++ b/docs/developer_docs.md
@@ -93,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
@@ -241,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
diff --git a/pyproject.toml b/pyproject.toml
index b64f849..f619056 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -88,3 +88,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"
+]