dmenv 0.20.1

Simple and practical virtualenv manager for Python
Documentation
# Usage

## A note about setup.py and setup.cfg

The following documentation assumes you are calling `setuptools.setup()` with no arguments and that all of `setuptools` options are set in the `setup.cfg` file. See [setuptools documentation](https://setuptools.readthedocs.io/en/latest/setuptools.html#configuring-setup-using-setup-cfg-files) for more details.

`dmenv` will still work otherwise, but please bear in mind that you will have to adapt the code samples below.

## Setup

First, `dmenv` needs a Python3 interpreter in PATH, which should be called `python` or `python3`. This is usually the case if you've just installed Python3, regardless of your operating system.

Second, `dmenv` needs a `setup.py` file to work.

* If you don't have a `setup.py` yet, you can run `dmenv init <project name>`
  to generate one, alongside a `setup.cfg` file. In this case, make sure to read the comments inside
  and edit it to fit your needs.

* If you already have a `setup.py` or a `setup.cfg` file that contains info about dependencies, please note that `dmenv` uses
 **"extras require"** dependencies to specify development dependencies, under the `dev` key.

You are now ready to use `dmenv`. Keep on reading about the two main commands: `dmenv lock` and `dmenv install`.

## dmenv lock

Here's what `dmenv lock` does:

* It looks for a binary named `python3` or `python` in the `PATH` environment variable.
* It runs a bit of Python code to determine the interpreter version (3.6, 3.7 ...).
* Then, it creates a virtual environment in `.venv/dev/<version>` using `python -m venv`.
  (This step is skipped if `dmenv` detects it is run from an existing virtual environment).
  Note that you may have to [configure other tools]./advanced_usage.md#configuring-other-tools to ignore this directory.


* Then it runs `pip install --editable .[dev]` so that your dev dependencies are
  installed, and the scripts listed in `entry_points` are created.

* Finally, it runs `pip freeze` to generate a `requirements.lock` file.

Now you can add the `requirements.lock` file to your version control system.


This leads us to the next command:

## dmenv install

Now that the complete list of dependencies and their versions is written in the
`requirements.lock` file, anyone can run `dmenv install` to install all the
dependencies and get exactly the same versions you got when you ran `dmenv lock`.

Hooray reproducible builds!


## dmenv run

One the virtual environment has been created, you can run any binary from the venv with the command
`dmenv run`.

For instance, assuming `pytest` is declared as a dependency:

```bash
$ dmenv run pytest
```

Note that you can also use `dmenv run` to run scripts from your project:

```bash
$ dmenv run foo.py
# Equivalent to:
$ dmenv run python foo.py
```


## Configuring other tools

Depending of your usage, you may need to tell other tools to ignore the `.venv` directory.

* **git**: add a line containing `.venv/` to the `.gitignore`.

```text
# should be already there if you use
# setup.py
*.egg-info
build/
dist/

# only directory in which `dmenv` will write files:
.venv/
```

* **pyflakes**, **pylint** and other linters: add some configuration in the `setup.cfg` file:

```ini
exclude =
  .venv
```

As an alternative, you can also ask `dmenv` to create its virtual environment *outside* your project,
by setting the `DMENV_VENV_OUTSIDE_PROJECT` environment variable to a non-empty value like `1`. It will then use
the [app_dirs crate](https://crates.io/crates/app_dirs) as a location to store the created virtual environments.

## Upgrading dmenv

If you have `wget` installed and used a pre-compiled binary, upgrading `dmenv` can be done in just one command:

```bash
# Replace <version> and <arch> with their correct value
$ wget \
  https://github.com/TankerHQ/dmenv/releases/download/v<version>/dmenv-<arch> \
  -O $(which dmenv)
```

If you've installed `dmenv` from source:

```bash
rustup update stable  # dmenv usually requires latest rust stable version
cargo install --force dmenv
```

## Adding a new dependency

This process is in two parts.

* First, add the dependency in `setup.cfg` or `setup.py`, in the `install_requires` section.
* Then, run `dmenv lock` to update the corresponding `lock file`.

The process changes lightly if you are working with a development dependency, or a dependency that is only used for production.
See the [advanced usage](./advanced_usage.md)  section for details.

## Upgrading a top-level dependency

Let's say your project depends on `foolib`. Version `1.3` works fine, but
`1.4` just came out and even if you don't need any new feature from `1.4`,
you'd like to check wether your project is compatible. [^1]

Assuming you already have a virtual environment containing `foolib 1.3`, you can can do so by running:

```bash
$ git status  # check that requirements.lock is clean
$ dmenv run -- pip install --upgrade foolib
```

Most of the time, `pip install --upgrade foolib` will do the right thing:

* it will keep other dependencies installed at their current version
* it will install new dependencies of `foolib 1.4` if they are missing
* if `foolib 1.4` contains a `bar >= 3.0` constraint and you have `bar == 2.0` in the virtualenv, `bar` will
  be upgraded too.

Then it's time to register the new dependencies in the lock:

```bash
$ dmenv lock
```

You can now inspect the differences in the lock file by hand, and if they are correct, commit and push a new version of the lock file.

## Going further

That's all for the basic usage of `dmenv`, you may proceed to the [goodies section](./goodies.md) or read on about [advanced dmenv usage](./advanced_usage.md)


[^1]: If you *do* need `foolib` in version 1.4 or later, you should express this constraint in the setup.py file instead, as explained in the *[upgrading just one regular dependency]./advanced_usage.md#upgrading_just_one_development_dependency*
section.