diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst new file mode 100644 index 00000000..25167196 --- /dev/null +++ b/.github/CONTRIBUTING.rst @@ -0,0 +1,35 @@ +Contributing to the project +=========================== + +Contributions and issues are most welcome! All issues and pull requests are +handled through GitHub_. Also, please check for any existing issues before +filing a new one. If you have a great idea but it involves big changes, please +file a ticket before making a pull request! We want to make sure you don't spend +your time coding something that might not fit the scope of the project. + +.. _GitHub: https://github.com/DiamondLightSource/python3-pip-skeleton-cli/issues + +Issue or Discussion? +-------------------- + +Github also offers discussions_ as a place to ask questions and share ideas. If +your issue is open ended and it is not obvious when it can be "closed", please +raise it as a discussion instead. + +.. _discussions: https://github.com/DiamondLightSource/python3-pip-skeleton-cli/discussions + +Code coverage +------------- + +While 100% code coverage does not make a library bug-free, it significantly +reduces the number of easily caught bugs! Please make sure coverage remains the +same or is improved by a pull request! + +Developer guide +--------------- + +The `Developer Guide`_ contains information on setting up a development +environment, running the tests and what standards the code and documentation +should follow. + +.. _Developer Guide: https://diamondlightsource.github.io/python3-pip-skeleton-cli/main/developer/how-to/contribute.html diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..fb7c6ee6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/pages/index.html b/.github/pages/index.html new file mode 100644 index 00000000..80f0a009 --- /dev/null +++ b/.github/pages/index.html @@ -0,0 +1,11 @@ + + + + + Redirecting to main branch + + + + + + \ No newline at end of file diff --git a/.github/pages/make_switcher.py b/.github/pages/make_switcher.py new file mode 100755 index 00000000..f4cffd1b --- /dev/null +++ b/.github/pages/make_switcher.py @@ -0,0 +1,92 @@ +import json +import logging +from argparse import ArgumentParser +from pathlib import Path +from subprocess import CalledProcessError, check_output +from typing import List, Optional + + +def report_output(stdout: bytes, label: str) -> List[str]: + ret = stdout.decode().strip().split("\n") + print(f"{label}: {ret}") + return ret + + +def get_branch_contents(ref: str) -> List[str]: + """Get the list of directories in a branch.""" + stdout = check_output(["git", "ls-tree", "-d", "--name-only", ref]) + return report_output(stdout, "Branch contents") + + +def get_sorted_tags_list() -> List[str]: + """Get a list of sorted tags in descending order from the repository.""" + stdout = check_output(["git", "tag", "-l", "--sort=-v:refname"]) + return report_output(stdout, "Tags list") + + +def get_versions(ref: str, add: Optional[str]) -> List[str]: + """Generate the file containing the list of all GitHub Pages builds.""" + # Get the directories (i.e. builds) from the GitHub Pages branch + try: + builds = set(get_branch_contents(ref)) + except CalledProcessError: + builds = set() + logging.warning(f"Cannot get {ref} contents") + + # Add and remove from the list of builds + if add: + builds.add(add) + + # Get a sorted list of tags + tags = get_sorted_tags_list() + + # Make the sorted versions list from main branches and tags + versions: List[str] = [] + for version in ["master", "main"] + tags: + if version in builds: + versions.append(version) + builds.remove(version) + + # Add in anything that is left to the bottom + versions += sorted(builds) + print(f"Sorted versions: {versions}") + return versions + + +def write_json(path: Path, repository: str, versions: str): + org, repo_name = repository.split("/") + struct = [ + dict(version=version, url=f"https://{org}.github.io/{repo_name}/{version}/") + for version in versions + ] + text = json.dumps(struct, indent=2) + print(f"JSON switcher:\n{text}") + path.write_text(text, encoding="utf-8") + + +def main(args=None): + parser = ArgumentParser( + description="Make a versions.json file from gh-pages directories" + ) + parser.add_argument( + "--add", + help="Add this directory to the list of existing directories", + ) + parser.add_argument( + "repository", + help="The GitHub org and repository name: ORG/REPO", + ) + parser.add_argument( + "output", + type=Path, + help="Path of write switcher.json to", + ) + args = parser.parse_args(args) + + # Write the versions file + versions = get_versions("origin/gh-pages", args.add) + write_json(args.output, args.repository, versions) + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/_check.yml b/.github/workflows/_check.yml new file mode 100644 index 00000000..a6139c19 --- /dev/null +++ b/.github/workflows/_check.yml @@ -0,0 +1,27 @@ +on: + workflow_call: + outputs: + branch-pr: + description: The PR number if the branch is in one + value: ${{ jobs.pr.outputs.branch-pr }} + +jobs: + pr: + runs-on: "ubuntu-latest" + outputs: + branch-pr: ${{ steps.script.outputs.result }} + steps: + - uses: actions/github-script@v7 + id: script + if: github.event_name == 'push' + with: + script: | + const prs = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + head: context.repo.owner + ':${{ github.ref_name }}' + }) + if (prs.data.length) { + console.log(`::notice ::Skipping CI on branch push as it is already run in PR #${prs.data[0]["number"]}`) + return prs.data[0]["number"] + } diff --git a/.github/workflows/_docs.yml b/.github/workflows/_docs.yml new file mode 100644 index 00000000..14862b9f --- /dev/null +++ b/.github/workflows/_docs.yml @@ -0,0 +1,52 @@ +on: + workflow_call: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install system packages + run: sudo apt-get install graphviz + + - name: Setup python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install python packages + uses: pip install -c requirements.txt + + - name: Build docs + run: sphinx-build -EW --keep-going -T docs build/html + + - name: Remove environment.pickle + run: rm build/html/.doctrees/environment.pickle + + - name: Move to versioned directory + run: mv build/html build/${GITHUB_REF_NAME//[^A-Za-z0-9._-]/_} + + - name: Upload built docs artifact + uses: actions/upload-artifact@v4 + with: + name: docs + path: build + + - name: Add other static pages files + run: cp .github/pages/* build + + - name: Write switcher.json + run: python .github/pages/make_switcher.py --add $DOCS_VERSION ${{ github.repository }} build/switcher.json + + - name: Publish Docs to gh-pages + if: github.event_name == 'push' && github.actor != 'dependabot[bot]' + # We pin to the SHA, not the tag, for security reasons. + # https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions + uses: peaceiris/actions-gh-pages@bd8c6b06eba6b3d25d72b7a1767993c0aeee42e7 # v3.9.2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: build + keep_files: true diff --git a/.github/workflows/_release.yml b/.github/workflows/_release.yml new file mode 100644 index 00000000..84f68ed6 --- /dev/null +++ b/.github/workflows/_release.yml @@ -0,0 +1,33 @@ +on: + workflow_call: + +jobs: + artifacts: + runs-on: ubuntu-latest + + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + + - name: Prepare release files + run: | + if [ -d docs ]; then + cd docs && zip -r docs.zip * + echo 'DOCS=docs/docs.zip' >> $GITHUB_ENV + fi + if [ -d dist ]; then + echo 'DIST=dist/*' >> $GITHUB_ENV + fi + + - name: Create GitHub Release + # We pin to the SHA, not the tag, for security reasons. + # https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions + uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15 + with: + prerelease: ${{ contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc') }} + files: | + ${{ env.DOCS }} + ${{ env.DIST }} + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..4c064316 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,31 @@ +name: CI + +on: + push: + pull_request: + +jobs: + check: + # TODO: Use the CI straight from the template + uses: ./.github/workflows/_check.yml + + docs: + needs: check + if: ${{ ! needs.check.outputs.branch-pr }} + uses: ./.github/workflows/_docs.yml + + pages: + if: github.ref_name == 'main' + needs: docs + uses: ./.github/workflows/_pages.yml + permissions: + pages: write + id-token: write + + release: + if: github.ref_type == 'tag' + needs: [dist, docs] + # TODO: Use the CI straight from the template + uses: ./.github/workflows/_release.yml + permissions: + contents: write diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml new file mode 100644 index 00000000..6dcaaeb4 --- /dev/null +++ b/.github/workflows/linkcheck.yml @@ -0,0 +1,26 @@ +name: Link Check + +on: + workflow_dispatch: + schedule: + # Run weekly to check URL links still resolve + - cron: "0 8 * * WED" + +jobs: + docs: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install python packages + uses: pip install -c requirements.txt + + - name: Check links + run: sphinx-build -b linkcheck -T docs build/html diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..d1638636 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..7f4957a8 --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ +[![CI](https://github.com/DiamondLightSource/python-copier-template/actions/workflows/ci.yml/badge.svg)](https://github.com/DiamondLightSource/python-copier-template/actions/workflows/ci.yml) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +# python-copier-template + + + +Diamond's opinionated [copier](https://copier.readthedocs.io) template for pure Python projects managed by pip. It can be optionally used to: + +- Create new projects from +- Update existing projects in line with it +- Keep projects in sync with changes to it +- Provide a source of inspiration to cherry-pick from + +Source | +:---: | :---: +Documentation | +Releases | + +It integrates the following tools: + +- [setuptools](https://setuptools.pypa.io) and [setuptools-scm](https://setuptools-scm.readthedocs.io) for packaging +- [pip](https://pip.pypa.io) and [pip-compile](https://pip-tools.readthedocs.io) to manage installation +- [pytest](https://docs.pytest.org) for code testing and coverage +- [pre-commit](https://pre-commit.com) to run linting and formatting such as [ruff](https://docs.astral.sh/ruff) +- [pyright](https://microsoft.github.io/pyright) for static type checking +- [sphinx](https://www.sphinx-doc.org) for tutorials, how-to guides, explanations and reference documentation +- [tox](https://tox.wiki) to run the above tasks locally and in CI +- [GitHub Actions](https://docs.github.com/en/actions) to provide CI and deployment to PyPI and GitHub Pages +- [VSCode](https://code.visualstudio.com/docs) settings for running the above tools on save + +## Create a new project via Developer Portal + +> [!NOTE] +> Template creation from the developer portal is currently under construction, so these instructions do not work yet + +Visit and you will see a list of templates that you can create. Pick the one marked `Python Template` and: + +- Choose GitHub as the hosting platform +- Enter your GitHub username as the organisation +- Choose from options to customize some template features + + +## Create a new project from the commandline + +You first need to install copier and have it be on your path. At Diamond you can do this with a venv: + +``` +$ module load python +$ python -m venv /scratch/$USER/copier-venv +$ source /scratch/$USER/copier-venv/bin/activate +$ python -m pip install copier +``` + +You can then use copier to copy from the template into a directory you have prepared: + +``` +$ mkdir /scratch/$USER/my-project +$ copier copy gh:DiamondLightSource/python-copier-template /scratch/$USER/my-project + +``` + + +See https://DiamondLightSource.github.io/python-copier-template for more detailed documentation. + diff --git a/README.rst b/README.rst deleted file mode 100644 index 6366fad4..00000000 --- a/README.rst +++ /dev/null @@ -1,15 +0,0 @@ -This is a work-in-progress to evaluate the use of Copier templates in the Dev Portal. - -To set up your PC at Diamond internally, you must install copier. One way to do this is via pipx. - -.. code-block:: shell - - python3 -m pip install --user pipx - python3 -m pipx ensurepath - pipx install copier - -To create a new project in your current directory, using this template and Copier from the command line, use: - -.. code-block:: shell - - copier copy gh:DiamondLighSource/python_copier_template . diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..fdfa2570 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,170 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +import sys +from pathlib import Path +from subprocess import check_output + +import requests + +# -- General configuration ------------------------------------------------ + +# General information about the project. +project = "python-copier-template" + +# The full version, including alpha/beta/rc tags. +release = check_output(['git', 'describe', '--always', '--tags']).decode() + +# The short X.Y version. +if "-" in release: + # Not on a tag, use branch name + root = Path(__file__).absolute().parent.parent + git_branch = check_output("git branch --show-current".split(), cwd=root) + version = git_branch.decode().strip() +else: + version = release + +extensions = [ + # For graphviz diagrams + "sphinx.ext.graphviz", + # For linking to external sphinx documentation + "sphinx.ext.intersphinx", + # Add a copy button to each code block + "sphinx_copybutton", + # For the card element + "sphinx_design", + # So we can write markdown files + "myst_parser", +] + +# So we can use the ::: syntax +myst_enable_extensions = ["colon_fence"] + +# If true, Sphinx will warn about all references where the target cannot +# be found. +nitpicky = True + +# A list of (type, target) tuples (by default empty) that should be ignored when +# generating warnings in "nitpicky mode". Note that type should include the +# domain name if present. Example entries would be ('py:func', 'int') or +# ('envvar', 'LD_LIBRARY_PATH'). +nitpick_ignore = [] + +# Output graphviz directive produced images in a scalable format +graphviz_output_format = "svg" + +# The name of a reST role (builtin or Sphinx extension) to use as the default +# role, that is, for text marked up `like this` +default_role = "any" + +# The suffix of source filenames. +source_suffix = ".rst" + +# The master toctree document. +master_doc = "index" + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# These patterns also affect html_static_path and html_extra_path +exclude_patterns = ["_build"] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# This means you can link things like `str` and `asyncio` to the relevant +# docs in the python documentation. +intersphinx_mapping = dict(python=("https://docs.python.org/3/", None)) + +# A dictionary of graphviz graph attributes for inheritance diagrams. +inheritance_graph_attrs = dict(rankdir="TB") + +# Common links that should be available on every page +rst_epilog = """ +.. _Diamond Light Source: http://www.diamond.ac.uk +.. _black: https://github.com/psf/black +.. _flake8: https://flake8.pycqa.org/en/latest/ +.. _isort: https://github.com/PyCQA/isort +.. _mypy: http://mypy-lang.org/ +.. _pre-commit: https://pre-commit.com/ +""" + +# Set copy-button to ignore python and bash prompts +# https://sphinx-copybutton.readthedocs.io/en/latest/use.html#using-regexp-prompt-identifiers +copybutton_prompt_text = r">>> |\.\.\. |\$ |In \[\d*\]: | {2,5}\.\.\.: | {5,8}: " +copybutton_prompt_is_regexp = True + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = "pydata_sphinx_theme" +github_repo = project +github_user = "DiamondLightSource" +switcher_json = f"https://{github_user}.github.io/{github_repo}/switcher.json" +switcher_exists = requests.get(switcher_json).ok +if not switcher_exists: + print( + "*** Can't read version switcher, is GitHub pages enabled? \n" + " Once Docs CI job has successfully run once, set the " + "Github pages source branch to be 'gh-pages' at:\n" + f" https://github.com/{github_user}/{github_repo}/settings/pages", + file=sys.stderr, + ) + +# Theme options for pydata_sphinx_theme +# We don't check switcher because there are 3 possible states for a repo: +# 1. New project, docs are not published so there is no switcher +# 2. Existing project with latest skeleton, switcher exists and works +# 3. Existing project with old skeleton that makes broken switcher, +# switcher exists but is broken +# Point 3 makes checking switcher difficult, because the updated skeleton +# will fix the switcher at the end of the docs workflow, but never gets a chance +# to complete as the docs build warns and fails. +html_theme_options = dict( + logo=dict( + text=project, + ), + use_edit_page_button=True, + github_url=f"https://github.com/{github_user}/{github_repo}", + icon_links=[ + dict( + name="PyPI", + url="https://pypi.org/project/python3-pip-skeleton", + icon="fas fa-cube", + ) + ], + switcher=dict( + json_url=switcher_json, + version_match=version, + ), + check_switcher=True, + navbar_end=["theme-switcher", "icon-links", "version-switcher"], + external_links=[ + dict( + name="Release Notes", + url=f"https://github.com/{github_user}/{github_repo}/releases", + ) + ], +) + +# A dictionary of values to pass into the template engine’s context for all pages +html_context = dict( + github_user=github_user, + github_repo=project, + github_version=version, + doc_path="docs", +) + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +html_show_copyright = False + +# Logo +html_logo = "images/dls-logo.svg" +html_favicon = html_logo diff --git a/docs/explanations.md b/docs/explanations.md new file mode 100644 index 00000000..73ab289b --- /dev/null +++ b/docs/explanations.md @@ -0,0 +1,10 @@ +# Explanations + +Explanations of how it works and why it works that way. + +```{toctree} +:maxdepth: 1 +:glob: + +explanations/* +``` diff --git a/docs/explanations/decisions.rst b/docs/explanations/decisions.rst new file mode 100644 index 00000000..5841e6ea --- /dev/null +++ b/docs/explanations/decisions.rst @@ -0,0 +1,17 @@ +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Architectural Decision Records +============================== + +We record major architectural decisions in Architecture Decision Records (ADRs), +as `described by Michael Nygard +`_. +Below is the list of our current ADRs. + +.. toctree:: + :maxdepth: 1 + :glob: + + decisions/* \ No newline at end of file diff --git a/docs/explanations/decisions/0001-record-architecture-decisions.rst b/docs/explanations/decisions/0001-record-architecture-decisions.rst new file mode 100644 index 00000000..b2d3d0fe --- /dev/null +++ b/docs/explanations/decisions/0001-record-architecture-decisions.rst @@ -0,0 +1,26 @@ +1. Record architecture decisions +================================ + +Date: 2022-02-18 + +Status +------ + +Accepted + +Context +------- + +We need to record the architectural decisions made on this project. + +Decision +-------- + +We will use Architecture Decision Records, as `described by Michael Nygard +`_. + +Consequences +------------ + +See Michael Nygard's article, linked above. To create new ADRs we will copy and +paste from existing ones. diff --git a/docs/explanations/decisions/0003-docs-structure.rst b/docs/explanations/decisions/0003-docs-structure.rst new file mode 100644 index 00000000..6c42b0ff --- /dev/null +++ b/docs/explanations/decisions/0003-docs-structure.rst @@ -0,0 +1,42 @@ +.. _documentation structure: + +3. Standard documentation structure +=================================== + +Date: 2023-01-18 + +Status +------ + +Accepted + +Context +------- + +Skeleton based project's documentation requires organizing. + +Decision +-------- + +Use the approach proposed by David Laing. + + :material-regular:`format_quote;2em` + + The Grand Unified Theory of Documentation + + -- David Laing + +There is a secret that needs to be understood in order to write good software +documentation: there isn't one thing called *documentation*, there are four. + +They are: *tutorials*, *how-to guides*, *technical reference* and *explanation*. +They represent four different purposes or functions, and require four different +approaches to their creation. Understanding the implications of this will help +improve most documentation - often immensely. + +`More information on this topic. `_ + +Consequences +------------ + +See article linked above. diff --git a/docs/explanations/decisions/0004-why-src.rst b/docs/explanations/decisions/0004-why-src.rst new file mode 100644 index 00000000..b09ea944 --- /dev/null +++ b/docs/explanations/decisions/0004-why-src.rst @@ -0,0 +1,50 @@ +.. _src: + +4. Use a source directory +========================= + +Date: 2023-01-18 + +Status +------ + +Accepted + +Context +------- + +We need to decide how to structure the source code in skeleton based projects. + + +Decision +-------- + +As per `Hynek's article`_ and summarized below. + +.. _Hynek's article: https://hynek.me/articles/testing-packaging/ + +The main advantage is that the source directory cannot shadow installed packages +as it would if it was in the root of the repository. This means that if you +install the package, then run the tests, they will run against the installed +package and not the source directory, testing for packaging bugs. + +A secondary advantage is symmetry, sources go in ``src/``, tests go in +``tests\``, docs go in ``docs``. + +This is tested in CI in the following way: + +- ``wheel`` job creates a wheel, then installs it in an isolated environment and + runs the cli. This checks ``install_requirements`` are sufficient to run the + cli. +- ``test`` job with ``lock: true`` does an `editable install`_ of the + package. This is the mode that is used at development time, as modifications + to sources can be tested without reinstalling. +- ``test`` job with ``lock: false`` does a regular install, which + checks that all files needed for the tests are packaged with the distribution. + +.. _editable install: https://pip.pypa.io/en/stable/cli/pip_install/#editable-installs + +Consequences +------------ + +See the article linked above. diff --git a/docs/explanations/decisions/0005-pyproject-toml.rst b/docs/explanations/decisions/0005-pyproject-toml.rst new file mode 100644 index 00000000..ee8a1177 --- /dev/null +++ b/docs/explanations/decisions/0005-pyproject-toml.rst @@ -0,0 +1,25 @@ +5. Use pyproject.toml +===================== + +Date: 2023-01-18 + +Status +------ + +Accepted + +Context +------- + +Need a decision on where to put the python project configuration. + +Decision +-------- + +Use pyproject.toml as per https://peps.python.org/pep-0518/ + + +Consequences +------------ + +See article linked above. \ No newline at end of file diff --git a/docs/explanations/decisions/0006-setuptools-scm.rst b/docs/explanations/decisions/0006-setuptools-scm.rst new file mode 100644 index 00000000..3f6f33a0 --- /dev/null +++ b/docs/explanations/decisions/0006-setuptools-scm.rst @@ -0,0 +1,28 @@ +6. Use setuptools_scm +===================== + +Date: 2023-01-18 + +Status +------ + +Accepted + +Context +------- + +We require a mechanism for generating version numbers in python. + +Decision +-------- + +Generate the version number from git tags using setuptools scm. + +See https://github.com/pypa/setuptools_scm/ + +Consequences +------------ + +Versions are generated automatically from git tags. This means you can +can verify if you are running a released version of the code as +setup tools scm adds a suffix to untagged commits. diff --git a/docs/explanations/decisions/0007-dev-dependencies.rst b/docs/explanations/decisions/0007-dev-dependencies.rst new file mode 100644 index 00000000..507551b4 --- /dev/null +++ b/docs/explanations/decisions/0007-dev-dependencies.rst @@ -0,0 +1,37 @@ +7. Installing developer environment +=================================== + +Date: 2023-01-18 + +Status +------ + +Accepted + +Context +------- + +We need to provide a way to setup a developer environment for a skeleton based +project. + +Decision +-------- + +Use optional dependencies in pyproject.toml. + +PEP 621 provides a mechanism for adding optional dependencies in pyproject.toml +https://peps.python.org/pep-0621/#dependencies-optional-dependencies. + +We supply a list of developer dependencies under the title "dev". These +developer dependencies enable building and testing the project and +its documentation. + +Consequences +------------ + +Any developer can update their virtual environment in order to work on +a skeleton based project with the command: + +```bash +pip install -e .[dev] +``` \ No newline at end of file diff --git a/docs/explanations/decisions/0008-use-tox.rst b/docs/explanations/decisions/0008-use-tox.rst new file mode 100644 index 00000000..3e259ce2 --- /dev/null +++ b/docs/explanations/decisions/0008-use-tox.rst @@ -0,0 +1,138 @@ +8. Use tox and pre-commit +========================= + +Date: 2023-01-18 + +Status +------ + +Accepted + +Context +------- + +We require an easy way to locally run the same checks as CI. This provides a +rapid inner-loop developer experience. + +Decision +-------- + +Use tox and pre-commit. + +tox is an automation tool that we use to run all checks in parallel, +see https://tox.wiki/en/latest/. + +pre-commit provides a hook into git commit which runs some of the checks +against the changes you are about to commit. + +Decision detail +--------------- + +There are a number of things that CI needs to run: + +- pytest +- black +- mypy +- flake8 +- isort +- build documentation + +The initial approach this module took was to integrate everything +under pytest that had a plugin, and isort under flake8: + +.. digraph:: initial + + bgcolor=transparent + graph [fontname="Lato" fontsize=10 style=filled fillcolor="#8BC4E9"] + node [fontname="Lato" fontsize=10 shape=box style=filled fillcolor="#8BC4E9"] + + subgraph cluster_0 { + label = "pytest" + "pytest-black" + "pytest-mypy" + subgraph cluster_1 { + label = "pytest-flake8" + "flake8-isort" + } + } + +This had the advantage that a ``pytest tests`` run in CI would catch and +report all test failures, but made each run take longer than it needed to. Also, +flake8 states that it `does not have a public, stable, Python API +`_ so did not +recommend the approach taken by pytest-flake8. + +To address this, the tree was rearranged: + +.. digraph:: rearranged + + bgcolor=transparent + graph [fontname="Lato" fontsize=10 style=filled fillcolor="#8BC4E9"] + node [fontname="Lato" fontsize=10 shape=box style=filled fillcolor="#8BC4E9"] + + pytest + black + mypy + subgraph cluster_1 { + label = "flake8" + "flake8-isort" + } + +If using VSCode, this will still run black, flake8 and mypy on file save, but +for those using other editors and for CI another solution was needed. Enter +`pre-commit `_. This allows hooks to be run at ``git +commit`` time on just the files that have changed, as well as on all tracked +files by CI. All that is needed is a one time install of the git commit hook:: + + $ pre-commit install + +Finally tox was added to run all of the CI checks including +the documentation build. mypy was moved out of the pre-commit and into tox +because it was quite long running and +therefore intrusive. tox can be invoked to run all the checks in +parallel with:: + + $ tox -p + +The graph now looks like: + +.. digraph:: rearranged + + bgcolor=transparent + graph [fontname="Lato" fontsize=10 style=filled fillcolor="#8BC4E9"] + node [fontname="Lato" fontsize=10 shape=box style=filled fillcolor="#8BC4E9"] + + subgraph cluster_0 + { + label = "tox -p" + pytest + mypy + "sphinx-build" + subgraph cluster_1 { + label = "pre-commit" + black + subgraph cluster_2 { + label = "flake8" + "flake8-isort" + } + } + } + +Now the workflow looks like this: + +- Save file, VSCode runs black, flake8 and mypy on it +- Run 'tox -p' and fix issues until it succeeds +- Commit files and pre-commit runs black and flake8 on them (if the + developer had not run tox then this catches some of the most common issues) +- Push to remote and CI runs black, flake8, mypy once on all files + (using tox), then pytest multiple times in a test matrix + + +Consequences +------------ + +Running ``tox -p`` before pushing to GitHub verifies that the CI will *most +likely* succeed. + +Committing changes to git will run all of the non-time critical checks and +help avoid some of the most common mistakes. \ No newline at end of file diff --git a/docs/explanations/decisions/0009-sphinx-theme.rst b/docs/explanations/decisions/0009-sphinx-theme.rst new file mode 100644 index 00000000..b80fee08 --- /dev/null +++ b/docs/explanations/decisions/0009-sphinx-theme.rst @@ -0,0 +1,24 @@ +9. Sphinx theme +=============== + +Date: 2023-01-18 + +Status +------ + +Accepted + +Context +------- + +Documentation requires a theme as well as a structure. + +Decision +-------- + +Use the pydata theme defined here https://pydata-sphinx-theme.readthedocs.io/ + +Consequences +------------ + +The documentation looks nice and has good navigation features. diff --git a/docs/explanations/decisions/0010-vscode-settings.rst b/docs/explanations/decisions/0010-vscode-settings.rst new file mode 100644 index 00000000..a676ace4 --- /dev/null +++ b/docs/explanations/decisions/0010-vscode-settings.rst @@ -0,0 +1,31 @@ +10. Include vscode settings +=========================== + +Date: 2023-01-18 + +Status +------ + +Accepted + +Context +------- + +For vscode users a couple of settings are required for neat integration with +the IDE. + +Decision +-------- + +Include a .vscode folder in the repo with some json files that enable: + +- recommended extension for best experience +- launcher to make debugging of python code override the coverage settings +- settings to make code verification match the tools in CI +- a task to launch the tox tests from the IDE + +Consequences +------------ + +Users of vscode should find that their development environment just works. +Users of other editors will be unaffected. \ No newline at end of file diff --git a/docs/explanations/decisions/0011-requirements-txt.rst b/docs/explanations/decisions/0011-requirements-txt.rst new file mode 100644 index 00000000..0247512e --- /dev/null +++ b/docs/explanations/decisions/0011-requirements-txt.rst @@ -0,0 +1,36 @@ +11. Pinning requirements +======================== + +Date: 2023-01-18 + +Status +------ + +Accepted + +Context +------- + +Require the ability to pin requirements for a guaranteed rebuild. +By default CI builds against the latest version of all dependencies, but we +need a mechanism for overriding this behaviour with a lock file +when there are issues. + +Decision +-------- + +Have every release generate requirements.txt files using pip freeze and +publish them as release assets. + +Request that the user download the asset and commit it into the repo in order +to lock dependencies for the next CI build. + +TODO: link to the How-To on pinning requirements to be written in +python3-pip-skeleton developer documentation. + +Consequences +------------ + +There is less overhead in managing lock files. Incoming issues with dependencies +will be highlighted early but can be worked around quickly if needed. + diff --git a/docs/explanations/decisions/0012-containers.rst b/docs/explanations/decisions/0012-containers.rst new file mode 100644 index 00000000..e53dd541 --- /dev/null +++ b/docs/explanations/decisions/0012-containers.rst @@ -0,0 +1,34 @@ +12. Use containers +================== + +Date: 2023-01-18 + +Status +------ + +Accepted + +Context +------- + +Allow developers and users to take advantage of containers. + +Decision +-------- + +Provide a single Dockerfile that can build two kinds of container: + +- a minimal runtime container that can be used to execute the application in + isolation without setting up a virtual environment or installing system + dependencies +- a devcontainer for working on the project with the same isolation as above + +CI builds the runtime container and publishes it to ghcr.io. + +A .devcontainer folder provides the means to build and launch the developer +container using vscode. + +Consequences +------------ + +We can label projects as cloud native. diff --git a/docs/explanations/skeleton.rst b/docs/explanations/skeleton.rst new file mode 100644 index 00000000..d1b7779d --- /dev/null +++ b/docs/explanations/skeleton.rst @@ -0,0 +1,81 @@ +.. _Skeleton: + +Working on the Skeleton Repo +============================ + +The python3-pip-skeleton_ repo has a protected main branch and is restricted to +rebase PRs only. +It is also squashed occasionally so some careful procedures are required. + +.. _python3-pip-skeleton: https://github.com/DiamondLightSource/python3-pip-skeleton + +main +---- + +This branch is what all adopters of the skeleton project merge from so needs +to be kept tidy. +In particular it must not have any #nnn which would refer to the wrong commit +when merged into other repos (and github will see them and add incorrect +messages in PRs and Issues). This branch is protected from push and +restricted so that it can only be updated by a PR with REBASE. + +dev-archive +----------- +This branch to tracks all commits, including those that are squashed out of +main. Force push is disallowed on this branch so that it can be kept as a +safe record of the history. + +Process for making a change +--------------------------- +To make changes. First take a new branch off of main, make your changes +and do a pull request to rebase main on the branch. + +- get a branch on main + + - git checkout main + - git reset --hard origin/main # because main may have been rebased + - git checkout -b feature +- Do the changes and test in CI with: + + - git add --all + - git commit -m'my changes' + - git push -u origin feature +- When happy with changes use PR to rebase main on feature. +- Next delete feature: + + - git push origin :feature + - git checkout main + - git branch -fd feature + + +Process for squashing main +-------------------------- + +Once a year or so tidy up the history of main to make new adoptions easy. +Otherwise multiple changes to the same line in the history may cause multiple +merge conflicts on that line during re-merge of skeleton into projects +that have already adopted. + +Perform these steps + +- Get the dev-archive branch to remember your main commits + + - git checkout dev-archive + - git merge main +- If there are conflicts + + - git checkout --theirs + - git add --all + - git commit # the commit message will be 'merged ...' you can + add to it if needed +- Now squash main right back to the original ededf000 + - git checkout main + - git reset --hard /origin/main + - git rebase -i ededf000 + - In the rebase edit screen replace all ``pick`` with ``s`` except the first + one. save and quit +- Now create a handoff branch + - git checkout dev-archive + - git checkout -b handoff/202x-xx-xx + - git merge main + - git push -u origin handoff/202x-xx-xx diff --git a/docs/explanations/structure.rst b/docs/explanations/structure.rst new file mode 100644 index 00000000..66766c2d --- /dev/null +++ b/docs/explanations/structure.rst @@ -0,0 +1,51 @@ +Skeleton Project Structure +========================== + +The skeleton project has the following folders at the root level. + +src +--- + +This folder contains the source code for the project. Typically this +contains a single folder with the package name for the project and the +folder contains python modules files. + +See `src` for details. + +tests +----- + +This folder holds all of the tests that will be run by pytest, both locally +and in CI. + +See `using pytest` + +docs +---- + +This folder contains the source for sphinx documentation. + +See `documentation structure` for details. + +.github +------- + +Configuration for the Continuous Integration Workflow on +github + +VSCode specific folders +----------------------- + +.devcontainer +~~~~~~~~~~~~~ + +Configuration for running the developer container for this project +in VSCode. + +.vscode +~~~~~~~ + +VSCode settings for this project. + +- enable static analysis in the editor +- enables python debugging. diff --git a/docs/explanations/why-use-skeleton.rst b/docs/explanations/why-use-skeleton.rst new file mode 100644 index 00000000..796e55ef --- /dev/null +++ b/docs/explanations/why-use-skeleton.rst @@ -0,0 +1,41 @@ +Why Use a Skeleton Structure? +============================= + +Many projects start from some kind of template. These define some basic +structure, customized with project specific variables, that developers can add +their code into. One example of this is cookiecutter_. + +.. _cookiecutter: https://cookiecutter.readthedocs.io + +The problem with this approach is that it is difficult to apply changes to the +template into projects that have been cut from it. Individual changes have to be +copy/pasted into the code, leading to partially applied fixes and missed +updates. + +This module takes a different approach, as explained in `jaraco's blog post`_. +It is a repo that can be forked, and updates merged to the skeleton can be +merged into projects tracking it with a ``git pull`` operation. No more +copy/pasting. + +.. _jaraco's blog post: https://blog.jaraco.com/a-project-skeleton-for-python-projects/ + +Why do you need the commandline tool? +------------------------------------- + +The reason for the commandline tool is because this skeleton module has more +code and docs content than `jaraco/skeleton`_. There are numerous references to +the repo and package name, so the commandline tool applies a single commit on +top of the repo that customizes it to the particular project. Once the initial +creation/adoption has occurred however, a simple ``git pull`` is sufficient to +keep it updated. + +.. _jaraco/skeleton: https://github.com/jaraco/skeleton + +What happens if the merges become too difficult? +------------------------------------------------ + +If projects diverge too much, then merging in changes will become increasingly +difficult. This is probably a sign that the approach the project has taken is +too different from the skeleton structure for it to be of much benefit. At this +point, the merge can be abandoned, the section from ``CONTRIBUTING.rst`` +deleted, and the project need not pull from the skeleton repo any more. diff --git a/docs/genindex.md b/docs/genindex.md new file mode 100644 index 00000000..73f1191b --- /dev/null +++ b/docs/genindex.md @@ -0,0 +1,3 @@ +# Index + + diff --git a/docs/how-to.md b/docs/how-to.md new file mode 100644 index 00000000..6b161417 --- /dev/null +++ b/docs/how-to.md @@ -0,0 +1,10 @@ +# How-to Guides + +Practical step-by-step guides for the more experienced user. + +```{toctree} +:maxdepth: 1 +:glob: + +how-to/* +``` diff --git a/docs/how-to/build-docs.rst b/docs/how-to/build-docs.rst new file mode 100644 index 00000000..79e3f780 --- /dev/null +++ b/docs/how-to/build-docs.rst @@ -0,0 +1,38 @@ +Build the docs using sphinx +=========================== + +You can build the `sphinx`_ based docs from the project directory by running:: + + $ tox -e docs + +This will build the static docs on the ``docs`` directory, which includes API +docs that pull in docstrings from the code. + +.. seealso:: + + `documentation_standards` + +The docs will be built into the ``build/html`` directory, and can be opened +locally with a web browse:: + + $ firefox build/html/index.html + +Autobuild +--------- + +You can also run an autobuild process, which will watch your ``docs`` +directory for changes and rebuild whenever it sees changes, reloading any +browsers watching the pages:: + + $ tox -e docs autobuild + +You can view the pages at localhost:: + + $ firefox http://localhost:8000 + +If you are making changes to source code too, you can tell it to watch +changes in this directory too:: + + $ tox -e docs autobuild -- --watch src + +.. _sphinx: https://www.sphinx-doc.org/ \ No newline at end of file diff --git a/docs/how-to/contribute.rst b/docs/how-to/contribute.rst new file mode 100644 index 00000000..65b72c8e --- /dev/null +++ b/docs/how-to/contribute.rst @@ -0,0 +1 @@ +.. include:: ../../.github/CONTRIBUTING.rst diff --git a/docs/how-to/excalidraw.rst b/docs/how-to/excalidraw.rst new file mode 100644 index 00000000..5d733cec --- /dev/null +++ b/docs/how-to/excalidraw.rst @@ -0,0 +1,18 @@ +How to embed Excalidraw diagrams +================================ + +Start off by creating your diagram in https://excalidraw.com + +.. raw:: html + :file: ../images/excalidraw-example.svg + +Click 'Save as image' and make sure the 'Embed scene' checkbox is enabled. This is required for loading your image back into Excalidraw should you wish to make changes later on. Name your file and export to SVG, saving it inside ``docs/images``. + +Add the following to embed it inside your documentation:: + + .. raw:: html + :file: ../images/my-diagram.excalidraw.svg + +It is preferred to use the above convention over ``.. image::`` in order to retain the font used by Excalidraw. + +Rebuild the docs and open the resulting html inside a browser. \ No newline at end of file diff --git a/docs/how-to/existing.rst b/docs/how-to/existing.rst new file mode 100644 index 00000000..fcc6cc08 --- /dev/null +++ b/docs/how-to/existing.rst @@ -0,0 +1,103 @@ +How to adopt the skeleton in an existing repo +============================================= + +If you have an existing repo and would like to adopt the skeleton structure +then you can use the commandline tool to merge the skeleton into your repo:: + + python3-pip-skeleton existing /path/to/existing/repo --org my_github_user_or_org --skeleton-org some_institution + +This will: + +- Take the repo name from the last element of the path +- Take the package name from the repo name unless overridden by ``--package`` +- Clone the existing repo in /tmp +- Create a new orphan merge branch from the skeleton repo +- Use the version of the skeleton in ``some_institution``'s organization (default ``DiamondLightSource``) +- Create a single commit that modifies the skeleton with the repo and package name +- Push that merge branch back to the existing repo +- Merge with the currently checked out branch, leaving you to fix the conflicts + +.. note:: + + To enable publishing to PyPI see `../how-to/pypi` + +.. note:: + + To install the pre-commit see `../../developer/how-to/lint` + +Example merge +------------- + +As an example, `scanspec #46 +`_ shows the what this +adoption looks like. The commandline tool was run on the existing repo:: + + $ cd /path/to/scanspec + $ git checkout -b adopt-skeleton + Switched to a new branch 'adopt-skeleton' + $ python3-pip-skeleton existing . + Auto-merging src/scanspec/__main__.py + CONFLICT (add/add): Merge conflict in src/scanspec/__main__.py + Auto-merging src/scanspec/__init__.py + CONFLICT (add/add): Merge conflict in src/scanspec/__init__.py + Auto-merging setup.cfg + CONFLICT (add/add): Merge conflict in setup.cfg + Auto-merging pyproject.toml + CONFLICT (add/add): Merge conflict in pyproject.toml + Auto-merging docs/tutorials/installation.rst + CONFLICT (add/add): Merge conflict in docs/tutorials/installation.rst + Auto-merging docs/reference/api.rst + CONFLICT (add/add): Merge conflict in docs/reference/api.rst + Auto-merging docs/index.rst + CONFLICT (add/add): Merge conflict in docs/index.rst + Auto-merging docs/conf.py + CONFLICT (add/add): Merge conflict in docs/conf.py + Auto-merging docs/_static/theme_overrides.css + CONFLICT (add/add): Merge conflict in docs/_static/theme_overrides.css + Auto-merging README.rst + CONFLICT (add/add): Merge conflict in README.rst + Auto-merging Pipfile + CONFLICT (add/add): Merge conflict in Pipfile + Auto-merging CONTRIBUTING.rst + CONFLICT (add/add): Merge conflict in CONTRIBUTING.rst + Auto-merging CHANGELOG.rst + CONFLICT (add/add): Merge conflict in CHANGELOG.rst + Auto-merging .vscode/settings.json + CONFLICT (add/add): Merge conflict in .vscode/settings.json + Auto-merging .vscode/launch.json + CONFLICT (add/add): Merge conflict in .vscode/launch.json + Auto-merging .github/workflows/docs.yml + CONFLICT (add/add): Merge conflict in .github/workflows/docs.yml + Auto-merging .github/workflows/code.yml + CONFLICT (add/add): Merge conflict in .github/workflows/code.yml + Auto-merging .gitattributes + CONFLICT (add/add): Merge conflict in .gitattributes + Automatic merge failed; fix conflicts and then commit the result. + + Please fix the conflicts above, then you can run: + git branch -d skeleton-merge-branch + Instructions on how to develop this module are in CONTRIBUTING.rst + +First of the boilerplate files were removed:: + + $ git rm src/scanspec/hello.py docs/images/dls-logo.svg docs/images/dls-favicon.ico docs/how-to/accomplish-a-task.rst docs/explanations/why-is-something-so.rst -f + rm 'docs/explanations/why-is-something-so.rst' + rm 'docs/how-to/accomplish-a-task.rst' + rm 'docs/images/dls-favicon.ico' + rm 'docs/images/dls-logo.svg' + rm 'src/scanspec/hello.py' + +Then the merge conflicts were fixed, and the dependencies updated:: + + $ pip install -e .[dev] + +The tests and docs were then run and checked:: + + $ tox -p + +Finally the results were committed, pushed, merged to main:: + + $ git commit + $ git push github adopt-skeleton + +.. image:: ../images/git_merge.png diff --git a/docs/how-to/lint.rst b/docs/how-to/lint.rst new file mode 100644 index 00000000..8f4e92db --- /dev/null +++ b/docs/how-to/lint.rst @@ -0,0 +1,41 @@ +Run linting using pre-commit +============================ + +Code linting is handled by black_, flake8_ and isort_ run under pre-commit_. + +Running pre-commit +------------------ + +You can run the above checks on all files with this command:: + + $ tox -e pre-commit + +Or you can install a pre-commit hook that will run each time you do a ``git +commit`` on just the files that have changed:: + + $ pre-commit install + +It is also possible to `automatically enable pre-commit on cloned repositories `_. +This will result in pre-commits being enabled on every repo your user clones from now on. + +Fixing issues +------------- + +If black reports an issue you can tell it to reformat all the files in the +repository:: + + $ black . + +Likewise with isort:: + + $ isort . + +If you get any flake8 issues you will have to fix those manually. + +VSCode support +-------------- + +The ``.vscode/settings.json`` will run black and isort formatters as well as +flake8 checking on save. Issues will be highlighted in the editor window. + + diff --git a/docs/how-to/maintain-your-own-skeleton.rst b/docs/how-to/maintain-your-own-skeleton.rst new file mode 100644 index 00000000..1350b935 --- /dev/null +++ b/docs/how-to/maintain-your-own-skeleton.rst @@ -0,0 +1,12 @@ +Creating a new skeleton fork +============================ + +There may be some features in the DiamondLightSource skeleton which aren't required, +or some you want to add which Diamond doesn't require. The python3-pip-skeleton can be used +with any ``https://github.com/SomeInstitution/python3-pip-skeleton`` forked from +``https://github.com/DiamondLightSource/python3-pip-skeleton`` by using ``--skeleton-org SomeInstitution`` +when implementing the skeleton on a new or existing repo. + +The forked skeleton repo has to have the name ``python3-pip-skeleton``. It can be changed however the +institution requires, then DiamondLightSource's skeleton can be periodically pulled from upstream +to acquire the latest changes. \ No newline at end of file diff --git a/docs/how-to/make-release.rst b/docs/how-to/make-release.rst new file mode 100644 index 00000000..d4585266 --- /dev/null +++ b/docs/how-to/make-release.rst @@ -0,0 +1,16 @@ +Make a release +============== + +To make a new release, please follow this checklist: + +- Choose a new PEP440 compliant release number (see https://peps.python.org/pep-0440/) +- Go to the GitHub release_ page +- Choose ``Draft New Release`` +- Click ``Choose Tag`` and supply the new tag you chose (click create new tag) +- Click ``Generate release notes``, review and edit these notes +- Choose a title and click ``Publish Release`` + +Note that tagging and pushing to the main branch has the same effect except that +you will not get the option to edit the release notes. + +.. _release: https://github.com/DiamondLightSource/python3-pip-skeleton-cli/releases \ No newline at end of file diff --git a/docs/how-to/pin-requirements.rst b/docs/how-to/pin-requirements.rst new file mode 100644 index 00000000..89639623 --- /dev/null +++ b/docs/how-to/pin-requirements.rst @@ -0,0 +1,74 @@ +Pinning Requirements +==================== + +Introduction +------------ + +By design this project only defines dependencies in one place, i.e. in +the ``requires`` table in ``pyproject.toml``. + +In the ``requires`` table it is possible to pin versions of some dependencies +as needed. For library projects it is best to leave pinning to a minimum so +that your library can be used by the widest range of applications. + +When CI builds the project it will use the latest compatible set of +dependencies available (after applying your pins and any dependencies' pins). + +This approach means that there is a possibility that a future build may +break because an updated release of a dependency has made a breaking change. + +The correct way to fix such an issue is to work out the minimum pinning in +``requires`` that will resolve the problem. However this can be quite hard to +do and may be time consuming when simply trying to release a minor update. + +For this reason we provide a mechanism for locking all dependencies to +the same version as a previous successful release. This is a quick fix that +should guarantee a successful CI build. + +Finding the lock files +---------------------- + +Every release of the project will have a set of requirements files published +as release assets. + +For example take a look at the release page for python3-pip-skeleton-cli here: +https://github.com/DiamondLightSource/python3-pip-skeleton-cli/releases/tag/3.3.0 + +There is a list of requirements*.txt files showing as assets on the release. + +There is one file for each time the CI installed the project into a virtual +environment. There are multiple of these as the CI creates a number of +different environments. + +The files are created using ``pip freeze`` and will contain a full list +of the dependencies and sub-dependencies with pinned versions. + +You can download any of these files by clicking on them. It is best to use +the one that ran with the lowest Python version as this is more likely to +be compatible with all the versions of Python in the test matrix. +i.e. ``requirements-test-ubuntu-latest-3.8.txt`` in this example. + +Applying the lock file +---------------------- + +To apply a lockfile: + +- copy the requirements file you have downloaded to the root of your + repository +- rename it to requirements.txt +- commit it into the repo +- push the changes + +The CI looks for a requirements.txt in the root and will pass it to pip +when installing each of the test environments. pip will then install exactly +the same set of packages as the previous release. + +Removing dependency locking from CI +----------------------------------- + +Once the reasons for locking the build have been resolved it is a good idea +to go back to an unlocked build. This is because you get an early indication +of any incoming problems. + +To restore unlocked builds in CI simply remove requirements.txt from the root +of the repo and push. diff --git a/docs/how-to/pypi.rst b/docs/how-to/pypi.rst new file mode 100644 index 00000000..2545226f --- /dev/null +++ b/docs/how-to/pypi.rst @@ -0,0 +1,25 @@ +Creating a PyPI Token +===================== + +To publish your package on PyPI requires a PyPI account and for GitHub Actions +to have a PyPI token authorizing access to that account. + +The simplest approach is to set up a PyPI token that is scoped to your PyPI account +and add it to the secrets for your GitHub Organization (or user). This means +that all new projects created in the Organization will automatically gain +permission to publish to PyPI. + +Alternatively you can create a project scoped token for each project. This +is more work but more secure as a bad actor that obtains the key can only +affect a single project. + +If you do not already have a PyPI account use this link: create_account_. + +To learn how to create a token and store it in Github see: adding_a_token_. +You can ignore the other sections of the page regarding Github Actions because +these are already provided by skeleton. Note that skeleton uses ``PYPI_TOKEN`` +as the secret name instead of ``PYPI_API_TOKEN`` described in the link. + + +.. _create_account: https://pypi.org/account/register/ +.. _adding_a_token: https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/#saving-credentials-on-github diff --git a/docs/how-to/run-container.rst b/docs/how-to/run-container.rst new file mode 100644 index 00000000..e9a3a052 --- /dev/null +++ b/docs/how-to/run-container.rst @@ -0,0 +1,15 @@ +Run in a container +================== + +Pre-built containers with python3-pip-skeleton-cli and its dependencies already +installed are available on `Github Container Registry +`_. + +Starting the container +---------------------- + +To pull the container from github container registry and run:: + + $ docker run --rm ghcr.io/DiamondLightSource/python3-pip-skeleton-cli:main --version + +To get a released version, use a numbered release instead of ``main``. diff --git a/docs/how-to/run-tests.rst b/docs/how-to/run-tests.rst new file mode 100644 index 00000000..6350ad84 --- /dev/null +++ b/docs/how-to/run-tests.rst @@ -0,0 +1,14 @@ +.. _using pytest: + +Run the tests using pytest +========================== + +Testing is done with pytest_. It will find functions in the project that `look +like tests`_, and run them to check for errors. You can run it with:: + + $ tox -e pytest + +It will also report coverage to the commandline and to ``cov.xml``. + +.. _pytest: https://pytest.org/ +.. _look like tests: https://docs.pytest.org/explanation/goodpractices.html#test-discovery diff --git a/docs/how-to/static-analysis.rst b/docs/how-to/static-analysis.rst new file mode 100644 index 00000000..065920e1 --- /dev/null +++ b/docs/how-to/static-analysis.rst @@ -0,0 +1,8 @@ +Run static analysis using mypy +============================== + +Static type analysis is done with mypy_. It checks type definition in source +files without running them, and highlights potential issues where types do not +match. You can run it with:: + + $ tox -e mypy diff --git a/docs/how-to/test-container.rst b/docs/how-to/test-container.rst new file mode 100644 index 00000000..a4a43a6f --- /dev/null +++ b/docs/how-to/test-container.rst @@ -0,0 +1,25 @@ +Container Local Build and Test +============================== + +CI builds a runtime container for the project. The local tests +checks available via ``tox -p`` do not verify this because not +all developers will have docker installed locally. + +If CI is failing to build the container, then it is best to fix and +test the problem locally. This would require that you have docker +or podman installed on your local workstation. + +In the following examples the command ``docker`` is interchangeable with +``podman`` depending on which container cli you have installed. + +To build the container and call it ``test``:: + + cd + docker build -t test . + +To verify that the container runs:: + + docker run -it test --help + +You can pass any other command line parameters to your application +instead of --help. diff --git a/docs/how-to/update-tools.rst b/docs/how-to/update-tools.rst new file mode 100644 index 00000000..c1075ee8 --- /dev/null +++ b/docs/how-to/update-tools.rst @@ -0,0 +1,16 @@ +Update the tools +================ + +This module is merged with the python3-pip-skeleton_. This is a generic +Python project structure which provides a means to keep tools and +techniques in sync between multiple Python projects. To update to the +latest version of the skeleton, run:: + + $ git pull --rebase=false https://github.com/DiamondLightSource/python3-pip-skeleton + +Any merge conflicts will indicate an area where something has changed that +conflicts with the setup of the current module. Check the `closed pull requests +`_ +of the skeleton module for more details. + +.. _python3-pip-skeleton: https://DiamondLightSource.github.io/python3-pip-skeleton diff --git a/docs/how-to/update.rst b/docs/how-to/update.rst new file mode 100644 index 00000000..db9e7ce1 --- /dev/null +++ b/docs/how-to/update.rst @@ -0,0 +1,14 @@ +How to update to the latest skeleton structure +============================================== + +If you used the commandline tool to create your repo (or adopt the skeleton +structure in an existing repo) some time ago, there may be some changes to the +structure that you could pick up. You can optionally check what differences +these changes make to the files by doing:: + + $ git fetch https://github.com/DiamondLightSource/python3-pip-skeleton main + $ git diff ...FETCH_HEAD + +To merge the changes in do:: + + $ git pull https://github.com/DiamondLightSource/python3-pip-skeleton main diff --git a/docs/images/dls-logo.svg b/docs/images/dls-logo.svg new file mode 100644 index 00000000..0af1a177 --- /dev/null +++ b/docs/images/dls-logo.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/images/excalidraw-example.svg b/docs/images/excalidraw-example.svg new file mode 100644 index 00000000..9f8b3fd9 --- /dev/null +++ b/docs/images/excalidraw-example.svg @@ -0,0 +1,16 @@ + + + eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1aXXObOFx1MDAxNH3Pr8i4r3WKvqW+pU13J1snTep02mans0OA2DRcdTAwMThcXMD56vS/r8AxQmBcdTAwMDduN9ntdOuHTJDOQVfiXHUwMDFl6d5cdTAwMGJft7a3XHUwMDA3+c08XHUwMDE4PN9cdTAwMWVcdTAwMDTXnlx1MDAxYoV+6l5ccp5cdTAwMTbtl0GahUmsu3B5nSWL1CuR0zyfZ8+fPTOMXHUwMDFkL5ktWUFcdTAwMTTMgjjPNO5Pfb29/bX8q3tCv+BcdTAwMGX5x1x1MDAwZvH49q+Tj1x1MDAxZc3PxrtMJKODklqCVsb4oTtLYt90XFzrVqZkdX1T2CVZdX1cdTAwMTX6+VS3oVrbNFxiJ9O80ejGk6hcdTAwMTjCqVqyPE0ugpdJlKTF0E9cXI5cdTAwMDJaXHUwMDFi+sz1LiZpsoj9XG6Tp26czd1Uz9TgzsMoXHUwMDFh5zfRco1cXG+6SINBY5T3d2bSRnvFy1x1MDAxMr2ihqWHnUzjICvWXHUwMDEzVa3J3PXCvFhcdTAwMDLkmHlcdTAwMTQ2zvf9cuk/Ne8/ddP53X1cdTAwMDZZcVGzLFxiikeDXHUwMDExxYJcdTAwMTOH46rHuFx1MDAwMKKi2XqYxKU7KFx1MDAwN1x0hVx1MDAxODW0MNvTbpCXdz13oywwS1ms4qumi9TdpOYqt55/hN5cdTAwMWSeXHUwMDFlvp1E4Zfsy3BcdTAwMTJkf1RmW+7ipmlyNah6vj1df99cdTAwMTU8XHUwMDBmrnP7RstcdTAwMTE/777YRePI3TuavkHZdLR7dlx1MDAxNo5qt737zyzuYu67y3lcIk6VZFx1MDAwMisplHm4UVx1MDAxOF/oznhcdTAwMTFFpi3xLszSbNXsbUjl/vk35m5cdEVIWyhEiLZQhNNcdTAwMTZcblx1MDAwNsgk4EI4zk8sk3IuLZkoppR299pDNipRfJNIXHUwMDE4xophQfl3iMTynpbHXHUwMDExzjnBXHUwMDAwj6ua50nYVKH5b9s8+fKi+v/T07XomjtcdTAwMTU/bPAt0URulr9MZrMw11x1MDAxMzkqjGhcdTAwMWGc5W6av1xiYz+MJ7rPaHh1vOz3OEtcbldLvEUxwaGzozcp6XCHXCJCXHUwMDE4ZVx1MDAwNNVQXHUwMDEzd15oZEdK5UitYM4wv+utNpJBXHUwMDEw+8agtrG7hVxip4HrN3s1r95X36nWq/70lry/TEen/sn48PgwOj99M75cdTAwMTm3VX+eandcXJ3VZU8hfCWNg5XCp6QtfLXuhDS4buVcdTAwMTNOzz3x/1M+J4pyKtYpXHUwMDFmUdRsXUlcdTAwMWZhobh2KkN7KOnr+EdcIvWfS5+A0FxmhEZAUzjMXHUwMDE2y3TUXHUwMDA1N5FR8cOdcFWHky648aviRzvhXHUwMDAyXHUwMDA2VyC4tNaddcJcdTAwMTFcZo5hcFx1MDAwMoMzXHUwMDE4XFzA4FxuXHUwMDA0V7CpKthTRVx1MDAwZVx1MDAwNvlcdTAwMThyXHUwMDE0yONcdTAwMTG2/GDY6fO1PKEk8E5cdTAwMDKz3H4oulx0XHUwMDFjSpBcdTAwMTZBdlx1MDAxMrhcdTAwMDMlIChcdTAwMDFDXHRcdTAwMDRKoFCCXHUwMDAwLqu9vfUg2Fx1MDAxMWJcdTAwMGbXXHUwMDEwXGJKsJe1U23I3nOH3XpcdTAwMTPW3jLsXHUwMDE2nLC9tVtAQlx1MDAwMlx09lY97Na0vVn3IVAogUNcdFx1MDAxMkhQ0Enb+3CPZVVcdTAwMDRKoFBcdTAwMDL7Z4Ru59tM2GpcdTAwMTBcdTAwMDfzVMe+Olx1MDAxZW9cdTAwMDbH4WxcdTAwMTHpqPPorlv35unCXHUwMDA0kmtzOWODZUE1/nL09enPwWR0ffx6fFx1MDAxMtxeXHUwMDA3Izo9il4t3FH/9MekMcu6h0mHVulcdTAwMGZ2TFuV/pimX9nPhuxHn4pcdTAwMThcdTAwMTNH4laNo1x1MDAxY2dj5UN3OUinP/LhS1x1MDAxZj9I/oNB6MfMllx1MDAwNFxijVx1MDAxMFxmXHUwMDBl3KMxcMfFXG6GJ8CDklx1MDAwMe/fOMR6xOJcdTAwMTJIQNBcdTAwMTGQgFx1MDAxMqAmNeL9XHUwMDFlXHUwMDA0XHUwMDA2JFx1MDAxMOghRlx1MDAxMey5IVxuPVcp0DNcdTAwMTDDMCkgxqBcdTAwMDRcdTAwMDUkNFx1MDAxMoRcdTAwMWVcdTAwMDSoSVx1MDAxY1x1MDAxYZhcbmjuKKAxmoCGXFxcdTAwMDJcdTAwMWGYXG5gvixhJaJGaN1cdTAwMDMvYHi1qSrfK4jtgZcgPHZg64NcdTAwMWRcdTAwMDbE81x1MDAwN8JvNXiPXHUwMDE0IFtcdTAwMDashr8vPo7Op3uvboLLsz3+ct+7unWPs7dO3/hYh4P2+1x1MDAwMWrOrNqLQfM2qVxukFxy7FeAvCFAJpRiSSVd+/pcdTAwMWPLZusqPuY6NFx1MDAxNsRcdTAwMWPUP1t0XGZcdTAwMGIyoadcdTAwMTi49lx1MDAwMYwxgaFcdTAwMDRcdTAwMDPWkzhcdTAwMTRv299Z4GpcdTAwMWOQnVx1MDAxNTT7+Oqu6TXKMN14XHUwMDA2w9fk2ZdcdTAwMDBcdTAwMWVcdTAwMDFaxrTTpj5cdTAwMDRohVx1MDAxYkFr6JjA3KK2XHUwMDFk9SRcdTAwMTBcZnNURKCVVWI/h1x1MDAxZXlcdTAwMDG0QNd4NdEjXGJcdTAwMDcmyLb6e+Ct4KOHPVx1MDAxMoa332P0wGMgXHUwMDFl9vq0kXL0wFx1MDAwM9eHXHUwMDAz10dcdTAwMDDXx35cdTAwMWbRXHUwMDAzXHUwMDBmq1xmbcZvNXiPVa2tXHUwMDFisFx1MDAxYf6+YHT993KtYNT63K5cZkS50yjUMrqz5ltOseZLXHUwMDE1XG6p1TpSnLOzx1xyRVGj/Vx1MDAwN/iUXHUwMDEzXHUwMDExrVx1MDAwNeJI0oo6y1XdXHUwMDE0imJGueSYXHUwMDE5O1x1MDAxZewjNcLrj1x1MDAxY1x1MDAxMIuWvqMnejJccrPa80nifFx1MDAxY95cdTAwMTZGm08+ytbf3FlcdTAwMTjdWEtcXNxiN1xuJ8XkXHUwMDA3nrY3SFx1MDAwN/UlyEPPjSrALPT9KKi7TFx1MDAxNmh7y6FMaO/poVxc3Zr2+Vx1MDAxMm2QpOEkjN3opD6Ze3SVvEv916NcdTAwMDN68Plm/Lsz+bB/SI8u+uhcbjnmXHUwMDE4XSZ4mLZkpdbkd79U1a0qKZlcdTAwMTJS4XVcdJ6p17Xef1BBXHUwMDE4XHUwMDE2Qj18hkcocWpq/i5Vufm/oqo8mcMkZc2irVx1MDAxZm32Uj9bd8fiwJ3Px7len8Hqe9HBZVx1MDAxOFxcvWi75lx1MDAxM8dxXG5yKb3CJ8tT9Ou3rW9/XHUwMDAzNtdm0SJ9 + + + + ThisThat \ No newline at end of file diff --git a/docs/images/git_merge.png b/docs/images/git_merge.png new file mode 100644 index 00000000..370ec242 Binary files /dev/null and b/docs/images/git_merge.png differ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..ccdee226 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,59 @@ +--- +html_theme.sidebar_secondary.remove: true +--- + +```{include} ../README.md +:end-before: + +::::{grid} 2 +:gutter: 4 + +:::{grid-item-card} {material-regular}`directions_walk;2em` +```{toctree} +:maxdepth: 2 +tutorials +``` ++++ +Tutorials for installation and typical usage. New users start here. +::: + +:::{grid-item-card} {material-regular}`directions;2em` +```{toctree} +:maxdepth: 2 +how-to +``` ++++ +Practical step-by-step guides for the more experienced user. +::: + +:::{grid-item-card} {material-regular}`info;2em` +```{toctree} +:maxdepth: 2 +explanations +``` ++++ +Explanations of how it works and why it works that way. +::: + +:::{grid-item-card} {material-regular}`menu_book;2em` +```{toctree} +:maxdepth: 2 +reference +``` ++++ +Technical reference material including APIs and release notes. +::: + +:::: diff --git a/docs/reference.md b/docs/reference.md new file mode 100644 index 00000000..5ef05fee --- /dev/null +++ b/docs/reference.md @@ -0,0 +1,12 @@ +# Reference + +Technical reference material including APIs and release notes. + +```{toctree} +:maxdepth: 1 +:glob: + +reference/* +genindex +Release Notes +``` diff --git a/docs/reference/standards.rst b/docs/reference/standards.rst new file mode 100644 index 00000000..b78a719e --- /dev/null +++ b/docs/reference/standards.rst @@ -0,0 +1,64 @@ +Standards +========= + +This document defines the code and documentation standards used in this +repository. + +Code Standards +-------------- + +The code in this repository conforms to standards set by the following tools: + +- black_ for code formatting +- flake8_ for style checks +- isort_ for import ordering +- mypy_ for static type checking + +.. seealso:: + + How-to guides `../how-to/lint` and `../how-to/static-analysis` + +.. _documentation_standards: + +Documentation Standards +----------------------- + +Docstrings are pre-processed using the Sphinx Napoleon extension. As such, +google-style_ is considered as standard for this repository. Please use type +hints in the function signature for types. For example: + +.. code:: python + + def func(arg1: str, arg2: int) -> bool: + """Summary line. + + Extended description of function. + + Args: + arg1: Description of arg1 + arg2: Description of arg2 + + Returns: + Description of return value + """ + return True + +.. _google-style: https://sphinxcontrib-napoleon.readthedocs.io/en/latest/index.html#google-vs-numpy + +Documentation is contained in the ``docs`` directory and extracted from +docstrings of the API. + +Docs follow the underlining convention:: + + Headling 1 (page title) + ======================= + + Heading 2 + --------- + + Heading 3 + ~~~~~~~~~ + +.. seealso:: + + How-to guide `../how-to/build-docs` \ No newline at end of file diff --git a/docs/tutorials.md b/docs/tutorials.md new file mode 100644 index 00000000..1fe66c54 --- /dev/null +++ b/docs/tutorials.md @@ -0,0 +1,10 @@ +# Tutorials + +Tutorials for installation and typical usage. New users start here. + +```{toctree} +:maxdepth: 1 +:glob: + +tutorials/* +``` diff --git a/docs/tutorials/dev-install.rst b/docs/tutorials/dev-install.rst new file mode 100644 index 00000000..032a76c1 --- /dev/null +++ b/docs/tutorials/dev-install.rst @@ -0,0 +1,60 @@ +Developer install +================= + +These instructions will take you through the minimal steps required to get a dev +environment setup, so you can run the tests locally. + +Clone the repository +-------------------- + +First clone the repository locally using `Git +`_:: + + $ git clone git://github.com/DiamondLightSource/python3-pip-skeleton-cli.git + +Install dependencies +-------------------- + +You can choose to either develop on the host machine using a `venv` (which +requires python 3.8 or later) or to run in a container under `VSCode +`_ + +.. tab-set:: + + .. tab-item:: Local virtualenv + + .. code:: + + $ cd python3-pip-skeleton-cli + $ python3 -m venv venv + $ source venv/bin/activate + $ pip install -e .[dev] + + .. tab-item:: VSCode devcontainer + + .. code:: + + $ vscode python3-pip-skeleton-cli + # Click on 'Reopen in Container' when prompted + # Open a new terminal + +See what was installed +---------------------- + +To see a graph of the python package dependency tree type:: + + $ pipdeptree + +Build and test +-------------- + +Now you have a development environment you can run the tests in a terminal:: + + $ tox -p + +This will run in parallel the following checks: + +- `../how-to/build-docs` +- `../how-to/run-tests` +- `../how-to/static-analysis` +- `../how-to/lint` diff --git a/docs/tutorials/installation.rst b/docs/tutorials/installation.rst new file mode 100644 index 00000000..77e96ca3 --- /dev/null +++ b/docs/tutorials/installation.rst @@ -0,0 +1,47 @@ +Installation +============ + +Check your version of python +---------------------------- + +You will need python 3.8 or later. You can check your version of python by +typing into a terminal:: + + $ python3 --version + + +Create a virtual environment +---------------------------- + +It is recommended that you install into a “virtual environment” so this +installation will not interfere with any existing Python software:: + + $ python3 -m venv /path/to/venv + $ source /path/to/venv/bin/activate + +.. note:: + + You may wish to deactivate any existing virual environments before sourcing the new + environment. Deactivation can be performed by executing: + + - :code:`conda deactivate` for conda + - :code:`deactivate` for venv or virtualenv + - :code:`exit` for pipenv + + +Installing the library +---------------------- + +You can now use ``pip`` to install the library and its dependencies:: + + $ python3 -m pip install python3-pip-skeleton + +If you require a feature that is not currently released you can also install +from github:: + + $ python3 -m pip install git+https://github.com/DiamondLightSource/python3-pip-skeleton-cli.git + +The library should now be installed and the commandline interface on your path. +You can check the version that has been installed by typing:: + + $ python3-pip-skeleton --version diff --git a/docs/tutorials/new.rst b/docs/tutorials/new.rst new file mode 100644 index 00000000..f73e5125 --- /dev/null +++ b/docs/tutorials/new.rst @@ -0,0 +1,119 @@ +Creating a new repo from the skeleton +===================================== + +Once you have followed the ``installation`` tutorial, you can use the +commandline tool to make a new repo that inherits the skeleton:: + + python3-pip-skeleton new /path/to/be/created --org my_github_user_or_org --skeleton-org some_institution + +This will: + +- Take the repo name from the last element of the path +- Take the package name from the repo name unless overridden by ``--package`` +- Create a new repo at the requested path, forked from the skeleton repo +- Create a single commit that modifies the skeleton with the repo and package name +- Use the version of the skeleton in ``some_institution``'s organization (default ``DiamondLightSource``) + + +Getting started with your new repo +---------------------------------- + +Your new repo has a workflow based on pip. The first thing to do is to use +pip to install packages in a virtual environment:: + + python -m venv .venv + source .venv/bin/activate + pip install -e .[dev] + +.. note:: + + You may wish to deactivate any existing virual environments before sourcing the new + environment. Deactivation can be performed by executing: + + - :code:`conda deactivate` for conda + - :code:`deactivate` for venv or virtualenv + - :code:`exit` for pipenv + +You can then run any entry points declared in setup.cfg e.g.:: + + python3-pip-skeleton --version + +will run the python interpreter with access to all the packages you need to +develop your repo. + +PyPI Token +---------- + +The Github Actions Continuous Integration will publish your package to PyPI. +To do so you need a PyPI account and and a PyPI Token configured in your +project or github Organization. + +see `../how-to/pypi` + +Setting up pre-commit +--------------------- + +To install the pre-commit see `../../developer/how-to/lint`. + +Running the tests +----------------- + +There are also some extra convenience scripts provided via tox:: + + tox -p + +Will run in parallel all of the checks that CI performs. + +It will run ``pytest`` to find all the unit tests and run them. The first time you +run this, there will be some failing tests:: + + ============================================================================ short test summary info ============================================================================ + FAILED tests/test_boilerplate_removed.py::test_module_description - AssertionError: Please change description in ./setup.cfg to be a one line description of your module + FAILED tests/test_boilerplate_removed.py::test_changed_README_intro - AssertionError: Please change ./README.rst to include an intro on what your module does + FAILED tests/test_boilerplate_removed.py::test_changed_README_body - AssertionError: Please change ./README.rst to include some features and why people should use it + FAILED tests/test_boilerplate_removed.py::test_removed_CHANGELOG_note - AssertionError: Please change ./CHANGELOG.rst To remove the note at the top + FAILED tests/test_boilerplate_removed.py::test_changed_CHANGELOG - AssertionError: Please change ./CHANGELOG.rst To summarize changes to your module as you make them + ========================================================================== 8 failed, 5 passed in 0.28s ========================================================================== + +When you change the template text mentioned in the error, these tests will pass. +If you intend to fix the test later, you can mark the tests as "expected to +fail" by adding a decorator to the relevant function. For example: + +.. code-block:: python + + @pytest.mark.xfail(reason="docs not written yet") + def test_explanations_written(): + ... + +Building the docs +----------------- + +There is also a convenience script for building the docs:: + + tox -e docs + +You can then view the docs output with a web browse:: + + firefox build/html/index.html + +Pushing to GitHub +----------------- + +To push the resulting repo to GitHub, first create an empty repo from the GitHub +website, then run the following:: + + git remote add $(cat .gitremotes) + git push -u github main + +This will then run the continuous integration (CI) jobs, which run the tests and +build the docs using the commands above. + +Once the docs build has passed, you can use the Settings on the repo page on the +GitHub website to enable github pages publishing of the ``gh-pages`` branch. + +What next? +---------- + +Now you can make the repo your own, add code, write docs, delete what you don't +like, then push a tag and CI will make a release and push it to PyPI. Look at +the `How-To <../index>` for articles on these and other topics. diff --git a/requirements.in b/requirements.in new file mode 100644 index 00000000..2dd41841 --- /dev/null +++ b/requirements.in @@ -0,0 +1,7 @@ +myst-parser +pip-tools +pre-commit +pydata-sphinx-theme>=0.12 +sphinx-autobuild +sphinx-copybutton +sphinx-design diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..7c2f71dd --- /dev/null +++ b/requirements.txt @@ -0,0 +1,145 @@ +# +# This file is autogenerated by pip-compile with Python 3.9 +# by the following command: +# +# pip-compile +# +accessible-pygments==0.0.4 + # via pydata-sphinx-theme +alabaster==0.7.16 + # via sphinx +babel==2.14.0 + # via + # pydata-sphinx-theme + # sphinx +beautifulsoup4==4.12.3 + # via pydata-sphinx-theme +build==1.0.3 + # via pip-tools +certifi==2023.11.17 + # via requests +cfgv==3.4.0 + # via pre-commit +charset-normalizer==3.3.2 + # via requests +click==8.1.7 + # via pip-tools +colorama==0.4.6 + # via sphinx-autobuild +distlib==0.3.8 + # via virtualenv +docutils==0.20.1 + # via + # myst-parser + # pydata-sphinx-theme + # sphinx +filelock==3.13.1 + # via virtualenv +identify==2.5.33 + # via pre-commit +idna==3.6 + # via requests +imagesize==1.4.1 + # via sphinx +importlib-metadata==7.0.1 + # via + # build + # sphinx +jinja2==3.1.3 + # via + # myst-parser + # sphinx +livereload==2.6.3 + # via sphinx-autobuild +markdown-it-py==3.0.0 + # via + # mdit-py-plugins + # myst-parser +markupsafe==2.1.4 + # via jinja2 +mdit-py-plugins==0.4.0 + # via myst-parser +mdurl==0.1.2 + # via markdown-it-py +myst-parser==2.0.0 + # via -r requirements.in +nodeenv==1.8.0 + # via pre-commit +packaging==23.2 + # via + # build + # pydata-sphinx-theme + # sphinx +pip-tools==7.3.0 + # via -r requirements.in +platformdirs==4.1.0 + # via virtualenv +pre-commit==3.6.0 + # via -r requirements.in +pydata-sphinx-theme==0.15.2 + # via -r requirements.in +pygments==2.17.2 + # via + # accessible-pygments + # pydata-sphinx-theme + # sphinx +pyproject-hooks==1.0.0 + # via build +pyyaml==6.0.1 + # via + # myst-parser + # pre-commit +requests==2.31.0 + # via sphinx +six==1.16.0 + # via livereload +snowballstemmer==2.2.0 + # via sphinx +soupsieve==2.5 + # via beautifulsoup4 +sphinx==7.2.6 + # via + # myst-parser + # pydata-sphinx-theme + # sphinx-autobuild + # sphinx-copybutton + # sphinx-design +sphinx-autobuild==2021.3.14 + # via -r requirements.in +sphinx-copybutton==0.5.2 + # via -r requirements.in +sphinx-design==0.5.0 + # via -r requirements.in +sphinxcontrib-applehelp==1.0.8 + # via sphinx +sphinxcontrib-devhelp==1.0.6 + # via sphinx +sphinxcontrib-htmlhelp==2.0.5 + # via sphinx +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==1.0.7 + # via sphinx +sphinxcontrib-serializinghtml==1.1.10 + # via sphinx +tomli==2.0.1 + # via + # build + # pip-tools + # pyproject-hooks +tornado==6.4 + # via livereload +typing-extensions==4.9.0 + # via pydata-sphinx-theme +urllib3==2.1.0 + # via requests +virtualenv==20.25.0 + # via pre-commit +wheel==0.42.0 + # via pip-tools +zipp==3.17.0 + # via importlib-metadata + +# The following packages are considered to be unsafe in a requirements file: +# pip +# setuptools