diff --git a/.python-version-default b/.python-version-default new file mode 100644 index 00000000..e4fba218 --- /dev/null +++ b/.python-version-default @@ -0,0 +1 @@ +3.12 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8e054210..e76db701 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,19 +1,201 @@ -Contributing -============ +# Contributing -Issues ------- -Issues are intended for bug report and feature requests. For any bug report please make sure to include the complete -stack trace and DEBUG level logs as well as reproduce steps. +Thank you for considering contributing to *subliminal*! -If you use the CLI, you can create a debug log file with `subliminal --debug [...] 2> debug.log`. +This document presents general guidelines to make contributions easier. -Pull Requests -------------- -You can contribute code and documentation with pull requests. Any code contribution must be unit tested and the pull -request open against the *develop* branch. +## Translations -Translations ------------- Contribution to translations can be made on [subliminal's transifex page](https://www.transifex.com/subliminal/subliminal/) Subliminal is configured to work with [transifex-client](http://docs.transifex.com/client/) + +## Issues + +Issues are intended for bug report and feature requests. +For any bug report please make sure to include the complete stack trace and DEBUG level logs as well as reproduce steps. + +If you use the CLI, you can create a debug log file with +`subliminal --debug [...] 2> debug.log`. + +## Pull Requests + +You can contribute code and documentation with pull requests. +Here follow some general guidelines for making a pull request. + +### Workflow + +- Any contribution is appreciated! +- Try to limit each pull request to *one* change only. +- Pull request should be linked to an issue. Create an issue first, +that is solved by this pull request. +- *Always* add tests and docs for your code. + If tests are not passing, ask for advice. +- Make sure your changes pass our [CI]. + You won't get any feedback until it's green unless you ask for it. +- For the CI to pass, the coverage must be 100%. + If you have problems to test something, open anyway and ask for advice. + In some situations, we may agree to add an `# pragma: no cover`. +- Once you've addressed review feedback, make sure to bump the pull request with a short note, so we know you're done. +- Don’t break backwards-compatibility. + + +### Local Development Environment + +You can (and should) run our test suite using [*tox*]. +However, you’ll probably want a more traditional environment as well. + +First, create a [virtual environment](https://virtualenv.pypa.io/) so you don't break your system-wide Python installation. +We recommend using the Python version from the `.python-version-default` file in project's root directory. + +--- + +Then, [fork](https://github.com/Diaoul/subliminal/fork) the repository on GitHub. + +Clone the fork to your computer: + +```console +$ git clone git@github.com:/subliminal.git +``` + +Or if you prefer to use Git via HTTPS: + +```console +$ git clone https://github.com//subliminal.git +``` + +Then add the *subliminal* repository as *upstream* remote: + +```console +$ git remote add -t main -m main --tags upstream https://github.com/Diaoul/subliminal.git +``` + +The next step is to sync your local copy with the upstream repository: + +```console +$ git fetch upstream +``` + +This is important to obtain eventually missing tags, which are needed to install the development version later on. + +Change into the newly created directory and after activating a virtual environment install an editable version of *subliminal* along with its tests and docs requirements: + +```console +$ cd subliminal +$ python -m pip install --upgrade pip wheel # PLEASE don't skip this step +$ python -m pip install -e '.[dev]' +``` + +At this point, + +```console +$ python -m pytest +``` + +should work and pass. +You can *significantly* speed up the test suite by installing [*pytest-xdist*](https://github.com/pytest-dev/pytest-xdist) +and passing `-n auto` to *pytest* to take advantage of all your CPU cores. + + +To build the documentation and run doctests, use: + +```console +$ tox run -e docs +``` + +You will find the built documentation in `docs/_build/html`. + + +--- + +To file a pull request, create a new branch on top of the upstream repository's `main` branch: + +```console +$ git fetch upstream +$ git checkout -b my_topical_branch upstream/main +``` + +Make your changes, push them to your fork (the remote *origin*): + +```console +$ git push -u origin +``` + +and publish the PR in GitHub's web interface! + +After your pull request is merged and the branch is no longer needed, delete it: + +```console +$ git checkout main +$ git push --delete origin my_topical_branch && git branch -D my_topical_branch +``` + +Before starting to work on your next pull request, run the following command to sync your local repository with the remote *upstream*: + +```console +$ git fetch upstream -u main:main +``` + +--- + +To avoid committing code that violates our style guide, we strongly advise you to install [*pre-commit*] and its hooks: + +```console +$ pre-commit install +``` + +This is not strictly necessary, because our [*tox*] file contains an environment that runs: + +```console +$ pre-commit run --all-files +``` + +and our CI has integration with [pre-commit.ci](https://pre-commit.ci). +But it's way more comfortable to run it locally and *git* catching avoidable errors. + + +### Changelog + +If your change is noteworthy, there needs to be a changelog entry so our users can learn about it! + +To avoid merge conflicts, we use the [*Towncrier*](https://pypi.org/project/towncrier) package to manage our changelog. +*towncrier* uses independent *Markdown* files for each pull request – so called *news fragments* – instead of one monolithic changelog file. +On release, those news fragments are compiled into our [`HISTORY.rst`](https://github.com/Diaoul/subliminal/blob/main/HISTORY.rst). + +You don't need to install *Towncrier* yourself, you just have to abide by a few simple rules: + +- For each pull request, add a new file into `changelog.d` with a filename adhering to the `issue#.(breaking|change|provider|refiner|deprecation|misc).md` schema: + For example, `changelog.d/42.change.md` for a non-breaking change that is proposed in issue #42. +- As with other docs, please use [semantic newlines] within news fragments. +- Wrap symbols like modules, functions, or classes into backticks so they are rendered in a `monospace font`. +- Wrap arguments into asterisks like in docstrings: + `Added new argument *an_argument*.` +- If you mention functions or other callables, add parentheses at the end of their names: + `subliminal.func()` or `subliminal.Class.method()`. + This makes the changelog a lot more readable. +- Prefer simple past tense or constructions with "now". + For example: + + + Added `subliminal.super_cool_func()`. + + `subliminal.func()` now doesn't crash anymore. +- If you want to reference multiple issues, copy the news fragment to another filename. + *Towncrier* will merge all news fragments with identical contents into one entry with multiple links to the respective pull requests. + +Example entry: + + ```md + Added `subliminal.super_cool_func()`. + The feature is really *super cool*. + + ``` + +`tox run -e changelog` will render the current changelog to the terminal if you have any doubts. + +--- + +*Thanks to Hynek and the [attrs development team](https://github.com/python-attrs/attrs) for the fantastic workflows and documentation, this file was shamelessly modified from theirs.* + + +[CI]: https://github.com/Diaoul/subliminal/actions?query=workflow%3ACI +[*pre-commit*]: https://pre-commit.com/ +[*tox*]: https://tox.wiki/ +[semantic newlines]: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ diff --git a/MANIFEST.in b/MANIFEST.in index 09049630..5e4af6bd 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -5,6 +5,7 @@ include Dockerfile include .dockerignore include .pre-commit-config.yaml include .readthedocs.yaml +include .python-version-default include tox.ini graft docs diff --git a/pyproject.toml b/pyproject.toml index 880d8d95..3d2613fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,11 +66,13 @@ test = [ "pytest>=6.0", "pytest-cov", "pytest-flakes", + "pytest-xdist", "sympy", "vcrpy>=1.6.1", "importlib_metadata>=4.6; python_version<'3.10'", ] dev = [ + "pre-commit", "doc8", "mypy", "ruff", diff --git a/tox.ini b/tox.ini index 1f4aeedc..b6497b5f 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,57 @@ [tox] -envlist = {py38,py39,py310,py311,py312}-{native,lxml} +min_version = 4 +env_list = + pre-commit, + py3{9,10,11,12}-tests, + changelog, + pre-commit, + docs, + docs-linkcheck, + +[testenv:.pkg] +pass_env = SETUPTOOLS_SCM_PRETEND_VERSION [testenv] -deps = - lxml: lxml -commands = pytest +package = wheel +wheel_build_env = .pkg +extras = + tests: test + coverage: test + mypy: test +commands = + tests: pytest {posargs:-n auto} + coverage: pytest --cov --cov-report term {posargs:-n auto} + mypy: mypy --install-types --non-interactive subliminal tests + + +[testenv:pre-commit] +description = + run pre-commit-defined linters under `{basepython}` +skip_install = True +basepython = python3 +deps = pre-commit>=2.9.3 +commands = pre-commit run --all-files --show-diff-on-failure {posargs:} +setenv = + # pre-commit and tools it launches are not clean of this warning. + PYTHONWARNDEFAULTENCODING= + + +[testenv:docs] +# Keep base_python in-sync with check.yaml/docs and .readthedocs.yaml. +base_python = py312 +extras = docs +commands = + sphinx-build -n -T -W --keep-going -b html -d {envtmpdir}/doctrees docs docs/_build/html + sphinx-build -n -T -W --keep-going -b doctest -d {envtmpdir}/doctrees docs docs/_build/html + +[testenv:docs-linkcheck] +package = editable +base_python = {[testenv:docs]base_python} +extras = {[testenv:docs]extras} +commands = sphinx-build -W --keep-going -b linkcheck -d {envtmpdir}/doctrees docs docs/_build/html + +[testenv:changelog] +extras = docs +allowlist_externals = towncrier +skip_install = true +commands = towncrier build --version main --draft