Commit 3a00ad8b by Sébastien Eustace

Merge branch 'master' into develop

parents c6a2d6e1 f341073a
...@@ -37,6 +37,16 @@ ...@@ -37,6 +37,16 @@
- The `pyproject.toml` configuration is now properly validated. - The `pyproject.toml` configuration is now properly validated.
## [0.12.17] - 2019-07-03
### Fixed
- Fixed dependency resolution with circular dependencies.
- Fixed encoding errors when reading files on Windows. (Thanks to [@vlcinsky](https://github.com/vlcinsky))
- Fixed unclear errors when executing commands in virtual environments. (Thanks to [@Imaclean74](https://github.com/Imaclean74))
- Fixed handling of `.venv` when it's not a directory. (Thanks to [@mpanarin](https://github.com/mpanarin))
## [0.12.16] - 2019-05-17 ## [0.12.16] - 2019-05-17
### Fixed ### Fixed
...@@ -708,7 +718,8 @@ Initial release ...@@ -708,7 +718,8 @@ Initial release
[Unreleased]: https://github.com/sdispater/poetry/compare/0.12.16...develop [Unreleased]: https://github.com/sdispater/poetry/compare/0.12.17...develop
[0.12.17]: https://github.com/sdispater/poetry/releases/tag/0.12.17
[0.12.16]: https://github.com/sdispater/poetry/releases/tag/0.12.16 [0.12.16]: https://github.com/sdispater/poetry/releases/tag/0.12.16
[0.12.15]: https://github.com/sdispater/poetry/releases/tag/0.12.15 [0.12.15]: https://github.com/sdispater/poetry/releases/tag/0.12.15
[0.12.14]: https://github.com/sdispater/poetry/releases/tag/0.12.14 [0.12.14]: https://github.com/sdispater/poetry/releases/tag/0.12.14
......
...@@ -33,7 +33,7 @@ from contextlib import closing ...@@ -33,7 +33,7 @@ from contextlib import closing
from contextlib import contextmanager from contextlib import contextmanager
from functools import cmp_to_key from functools import cmp_to_key
from gzip import GzipFile from gzip import GzipFile
from io import UnsupportedOperation from io import UnsupportedOperation, open
try: try:
from urllib.error import HTTPError from urllib.error import HTTPError
...@@ -58,6 +58,10 @@ try: ...@@ -58,6 +58,10 @@ try:
except ImportError: except ImportError:
winreg = None winreg = None
try:
u = unicode
except NameError:
u = str
WINDOWS = sys.platform.startswith("win") or (sys.platform == "cli" and os.name == "nt") WINDOWS = sys.platform.startswith("win") or (sys.platform == "cli" and os.name == "nt")
...@@ -191,6 +195,7 @@ POETRY_LIB_BACKUP = os.path.join(POETRY_HOME, "lib-backup") ...@@ -191,6 +195,7 @@ POETRY_LIB_BACKUP = os.path.join(POETRY_HOME, "lib-backup")
BIN = """#!/usr/bin/env python BIN = """#!/usr/bin/env python
# -*- coding: utf-8 -*-
import glob import glob
import sys import sys
import os import os
...@@ -205,7 +210,7 @@ if __name__ == "__main__": ...@@ -205,7 +210,7 @@ if __name__ == "__main__":
main() main()
""" """
BAT = '@echo off\r\npython "{poetry_bin}" %*\r\n' BAT = u('@echo off\r\npython "{poetry_bin}" %*\r\n')
PRE_MESSAGE = """# Welcome to {poetry}! PRE_MESSAGE = """# Welcome to {poetry}!
...@@ -387,7 +392,9 @@ class Installer: ...@@ -387,7 +392,9 @@ class Installer:
current_version = None current_version = None
if os.path.exists(POETRY_LIB): if os.path.exists(POETRY_LIB):
with open(os.path.join(POETRY_LIB, "poetry", "__version__.py")) as f: with open(
os.path.join(POETRY_LIB, "poetry", "__version__.py"), encoding="utf-8"
) as f:
version_content = f.read() version_content = f.read()
current_version_re = re.match( current_version_re = re.match(
...@@ -563,15 +570,17 @@ class Installer: ...@@ -563,15 +570,17 @@ class Installer:
if WINDOWS: if WINDOWS:
with open(os.path.join(POETRY_BIN, "poetry.bat"), "w") as f: with open(os.path.join(POETRY_BIN, "poetry.bat"), "w") as f:
f.write( f.write(
BAT.format( u(
poetry_bin=os.path.join(POETRY_BIN, "poetry").replace( BAT.format(
os.environ["USERPROFILE"], "%USERPROFILE%" poetry_bin=os.path.join(POETRY_BIN, "poetry").replace(
os.environ["USERPROFILE"], "%USERPROFILE%"
)
) )
) )
) )
with open(os.path.join(POETRY_BIN, "poetry"), "w") as f: with open(os.path.join(POETRY_BIN, "poetry"), "w", encoding="utf-8") as f:
f.write(BIN) f.write(u(BIN))
if not WINDOWS: if not WINDOWS:
# Making the file executable # Making the file executable
...@@ -583,7 +592,7 @@ class Installer: ...@@ -583,7 +592,7 @@ class Installer:
return return
with open(os.path.join(POETRY_HOME, "env"), "w") as f: with open(os.path.join(POETRY_HOME, "env"), "w") as f:
f.write(self.get_export_string()) f.write(u(self.get_export_string()))
def update_path(self): def update_path(self):
""" """
...@@ -608,7 +617,7 @@ class Installer: ...@@ -608,7 +617,7 @@ class Installer:
if addition not in content: if addition not in content:
with open(profile, "a") as f: with open(profile, "a") as f:
f.write(addition) f.write(u(addition))
updated.append(os.path.relpath(profile, HOME)) updated.append(os.path.relpath(profile, HOME))
......
...@@ -995,6 +995,15 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*" ...@@ -995,6 +995,15 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*"
version = "1.12.0" version = "1.12.0"
[[package]] [[package]]
category = "main"
description = "A backport of the subprocess module from Python 3 for use on 2.x."
marker = "python_version >= \"2.7\" and python_version < \"2.8\" or python_version >= \"3.4\" and python_version < \"3.5\""
name = "subprocess32"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4"
version = "3.5.4"
[[package]]
category = "dev" category = "dev"
description = "ANSII Color formatting for output in terminal." description = "ANSII Color formatting for output in terminal."
name = "termcolor" name = "termcolor"
...@@ -1139,14 +1148,14 @@ description = "Backport of pathlib-compatible object wrapper for zip files" ...@@ -1139,14 +1148,14 @@ description = "Backport of pathlib-compatible object wrapper for zip files"
name = "zipp" name = "zipp"
optional = false optional = false
python-versions = ">=2.7" python-versions = ">=2.7"
version = "0.5.1" version = "0.5.2"
[package.extras] [package.extras]
docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
testing = ["pathlib2", "contextlib2", "unittest2"] testing = ["pathlib2", "contextlib2", "unittest2"]
[metadata] [metadata]
content-hash = "1de9e8afcc93d2a5ad0f30746c26b58ae818c3f821460e3281ba4e34184a0f17" content-hash = "c556af6b9f162b11c459c8f6f873d466ce46115657c6ca50c0d1b0754ba3a998"
python-versions = "~2.7 || ^3.4" python-versions = "~2.7 || ^3.4"
[metadata.hashes] [metadata.hashes]
...@@ -1223,6 +1232,7 @@ scandir = ["2586c94e907d99617887daed6c1d102b5ca28f1085f90446554abf1faf73123e", " ...@@ -1223,6 +1232,7 @@ scandir = ["2586c94e907d99617887daed6c1d102b5ca28f1085f90446554abf1faf73123e", "
secretstorage = ["3af65c87765323e6f64c83575b05393f9e003431959c9395d1791d51497f29b6", "20c797ae48a4419f66f8d28fc221623f11fc45b6828f96bdb1ad9990acb59f92", "7a119fb52a88e398dbb22a4b3eb39b779bfbace7e4153b7bc6e5954d86282a8a"] secretstorage = ["3af65c87765323e6f64c83575b05393f9e003431959c9395d1791d51497f29b6", "20c797ae48a4419f66f8d28fc221623f11fc45b6828f96bdb1ad9990acb59f92", "7a119fb52a88e398dbb22a4b3eb39b779bfbace7e4153b7bc6e5954d86282a8a"]
shellingham = ["77d37a4fd287c1e663006f7ecf1b9deca9ad492d0082587bd813c44eb49e4e62", "985b23bbd1feae47ca6a6365eacd314d93d95a8a16f8f346945074c28fe6f3e0"] shellingham = ["77d37a4fd287c1e663006f7ecf1b9deca9ad492d0082587bd813c44eb49e4e62", "985b23bbd1feae47ca6a6365eacd314d93d95a8a16f8f346945074c28fe6f3e0"]
six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"] six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"]
subprocess32 = ["88e37c1aac5388df41cc8a8456bb49ebffd321a3ad4d70358e3518176de3a56b", "eb2937c80497978d181efa1b839ec2d9622cf9600a039a79d0e108d1f9aec79d"]
termcolor = ["1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"] termcolor = ["1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"]
toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"] toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"]
tomlkit = ["a8d806f3a453c2d292afe97918398354e405b93919e2e68771a3fd0a90e89576", "c6b0c11b85e888c12330c7605d43c1446aa148cd421163f90ca46ea813f2c336"] tomlkit = ["a8d806f3a453c2d292afe97918398354e405b93919e2e68771a3fd0a90e89576", "c6b0c11b85e888c12330c7605d43c1446aa148cd421163f90ca46ea813f2c336"]
...@@ -1233,4 +1243,4 @@ urllib3 = ["2393a695cd12afedd0dcb26fe5d50d0cf248e5a66f75dbd89a3d4eb333a61af4", " ...@@ -1233,4 +1243,4 @@ urllib3 = ["2393a695cd12afedd0dcb26fe5d50d0cf248e5a66f75dbd89a3d4eb333a61af4", "
virtualenv = ["b7335cddd9260a3dd214b73a2521ffc09647bde3e9457fcca31dc3be3999d04a", "d28ca64c0f3f125f59cabf13e0a150e1c68e5eea60983cc4395d88c584495783"] virtualenv = ["b7335cddd9260a3dd214b73a2521ffc09647bde3e9457fcca31dc3be3999d04a", "d28ca64c0f3f125f59cabf13e0a150e1c68e5eea60983cc4395d88c584495783"]
wcwidth = ["3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", "f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"] wcwidth = ["3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", "f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"]
webencodings = ["a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", "b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"] webencodings = ["a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", "b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"]
zipp = ["8c1019c6aad13642199fbe458275ad6a84907634cc9f0989877ccc4a2840139d", "ca943a7e809cc12257001ccfb99e3563da9af99d52f261725e96dfe0f9275bc3"] zipp = ["4970c3758f4e89a7857a973b1e2a5d75bcdc47794442f2e2dd4fe8e0466e809a", "8a5712cfd3bb4248015eb3b0b3c54a5f6ee3f2425963ef2a0125b8bc40aafaec"]
...@@ -12,7 +12,7 @@ class CacheClearCommand(Command): ...@@ -12,7 +12,7 @@ class CacheClearCommand(Command):
description = "Clears Poetry's cache." description = "Clears Poetry's cache."
arguments = [argument("cache", description="The name of the cache to clear.")] arguments = [argument("cache", description="The name of the cache to clear.")]
options = [option("all", description="Clear all caches.")] options = [option("all", description="Clear all entries in cache.")]
def handle(self): def handle(self):
from cachy import CacheManager from cachy import CacheManager
......
...@@ -197,7 +197,7 @@ The <info>init</info> command creates a basic <comment>pyproject.toml</> file in ...@@ -197,7 +197,7 @@ The <info>init</info> command creates a basic <comment>pyproject.toml</> file in
return 1 return 1
with (Path.cwd() / "pyproject.toml").open("w") as f: with (Path.cwd() / "pyproject.toml").open("w", encoding="utf-8") as f:
f.write(content) f.write(content)
def _determine_requirements( def _determine_requirements(
......
...@@ -189,7 +189,7 @@ class PipInstaller(BaseInstaller): ...@@ -189,7 +189,7 @@ class PipInstaller(BaseInstaller):
# We also need it for non-PEP-517 packages # We also need it for non-PEP-517 packages
builder = SdistBuilder(Poetry.create(pyproject.parent), NullEnv(), NullIO()) builder = SdistBuilder(Poetry.create(pyproject.parent), NullEnv(), NullIO())
with open(setup, "w") as f: with open(setup, "w", encoding="utf-8") as f:
f.write(decode(builder.build_setup())) f.write(decode(builder.build_setup()))
if package.develop: if package.develop:
......
...@@ -3,6 +3,7 @@ import os ...@@ -3,6 +3,7 @@ import os
import jsonschema import jsonschema
from io import open
from typing import List from typing import List
SCHEMA_DIR = os.path.join(os.path.dirname(__file__), "schemas") SCHEMA_DIR = os.path.join(os.path.dirname(__file__), "schemas")
...@@ -19,7 +20,7 @@ def validate_object(obj, schema_name): # type: (dict, str) -> List[str] ...@@ -19,7 +20,7 @@ def validate_object(obj, schema_name): # type: (dict, str) -> List[str]
if not os.path.exists(schema): if not os.path.exists(schema):
raise ValueError("Schema {} does not exist.".format(schema_name)) raise ValueError("Schema {} does not exist.".format(schema_name))
with open(schema) as f: with open(schema, encoding="utf-8") as f:
schema = json.loads(f.read()) schema = json.loads(f.read())
validator = jsonschema.Draft7Validator(schema) validator = jsonschema.Draft7Validator(schema)
......
...@@ -140,7 +140,7 @@ class Layout(object): ...@@ -140,7 +140,7 @@ class Layout(object):
tests.mkdir() tests.mkdir()
tests_init.touch(exist_ok=False) tests_init.touch(exist_ok=False)
with tests_default.open("w") as f: with tests_default.open("w", encoding="utf-8") as f:
f.write( f.write(
TESTS_DEFAULT.format( TESTS_DEFAULT.format(
package_name=self._package_name, version=self._version package_name=self._package_name, version=self._version
...@@ -152,5 +152,5 @@ class Layout(object): ...@@ -152,5 +152,5 @@ class Layout(object):
poetry = path / "pyproject.toml" poetry = path / "pyproject.toml"
with poetry.open("w") as f: with poetry.open("w", encoding="utf-8") as f:
f.write(content) f.write(content)
...@@ -14,5 +14,5 @@ class SrcLayout(Layout): ...@@ -14,5 +14,5 @@ class SrcLayout(Layout):
package_path.mkdir(parents=True) package_path.mkdir(parents=True)
with package_init.open("w") as f: with package_init.open("w", encoding="utf-8") as f:
f.write(DEFAULT.format(version=self._version)) f.write(DEFAULT.format(version=self._version))
...@@ -14,5 +14,5 @@ class StandardLayout(Layout): ...@@ -14,5 +14,5 @@ class StandardLayout(Layout):
package_path.mkdir() package_path.mkdir()
with package_init.open("w") as f: with package_init.open("w", encoding="utf-8") as f:
f.write(DEFAULT.format(version=self._version)) f.write(DEFAULT.format(version=self._version))
...@@ -40,13 +40,13 @@ def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None): ...@@ -40,13 +40,13 @@ def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
dist_info.mkdir() dist_info.mkdir()
if "scripts" in poetry.local_config or "plugins" in poetry.local_config: if "scripts" in poetry.local_config or "plugins" in poetry.local_config:
with (dist_info / "entry_points.txt").open("w") as f: with (dist_info / "entry_points.txt").open("w", encoding="utf-8") as f:
builder._write_entry_points(f) builder._write_entry_points(f)
with (dist_info / "WHEEL").open("w") as f: with (dist_info / "WHEEL").open("w", encoding="utf-8") as f:
builder._write_wheel_file(f) builder._write_wheel_file(f)
with (dist_info / "METADATA").open("w") as f: with (dist_info / "METADATA").open("w", encoding="utf-8") as f:
builder._write_metadata_file(f) builder._write_metadata_file(f)
return dist_info.name return dist_info.name
......
...@@ -46,7 +46,7 @@ class Metadata: ...@@ -46,7 +46,7 @@ class Metadata:
meta.version = normalize_version(package.version.text) meta.version = normalize_version(package.version.text)
meta.summary = package.description meta.summary = package.description
if package.readme: if package.readme:
with package.readme.open() as f: with package.readme.open(encoding="utf-8") as f:
meta.description = f.read() meta.description = f.read()
meta.keywords = ",".join(package.keywords) meta.keywords = ",".join(package.keywords)
......
...@@ -391,7 +391,7 @@ class Provider: ...@@ -391,7 +391,7 @@ class Provider:
reqs = [] reqs = []
requires = egg_info / "requires.txt" requires = egg_info / "requires.txt"
if requires.exists(): if requires.exists():
with requires.open() as f: with requires.open(encoding="utf-8") as f:
reqs = parse_requires(f.read()) reqs = parse_requires(f.read())
finally: finally:
os.chdir(current_dir) os.chdir(current_dir)
......
...@@ -251,7 +251,10 @@ class Solver: ...@@ -251,7 +251,10 @@ class Solver:
break break
if previous and previous["name"] == dependency.name: if previous and previous["name"] == dependency.name:
break # We have a circular dependency.
# Since the dependencies are resolved we can
# simply skip it because we already have it
continue
for pkg in packages: for pkg in packages:
if pkg.name == dependency.name and dependency.constraint.allows( if pkg.name == dependency.name and dependency.constraint.allows(
......
...@@ -549,7 +549,7 @@ class PyPiRepository(Repository): ...@@ -549,7 +549,7 @@ class PyPiRepository(Repository):
requires = egg_info / "requires.txt" requires = egg_info / "requires.txt"
if requires.exists(): if requires.exists():
with requires.open() as f: with requires.open(encoding="utf-8") as f:
info["requires_dist"] = parse_requires(f.read()) info["requires_dist"] = parse_requires(f.read())
return info return info
...@@ -561,7 +561,7 @@ class PyPiRepository(Repository): ...@@ -561,7 +561,7 @@ class PyPiRepository(Repository):
requires = egg_info / "requires.txt" requires = egg_info / "requires.txt"
if requires.exists(): if requires.exists():
with requires.open() as f: with requires.open(encoding="utf-8") as f:
info["requires_dist"] = parse_requires(f.read()) info["requires_dist"] = parse_requires(f.read())
return info return info
......
import json import json
import os import os
from io import open
from .license import License from .license import License
from .updater import Updater from .updater import Updater
...@@ -26,7 +28,7 @@ def load_licenses(): ...@@ -26,7 +28,7 @@ def load_licenses():
licenses_file = os.path.join(os.path.dirname(__file__), "data", "licenses.json") licenses_file = os.path.join(os.path.dirname(__file__), "data", "licenses.json")
with open(licenses_file) as f: with open(licenses_file, encoding="utf-8") as f:
data = json.loads(f.read()) data = json.loads(f.read())
for name, license in data.items(): for name, license in data.items():
......
import json import json
import os import os
from io import open
try: try:
from urllib.request import urlopen from urllib.request import urlopen
except ImportError: except ImportError:
...@@ -20,7 +22,7 @@ class Updater: ...@@ -20,7 +22,7 @@ class Updater:
licenses_url = self._base_url + "licenses.json" licenses_url = self._base_url + "licenses.json"
with open(file, "w") as f: with open(file, "w", encoding="utf-8") as f:
f.write( f.write(
json.dumps(self.get_licenses(licenses_url), indent=2, sort_keys=True) json.dumps(self.get_licenses(licenses_url), indent=2, sort_keys=True)
) )
......
...@@ -46,6 +46,13 @@ if PY35: ...@@ -46,6 +46,13 @@ if PY35:
else: else:
from pathlib2 import Path from pathlib2 import Path
if PY35:
import subprocess as subprocess
from subprocess import CalledProcessError
else:
import subprocess32 as subprocess
from subprocess32 import CalledProcessError
if not PY36: if not PY36:
from collections import OrderedDict from collections import OrderedDict
......
...@@ -5,7 +5,6 @@ import os ...@@ -5,7 +5,6 @@ import os
import platform import platform
import re import re
import shutil import shutil
import subprocess
import sys import sys
import sysconfig import sysconfig
import warnings import warnings
...@@ -13,7 +12,6 @@ import warnings ...@@ -13,7 +12,6 @@ import warnings
import tomlkit import tomlkit
from contextlib import contextmanager from contextlib import contextmanager
from subprocess import CalledProcessError
from typing import Any from typing import Any
from typing import Dict from typing import Dict
from typing import List from typing import List
...@@ -25,10 +23,12 @@ from clikit.api.io import IO ...@@ -25,10 +23,12 @@ from clikit.api.io import IO
from poetry.config import Config from poetry.config import Config
from poetry.locations import CACHE_DIR from poetry.locations import CACHE_DIR
from poetry.semver.version import Version from poetry.semver.version import Version
from poetry.utils._compat import CalledProcessError
from poetry.utils._compat import Path from poetry.utils._compat import Path
from poetry.utils._compat import decode from poetry.utils._compat import decode
from poetry.utils._compat import encode from poetry.utils._compat import encode
from poetry.utils._compat import list_to_shell_command from poetry.utils._compat import list_to_shell_command
from poetry.utils._compat import subprocess
from poetry.utils.toml_file import TomlFile from poetry.utils.toml_file import TomlFile
from poetry.version.markers import BaseMarker from poetry.version.markers import BaseMarker
...@@ -116,11 +116,14 @@ class EnvError(Exception): ...@@ -116,11 +116,14 @@ class EnvError(Exception):
class EnvCommandError(EnvError): class EnvCommandError(EnvError):
def __init__(self, e): # type: (CalledProcessError) -> None def __init__(self, e, input=None): # type: (CalledProcessError) -> None
message = "Command {} errored with the following output: \n{}".format( self.e = e
e.cmd, decode(e.output)
)
message = "Command {} errored with the following return code {}, and output: \n{}".format(
e.cmd, e.returncode, decode(e.output)
)
if input:
message += "input was : {}".format(input)
super(EnvCommandError, self).__init__(message) super(EnvCommandError, self).__init__(message)
...@@ -266,7 +269,7 @@ class EnvManager(object): ...@@ -266,7 +269,7 @@ class EnvManager(object):
if not in_venv or env is not None: if not in_venv or env is not None:
# Checking if a local virtualenv exists # Checking if a local virtualenv exists
if (cwd / ".venv").exists(): if (cwd / ".venv").exists() and (cwd / ".venv").is_dir():
venv = cwd / ".venv" venv = cwd / ".venv"
return VirtualEnv(venv) return VirtualEnv(venv)
...@@ -682,20 +685,19 @@ class Env(object): ...@@ -682,20 +685,19 @@ class Env(object):
if shell: if shell:
cmd = list_to_shell_command(cmd) cmd = list_to_shell_command(cmd)
try: try:
if self._is_windows: if self._is_windows:
kwargs["shell"] = True kwargs["shell"] = True
if input_: if input_:
p = subprocess.Popen( output = subprocess.run(
cmd, cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
input=encode(input_),
check=True,
**kwargs **kwargs
) ).stdout
output = p.communicate(encode(input_))[0]
elif call: elif call:
return subprocess.call(cmd, stderr=subprocess.STDOUT, **kwargs) return subprocess.call(cmd, stderr=subprocess.STDOUT, **kwargs)
else: else:
...@@ -703,7 +705,7 @@ class Env(object): ...@@ -703,7 +705,7 @@ class Env(object):
cmd, stderr=subprocess.STDOUT, **kwargs cmd, stderr=subprocess.STDOUT, **kwargs
) )
except CalledProcessError as e: except CalledProcessError as e:
raise EnvCommandError(e) raise EnvCommandError(e, input=input_)
return decode(output) return decode(output)
......
...@@ -51,6 +51,8 @@ keyring = [ ...@@ -51,6 +51,8 @@ keyring = [
{ version = "^18.0", python = "~2.7 || ~3.4" }, { version = "^18.0", python = "~2.7 || ~3.4" },
{ version = "^19.0", python = "^3.5" } { version = "^19.0", python = "^3.5" }
] ]
# Use subprocess32 for Python 2.7 and 3.4
subprocess32 = { version = "^3.5", python = "~2.7 || ~3.4" }
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
pytest = "^4.1" pytest = "^4.1"
......
...@@ -172,7 +172,7 @@ def project_directory(): ...@@ -172,7 +172,7 @@ def project_directory():
def poetry(repo, project_directory): def poetry(repo, project_directory):
p = Poetry.create(Path(__file__).parent.parent / "fixtures" / project_directory) p = Poetry.create(Path(__file__).parent.parent / "fixtures" / project_directory)
with p.file.path.open() as f: with p.file.path.open(encoding="utf-8") as f:
content = f.read() content = f.read()
p.pool.remove_repository("pypi") p.pool.remove_repository("pypi")
...@@ -180,7 +180,7 @@ def poetry(repo, project_directory): ...@@ -180,7 +180,7 @@ def poetry(repo, project_directory):
yield p yield p
with p.file.path.open("w") as f: with p.file.path.open("w", encoding="utf-8") as f:
f.write(content) f.write(content)
......
...@@ -120,11 +120,11 @@ My Package ...@@ -120,11 +120,11 @@ My Package
assert (dist_info / "WHEEL").exists() assert (dist_info / "WHEEL").exists()
assert (dist_info / "METADATA").exists() assert (dist_info / "METADATA").exists()
with (dist_info / "entry_points.txt").open() as f: with (dist_info / "entry_points.txt").open(encoding="utf-8") as f:
assert entry_points == decode(f.read()) assert entry_points == decode(f.read())
with (dist_info / "WHEEL").open() as f: with (dist_info / "WHEEL").open(encoding="utf-8") as f:
assert wheel_data == decode(f.read()) assert wheel_data == decode(f.read())
with (dist_info / "METADATA").open() as f: with (dist_info / "METADATA").open(encoding="utf-8") as f:
assert metadata == decode(f.read()) assert metadata == decode(f.read())
...@@ -725,20 +725,27 @@ def test_solver_circular_dependency(solver, repo, package): ...@@ -725,20 +725,27 @@ def test_solver_circular_dependency(solver, repo, package):
package_b = get_package("B", "1.0") package_b = get_package("B", "1.0")
package_b.add_dependency("A", "^1.0") package_b.add_dependency("A", "^1.0")
package_b.add_dependency("C", "^1.0")
package_c = get_package("C", "1.0")
repo.add_package(package_a) repo.add_package(package_a)
repo.add_package(package_b) repo.add_package(package_b)
repo.add_package(package_c)
ops = solver.solve() ops = solver.solve()
check_solver_result( check_solver_result(
ops, ops,
[ [
{"job": "install", "package": package_c},
{"job": "install", "package": package_b}, {"job": "install", "package": package_b},
{"job": "install", "package": package_a}, {"job": "install", "package": package_a},
], ],
) )
assert "main" == ops[0].package.category
def test_solver_duplicate_dependencies_same_constraint(solver, repo, package): def test_solver_duplicate_dependencies_same_constraint(solver, repo, package):
package.add_dependency("A") package.add_dependency("A")
......
...@@ -31,7 +31,7 @@ class MockRepository(LegacyRepository): ...@@ -31,7 +31,7 @@ class MockRepository(LegacyRepository):
if not fixture.exists(): if not fixture.exists():
return return
with fixture.open() as f: with fixture.open(encoding="utf-8") as f:
return Page(self._url + endpoint, f.read(), {}) return Page(self._url + endpoint, f.read(), {})
def _download(self, url, dest): def _download(self, url, dest):
......
...@@ -36,7 +36,7 @@ class MockRepository(PyPiRepository): ...@@ -36,7 +36,7 @@ class MockRepository(PyPiRepository):
if not fixture.exists(): if not fixture.exists():
return return
with fixture.open() as f: with fixture.open(encoding="utf-8") as f:
return json.loads(f.read()) return json.loads(f.read())
def _download(self, url, dest): def _download(self, url, dest):
......
import os import os
import pytest
import shutil import shutil
import sys import sys
import tomlkit import tomlkit
from clikit.io import NullIO from clikit.io import NullIO
from poetry.semver import Version from poetry.semver import Version
from poetry.utils._compat import Path from poetry.utils._compat import Path
from poetry.utils.env import EnvManager from poetry.utils.env import EnvManager
from poetry.utils.env import EnvCommandError
from poetry.utils.env import VirtualEnv from poetry.utils.env import VirtualEnv
from poetry.utils.toml_file import TomlFile from poetry.utils.toml_file import TomlFile
MINIMAL_SCRIPT = """\
print("Minimal Output"),
"""
# Script expected to fail.
ERRORING_SCRIPT = """\
import nullpackage
print("nullpackage loaded"),
"""
def test_virtualenvs_with_spaces_in_their_path_work_as_expected(tmp_dir, config): def test_virtualenvs_with_spaces_in_their_path_work_as_expected(tmp_dir, config):
venv_path = Path(tmp_dir) / "Virtual Env" venv_path = Path(tmp_dir) / "Virtual Env"
...@@ -30,6 +45,7 @@ def test_env_get_in_project_venv(tmp_dir, config): ...@@ -30,6 +45,7 @@ def test_env_get_in_project_venv(tmp_dir, config):
assert venv.path == Path(tmp_dir) / ".venv" assert venv.path == Path(tmp_dir) / ".venv"
shutil.rmtree(str(venv.path))
CWD = Path(__file__).parent.parent / "fixtures" / "simple_project" CWD = Path(__file__).parent.parent / "fixtures" / "simple_project"
...@@ -452,13 +468,19 @@ def test_remove_also_deactivates(tmp_dir, config, mocker): ...@@ -452,13 +468,19 @@ def test_remove_also_deactivates(tmp_dir, config, mocker):
assert venv_name not in envs assert venv_name not in envs
def test_env_has_symlinks_on_nix(tmp_dir, config): @pytest.fixture
venv_path = Path(tmp_dir) def tmp_venv(tmp_dir, config, request):
venv_path = Path(tmp_dir) / "venv"
EnvManager(config).build_venv(str(venv_path)) EnvManager(config).build_venv(str(venv_path))
venv = VirtualEnv(venv_path) venv = VirtualEnv(venv_path)
yield venv
shutil.rmtree(str(venv.path))
def test_env_has_symlinks_on_nix(tmp_dir, tmp_venv):
venv_available = False venv_available = False
try: try:
from venv import EnvBuilder from venv import EnvBuilder
...@@ -468,4 +490,20 @@ def test_env_has_symlinks_on_nix(tmp_dir, config): ...@@ -468,4 +490,20 @@ def test_env_has_symlinks_on_nix(tmp_dir, config):
pass pass
if os.name != "nt" and venv_available: if os.name != "nt" and venv_available:
assert os.path.islink(venv.python) assert os.path.islink(tmp_venv.python)
def test_run_with_input(tmp_dir, tmp_venv):
result = tmp_venv.run("python", "-", input_=MINIMAL_SCRIPT)
assert result == "Minimal Output" + os.linesep
def test_run_with_input_non_zero_return(tmp_dir, tmp_venv):
with pytest.raises(EnvCommandError) as processError:
# Test command that will return non-zero returncode.
result = tmp_venv.run("python", "-", input_=ERRORING_SCRIPT)
assert processError.value.e.returncode == 1
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