Skip to content

Commit 1554104

Browse files
asottilegaborbernat
authored andcommitted
Implement --devenv (#1326)
1 parent 7237c9d commit 1554104

File tree

4 files changed

+97
-5
lines changed

4 files changed

+97
-5
lines changed

docs/changelog/1326.feature.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add the ``--devenv ENVDIR`` option for creating development environments from ``[testenv]`` configurations - by :user:`asottile`.

docs/example/devenv.rst

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,44 @@ environments. It can also be used for setting up normalized project development
1010
environments and thus help reduce the risk of different team members using
1111
mismatched development environments.
1212

13+
14+
Creating development environments using the ``--devenv`` option
15+
===============================================================
16+
17+
The easiest way to set up a development environment is to use the ``--devenv``
18+
option along with your existing configured ``testenv``s. The ``--devenv``
19+
option accepts a single argument, the location you want to create a development
20+
environment at.
21+
22+
For example, if I wanted to replicate the ``py36`` environment, I could run::
23+
24+
$ tox --devenv venv-py36 -e py36
25+
...
26+
$ source venv-py36/bin/activate
27+
(venv-py36) $ python --version
28+
Python 3.6.7
29+
30+
The ``--devenv`` option skips the ``commands=`` section of that configured
31+
test environment and always sets ``usedevelop=true`` for the environment that
32+
is created.
33+
34+
If you don't specify an environment with ``-e``, the devenv feature will
35+
default to ``-e py`` -- usually taking the interpreter you're running ``tox``
36+
with and the default ``[testenv]`` configuration.
37+
38+
Creating development environments using configuration
39+
=====================================================
40+
1341
Here are some examples illustrating how to set up a project's development
1442
environment using tox. For illustration purposes, let us call the development
1543
environment ``dev``.
1644

1745

1846
Example 1: Basic scenario
19-
=========================
47+
-------------------------
2048

2149
Step 1 - Configure the development environment
22-
----------------------------------------------
50+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2351

2452
First, we prepare the tox configuration for our development environment by
2553
defining a ``[testenv:dev]`` section in the project's ``tox.ini``
@@ -54,7 +82,7 @@ configuration:
5482
5583
5684
Step 2 - Create the development environment
57-
-------------------------------------------
85+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5886

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

6997

7098
Example 2: A more complex scenario
71-
==================================
99+
----------------------------------
72100

73101
Let us say we want our project development environment to:
74102

src/tox/config/__init__.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,9 @@ def tox_addoption(parser):
415415
metavar="envlist",
416416
help="work against specified environments (ALL selects all).",
417417
)
418+
parser.add_argument(
419+
"--devenv", help="sets up a development environment based on the tox configuration."
420+
)
418421
parser.add_argument("--notest", action="store_true", help="skip invoking test commands.")
419422
parser.add_argument(
420423
"--sdistonly", action="store_true", help="only perform the sdist packaging activity."
@@ -497,12 +500,19 @@ def tox_addoption(parser):
497500
"args", nargs="*", help="additional arguments available to command positional substitution"
498501
)
499502

503+
def _set_envdir_from_devenv(testenv_config, value):
504+
if testenv_config.config.option.devenv:
505+
return py.path.local(testenv_config.config.option.devenv)
506+
else:
507+
return value
508+
500509
parser.add_testenv_attribute(
501510
name="envdir",
502511
type="path",
503512
default="{toxworkdir}/{envname}",
504513
help="set venv directory -- be very careful when changing this as tox "
505514
"will remove this directory when recreating an environment",
515+
postprocess=_set_envdir_from_devenv,
506516
)
507517

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

752762
def develop(testenv_config, value):
753763
option = testenv_config.config.option
754-
return not option.installpkg and (value or option.develop)
764+
return not option.installpkg and (value or option.develop or bool(option.devenv))
755765

756766
parser.add_testenv_attribute(
757767
name="usedevelop",
@@ -1106,6 +1116,12 @@ def run(name, section, subs, config):
11061116

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

1119+
if config.option.devenv:
1120+
config.option.notest = True
1121+
1122+
if config.option.devenv and len(config.envlist) != 1:
1123+
feedback("--devenv requires only a single -e", sysexit=True)
1124+
11091125
def handle_provision(self, config, reader):
11101126
requires_list = reader.getlist("requires")
11111127
config.minversion = reader.getstring("minversion", None)
@@ -1251,6 +1267,7 @@ def _getenvdata(self, reader, config):
12511267
(os.environ.get(PARALLEL_ENV_VAR_KEY), True),
12521268
(from_option, True),
12531269
(from_environ, True),
1270+
("py" if self.config.option.devenv else None, False),
12541271
(from_config, False),
12551272
)
12561273
env_str, envlist_explicit = next(((i, e) for i, e in candidates if i), ([], False))

tests/unit/test_z_cmdline.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,52 @@ def test_notest_setup_py_error(initproj, cmd):
789789
assert re.search("ERROR:.*InvocationError", result.out)
790790

791791

792+
def test_devenv(initproj, cmd):
793+
initproj(
794+
"example123",
795+
filedefs={
796+
"setup.py": """\
797+
from setuptools import setup
798+
setup(name='x')
799+
""",
800+
"tox.ini": """\
801+
[tox]
802+
# envlist is ignored for --devenv
803+
envlist = foo,bar,baz
804+
805+
[testenv]
806+
# --devenv implies --notest
807+
commands = python -c "exit(1)"
808+
""",
809+
},
810+
)
811+
result = cmd("--devenv", "venv")
812+
result.assert_success()
813+
# `--devenv` defaults to the `py` environment and a develop install
814+
assert "py develop-inst:" in result.out
815+
assert re.search("py create:.*venv", result.out)
816+
817+
818+
def test_devenv_does_not_allow_multiple_environments(initproj, cmd):
819+
initproj(
820+
"example123",
821+
filedefs={
822+
"setup.py": """\
823+
from setuptools import setup
824+
setup(name='x')
825+
""",
826+
"tox.ini": """\
827+
[tox]
828+
envlist=foo,bar,baz
829+
""",
830+
},
831+
)
832+
833+
result = cmd("--devenv", "venv", "-e", "foo,bar")
834+
result.assert_fail()
835+
assert result.err == "ERROR: --devenv requires only a single -e\n"
836+
837+
792838
def test_PYC(initproj, cmd, monkeypatch):
793839
initproj("example123", filedefs={"tox.ini": ""})
794840
monkeypatch.setenv("PYTHONDOWNWRITEBYTECODE", "1")

0 commit comments

Comments
 (0)