Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement --devenv #1326

Merged
merged 1 commit into from
Jun 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/changelog/1326.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add the ``--devenv ENVDIR`` option for creating development environments from ``[testenv]`` configurations - by :user:`asottile`.
36 changes: 32 additions & 4 deletions docs/example/devenv.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,44 @@ environments. It can also be used for setting up normalized project development
environments and thus help reduce the risk of different team members using
mismatched development environments.


Creating development environments using the ``--devenv`` option
===============================================================

The easiest way to set up a development environment is to use the ``--devenv``
option along with your existing configured ``testenv``s. The ``--devenv``
option accepts a single argument, the location you want to create a development
environment at.

For example, if I wanted to replicate the ``py36`` environment, I could run::

$ tox --devenv venv-py36 -e py36
...
$ source venv-py36/bin/activate
(venv-py36) $ python --version
Python 3.6.7

The ``--devenv`` option skips the ``commands=`` section of that configured
test environment and always sets ``usedevelop=true`` for the environment that
is created.

If you don't specify an environment with ``-e``, the devenv feature will
default to ``-e py`` -- usually taking the interpreter you're running ``tox``
with and the default ``[testenv]`` configuration.

Creating development environments using configuration
=====================================================

Here are some examples illustrating how to set up a project's development
environment using tox. For illustration purposes, let us call the development
environment ``dev``.


Example 1: Basic scenario
=========================
-------------------------

Step 1 - Configure the development environment
----------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

First, we prepare the tox configuration for our development environment by
defining a ``[testenv:dev]`` section in the project's ``tox.ini``
Expand Down Expand Up @@ -54,7 +82,7 @@ configuration:


Step 2 - Create the development environment
-------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Once the ``[testenv:dev]`` configuration section has been defined, we create
the actual development environment by running the following:
Expand All @@ -68,7 +96,7 @@ This creates the environment at the path specified by the environment's


Example 2: A more complex scenario
==================================
----------------------------------

Let us say we want our project development environment to:

Expand Down
19 changes: 18 additions & 1 deletion src/tox/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,9 @@ def tox_addoption(parser):
metavar="envlist",
help="work against specified environments (ALL selects all).",
)
parser.add_argument(
"--devenv", help="sets up a development environment based on the tox configuration."
)
parser.add_argument("--notest", action="store_true", help="skip invoking test commands.")
parser.add_argument(
"--sdistonly", action="store_true", help="only perform the sdist packaging activity."
Expand Down Expand Up @@ -497,12 +500,19 @@ def tox_addoption(parser):
"args", nargs="*", help="additional arguments available to command positional substitution"
)

def _set_envdir_from_devenv(testenv_config, value):
if testenv_config.config.option.devenv:
return py.path.local(testenv_config.config.option.devenv)
else:
return value

parser.add_testenv_attribute(
name="envdir",
type="path",
default="{toxworkdir}/{envname}",
help="set venv directory -- be very careful when changing this as tox "
"will remove this directory when recreating an environment",
postprocess=_set_envdir_from_devenv,
)

# add various core venv interpreter attributes
Expand Down Expand Up @@ -751,7 +761,7 @@ def pip_pre(testenv_config, value):

def develop(testenv_config, value):
option = testenv_config.config.option
return not option.installpkg and (value or option.develop)
return not option.installpkg and (value or option.develop or bool(option.devenv))

parser.add_testenv_attribute(
name="usedevelop",
Expand Down Expand Up @@ -1106,6 +1116,12 @@ def run(name, section, subs, config):

config.skipsdist = reader.getbool("skipsdist", all_develop)

if config.option.devenv:
config.option.notest = True

if config.option.devenv and len(config.envlist) != 1:
feedback("--devenv requires only a single -e", sysexit=True)

def handle_provision(self, config, reader):
requires_list = reader.getlist("requires")
config.minversion = reader.getstring("minversion", None)
Expand Down Expand Up @@ -1251,6 +1267,7 @@ def _getenvdata(self, reader, config):
(os.environ.get(PARALLEL_ENV_VAR_KEY), True),
(from_option, True),
(from_environ, True),
("py" if self.config.option.devenv else None, False),
(from_config, False),
)
env_str, envlist_explicit = next(((i, e) for i, e in candidates if i), ([], False))
Expand Down
46 changes: 46 additions & 0 deletions tests/unit/test_z_cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,52 @@ def test_notest_setup_py_error(initproj, cmd):
assert re.search("ERROR:.*InvocationError", result.out)


def test_devenv(initproj, cmd):
asottile marked this conversation as resolved.
Show resolved Hide resolved
initproj(
"example123",
filedefs={
"setup.py": """\
from setuptools import setup
setup(name='x')
""",
"tox.ini": """\
[tox]
# envlist is ignored for --devenv
envlist = foo,bar,baz

[testenv]
# --devenv implies --notest
commands = python -c "exit(1)"
""",
},
)
result = cmd("--devenv", "venv")
result.assert_success()
# `--devenv` defaults to the `py` environment and a develop install
assert "py develop-inst:" in result.out
assert re.search("py create:.*venv", result.out)


def test_devenv_does_not_allow_multiple_environments(initproj, cmd):
initproj(
"example123",
filedefs={
"setup.py": """\
from setuptools import setup
setup(name='x')
""",
"tox.ini": """\
[tox]
envlist=foo,bar,baz
""",
},
)

result = cmd("--devenv", "venv", "-e", "foo,bar")
result.assert_fail()
assert result.err == "ERROR: --devenv requires only a single -e\n"


def test_PYC(initproj, cmd, monkeypatch):
initproj("example123", filedefs={"tox.ini": ""})
monkeypatch.setenv("PYTHONDOWNWRITEBYTECODE", "1")
Expand Down