Commit 32c87c9d by Sébastien Eustace Committed by GitHub

Merge pull request #2691 from abn/merge-master-into-develop

Merge unreleased changes from master into develop
parents ca1c3977 9ab737d6
...@@ -48,7 +48,6 @@ jobs: ...@@ -48,7 +48,6 @@ jobs:
- name: Install poetry - name: Install poetry
shell: bash shell: bash
run: | run: |
curl -fsS -o get-poetry.py https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py
python get-poetry.py -y --preview python get-poetry.py -y --preview
echo "::set-env name=PATH::$HOME/.poetry/bin:$PATH" echo "::set-env name=PATH::$HOME/.poetry/bin:$PATH"
......
...@@ -50,7 +50,7 @@ This release **must** be downloaded via the `get-poetry.py` script and not via t ...@@ -50,7 +50,7 @@ This release **must** be downloaded via the `get-poetry.py` script and not via t
- The exceptions are now beautifully displayed in the terminal with various level of details depending on the verbosity ([2230](https://github.com/python-poetry/poetry/pull/2230)). - The exceptions are now beautifully displayed in the terminal with various level of details depending on the verbosity ([2230](https://github.com/python-poetry/poetry/pull/2230)).
## [1.0.9] - 2010-06-09 ## [1.0.9] - 2020-06-09
### Fixed ### Fixed
......
...@@ -480,7 +480,7 @@ poetry export -f requirements.txt > requirements.txt ...@@ -480,7 +480,7 @@ poetry export -f requirements.txt > requirements.txt
The `env` command regroups sub commands to interact with the virtualenvs The `env` command regroups sub commands to interact with the virtualenvs
associated with a specific project. associated with a specific project.
See [Managing environments](/docs/managing-environments.md) for more information about these commands. See [Managing environments](/docs/managing-environments/) for more information about these commands.
## cache ## cache
......
...@@ -33,7 +33,7 @@ curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poet ...@@ -33,7 +33,7 @@ curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poet
!!! note !!! note
You only need to install Poetry once. It will automatically pick up the current You only need to install Poetry once. It will automatically pick up the current
Python version and use it to [create virtualenvs](/docs/managing-environments.md) accordingly. Python version and use it to [create virtualenvs](/docs/managing-environments) accordingly.
The installer installs the `poetry` tool to Poetry's `bin` directory. The installer installs the `poetry` tool to Poetry's `bin` directory.
On Unix it is located at `$HOME/.poetry/bin` and on Windows at `%USERPROFILE%\.poetry\bin`. On Unix it is located at `$HOME/.poetry/bin` and on Windows at `%USERPROFILE%\.poetry\bin`.
...@@ -82,6 +82,15 @@ POETRY_VERSION=0.12.0 python get-poetry.py ...@@ -82,6 +82,15 @@ POETRY_VERSION=0.12.0 python get-poetry.py
Note that the installer does not support Poetry releases < 0.12.0. Note that the installer does not support Poetry releases < 0.12.0.
!!!note
The setup script must be able to find one of following executables in your shell's path environment:
- `python` (which can be a py3 or py2 interpreter)
- `python3`
- `py.exe -3` (Windows)
- `py.exe -2` (Windows)
### Alternative installation methods (not recommended) ### Alternative installation methods (not recommended)
!!!note !!!note
......
...@@ -92,7 +92,7 @@ poetry env info --path ...@@ -92,7 +92,7 @@ poetry env info --path
## Listing the environments associated with the project ## Listing the environments associated with the project
You can also list all the virtual environments associated with the current virtual environment You can also list all the virtual environments associated with the current project
with the `env list` command: with the `env list` command:
```bash ```bash
......
...@@ -38,7 +38,7 @@ The recommended notation for the most common licenses is (alphabetical): ...@@ -38,7 +38,7 @@ The recommended notation for the most common licenses is (alphabetical):
* MIT * MIT
Optional, but it is highly recommended to supply this. Optional, but it is highly recommended to supply this.
More identifiers are listed at the [SPDX Open Source License Registry](https://www.spdx.org/licenses/). More identifiers are listed at the [SPDX Open Source License Registry](https://spdx.org/licenses/).
!!!note !!!note
......
...@@ -449,6 +449,26 @@ class Installer: ...@@ -449,6 +449,26 @@ class Installer:
break break
current_version = None
if os.path.exists(POETRY_LIB):
with open(
os.path.join(POETRY_LIB, "poetry", "__version__.py"), encoding="utf-8"
) as f:
version_content = f.read()
current_version_re = re.match(
'(?ms).*__version__ = "(.+)".*', version_content
)
if not current_version_re:
print(
colorize(
"warning",
"Unable to get the current Poetry version. Assuming None",
)
)
else:
current_version = current_version_re.group(1)
if current_version == version and not self._force: if current_version == version and not self._force:
print("Latest version already installed.") print("Latest version already installed.")
return None, current_version return None, current_version
...@@ -637,6 +657,7 @@ class Installer: ...@@ -637,6 +657,7 @@ class Installer:
if match and tuple(map(int, match.groups())) >= (3, 0): if match and tuple(map(int, match.groups())) >= (3, 0):
# favor the first py3 executable we can find. # favor the first py3 executable we can find.
return executable return executable
if fallback is None: if fallback is None:
# keep this one as the fallback; it was the first valid executable we found. # keep this one as the fallback; it was the first valid executable we found.
fallback = executable fallback = executable
...@@ -669,7 +690,9 @@ class Installer: ...@@ -669,7 +690,9 @@ class Installer:
) )
with open(os.path.join(POETRY_BIN, "poetry"), "w", encoding="utf-8") as f: with open(os.path.join(POETRY_BIN, "poetry"), "w", encoding="utf-8") as f:
if not WINDOWS: if WINDOWS:
python_executable = "python"
f.write(u("#!/usr/bin/env {}\n".format(python_executable))) f.write(u("#!/usr/bin/env {}\n".format(python_executable)))
f.write(u(BIN)) f.write(u(BIN))
......
...@@ -47,11 +47,18 @@ class AddCommand(InstallerCommand, InitCommand): ...@@ -47,11 +47,18 @@ class AddCommand(InstallerCommand, InitCommand):
), ),
option("lock", None, "Do not perform operations (only update the lockfile)."), option("lock", None, "Do not perform operations (only update the lockfile)."),
] ]
help = (
help = """The add command adds required packages to your <comment>pyproject.toml</> and installs them. "The add command adds required packages to your <comment>pyproject.toml</> and installs them.\n\n"
"If you do not specify a version constraint, poetry will choose a suitable one based on the available package versions.\n\n"
If you do not specify a version constraint, poetry will choose a suitable one based on the available package versions. "You can specify a package in the following forms:\n"
""" " - A single name (<b>requests</b>)\n"
" - A name and a constraint (<b>requests@^2.23.0</b>)\n"
" - A git url (<b>git+https://github.com/python-poetry/poetry.git</b>)\n"
" - A git url with a revision (<b>git+https://github.com/python-poetry/poetry.git#develop</b>)\n"
" - A file path (<b>../my-package/my-package.whl</b>)\n"
" - A directory (<b>../my-package/</b>)\n"
" - A url (<b>https://example.com/packages/my-package-0.1.0.tar.gz</b>)\n"
)
loggers = ["poetry.repositories.pypi_repository"] loggers = ["poetry.repositories.pypi_repository"]
......
...@@ -149,7 +149,7 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the ...@@ -149,7 +149,7 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the
help_message = ( help_message = (
"You can specify a package in the following forms:\n" "You can specify a package in the following forms:\n"
" - A single name (<b>requests</b>)\n" " - A single name (<b>requests</b>)\n"
" - A name and a constraint (<b>requests ^2.23.0</b>)\n" " - A name and a constraint (<b>requests@^2.23.0</b>)\n"
" - A git url (<b>git+https://github.com/python-poetry/poetry.git</b>)\n" " - A git url (<b>git+https://github.com/python-poetry/poetry.git</b>)\n"
" - A git url with a revision (<b>git+https://github.com/python-poetry/poetry.git#develop</b>)\n" " - A git url with a revision (<b>git+https://github.com/python-poetry/poetry.git#develop</b>)\n"
" - A file path (<b>../my-package/my-package.whl</b>)\n" " - A file path (<b>../my-package/my-package.whl</b>)\n"
......
...@@ -142,7 +142,7 @@ class PipInstaller(BaseInstaller): ...@@ -142,7 +142,7 @@ class PipInstaller(BaseInstaller):
if package.source_type in ["file", "directory"]: if package.source_type in ["file", "directory"]:
if package.root_dir: if package.root_dir:
req = os.path.join(package.root_dir, package.source_url) req = (package.root_dir / package.source_url).as_posix()
else: else:
req = os.path.realpath(package.source_url) req = os.path.realpath(package.source_url)
...@@ -185,7 +185,7 @@ class PipInstaller(BaseInstaller): ...@@ -185,7 +185,7 @@ class PipInstaller(BaseInstaller):
from poetry.utils.toml_file import TomlFile from poetry.utils.toml_file import TomlFile
if package.root_dir: if package.root_dir:
req = os.path.join(package.root_dir, package.source_url) req = (package.root_dir / package.source_url).as_posix()
else: else:
req = os.path.realpath(package.source_url) req = os.path.realpath(package.source_url)
......
...@@ -424,7 +424,7 @@ class EnvManager(object): ...@@ -424,7 +424,7 @@ class EnvManager(object):
if venv.path.name == python: if venv.path.name == python:
# Exact virtualenv name # Exact virtualenv name
if not envs_file.exists(): if not envs_file.exists():
self.remove_venv(str(venv.path)) self.remove_venv(venv.path)
return venv return venv
...@@ -434,7 +434,7 @@ class EnvManager(object): ...@@ -434,7 +434,7 @@ class EnvManager(object):
current_env = envs.get(base_env_name) current_env = envs.get(base_env_name)
if not current_env: if not current_env:
self.remove_venv(str(venv.path)) self.remove_venv(venv.path)
return venv return venv
...@@ -442,7 +442,7 @@ class EnvManager(object): ...@@ -442,7 +442,7 @@ class EnvManager(object):
del envs[base_env_name] del envs[base_env_name]
envs_file.write(envs) envs_file.write(envs)
self.remove_venv(str(venv.path)) self.remove_venv(venv.path)
return venv return venv
...@@ -496,7 +496,7 @@ class EnvManager(object): ...@@ -496,7 +496,7 @@ class EnvManager(object):
del envs[base_env_name] del envs[base_env_name]
envs_file.write(envs) envs_file.write(envs)
self.remove_venv(str(venv)) self.remove_venv(venv)
return VirtualEnv(venv) return VirtualEnv(venv)
...@@ -642,7 +642,7 @@ class EnvManager(object): ...@@ -642,7 +642,7 @@ class EnvManager(object):
"Creating virtualenv <c1>{}</> in {}".format(name, str(venv_path)) "Creating virtualenv <c1>{}</> in {}".format(name, str(venv_path))
) )
self.build_venv(str(venv), executable=executable) self.build_venv(venv, executable=executable)
else: else:
if force: if force:
if not env.is_sane(): if not env.is_sane():
...@@ -654,8 +654,8 @@ class EnvManager(object): ...@@ -654,8 +654,8 @@ class EnvManager(object):
io.write_line( io.write_line(
"Recreating virtualenv <c1>{}</> in {}".format(name, str(venv)) "Recreating virtualenv <c1>{}</> in {}".format(name, str(venv))
) )
self.remove_venv(str(venv)) self.remove_venv(venv)
self.build_venv(str(venv), executable=executable) self.build_venv(venv, executable=executable)
elif io.is_very_verbose(): elif io.is_very_verbose():
io.write_line("Virtualenv <c1>{}</> already exists.".format(name)) io.write_line("Virtualenv <c1>{}</> already exists.".format(name))
...@@ -680,21 +680,41 @@ class EnvManager(object): ...@@ -680,21 +680,41 @@ class EnvManager(object):
@classmethod @classmethod
def build_venv( def build_venv(
cls, path, executable=None cls, path, executable=None
): # type: (str, Optional[Union[str, Path]]) -> virtualenv.run.session.Session ): # type: (Union[Path,str], Optional[Union[str, Path]]) -> virtualenv.run.session.Session
if isinstance(executable, Path): if isinstance(executable, Path):
executable = executable.resolve() executable = executable.resolve().as_posix()
return virtualenv.cli_run( return virtualenv.cli_run(
[ [
"--no-download", "--no-download",
"--no-periodic-update", "--no-periodic-update",
"--python", "--python",
executable or sys.executable, executable or sys.executable,
path, str(path),
] ]
) )
def remove_venv(self, path): # type: (str) -> None @classmethod
shutil.rmtree(path) def remove_venv(cls, path): # type: (Union[Path,str]) -> None
if isinstance(path, str):
path = Path(path)
assert path.is_dir()
try:
shutil.rmtree(str(path))
return
except OSError as e:
# Continue only if e.errno == 16
if e.errno != 16: # ERRNO 16: Device or resource busy
raise e
# Delete all files and folders but the toplevel one. This is because sometimes
# the venv folder is mounted by the OS, such as in a docker volume. In such
# cases, an attempt to delete the folder itself will result in an `OSError`.
# See https://github.com/python-poetry/poetry/pull/2064
for file_path in path.iterdir():
if file_path.is_file() or file_path.is_symlink():
file_path.unlink()
elif file_path.is_dir():
shutil.rmtree(str(file_path))
def get_base_prefix(self): # type: () -> Path def get_base_prefix(self): # type: () -> Path
if hasattr(sys, "real_prefix"): if hasattr(sys, "real_prefix"):
......
...@@ -94,6 +94,8 @@ class Shell: ...@@ -94,6 +94,8 @@ class Shell:
suffix = ".fish" suffix = ".fish"
elif "csh" == self._name: elif "csh" == self._name:
suffix = ".csh" suffix = ".csh"
elif "tcsh" == self._name:
suffix = ".csh"
else: else:
suffix = "" suffix = ""
...@@ -104,6 +106,8 @@ class Shell: ...@@ -104,6 +106,8 @@ class Shell:
return "source" return "source"
elif "csh" == self._name: elif "csh" == self._name:
return "source" return "source"
elif "tcsh" == self._name:
return "source"
return "." return "."
......
import os import os
import shutil
import sys import sys
from typing import Optional
from typing import Union
import tomlkit import tomlkit
from cleo.testers import CommandTester from cleo.testers import CommandTester
...@@ -16,12 +18,8 @@ from poetry.utils.toml_file import TomlFile ...@@ -16,12 +18,8 @@ from poetry.utils.toml_file import TomlFile
CWD = Path(__file__).parent.parent / "fixtures" / "simple_project" CWD = Path(__file__).parent.parent / "fixtures" / "simple_project"
def build_venv(path, executable=None): def build_venv(path, executable=None): # type: (Union[Path,str], Optional[str]) -> ()
os.mkdir(path) os.mkdir(str(path))
def remove_venv(path):
shutil.rmtree(path)
def check_output_wrapper(version=Version.parse("3.7.1")): def check_output_wrapper(version=Version.parse("3.7.1")):
...@@ -62,7 +60,7 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file(app, tmp_dir, m ...@@ -62,7 +60,7 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file(app, tmp_dir, m
) )
m.assert_called_with( m.assert_called_with(
os.path.join(tmp_dir, "{}-py3.7".format(venv_name)), executable="python3.7" Path(tmp_dir) / "{}-py3.7".format(venv_name), executable="python3.7"
) )
envs_file = TomlFile(Path(tmp_dir) / "envs.toml") envs_file = TomlFile(Path(tmp_dir) / "envs.toml")
......
...@@ -2,6 +2,9 @@ import os ...@@ -2,6 +2,9 @@ import os
import shutil import shutil
import sys import sys
from typing import Optional
from typing import Union
import pytest import pytest
import tomlkit import tomlkit
...@@ -84,12 +87,8 @@ def test_env_get_in_project_venv(manager, poetry): ...@@ -84,12 +87,8 @@ def test_env_get_in_project_venv(manager, poetry):
shutil.rmtree(str(venv.path)) shutil.rmtree(str(venv.path))
def build_venv(path, executable=None): def build_venv(path, executable=None): # type: (Union[Path,str], Optional[str]) -> ()
os.mkdir(path) os.mkdir(str(path))
def remove_venv(path):
shutil.rmtree(path)
def check_output_wrapper(version=Version.parse("3.7.1")): def check_output_wrapper(version=Version.parse("3.7.1")):
...@@ -126,7 +125,7 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file( ...@@ -126,7 +125,7 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file(
venv_name = EnvManager.generate_env_name("simple-project", str(poetry.file.parent)) venv_name = EnvManager.generate_env_name("simple-project", str(poetry.file.parent))
m.assert_called_with( m.assert_called_with(
os.path.join(tmp_dir, "{}-py3.7".format(venv_name)), executable="python3.7" Path(tmp_dir) / "{}-py3.7".format(venv_name), executable="python3.7"
) )
envs_file = TomlFile(Path(tmp_dir) / "envs.toml") envs_file = TomlFile(Path(tmp_dir) / "envs.toml")
...@@ -244,7 +243,7 @@ def test_activate_activates_different_virtualenv_with_envs_file( ...@@ -244,7 +243,7 @@ def test_activate_activates_different_virtualenv_with_envs_file(
env = manager.activate("python3.6", NullIO()) env = manager.activate("python3.6", NullIO())
m.assert_called_with( m.assert_called_with(
os.path.join(tmp_dir, "{}-py3.6".format(venv_name)), executable="python3.6" Path(tmp_dir) / "{}-py3.6".format(venv_name), executable="python3.6"
) )
assert envs_file.exists() assert envs_file.exists()
...@@ -290,17 +289,15 @@ def test_activate_activates_recreates_for_different_patch( ...@@ -290,17 +289,15 @@ def test_activate_activates_recreates_for_different_patch(
"poetry.utils.env.EnvManager.build_venv", side_effect=build_venv "poetry.utils.env.EnvManager.build_venv", side_effect=build_venv
) )
remove_venv_m = mocker.patch( remove_venv_m = mocker.patch(
"poetry.utils.env.EnvManager.remove_venv", side_effect=remove_venv "poetry.utils.env.EnvManager.remove_venv", side_effect=EnvManager.remove_venv
) )
env = manager.activate("python3.7", NullIO()) env = manager.activate("python3.7", NullIO())
build_venv_m.assert_called_with( build_venv_m.assert_called_with(
os.path.join(tmp_dir, "{}-py3.7".format(venv_name)), executable="python3.7" Path(tmp_dir) / "{}-py3.7".format(venv_name), executable="python3.7"
)
remove_venv_m.assert_called_with(
os.path.join(tmp_dir, "{}-py3.7".format(venv_name))
) )
remove_venv_m.assert_called_with(Path(tmp_dir) / "{}-py3.7".format(venv_name))
assert envs_file.exists() assert envs_file.exists()
envs = envs_file.read() envs = envs_file.read()
...@@ -341,7 +338,7 @@ def test_activate_does_not_recreate_when_switching_minor( ...@@ -341,7 +338,7 @@ def test_activate_does_not_recreate_when_switching_minor(
"poetry.utils.env.EnvManager.build_venv", side_effect=build_venv "poetry.utils.env.EnvManager.build_venv", side_effect=build_venv
) )
remove_venv_m = mocker.patch( remove_venv_m = mocker.patch(
"poetry.utils.env.EnvManager.remove_venv", side_effect=remove_venv "poetry.utils.env.EnvManager.remove_venv", side_effect=EnvManager.remove_venv
) )
env = manager.activate("python3.6", NullIO()) env = manager.activate("python3.6", NullIO())
...@@ -536,6 +533,54 @@ def test_remove_also_deactivates(tmp_dir, manager, poetry, config, mocker): ...@@ -536,6 +533,54 @@ def test_remove_also_deactivates(tmp_dir, manager, poetry, config, mocker):
assert venv_name not in envs assert venv_name not in envs
def test_remove_keeps_dir_if_not_deleteable(tmp_dir, manager, poetry, config, mocker):
# Ensure we empty rather than delete folder if its is an active mount point.
# See https://github.com/python-poetry/poetry/pull/2064
config.merge({"virtualenvs": {"path": str(tmp_dir)}})
venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent))
venv_path = Path(tmp_dir) / "{}-py3.6".format(venv_name)
venv_path.mkdir()
folder1_path = venv_path / "folder1"
folder1_path.mkdir()
file1_path = folder1_path / "file1"
file1_path.touch(exist_ok=False)
file2_path = venv_path / "file2"
file2_path.touch(exist_ok=False)
mocker.patch(
"poetry.utils._compat.subprocess.check_output",
side_effect=check_output_wrapper(Version.parse("3.6.6")),
)
original_rmtree = shutil.rmtree
def err_on_rm_venv_only(path, *args, **kwargs):
print(path)
if path == str(venv_path):
raise OSError(16, "Test error") # ERRNO 16: Device or resource busy
else:
original_rmtree(path)
m = mocker.patch("shutil.rmtree", side_effect=err_on_rm_venv_only)
venv = manager.remove("{}-py3.6".format(venv_name))
m.assert_any_call(str(venv_path))
assert venv_path == venv.path
assert venv_path.exists()
assert not folder1_path.exists()
assert not file1_path.exists()
assert not file2_path.exists()
m.side_effect = original_rmtree # Avoid teardown using `err_on_rm_venv_only`
@pytest.mark.skipif( @pytest.mark.skipif(
os.name == "nt" or PY2, reason="Symlinks are not support for Windows" os.name == "nt" or PY2, reason="Symlinks are not support for Windows"
) )
...@@ -579,7 +624,7 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_generic_ ...@@ -579,7 +624,7 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_generic_
manager.create_venv(NullIO()) manager.create_venv(NullIO())
m.assert_called_with( m.assert_called_with(
str(Path("/foo/virtualenvs/{}-py3.7".format(venv_name))), executable="python3" Path("/foo/virtualenvs/{}-py3.7".format(venv_name)), executable="python3"
) )
...@@ -603,7 +648,7 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_specific ...@@ -603,7 +648,7 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_specific
manager.create_venv(NullIO()) manager.create_venv(NullIO())
m.assert_called_with( m.assert_called_with(
str(Path("/foo/virtualenvs/{}-py3.8".format(venv_name))), executable="python3.8" Path("/foo/virtualenvs/{}-py3.8".format(venv_name)), executable="python3.8"
) )
...@@ -686,12 +731,10 @@ def test_create_venv_uses_patch_version_to_detect_compatibility( ...@@ -686,12 +731,10 @@ def test_create_venv_uses_patch_version_to_detect_compatibility(
assert not check_output.called assert not check_output.called
m.assert_called_with( m.assert_called_with(
str(
Path( Path(
"/foo/virtualenvs/{}-py{}.{}".format( "/foo/virtualenvs/{}-py{}.{}".format(
venv_name, version.major, version.minor venv_name, version.major, version.minor
) )
)
), ),
executable=None, executable=None,
) )
...@@ -725,12 +768,10 @@ def test_create_venv_uses_patch_version_to_detect_compatibility_with_executable( ...@@ -725,12 +768,10 @@ def test_create_venv_uses_patch_version_to_detect_compatibility_with_executable(
assert check_output.called assert check_output.called
m.assert_called_with( m.assert_called_with(
str(
Path( Path(
"/foo/virtualenvs/{}-py{}.{}".format( "/foo/virtualenvs/{}-py{}.{}".format(
venv_name, version.major, version.minor - 1 venv_name, version.major, version.minor - 1
) )
)
), ),
executable="python{}.{}".format(version.major, version.minor - 1), executable="python{}.{}".format(version.major, version.minor - 1),
) )
...@@ -763,9 +804,7 @@ def test_activate_with_in_project_setting_does_not_fail_if_no_venvs_dir( ...@@ -763,9 +804,7 @@ def test_activate_with_in_project_setting_does_not_fail_if_no_venvs_dir(
manager.activate("python3.7", NullIO()) manager.activate("python3.7", NullIO())
m.assert_called_with( m.assert_called_with(poetry.file.parent / ".venv", executable="python3.7")
os.path.join(str(poetry.file.parent), ".venv"), executable="python3.7"
)
envs_file = TomlFile(Path(tmp_dir) / "virtualenvs" / "envs.toml") envs_file = TomlFile(Path(tmp_dir) / "virtualenvs" / "envs.toml")
assert not envs_file.exists() assert not envs_file.exists()
......
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