Commit 3c26c8d0 by Sébastien Eustace Committed by GitHub

New env command and sub commands (#731)

* Add a env:info command

* Add env:use command

* Fix tests on Windows

* Fix tests

* Fix tests

* Fix tests for Python 3.5

* Use a hash in virtualenv names dependent on the project’s path

* Add tests for the `env use` command

* Fix tests

* Add a `env list` command

* Fix venvs being recreated when switching minor Python versions

* Add a `env remove` command

* Update CHANGELOG

* Update documentation
parent 41c2736d
......@@ -5,6 +5,10 @@
### Added
- Added an `export` command to export the lock file to other formats (only `requirements.txt` is currently supported).
- Added a `env info` command to get basic information about the current environment.
- Added a `env use` command to control the Python version used by the project.
- Added a `env list` command to list the virtualenvs associated with the current project.
- Added a `env remove` command to delete virtualenvs associated with the current project.
### Changed
......@@ -13,6 +17,7 @@
- The `debug:info` command has been renamed to `debug info`.
- The `debug:resolve` command has been renamed to `debug resolve`.
- The `self:update` command has been renamed to `self update`.
- Changed the way virtualenvs are stored (names now depend on the project's path).
### Fixed
......
......@@ -155,19 +155,99 @@ When you execute the `install` command (or any other "install" commands like `ad
Poetry will check if it's currently inside a virtualenv and, if not, will use an existing one
or create a brand new one for you to always work isolated from your global Python installation.
!!!note
By default, Poetry will use the currently activated Python version
to create the virtualenv for the current project.
To easily switch between Python versions, it is recommended to
use [pyenv](https://github.com/pyenv/pyenv) or similar tools.
For instance, if your project is Python 2.7 only, a standard workflow
would be:
```bash
pyenv install 2.7.15
pyenv local 2.7.15 # Activate Python 2.7 for the current project
poetry install
```
However, this might not be feasible for your system, especially Windows where `pyenv`,
is not available. To circumvent that you can use the `env use` command to tell
Poetry which Python version to use for the current project.
To create the virtualenv for the current project, Poetry will use
the currently activated Python version.
```bash
poetry env use /full/path/to/python
```
If you have the python executable in your `PATH` you can use it:
```bash
poetry env use python3.7
```
To easily switch between Python versions, it is recommended to
use [pyenv](https://github.com/pyenv/pyenv) or similar tools.
You can even just use the minor Python version in this case:
For instance, if your project is Python 2.7 only, a standard workflow
would be:
```bash
poetry env use 3.7
```
If you want to disable the explicitly activated virtualenv, you can use the
special `system` Python version to retrieve the default behavior:
```bash
poetry env use system
```
If you want to get basic information about the currently activated virtualenv,
you can use the `env info` command:
```bash
poetry env info
```
will output something similar to this:
```text
Virtualenv
Python: 3.7.1
Implementation: CPython
Path: /path/to/poetry/cache/virtualenvs/test-O3eWbxRl-py3.7
Valid: True
System
Platform: darwin
OS: posix
Python: /path/to/main/python
```
If you only want to know the path to the virtualenv, you can pass the `--path` option
to `env info`:
```bash
poetry env info --path
```
You can also list all the virtualenvs associated with the current virtualenv
with the `env list` command:
```bash
poetry env list
```
will output something like the following:
```text
test-O3eWbxRl-py2.7
test-O3eWbxRl-py3.6
test-O3eWbxRl-py3.7 (Activated)
```
Finally, you can delete existing virtualenvs by using `env remove`:
```bash
poetry env remove /full/path/to/python
poetry env remove python3.7
poetry env remove 3.7
poetry env remove test-O3eWbxRl-py3.7
```
```bash
pyenv install 2.7.15
pyenv local 2.7.15 # Activate Python 2.7 for the current project
poetry install
```
If your remove the currently activated virtualenv, it will be automatically deactivated.
......@@ -375,3 +375,112 @@ poetry export -f requirements.txt
!!!note
Only the `requirements.txt` format is currently supported.
## env
The `env` command regroups sub commands to interact with the virtualenvs
associated with a specific project.
### env use
The `env use` command tells Poetry which Python version
to use for the current project.
```bash
poetry env use /full/path/to/python
```
If you have the python executable in your `PATH` you can use it:
```bash
poetry env use python3.7
```
You can even just use the minor Python version in this case:
```bash
poetry env use 3.7
```
If you want to disable the explicitly activated virtualenv, you can use the
special `system` Python version to retrieve the default behavior:
```bash
poetry env use system
```
### env info
The `env info` command displays basic information about the currently activated virtualenv:
```bash
poetry env info
```
will output something similar to this:
```text
Virtualenv
Python: 3.7.1
Implementation: CPython
Path: /path/to/poetry/cache/virtualenvs/test-O3eWbxRl-py3.7
Valid: True
System
Platform: darwin
OS: posix
Python: /path/to/main/python
```
If you only want to know the path to the virtualenv, you can pass the `--path` option
to `env info`:
```bash
poetry env info --path
```
#### Options
* `--path`: Only display the path of the virtualenv.
### env list
The `env list` command lists all the virtualenvs associated with the current virtualenv.
```bash
poetry env list
```
will output something like the following:
```text
test-O3eWbxRl-py2.7
test-O3eWbxRl-py3.6
test-O3eWbxRl-py3.7 (Activated)
```
#### Options
* `--full-path`: Display the full path of the virtualenvs.
### env remove
The `env remove` command deletes virtualenvs associated with the current project:
```bash
poetry env remove /full/path/to/python
```
Similarly to `env use`, you can either pass `python3.7`, `3.7` or the name of
the virtualenv (as returned by `env list`):
```bash
poetry env remove python3.7
poetry env remove 3.7
poetry env remove test-O3eWbxRl-py3.7
```
!!!note
If your remove the currently activated virtualenv, it will be automatically deactivated.
......@@ -33,6 +33,8 @@ from .commands.self import SelfCommand
from .config import ApplicationConfig
from .commands.env import EnvCommand
class Application(BaseApplication):
def __init__(self):
......@@ -89,6 +91,9 @@ class Application(BaseApplication):
# Debug command
commands += [DebugCommand()]
# Env command
commands += [EnvCommand()]
# Self commands
commands += [SelfCommand()]
......
import os
import sys
from clikit.args import StringArgs
from ..command import Command
......@@ -12,54 +14,21 @@ class DebugInfoCommand(Command):
"""
def handle(self):
from ....utils.env import Env
poetry = self.poetry
env = Env.get(poetry.file.parent)
poetry_python_version = ".".join(str(s) for s in sys.version_info[:3])
self.line("")
self.line("<b>Poetry</b>")
self.line("")
self.line("<info>Version</info>: <comment>{}</>".format(poetry.VERSION))
self.line("<info>Python</info>: <comment>{}</>".format(poetry_python_version))
self.line("")
env_python_version = ".".join(str(s) for s in env.version_info[:3])
self.line("<b>Virtualenv</b>")
self.line("")
listing = [
"<info>Python</info>: <comment>{}</>".format(env_python_version),
"<info>Implementation</info>: <comment>{}</>".format(
env.python_implementation
),
"<info>Path</info>: <comment>{}</>".format(
env.path if env.is_venv() else "NA"
),
]
if env.is_venv():
listing.append(
"<info>Valid</info>: <{tag}>{is_valid}</{tag}>".format(
tag="comment" if env.is_sane() else "error", is_valid=env.is_sane()
)
self.line(
"\n".join(
[
"<info>Version</info>: <comment>{}</>".format(self.poetry.VERSION),
"<info>Python</info>: <comment>{}</>".format(
poetry_python_version
),
]
)
)
args = StringArgs("")
command = self.application.get_command("env").get_sub_command("info")
for line in listing:
self.line(line)
self.line("")
self.line("<b>System</b>")
self.line("")
listing = [
"<info>Platform</info>: <comment>{}</>".format(sys.platform),
"<info>OS</info>: <comment>{}</>".format(os.name),
"<info>Python</info>: <comment>{}</>".format(env.base),
]
for line in listing:
self.line(line)
self.line("")
return command.run(args, self._io)
......@@ -24,7 +24,7 @@ class DebugResolveCommand(Command):
from poetry.puzzle import Solver
from poetry.repositories.repository import Repository
from poetry.semver import parse_constraint
from poetry.utils.env import Env
from poetry.utils.env import EnvManager
packages = self.argument("package")
......@@ -78,7 +78,7 @@ class DebugResolveCommand(Command):
return 0
env = Env.get(self.poetry.file.parent)
env = EnvManager(self.poetry.config).get(self.poetry.file.parent)
current_python_version = parse_constraint(
".".join(str(v) for v in env.version_info)
)
......
from ..command import Command
from .info import EnvInfoCommand
from .list import EnvListCommand
from .remove import EnvRemoveCommand
from .use import EnvUseCommand
class EnvCommand(Command):
"""
Interact with Poetry's project environments.
env
"""
commands = [EnvInfoCommand(), EnvListCommand(), EnvRemoveCommand(), EnvUseCommand()]
def handle(self): # type: () -> int
return self.call("help", self._config.name)
from ..command import Command
class EnvInfoCommand(Command):
"""
Display information about the current environment.
info
{--p|path : Only display the environment's path}
"""
def handle(self):
from poetry.utils.env import EnvManager
poetry = self.poetry
env = EnvManager(poetry.config).get(cwd=poetry.file.parent)
if self.option("path"):
if not env.is_venv():
return 1
self.write(str(env.path))
return
self._display_complete_info(env)
def _display_complete_info(self, env):
env_python_version = ".".join(str(s) for s in env.version_info[:3])
self.line("")
self.line("<b>Virtualenv</b>")
listing = [
"<info>Python</info>: <comment>{}</>".format(env_python_version),
"<info>Implementation</info>: <comment>{}</>".format(
env.python_implementation
),
"<info>Path</info>: <comment>{}</>".format(
env.path if env.is_venv() else "NA"
),
]
if env.is_venv():
listing.append(
"<info>Valid</info>: <{tag}>{is_valid}</{tag}>".format(
tag="comment" if env.is_sane() else "error", is_valid=env.is_sane()
)
)
self.line("\n".join(listing))
self.line("")
self.line("<b>System</b>")
self.line(
"\n".join(
[
"<info>Platform</info>: <comment>{}</>".format(env.platform),
"<info>OS</info>: <comment>{}</>".format(env.os),
"<info>Python</info>: <comment>{}</>".format(env.base),
]
)
)
from ..command import Command
class EnvListCommand(Command):
"""
List all virtualenvs associated with the current project.
list
{--full-path : Output the full paths of the virtualenvs}
"""
def handle(self):
from poetry.utils.env import EnvManager
poetry = self.poetry
manager = EnvManager(poetry.config)
current_env = manager.get(self.poetry.file.parent)
for venv in manager.list(self.poetry.file.parent):
name = venv.path.name
if self.option("full-path"):
name = str(venv.path)
if venv == current_env:
self.line("<info>{} (Activated)</info>".format(name))
continue
self.line(name)
from ..command import Command
class EnvRemoveCommand(Command):
"""
Remove a specific virtualenv associated with the project.
remove
{python : The python executable to remove the virtualenv for.}
"""
def handle(self):
from poetry.utils.env import EnvManager
poetry = self.poetry
manager = EnvManager(poetry.config)
venv = manager.remove(self.argument("python"), poetry.file.parent)
self.line("Deleted virtualenv: <comment>{}</comment>".format(venv.path))
from ..command import Command
class EnvUseCommand(Command):
"""
Activate or create a new virtualenv for the current project.
use
{python : The python executable to use.}
"""
def handle(self):
from poetry.utils.env import EnvManager
poetry = self.poetry
manager = EnvManager(poetry.config)
if self.argument("python") == "system":
manager.deactivate(poetry.file.parent, self._io)
return
env = manager.activate(self.argument("python"), poetry.file.parent, self._io)
self.line("Using virtualenv: <comment>{}</>".format(env.path))
......@@ -37,7 +37,7 @@ The <info>init</info> command creates a basic <comment>pyproject.toml</> file in
def handle(self):
from poetry.layouts import layout
from poetry.utils._compat import Path
from poetry.utils.env import Env
from poetry.utils.env import EnvManager
from poetry.vcs.git import GitConfig
if (Path.cwd() / "pyproject.toml").exists():
......@@ -100,7 +100,7 @@ The <info>init</info> command creates a basic <comment>pyproject.toml</> file in
question.set_validator(self._validate_license)
license = self.ask(question)
current_env = Env.get(Path.cwd())
current_env = EnvManager().get(Path.cwd())
default_python = "^{}".format(
".".join(str(v) for v in current_env.version_info[:2])
)
......
......@@ -14,7 +14,7 @@ class NewCommand(Command):
def handle(self):
from poetry.layouts import layout
from poetry.utils._compat import Path
from poetry.utils.env import Env
from poetry.utils.env import EnvManager
from poetry.vcs.git import GitConfig
if self.option("src"):
......@@ -45,7 +45,7 @@ class NewCommand(Command):
if author_email:
author += " <{}>".format(author_email)
current_env = Env.get(Path.cwd())
current_env = EnvManager().get(Path.cwd())
default_python = "^{}".format(
".".join(str(v) for v in current_env.version_info[:2])
)
......
......@@ -57,18 +57,20 @@ class ApplicationConfig(BaseApplicationConfig):
def set_env(self, event, event_name, _): # type: (PreHandleEvent, str, ...) -> None
from poetry.semver import parse_constraint
from poetry.utils.env import Env
from poetry.utils.env import EnvManager
command = event.command.config.handler
command = event.command.config.handler # type: EnvCommand
if not isinstance(command, EnvCommand):
return
io = event.io
poetry = command.poetry
env_manager = EnvManager(poetry.config)
# Checking compatibility of the current environment with
# the python dependency specified in pyproject.toml
current_env = Env.get(poetry.file.parent)
current_env = env_manager.get(poetry.file.parent)
supported_python = poetry.package.python_constraint
current_python = parse_constraint(
".".join(str(v) for v in current_env.version_info[:3])
......@@ -82,7 +84,7 @@ class ApplicationConfig(BaseApplicationConfig):
)
)
env = Env.create_venv(poetry.file.parent, io, poetry.package.name)
env = env_manager.create_venv(poetry.file.parent, io, poetry.package.name)
if env.is_venv() and io.is_verbose():
io.write_line("Using virtualenv: <comment>{}</>".format(env.path))
......
......@@ -30,7 +30,7 @@ from poetry.utils._compat import PY35
from poetry.utils._compat import Path
from poetry.utils.helpers import parse_requires
from poetry.utils.helpers import safe_rmtree
from poetry.utils.env import Env
from poetry.utils.env import EnvManager
from poetry.utils.env import EnvCommandError
from poetry.utils.setup_reader import SetupReader
......@@ -260,7 +260,7 @@ class Provider:
try:
cwd = dependency.full_path
venv = Env.get(cwd)
venv = EnvManager().get(cwd)
venv.run("python", "setup.py", "egg_info")
except EnvCommandError:
result = SetupReader.read_from_directory(dependency.full_path)
......
......@@ -47,12 +47,22 @@ def mock_clone(_, source, dest):
@pytest.fixture
def tmp_dir():
dir_ = tempfile.mkdtemp(prefix="poetry_")
yield dir_
shutil.rmtree(dir_)
@pytest.fixture
def environ():
original_environ = os.environ
original_environ = dict(os.environ)
yield os.environ
yield
os.environ = original_environ
os.environ.clear()
os.environ.update(original_environ)
@pytest.fixture(autouse=True)
......
import pytest
from cleo.testers import CommandTester
from poetry.utils._compat import Path
from poetry.utils.env import MockEnv
@pytest.fixture(autouse=True)
def setup(mocker):
mocker.patch(
"poetry.utils.env.EnvManager.get",
return_value=MockEnv(
path=Path("/prefix"), base=Path("/base/prefix"), is_venv=True
),
)
def test_env_info_displays_complete_info(app):
command = app.find("env info")
tester = CommandTester(command)
tester.execute()
expected = """
Virtualenv
Python: 3.7.0
Implementation: CPython
Path: {prefix}
Valid: True
System
Platform: darwin
OS: posix
Python: {base_prefix}
""".format(
prefix=str(Path("/prefix")), base_prefix=str(Path("/base/prefix"))
)
assert expected == tester.io.fetch_output()
def test_env_info_displays_path_only(app):
command = app.find("env info")
tester = CommandTester(command)
tester.execute("--path")
expected = str(Path("/prefix"))
assert expected == tester.io.fetch_output()
import tomlkit
from cleo.testers import CommandTester
from poetry.utils._compat import Path
from poetry.utils.env import EnvManager
from poetry.utils.toml_file import TomlFile
def test_none_activated(app, tmp_dir, config):
app.poetry._config = config
config.add_property("settings.virtualenvs.path", str(tmp_dir))
venv_name = EnvManager.generate_env_name(
"simple_project", str(app.poetry.file.parent)
)
(Path(tmp_dir) / "{}-py3.7".format(venv_name)).mkdir()
(Path(tmp_dir) / "{}-py3.6".format(venv_name)).mkdir()
command = app.find("env list")
tester = CommandTester(command)
tester.execute()
expected = """\
{}-py3.6
{}-py3.7
""".format(
venv_name, venv_name
)
assert expected == tester.io.fetch_output()
def test_activated(app, tmp_dir, config):
app.poetry._config = config
config.add_property("settings.virtualenvs.path", str(tmp_dir))
venv_name = EnvManager.generate_env_name(
"simple_project", str(app.poetry.file.parent)
)
(Path(tmp_dir) / "{}-py3.7".format(venv_name)).mkdir()
(Path(tmp_dir) / "{}-py3.6".format(venv_name)).mkdir()
envs_file = TomlFile(Path(tmp_dir) / "envs.toml")
doc = tomlkit.document()
doc[venv_name] = {"minor": "3.7", "patch": "3.7.0"}
envs_file.write(doc)
command = app.find("env list")
tester = CommandTester(command)
tester.execute()
expected = """\
{}-py3.6
{}-py3.7 (Activated)
""".format(
venv_name, venv_name
)
assert expected == tester.io.fetch_output()
from cleo.testers import CommandTester
from poetry.utils._compat import Path
from poetry.utils.env import EnvManager
from .test_use import Version
from .test_use import check_output_wrapper
def test_remove_by_python_version(app, tmp_dir, config, mocker):
app.poetry._config = config
config.add_property("settings.virtualenvs.path", str(tmp_dir))
venv_name = EnvManager.generate_env_name(
"simple_project", str(app.poetry.file.parent)
)
(Path(tmp_dir) / "{}-py3.7".format(venv_name)).mkdir()
(Path(tmp_dir) / "{}-py3.6".format(venv_name)).mkdir()
mocker.patch(
"subprocess.check_output",
side_effect=check_output_wrapper(Version.parse("3.6.6")),
)
command = app.find("env remove")
tester = CommandTester(command)
tester.execute("3.6")
assert not (Path(tmp_dir) / "{}-py3.6".format(venv_name)).exists()
expected = "Deleted virtualenv: {}\n".format(
(Path(tmp_dir) / "{}-py3.6".format(venv_name))
)
assert expected == tester.io.fetch_output()
def test_remove_by_name(app, tmp_dir, config, mocker):
app.poetry._config = config
config.add_property("settings.virtualenvs.path", str(tmp_dir))
venv_name = EnvManager.generate_env_name(
"simple_project", str(app.poetry.file.parent)
)
(Path(tmp_dir) / "{}-py3.7".format(venv_name)).mkdir()
(Path(tmp_dir) / "{}-py3.6".format(venv_name)).mkdir()
mocker.patch(
"subprocess.check_output",
side_effect=check_output_wrapper(Version.parse("3.6.6")),
)
command = app.find("env remove")
tester = CommandTester(command)
tester.execute("{}-py3.6".format(venv_name))
assert not (Path(tmp_dir) / "{}-py3.6".format(venv_name)).exists()
expected = "Deleted virtualenv: {}\n".format(
(Path(tmp_dir) / "{}-py3.6".format(venv_name))
)
assert expected == tester.io.fetch_output()
import os
import shutil
import sys
import tomlkit
from cleo.testers import CommandTester
from poetry.semver import Version
from poetry.utils._compat import Path
from poetry.utils.env import EnvManager
from poetry.utils.env import MockEnv
from poetry.utils.toml_file import TomlFile
CWD = Path(__file__).parent.parent / "fixtures" / "simple_project"
def build_venv(path, executable=None):
os.mkdir(path)
def remove_venv(path):
shutil.rmtree(path)
def check_output_wrapper(version=Version.parse("3.7.1")):
def check_output(cmd, *args, **kwargs):
if "sys.version_info[:3]" in cmd:
return version.text
elif "sys.version_info[:2]" in cmd:
return "{}.{}".format(version.major, version.minor)
else:
return str(Path("/prefix"))
return check_output
def test_activate_activates_non_existing_virtualenv_no_envs_file(
app, tmp_dir, config, mocker
):
app.poetry._config = config
if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"]
config.add_property("settings.virtualenvs.path", str(tmp_dir))
mocker.patch("subprocess.check_output", side_effect=check_output_wrapper())
mocker.patch(
"subprocess.Popen.communicate",
side_effect=[("/prefix", None), ("/prefix", None)],
)
m = mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=build_venv)
command = app.find("env use")
tester = CommandTester(command)
tester.execute("3.7")
venv_name = EnvManager.generate_env_name(
"simple_project", str(app.poetry.file.parent)
)
m.assert_called_with(
os.path.join(tmp_dir, "{}-py3.7".format(venv_name)), executable="python3.7"
)
envs_file = TomlFile(Path(tmp_dir) / "envs.toml")
assert envs_file.exists()
envs = envs_file.read()
assert envs[venv_name]["minor"] == "3.7"
assert envs[venv_name]["patch"] == "3.7.1"
expected = """\
Creating virtualenv {} in {}
Using virtualenv: {}
""".format(
"{}-py3.7".format(venv_name),
tmp_dir,
os.path.join(tmp_dir, "{}-py3.7".format(venv_name)),
)
assert expected == tester.io.fetch_output()
def test_get_prefers_explicitly_activated_virtualenvs_over_env_var(
app, tmp_dir, config, mocker
):
app.poetry._config = config
os.environ["VIRTUAL_ENV"] = "/environment/prefix"
venv_name = EnvManager.generate_env_name(
"simple_project", str(app.poetry.file.parent)
)
current_python = sys.version_info[:3]
python_minor = ".".join(str(v) for v in current_python[:2])
python_patch = ".".join(str(v) for v in current_python)
config.add_property("settings.virtualenvs.path", str(tmp_dir))
(Path(tmp_dir) / "{}-py{}".format(venv_name, python_minor)).mkdir()
envs_file = TomlFile(Path(tmp_dir) / "envs.toml")
doc = tomlkit.document()
doc[venv_name] = {"minor": python_minor, "patch": python_patch}
envs_file.write(doc)
mocker.patch(
"subprocess.check_output",
side_effect=check_output_wrapper(Version(*current_python)),
)
mocker.patch(
"subprocess.Popen.communicate",
side_effect=[("/prefix", None), ("/prefix", None), ("/prefix", None)],
)
command = app.find("env use")
tester = CommandTester(command)
tester.execute(python_minor)
expected = """\
Using virtualenv: {}
""".format(
os.path.join(tmp_dir, "{}-py{}".format(venv_name, python_minor))
)
assert expected == tester.io.fetch_output()
def test_get_prefers_explicitly_activated_non_existing_virtualenvs_over_env_var(
app, tmp_dir, config, mocker
):
app.poetry._config = config
os.environ["VIRTUAL_ENV"] = "/environment/prefix"
venv_name = EnvManager.generate_env_name(
"simple_project", str(app.poetry.file.parent)
)
current_python = sys.version_info[:3]
python_minor = ".".join(str(v) for v in current_python[:2])
config.add_property("settings.virtualenvs.path", str(tmp_dir))
mocker.patch(
"poetry.utils.env.EnvManager._env",
new_callable=mocker.PropertyMock,
return_value=MockEnv(
path=Path("/environment/prefix"),
base=Path("/base/prefix"),
version_info=current_python,
is_venv=True,
),
)
mocker.patch(
"subprocess.check_output",
side_effect=check_output_wrapper(Version(*current_python)),
)
mocker.patch(
"subprocess.Popen.communicate",
side_effect=[("/prefix", None), ("/prefix", None), ("/prefix", None)],
)
mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=build_venv)
command = app.find("env use")
tester = CommandTester(command)
tester.execute(python_minor)
expected = """\
Creating virtualenv {} in {}
Using virtualenv: {}
""".format(
"{}-py{}".format(venv_name, python_minor),
tmp_dir,
os.path.join(tmp_dir, "{}-py{}".format(venv_name, python_minor)),
)
assert expected == tester.io.fetch_output()
......@@ -37,7 +37,7 @@ classifiers = [
# Requirements
[tool.poetry.dependencies]
python = "~2.7 || ^3.6"
python = "~2.7 || ^3.4"
foo = "^1.0"
"""
......
import sys
from cleo.testers import CommandTester
from poetry.utils._compat import Path
......@@ -126,9 +127,11 @@ description = ""
authors = ["Your Name <you@example.com>"]
[tool.poetry.dependencies]
python = "^3.7"
python = "^{python}"
[tool.poetry.dev-dependencies]
"""
""".format(
python=".".join(str(c) for c in sys.version_info[:2])
)
assert expected in tester.io.fetch_output()
from cleo.testers import CommandTester
from poetry.utils._compat import Path
from poetry.utils.env import MockEnv
def test_run_passes_all_args(app, mocker):
env = MockEnv(is_venv=True)
mocker.patch("poetry.utils.env.Env.get", return_value=env)
env = MockEnv(path=Path("/prefix"), base=Path("/base/prefix"), is_venv=True)
mocker.patch("poetry.utils.env.EnvManager.get", return_value=env)
command = app.find("run")
tester = CommandTester(command)
......
......@@ -17,7 +17,6 @@ from poetry.packages import Locker as BaseLocker
from poetry.repositories import Pool
from poetry.repositories import Repository as BaseRepository
from poetry.utils._compat import Path
from poetry.utils.env import MockEnv
from poetry.utils.toml_file import TomlFile
from poetry.repositories.exceptions import PackageNotFound
......@@ -49,11 +48,7 @@ def installed():
@pytest.fixture(autouse=True)
def setup(mocker, installer, installed):
mocker.patch(
"poetry.utils.env.Env.get", return_value=MockEnv(is_venv=True, execute=True)
)
def setup(mocker, installer, installed, config):
# Set Installer's installer
p = mocker.patch("poetry.installation.installer.Installer._get_installer")
p.return_value = installer
......
......@@ -20,7 +20,7 @@ classifiers = [
# Requirements
[tool.poetry.dependencies]
python = "~2.7 || ^3.6"
python = "~2.7 || ^3.4"
cachy = "^0.1.0"
pendulum = "^2.0.0"
......
......@@ -22,7 +22,7 @@ classifiers = [
# Requirements
[tool.poetry.dependencies]
python = "~2.7 || ^3.6"
python = "~2.7 || ^3.4"
# File dependency
demo = { path = "../distributions/demo-0.1.0-py2.py3-none-any.whl" }
......
......@@ -22,4 +22,4 @@ classifiers = [
# Requirements
[tool.poetry.dependencies]
python = "~2.7 || ^3.6"
python = "~2.7 || ^3.4"
......@@ -81,7 +81,7 @@ def test_search_for_vcs_setup_egg_info_with_extras(provider):
@pytest.mark.skipif(not PY35, reason="AST parsing does not work for Python <3.4")
def test_search_for_vcs_read_setup(provider, mocker):
mocker.patch("poetry.utils.env.Env.get", return_value=MockEnv())
mocker.patch("poetry.utils.env.EnvManager.get", return_value=MockEnv())
dependency = VCSDependency("demo", "git", "https://github.com/demo/demo.git")
......@@ -98,7 +98,7 @@ def test_search_for_vcs_read_setup(provider, mocker):
@pytest.mark.skipif(not PY35, reason="AST parsing does not work for Python <3.4")
def test_search_for_vcs_read_setup_with_extras(provider, mocker):
mocker.patch("poetry.utils.env.Env.get", return_value=MockEnv())
mocker.patch("poetry.utils.env.EnvManager.get", return_value=MockEnv())
dependency = VCSDependency("demo", "git", "https://github.com/demo/demo.git")
dependency.extras.append("foo")
......@@ -118,7 +118,7 @@ def test_search_for_vcs_read_setup_with_extras(provider, mocker):
def test_search_for_vcs_read_setup_raises_error_if_no_version(provider, mocker):
mocker.patch("poetry.utils.env.Env.get", return_value=MockEnv())
mocker.patch("poetry.utils.env.EnvManager.get", return_value=MockEnv())
dependency = VCSDependency("demo", "git", "https://github.com/demo/no-version.git")
......@@ -176,7 +176,7 @@ def test_search_for_directory_setup_egg_info_with_extras(provider):
@pytest.mark.skipif(not PY35, reason="AST parsing does not work for Python <3.4")
def test_search_for_directory_setup_read_setup(provider, mocker):
mocker.patch("poetry.utils.env.Env.get", return_value=MockEnv())
mocker.patch("poetry.utils.env.EnvManager.get", return_value=MockEnv())
dependency = DirectoryDependency(
"demo",
......@@ -201,7 +201,7 @@ def test_search_for_directory_setup_read_setup(provider, mocker):
@pytest.mark.skipif(not PY35, reason="AST parsing does not work for Python <3.4")
def test_search_for_directory_setup_read_setup_with_extras(provider, mocker):
mocker.patch("poetry.utils.env.Env.get", return_value=MockEnv())
mocker.patch("poetry.utils.env.EnvManager.get", return_value=MockEnv())
dependency = DirectoryDependency(
"demo",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment