mirror of
https://github.com/enpaul/tox-poetry-installer.git
synced 2024-10-29 19:47:00 +00:00
Proofreading and editing fixes
Check spelling more thoroughly Improve clarity in a few places Fix grammar mistakes Fix docs that didn't get updated for the 0.2 overhaul
This commit is contained in:
parent
2e1d5fc922
commit
5411025612
151
README.md
151
README.md
@ -1,9 +1,9 @@
|
|||||||
# tox-poetry-installer
|
# tox-poetry-installer
|
||||||
|
|
||||||
A plugin for [Tox](https://tox.readthedocs.io/en/latest/) that allows test environment
|
A plugin for [Tox](https://tox.readthedocs.io/en/latest/) that allows test environment
|
||||||
dependencies to be installed using [Poetry](https://python-poetry.org/) using its lockfile.
|
dependencies to be installed using [Poetry](https://python-poetry.org/) from its lockfile.
|
||||||
|
|
||||||
⚠️ **This project is alpha software and should not be used in a production capacity** ⚠️
|
⚠️ **This project is alpha software and should not be used in production environments** ⚠️
|
||||||
|
|
||||||
[![image](https://img.shields.io/pypi/l/tox-poetry-installer)](https://opensource.org/licenses/MIT)
|
[![image](https://img.shields.io/pypi/l/tox-poetry-installer)](https://opensource.org/licenses/MIT)
|
||||||
[![image](https://img.shields.io/pypi/v/tox-poetry-installer)](https://pypi.org/project/tox-poetry-installer/)
|
[![image](https://img.shields.io/pypi/v/tox-poetry-installer)](https://pypi.org/project/tox-poetry-installer/)
|
||||||
@ -31,7 +31,7 @@ Related resources:
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Add the plugin as a development dependency a project using Poetry:
|
Add the plugin as a development dependency of a Poetry project:
|
||||||
|
|
||||||
```
|
```
|
||||||
~ $: poetry add tox-poetry-installer --dev
|
~ $: poetry add tox-poetry-installer --dev
|
||||||
@ -43,11 +43,10 @@ Confirm that the plugin is installed, and Tox recognizes it, by checking the Tox
|
|||||||
~ $: poetry run tox --version
|
~ $: poetry run tox --version
|
||||||
3.20.0 imported from .venv/lib64/python3.8/site-packages/tox/__init__.py
|
3.20.0 imported from .venv/lib64/python3.8/site-packages/tox/__init__.py
|
||||||
registered plugins:
|
registered plugins:
|
||||||
tox-poetry-installer-0.2.0 at .venv/lib64/python3.8/site-packages/tox_poetry_installer.py
|
tox-poetry-installer-0.2.2 at .venv/lib64/python3.8/site-packages/tox_poetry_installer.py
|
||||||
```
|
```
|
||||||
|
|
||||||
If using in a CI/automation environment using Pip, ensure that the plugin is installed to the
|
If using Pip, ensure that the plugin is installed to the same environment as Tox:
|
||||||
same environment as Tox:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
# Calling the virtualenv's 'pip' binary directly will cause pip to install to that virtualenv
|
# Calling the virtualenv's 'pip' binary directly will cause pip to install to that virtualenv
|
||||||
@ -77,8 +76,8 @@ commands = ...
|
|||||||
```
|
```
|
||||||
|
|
||||||
To require specific dependencies be installed from the Poetry lockfile, and let the rest be
|
To require specific dependencies be installed from the Poetry lockfile, and let the rest be
|
||||||
installed using the default Tox installation method, add the suffix `@poetry` to the dependencies.
|
installed using the default Tox installation backend, add the suffix `@poetry` to the dependencies.
|
||||||
In the example below the `pytest`, `pytest-cov`, and `black` dependencies will be installed using
|
In the example below the `pytest`, `pytest-cov`, and `black` dependencies will be installed from
|
||||||
the lockfile while `pylint` and `mypy` will be installed using the versions specified here:
|
the lockfile while `pylint` and `mypy` will be installed using the versions specified here:
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
@ -100,7 +99,7 @@ one Tox is testing) will always be installed from the lockfile.
|
|||||||
|
|
||||||
## Usage Examples
|
## Usage Examples
|
||||||
|
|
||||||
After installing the plugin to a project, your Tox automation is already benefiting from the
|
After installing the plugin to a project your Tox automation is already benefiting from the
|
||||||
lockfile: when Tox installs your project package to one of your environments, all the dependencies
|
lockfile: when Tox installs your project package to one of your environments, all the dependencies
|
||||||
of your project package will be installed using the versions specified in the lockfile. This
|
of your project package will be installed using the versions specified in the lockfile. This
|
||||||
happens automatically and requires no configuration changes.
|
happens automatically and requires no configuration changes.
|
||||||
@ -108,7 +107,7 @@ happens automatically and requires no configuration changes.
|
|||||||
But what about the rest of your Tox environment dependencies?
|
But what about the rest of your Tox environment dependencies?
|
||||||
|
|
||||||
Let's use an example `tox.ini` file, below, that defines two environments: the main `testenv` for
|
Let's use an example `tox.ini` file, below, that defines two environments: the main `testenv` for
|
||||||
running the project tests and `testenv:check` for running some other helpful checks:
|
running the project tests and `testenv:check` for running some other helpful tools:
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
[tox]
|
[tox]
|
||||||
@ -152,9 +151,9 @@ Running Tox using this config gives us this error:
|
|||||||
tox_poetry_installer.LockedDepVersionConflictError: Locked dependency 'pylint >=2.4.4,<2.6.0' cannot include version specifier
|
tox_poetry_installer.LockedDepVersionConflictError: Locked dependency 'pylint >=2.4.4,<2.6.0' cannot include version specifier
|
||||||
```
|
```
|
||||||
|
|
||||||
This is because we told the Tox environment to require all dependencies to be locked, but then also
|
This is because we told the Tox environment to require all dependencies be locked, but then also
|
||||||
specified a specific version constraint for Pylint. With the `require_locked_deps = true` setting
|
specified a specific version constraint for Pylint. With the `require_locked_deps = true` setting
|
||||||
Tox expects all dependencies to take their version from the lockfile, so when it got conflicting
|
Tox expects all dependencies to take their version from the lockfile, so when it gets conflicting
|
||||||
information it errors. We can fix this by simply removing all version specifiers from the
|
information it errors. We can fix this by simply removing all version specifiers from the
|
||||||
environment dependency list:
|
environment dependency list:
|
||||||
|
|
||||||
@ -175,9 +174,9 @@ recreated.
|
|||||||
|
|
||||||
Now let's look at the `testenv` environment. Let's make the same changes to the `testenv`
|
Now let's look at the `testenv` environment. Let's make the same changes to the `testenv`
|
||||||
environment that we made to `testenv:check` above; remove the PyTest version and add
|
environment that we made to `testenv:check` above; remove the PyTest version and add
|
||||||
`require_locked_deps = true`. Then imagine that we want to add a new (made up) tool the test
|
`require_locked_deps = true`. Then imagine that we want to add the
|
||||||
environment called `crash_override` to the environment: we can add `crash-override` as a dependency
|
[Requests](https://requests.readthedocs.io/en/master/) library to the test environment: we
|
||||||
of the test environment, but this will cause an error:
|
can add `requests` as a dependency of the test environment, but this will cause an error:
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
[testenv]
|
[testenv]
|
||||||
@ -185,30 +184,29 @@ description = Run the tests
|
|||||||
require_locked_deps = true
|
require_locked_deps = true
|
||||||
deps =
|
deps =
|
||||||
pytest
|
pytest
|
||||||
crash-override
|
requests
|
||||||
commands = ...
|
commands = ...
|
||||||
```
|
```
|
||||||
|
|
||||||
Running Tox with this config gives us this error:
|
Running Tox with this config gives us this error:
|
||||||
|
|
||||||
```
|
```
|
||||||
tox_poetry_installer.LockedDepNotFoundError: No version of locked dependency 'crash-override' found in the project lockfile
|
tox_poetry_installer.LockedDepNotFoundError: No version of locked dependency 'requests' found in the project lockfile
|
||||||
```
|
```
|
||||||
|
|
||||||
This is because `crash-override` is not in our lockfile. Tox will refuse to install a dependency
|
This is because `requests` is not in our lockfile yet. Tox will refuse to install a dependency
|
||||||
that isn't in the lockfile to an an environment that specifies `require_locked_deps = true`. We
|
that isn't in the lockfile to an an environment that specifies `require_locked_deps = true`. We
|
||||||
could fix this (if `crash-override` was a real package) by running
|
can fix this by running `poetry add requests --dev` to add it to the lockfile.
|
||||||
`poetry add crash-override --dev` to add it to the lockfile.
|
|
||||||
|
|
||||||
Now let's combine dependencies from the lockfile ("locked dependencies") with dependencies that are
|
Now let's combine dependencies from the lockfile with dependencies that are
|
||||||
specified inline in the environment configuration ("unlocked dependencies").
|
specified in-line in the Tox environment configuration.
|
||||||
[This isn't generally recommended of course](#why-would-i-use-this), but it's a valid use case and
|
[This isn't generally recommended](#why-would-i-use-this), but it is a valid use case and
|
||||||
fully supported by this plugin. Let's modify the `testenv` configuration to install PyTest from the
|
fully supported by this plugin. Let's modify the `testenv` configuration to install PyTest
|
||||||
lockfile but then install an older version of the
|
from the lockfile but then install an older version of the Requests library.
|
||||||
[Requests](https://requests.readthedocs.io/en/master/) library.
|
|
||||||
|
|
||||||
The first thing to do is remove the `require_locked_deps = true` setting so that we can install
|
The first thing to do is remove the `require_locked_deps = true` setting so that we can install
|
||||||
Requests as an unlocked dependency. Then we can add our version of requests to the dependency list:
|
Requests as an unlocked dependency. Then we can add our version specifier to the `requests`
|
||||||
|
entry in the dependency list:
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
[testenv]
|
[testenv]
|
||||||
@ -220,7 +218,8 @@ commands = ...
|
|||||||
```
|
```
|
||||||
|
|
||||||
However we still want `pytest` to be installed from the lockfile, so the final step is to tell Tox
|
However we still want `pytest` to be installed from the lockfile, so the final step is to tell Tox
|
||||||
to install it from the lockfile by adding the suffix `@poetry` to it:
|
to install it from the lockfile by adding the suffix `@poetry` to the `pytest` entry in the
|
||||||
|
dependency list:
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
[testenv]
|
[testenv]
|
||||||
@ -233,7 +232,7 @@ commands = ...
|
|||||||
|
|
||||||
Now when the `testenv` environment is created it will install PyTest (and all of its dependencies)
|
Now when the `testenv` environment is created it will install PyTest (and all of its dependencies)
|
||||||
from the lockfile while it will install Requests (and all of its dependencies) using the default
|
from the lockfile while it will install Requests (and all of its dependencies) using the default
|
||||||
Tox installation backend using Pip.
|
Tox installation backend.
|
||||||
|
|
||||||
|
|
||||||
## Known Drawbacks and Problems
|
## Known Drawbacks and Problems
|
||||||
@ -256,7 +255,7 @@ Tox installation backend using Pip.
|
|||||||
|
|
||||||
* Tox environments automatically inherit their settings from the main `testenv` environment. This
|
* Tox environments automatically inherit their settings from the main `testenv` environment. This
|
||||||
means that if the `require_locked_deps = true` is specified for the `testenv` environment then
|
means that if the `require_locked_deps = true` is specified for the `testenv` environment then
|
||||||
all environments will also require locked dependencies. This can be overridden by explicitly
|
all environments will also require locked dependencies. This can be overwritten by explicitly
|
||||||
specifying `require_locked_deps = false` on child environments where unlocked dependencies are
|
specifying `require_locked_deps = false` on child environments where unlocked dependencies are
|
||||||
needed.
|
needed.
|
||||||
|
|
||||||
@ -272,20 +271,20 @@ Tox installation backend using Pip.
|
|||||||
|
|
||||||
**Introduction**
|
**Introduction**
|
||||||
|
|
||||||
The lockfile is a file generated by a package manager for a project that lists what
|
The lockfile is a file generated by a package manager for a project that records what
|
||||||
dependencies are installed, the versions of those dependencies, and additional metadata that
|
dependencies are installed, the versions of those dependencies, and any additional metadata that
|
||||||
the package manager can use to recreate the local project environment. This allows developers
|
the package manager needs to recreate the local project environment. This allows developers
|
||||||
to have confidence that a bug they are encountering that may be caused by one of their
|
to have confidence that a bug they are encountering that may be caused by one of their
|
||||||
dependencies will be reproducible on another device. In addition, installing a project
|
dependencies will be reproducible on another device. In addition, installing a project
|
||||||
environment from a lockfile gives confidence that automated systems running tests or performing
|
environment from a lockfile gives confidence that automated systems running tests or performing
|
||||||
builds are using the same environment that a developer is.
|
builds are using the same environment as a developer.
|
||||||
|
|
||||||
[Poetry](https://python-poetry.org/) is a project dependency manager for Python projects, and
|
[Poetry](https://python-poetry.org/) is a project dependency manager for Python projects, and
|
||||||
as such it creates and manages a lockfile so that its users can benefit from all the features
|
so it creates and manages a lockfile so that its users can benefit from all the features
|
||||||
described above. [Tox](https://tox.readthedocs.io/en/latest/#what-is-tox) is an automation tool
|
described above. [Tox](https://tox.readthedocs.io/en/latest/#what-is-tox) is an automation tool
|
||||||
that allows Python developers to run tests suites, perform builds, and automate tasks within
|
that allows Python developers to run tests suites, perform builds, and automate tasks within
|
||||||
self contained [Python virtual environments](https://docs.python.org/3/tutorial/venv.html).
|
self-contained [Python virtual environments](https://docs.python.org/3/tutorial/venv.html).
|
||||||
To make these environments useful, Tox supports installing per-environment dependencies.
|
To make these environments useful Tox supports installing dependencies in each environment.
|
||||||
However, since these environments are created on the fly and Tox does not maintain a lockfile,
|
However, since these environments are created on the fly and Tox does not maintain a lockfile,
|
||||||
there can be subtle differences between the dependencies a developer is using and the
|
there can be subtle differences between the dependencies a developer is using and the
|
||||||
dependencies Tox uses.
|
dependencies Tox uses.
|
||||||
@ -293,19 +292,17 @@ dependencies Tox uses.
|
|||||||
This is where this plugin comes into play.
|
This is where this plugin comes into play.
|
||||||
|
|
||||||
By default Tox uses [Pip](https://docs.python.org/3/tutorial/venv.html) to install the
|
By default Tox uses [Pip](https://docs.python.org/3/tutorial/venv.html) to install the
|
||||||
PEP-508 compliant dependencies to a test environment. A more robust way to do this is to
|
PEP-508 compliant dependencies to a test environment. This plugin extends the default
|
||||||
install dependencies directly from the lockfile so that the version installed to the Tox
|
Tox dependency installation behavior to support installing dependencies using a Poetry-based
|
||||||
environment always matches the version Poetry specifies. This plugin overwrites the default
|
installation method that makes use of the dependency metadata from Poetry's lockfile.
|
||||||
Tox dependency installation behavior and replaces it with a Poetry-based installation using
|
|
||||||
the dependency metadata from the lockfile.
|
|
||||||
|
|
||||||
**The Problem**
|
**The Problem**
|
||||||
|
|
||||||
Environment dependencies for a Tox environment are usually done in PEP-508 format like the
|
Environment dependencies for a Tox environment are usually specified in PEP-508 format, like
|
||||||
below example
|
the below example:
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
# tox.ini
|
# from tox.ini
|
||||||
...
|
...
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
@ -318,31 +315,35 @@ deps =
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
Perhaps these dependencies are also useful during development, so they can be added to the
|
Let's assume these dependencies are also useful during development, so they can be added to the
|
||||||
Poetry environment using this command:
|
Poetry environment using this command:
|
||||||
|
|
||||||
```
|
```
|
||||||
poetry add foo==1.2.3 bar>=1.3,<2.0 baz --dev
|
poetry add --dev \
|
||||||
|
foo==1.2.3 \
|
||||||
|
bar>=1.3,<2.0 \
|
||||||
|
baz
|
||||||
```
|
```
|
||||||
|
|
||||||
However there are three potential problems that could arise from each of these environment
|
However there is a potential problem that could arise from each of these environment
|
||||||
dependencies that would _only_ appear in the Tox environment and not in the Poetry
|
dependencies that would _only_ appear in the Tox environment and not in the Poetry
|
||||||
environment:
|
environment in use by a developer:
|
||||||
|
|
||||||
* **The `foo` dependency is pinned to a specific version:** let's imagine a security
|
* **The `foo` dependency is pinned to a specific version:** let's imagine a security
|
||||||
vulnerability is discovered in `foo` and the maintainers release version `1.2.4` to fix
|
vulnerability is discovered in `foo` and the maintainers release version `1.2.4` to fix
|
||||||
it. A developer can run `poetry remove foo && poetry add foo^1.2` to get the new version,
|
it. A developer can run `poetry remove foo` and then `poetry add foo^1.2` to get the new
|
||||||
but the Tox environment is left unchanged. The developer environment specified by the
|
version, but the Tox environment is left unchanged. The development environment, as defined by
|
||||||
lockfile is now patched against the vulnerability, but the Tox environment is not.
|
the lockfile, is now patched against the vulnerability but the Tox environment is not.
|
||||||
|
|
||||||
* **The `bar` dependency specifies a dynamic range:** a dynamic range allows a range of
|
* **The `bar` dependency specifies a dynamic range:** a dynamic range allows a range of
|
||||||
versions to be installed, but the lockfile will have an exact version specified so that
|
versions to be installed, but the lockfile will have an exact version specified so that
|
||||||
the Poetry environment is reproducible; this allows versions to be updated with
|
the Poetry environment is reproducible; this allows versions to be updated with
|
||||||
`poetry update` rather than with the `remove` and `add` used above. If the maintainers of
|
`poetry update` rather than with the `remove` and `add` commands used above. If the
|
||||||
`bar` release version `1.6.0` then the Tox environment will install it because it is valid
|
maintainers of `bar` release version `1.6.0` then the Tox environment will install it
|
||||||
for the specified version range, meanwhile the Poetry environment will continue to install
|
because it is valid for the specified version range. Meanwhile the Poetry environment will
|
||||||
the version from the lockfile until `poetry update bar` explicitly updates it. The
|
continue to install the version from the lockfile until `poetry update bar` explicitly
|
||||||
development environment is now has a different version of `bar` than the Tox environment.
|
updates it. The development environment is now has a different version of `bar` than the Tox
|
||||||
|
environment.
|
||||||
|
|
||||||
* **The `baz` dependency is unpinned:** unpinned dependencies are
|
* **The `baz` dependency is unpinned:** unpinned dependencies are
|
||||||
[generally a bad idea](https://python-poetry.org/docs/faq/#why-are-unbound-version-constraints-a-bad-idea),
|
[generally a bad idea](https://python-poetry.org/docs/faq/#why-are-unbound-version-constraints-a-bad-idea),
|
||||||
@ -351,27 +352,26 @@ Poetry environment using this command:
|
|||||||
but Pip (via Tox) will interpret it as a wildcard. If the latest version of `baz` is `1.0.0`
|
but Pip (via Tox) will interpret it as a wildcard. If the latest version of `baz` is `1.0.0`
|
||||||
then `poetry add baz` will result in a constraint of `baz>=1.0.0,<2.0.0` while the Tox
|
then `poetry add baz` will result in a constraint of `baz>=1.0.0,<2.0.0` while the Tox
|
||||||
environment will have a constraint of `baz==*`. The Tox environment can now install an
|
environment will have a constraint of `baz==*`. The Tox environment can now install an
|
||||||
incompatible version of `baz` that cannot be easily caught using `poetry update`.
|
incompatible version of `baz` and any errors that causes cannot be replicated using `poetry update`.
|
||||||
|
|
||||||
All of these problems can apply not only to the dependencies specified for a Tox environment,
|
All of these problems can apply not only to the dependencies specified for a Tox environment,
|
||||||
but also to the dependencies of those dependencies, and so on.
|
but also to the dependencies of those dependencies, those dependencies' dependencies, and so on.
|
||||||
|
|
||||||
**The Solution**
|
**The Solution**
|
||||||
|
|
||||||
This plugin requires that all dependencies specified for all Tox environments be unbound
|
This plugin allows dependencies specified in Tox environment take their version directly from
|
||||||
with no version constraint specified at all. This seems counter-intuitive given the problems
|
the Poetry lockfile without needing an independent version to be specified in the Tox
|
||||||
outlined above, but what it allows the plugin to do is offload all version management to
|
environment configuration. The modified version of the example environment given below appears
|
||||||
Poetry.
|
less stable than the one presented above because it does not specify any versions for its
|
||||||
|
dependencies:
|
||||||
On initial inspection, the environment below appears less stable than the one presented above
|
|
||||||
because it does not specify any versions for its dependencies:
|
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
# tox.ini
|
# from tox.ini
|
||||||
...
|
...
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
description = Some very cool tests
|
description = Some very cool tests
|
||||||
|
require_locked_deps = true
|
||||||
deps =
|
deps =
|
||||||
foo
|
foo
|
||||||
bar
|
bar
|
||||||
@ -380,19 +380,16 @@ deps =
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
However with the `tox-poetry-installer` plugin installed this instructs Tox to install these
|
However with the `tox-poetry-installer` plugin installed the `require_locked_deps = true`
|
||||||
dependencies using the Poetry lockfile so that the version installed to the Tox environment
|
setting means that Tox will install these dependencies from the Poetry lockfile so that the
|
||||||
exactly matches the version Poetry is managing. When `poetry update` updates the lockfile
|
version installed to the Tox environment exactly matches the version Poetry is managing. When
|
||||||
with new dependency versions, Tox will automatically install these new versions without needing
|
`poetry update` updates the lockfile with new versions of these dependencies, Tox will
|
||||||
any changes to the configuration.
|
automatically install these new versions without needing any changes to the configuration.
|
||||||
|
|
||||||
All dependencies are specified in one place (the lockfile) and dependency version management is
|
|
||||||
handled by a tool dedicated to that task (Poetry).
|
|
||||||
|
|
||||||
|
|
||||||
## Developing
|
## Developing
|
||||||
|
|
||||||
This project requires Poetry-1.0+, see the [installation instructions here](https://python-poetry.org/docs/#installation).
|
This project requires Poetry version 1.0+, see the [installation instructions here](https://python-poetry.org/docs/#installation).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Clone the repository...
|
# Clone the repository...
|
||||||
@ -435,7 +432,7 @@ releases on PyPI.
|
|||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
This project is under active development and is classified as alpha software, not yet ready
|
This project is under active development and is classified as alpha software, not yet ready
|
||||||
usage in production systems.
|
for usage in production environments.
|
||||||
|
|
||||||
* Beta classification will be assigned when the initial feature set is finalized
|
* Beta classification will be assigned when the initial feature set is finalized
|
||||||
* Stable classification will be assigned when the test suite covers an acceptable number of
|
* Stable classification will be assigned when the test suite covers an acceptable number of
|
||||||
|
Loading…
Reference in New Issue
Block a user