From 492b78b068d6738f6fb01f4e90c932fb97544b9f Mon Sep 17 00:00:00 2001 From: Mike Kaplinskiy Date: Tue, 12 Jan 2016 17:47:59 -0800 Subject: [PATCH 1/5] Change Link to work properly under Windows This also fixes handling of weird characters in the filename (e.g. test#binary.pex is no longer a url fragment). --- pex/compatibility.py | 13 +++++++++++++ pex/crawler.py | 6 +++--- pex/http.py | 2 +- pex/link.py | 21 +++++++++++++++------ pex/resolver.py | 6 +++--- pex/translator.py | 4 ++-- tests/test_link.py | 12 +++++++++++- 7 files changed, 48 insertions(+), 16 deletions(-) diff --git a/pex/compatibility.py b/pex/compatibility.py index 1a86d5f8b..97139e135 100644 --- a/pex/compatibility.py +++ b/pex/compatibility.py @@ -4,6 +4,7 @@ # This file contains several 2.x/3.x compatibility checkstyle violations for a reason # checkstyle: noqa +import os from abc import ABCMeta from numbers import Integral, Real from sys import version_info as sys_version_info @@ -81,15 +82,27 @@ def nested(*context_managers): from contextlib import nested +if PY3: + from urllib.request import pathname2url, url2pathname +else: + from urllib import pathname2url, url2pathname + + +WINDOWS = os.name == 'nt' + + __all__ = ( 'AbstractClass', 'BytesIO', 'PY2', 'PY3', 'StringIO', + 'WINDOWS', 'bytes', 'exec_function', 'nested', + 'pathname2url', 'string', 'to_bytes', + 'url2pathname', ) diff --git a/pex/crawler.py b/pex/crawler.py index 00b70fb73..ee89d7fee 100644 --- a/pex/crawler.py +++ b/pex/crawler.py @@ -85,11 +85,11 @@ def reset_cache(cls): @classmethod def crawl_local(cls, link): try: - dirents = os.listdir(link.path) + dirents = os.listdir(link.local_path) except OSError as e: - TRACER.log('Failed to read %s: %s' % (link.path, e), V=1) + TRACER.log('Failed to read %s: %s' % (link.local_path, e), V=1) return set(), set() - files, dirs = partition([os.path.join(link.path, fn) for fn in dirents], os.path.isdir) + files, dirs = partition([os.path.join(link.local_path, fn) for fn in dirents], os.path.isdir) return set(map(Link.from_filename, files)), set(map(Link.from_filename, dirs)) @classmethod diff --git a/pex/http.py b/pex/http.py index 116661553..5b91a5c7b 100644 --- a/pex/http.py +++ b/pex/http.py @@ -212,7 +212,7 @@ def __init__(self, session=None, verify=True, env=ENV): def open(self, link): # requests does not support file:// -- so we must short-circuit manually if link.local: - return open(link.path, 'rb') # noqa: T802 + return open(link.local_path, 'rb') # noqa: T802 for attempt in range(self._max_retries + 1): try: return StreamFilelike(self._session.get( diff --git a/pex/link.py b/pex/link.py index 2146a7f8b..c8f8664f2 100644 --- a/pex/link.py +++ b/pex/link.py @@ -8,7 +8,7 @@ from collections import Iterable from .compatibility import string as compatible_string -from .compatibility import PY3 +from .compatibility import PY3, WINDOWS, pathname2url, url2pathname from .util import Memoizer if PY3: @@ -52,7 +52,8 @@ def wrap_iterable(cls, url_or_urls): @classmethod def _normalize(cls, filename): - return 'file://' + os.path.realpath(os.path.expanduser(filename)) + return urlparse.urljoin('file:', pathname2url( + os.path.realpath(os.path.expanduser(filename)))) # A cache for the result of from_filename _FROM_FILENAME_CACHE = Memoizer() @@ -72,8 +73,10 @@ def __init__(self, url): :param url: A string-like object representing a url. """ purl = urlparse.urlparse(url) - if purl.scheme == '': + if purl.scheme == '' or ( + WINDOWS and len(purl.scheme) == 1): # This is likely a drive letter. purl = urlparse.urlparse(self._normalize(url)) + self._url = purl def __ne__(self, other): @@ -95,12 +98,18 @@ def join(self, href): @property def filename(self): """The basename of this url.""" - return posixpath.basename(self._url.path) + return urlparse.unquote(posixpath.basename(self._url.path)) @property def path(self): """The full path of this url with any hostname and scheme components removed.""" - return self._url.path + return urlparse.unquote(self._url.path) + + @property + def local_path(self): + """Returns the local filesystem path (only works for file:// urls).""" + assert self.local, 'local_path called on a non-file:// url %s' % (self.url,) + return url2pathname(self.path) @property def url(self): @@ -110,7 +119,7 @@ def url(self): @property def fragment(self): """The url fragment following '#' if any.""" - return self._url.fragment + return urlparse.unquote(self._url.fragment) @property def scheme(self): diff --git a/pex/resolver.py b/pex/resolver.py index b65fcc1ca..e7669c42b 100644 --- a/pex/resolver.py +++ b/pex/resolver.py @@ -162,7 +162,7 @@ def build(self, package, options): local_package = Package.from_href(context.fetch(package)) if local_package is None: raise Untranslateable('Could not fetch package %s' % package) - with TRACER.timed('Translating %s into distribution' % local_package.path, V=2): + with TRACER.timed('Translating %s into distribution' % local_package.local_path, V=2): dist = translator.translate(local_package) if dist is None: raise Untranslateable('Package %s is not translateable by %s' % (package, translator)) @@ -221,7 +221,7 @@ class CachingResolver(Resolver): def filter_packages_by_ttl(cls, packages, ttl, now=None): now = now if now is not None else time.time() return [package for package in packages - if package.remote or package.local and (now - os.path.getmtime(package.path)) < ttl] + if package.remote or package.local and (now - os.path.getmtime(package.local_path)) < ttl] def __init__(self, cache, cache_ttl, *args, **kw): self.__cache = cache @@ -251,7 +251,7 @@ def build(self, package, options): # cache package locally if package.remote: package = Package.from_href(options.get_context().fetch(package, into=self.__cache)) - os.utime(package.path, None) + os.utime(package.local_path, None) # build into distribution dist = super(CachingResolver, self).build(package, options) diff --git a/pex/translator.py b/pex/translator.py index 880034346..67bb84b29 100644 --- a/pex/translator.py +++ b/pex/translator.py @@ -88,7 +88,7 @@ def translate(self, package, into=None): installer = None version = self._interpreter.version - unpack_path = Archiver.unpack(package.path) + unpack_path = Archiver.unpack(package.local_path) into = into or safe_mkdtemp() try: @@ -147,7 +147,7 @@ def translate(self, package, into=None): return None into = into or safe_mkdtemp() target_path = os.path.join(into, package.filename) - safe_copy(package.path, target_path) + safe_copy(package.local_path, target_path) return DistributionHelper.distribution_from_path(target_path) diff --git a/tests/test_link.py b/tests/test_link.py index 586dada0a..e3bd981f4 100644 --- a/tests/test_link.py +++ b/tests/test_link.py @@ -51,7 +51,17 @@ def test_link_schemes(): link = Link('/foo/bar') assert link.scheme == 'file' assert link.local - assert link.path == os.path.realpath('/foo/bar') + assert link.local_path == os.path.realpath('/foo/bar') + + +def test_link_escaping(): + link = Link('/foo/bar#baz.pex') + assert link.scheme == 'file' + assert link.local + assert link.local_path == os.path.realpath('/foo/bar#baz.pex') + + link = Link('http://www.google.com/%20/%3Afile+%2B2.tar.gz') + assert link.filename == ':file++2.tar.gz' def test_link_equality(): From 329ac6c1b6d540d10ecbd04211869d3413fc3d25 Mon Sep 17 00:00:00 2001 From: Mike Kaplinskiy Date: Tue, 12 Jan 2016 17:49:25 -0800 Subject: [PATCH 2/5] Make code hashes consistent on windows between directories & zips. Resolve the path before relativizing it & always use / as the path separator in the hash. --- pex/util.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pex/util.py b/pex/util.py index d5e3c494b..00e4f6342 100644 --- a/pex/util.py +++ b/pex/util.py @@ -119,7 +119,9 @@ def hash(cls, path, digest=None, hasher=sha1): @classmethod def _compute_hash(cls, names, stream_factory): digest = sha1() - digest.update(''.join(names).encode('utf-8')) + # Always use / as the path separator, since that's what zip uses. + hashed_names = [n.replace(os.sep, '/') for n in names] + digest.update(''.join(hashed_names).encode('utf-8')) for name in names: with contextlib.closing(stream_factory(name)) as fp: cls.update_hash(fp, digest) @@ -137,7 +139,7 @@ def stream_factory(name): @classmethod def _iter_files(cls, directory): - normpath = os.path.normpath(directory) + normpath = os.path.realpath(os.path.normpath(directory)) for root, _, files in os.walk(normpath): for f in files: yield os.path.relpath(os.path.join(root, f), normpath) From 1fe5a4ec5d0e201935e4a195729c1f75ae9ef9a9 Mon Sep 17 00:00:00 2001 From: Mike Kaplinskiy Date: Tue, 12 Jan 2016 17:50:23 -0800 Subject: [PATCH 3/5] Fix egg resolution on windows. The egg metadata code would incorrectly try to munge a windows path as a posix one. Instead treat the zip_pre[fix] as OS-dependent and normalize only the suffix. --- pex/finders.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pex/finders.py b/pex/finders.py index eb3be61f5..19074a644 100644 --- a/pex/finders.py +++ b/pex/finders.py @@ -126,7 +126,7 @@ class FixedEggMetadata(pkg_resources.EggMetadata): @classmethod def normalized_elements(cls, path): path_split = path.split('/') - while path_split[-1] in ('', '.'): + while path_split and path_split[-1] in ('', '.'): path_split.pop(-1) return path_split @@ -136,10 +136,9 @@ def _fn(self, base, resource_name): return '/'.join(self.normalized_elements(original_fn)) def _zipinfo_name(self, fspath): - fspath = self.normalized_elements(fspath) - zip_pre = self.normalized_elements(self.zip_pre) - if fspath[:len(zip_pre)] == zip_pre: - return '/'.join(fspath[len(zip_pre):]) + # Make sure to not normalize the zip_pre - that's an OS-native path. + if fspath.startswith(self.zip_pre): + return '/'.join(self.normalized_elements(fspath[len(self.zip_pre):])) assert "%s is not a subpath of %s" % (fspath, self.zip_pre) From edd0b3e0f3d5c04d5251bb26ca74dfcda70bca13 Mon Sep 17 00:00:00 2001 From: Mike Kaplinskiy Date: Tue, 12 Jan 2016 17:52:25 -0800 Subject: [PATCH 4/5] Don't use gztar sdists on windows. tar isn't as readily available; zip works fine. --- pex/installer.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pex/installer.py b/pex/installer.py index acb0bf0c6..e2e955a96 100644 --- a/pex/installer.py +++ b/pex/installer.py @@ -11,6 +11,7 @@ from pkg_resources import Distribution, PathMetadata from .common import safe_mkdtemp, safe_rmtree +from .compatibility import WINDOWS from .interpreter import PythonInterpreter from .tracer import TRACER from .version import SETUPTOOLS_REQUIREMENT, WHEEL_REQUIREMENT @@ -209,7 +210,10 @@ class Packager(DistributionPackager): """ def _setup_command(self): - return ['sdist', '--formats=gztar', '--dist-dir=%s' % self._install_tmp] + if WINDOWS: + return ['sdist', '--formats=zip', '--dist-dir=%s' % self._install_tmp] + else: + return ['sdist', '--formats=gztar', '--dist-dir=%s' % self._install_tmp] @after_installation def sdist(self): From f03ce12a4fc87156c5dfd7928a3bab2d12e81435 Mon Sep 17 00:00:00 2001 From: Mike Kaplinskiy Date: Tue, 12 Jan 2016 17:53:12 -0800 Subject: [PATCH 5/5] Make the tests pass on windows. The main points of note are: - Use temporary_filename() to get a filename without any open handles (Windows will not let you unlink a file that has open handles). - Get rid of NamedTemporaryFile/temporary_file in lieu of using our helper in util. - Pexs aren't executable on windows directly - run them as `python ...` - Skip soft/hard link tests on windows - Small fixes w.r.t. / vs \ and s/\r//g --- pex/testing.py | 20 +++++++++++++++++--- tests/test_environment.py | 37 +++++++++++++++++++------------------ tests/test_http.py | 6 +++--- tests/test_integration.py | 8 ++++++-- tests/test_pex.py | 3 ++- tests/test_pex_builder.py | 4 +++- tests/test_pex_info.py | 7 +++++-- tests/test_util.py | 22 ++++++++-------------- tests/test_variables.py | 9 ++++----- 9 files changed, 67 insertions(+), 49 deletions(-) diff --git a/pex/testing.py b/pex/testing.py index cded62c0a..2726486f7 100644 --- a/pex/testing.py +++ b/pex/testing.py @@ -5,6 +5,7 @@ import os import random import subprocess +import sys import tempfile import zipfile from textwrap import dedent @@ -13,7 +14,7 @@ from .compatibility import nested from .installer import EggInstaller, Packager from .pex_builder import PEXBuilder -from .util import DistributionHelper +from .util import DistributionHelper, named_temporary_file @contextlib.contextmanager @@ -25,6 +26,19 @@ def temporary_dir(): safe_rmtree(td) +@contextlib.contextmanager +def temporary_filename(): + """Creates a temporary filename. + + This is useful when you need to pass a filename to an API. Windows requires all + handles to a file be closed before deleting/renaming it, so this makes it a bit + simpler.""" + with named_temporary_file() as fp: + fp.write(b'') + fp.close() + yield fp.name + + def random_bytes(length): return ''.join( map(chr, (random.randint(ord('a'), ord('z')) for _ in range(length)))).encode('utf-8') @@ -162,12 +176,12 @@ def write_simple_pex(td, exe_contents, dists=None, coverage=False): # TODO(wickman) Why not PEX.run? def run_simple_pex(pex, args=(), env=None): po = subprocess.Popen( - [pex] + list(args), + [sys.executable, pex] + list(args), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env) po.wait() - return po.stdout.read(), po.returncode + return po.stdout.read().replace(b'\r', b''), po.returncode def run_simple_pex_test(body, args=(), env=None, dists=None, coverage=False): diff --git a/tests/test_environment.py b/tests/test_environment.py index 0c3baaaca..adf06e4b1 100644 --- a/tests/test_environment.py +++ b/tests/test_environment.py @@ -4,13 +4,13 @@ import os from contextlib import contextmanager -from twitter.common.contextutil import temporary_dir, temporary_file +from twitter.common.contextutil import temporary_dir from pex.compatibility import nested from pex.environment import PEXEnvironment from pex.pex_builder import PEXBuilder from pex.pex_info import PexInfo -from pex.testing import make_bdist +from pex.testing import make_bdist, temporary_filename @contextmanager @@ -22,64 +22,65 @@ def yield_pex_builder(zip_safe=True): def test_force_local(): - with nested(yield_pex_builder(), temporary_dir(), temporary_file()) as (pb, pex_root, pex_file): + with nested(yield_pex_builder(), temporary_dir(), temporary_filename()) as ( + pb, pex_root, pex_file): pb.info.pex_root = pex_root - pb.build(pex_file.name) + pb.build(pex_file) - code_cache = PEXEnvironment.force_local(pex_file.name, pb.info) + code_cache = PEXEnvironment.force_local(pex_file, pb.info) assert os.path.exists(pb.info.zip_unsafe_cache) assert len(os.listdir(pb.info.zip_unsafe_cache)) == 1 assert [os.path.basename(code_cache)] == os.listdir(pb.info.zip_unsafe_cache) assert set(os.listdir(code_cache)) == set([PexInfo.PATH, '__main__.py', '__main__.pyc']) # idempotence - assert PEXEnvironment.force_local(pex_file.name, pb.info) == code_cache + assert PEXEnvironment.force_local(pex_file, pb.info) == code_cache def normalize(path): - return os.path.normpath(os.path.realpath(path)) + return os.path.normpath(os.path.realpath(path)).lower() def test_write_zipped_internal_cache(): # zip_safe pex will not be written to install cache unless always_write_cache - with nested(yield_pex_builder(zip_safe=True), temporary_dir(), temporary_file()) as ( + with nested(yield_pex_builder(zip_safe=True), temporary_dir(), temporary_filename()) as ( pb, pex_root, pex_file): pb.info.pex_root = pex_root - pb.build(pex_file.name) + pb.build(pex_file) - existing, new, zip_safe = PEXEnvironment.write_zipped_internal_cache(pex_file.name, pb.info) + existing, new, zip_safe = PEXEnvironment.write_zipped_internal_cache(pex_file, pb.info) assert len(zip_safe) == 1 assert normalize(zip_safe[0].location).startswith( - normalize(os.path.join(pex_file.name, pb.info.internal_cache))), ( + normalize(os.path.join(pex_file, pb.info.internal_cache))), ( 'loc: %s, cache: %s' % ( normalize(zip_safe[0].location), - normalize(os.path.join(pex_file.name, pb.info.internal_cache)))) + normalize(os.path.join(pex_file, pb.info.internal_cache)))) pb.info.always_write_cache = True - existing, new, zip_safe = PEXEnvironment.write_zipped_internal_cache(pex_file.name, pb.info) + existing, new, zip_safe = PEXEnvironment.write_zipped_internal_cache(pex_file, pb.info) assert len(new) == 1 assert normalize(new[0].location).startswith(normalize(pb.info.install_cache)) # Check that we can read from the cache - existing, new, zip_safe = PEXEnvironment.write_zipped_internal_cache(pex_file.name, pb.info) + existing, new, zip_safe = PEXEnvironment.write_zipped_internal_cache(pex_file, pb.info) assert len(existing) == 1 assert normalize(existing[0].location).startswith(normalize(pb.info.install_cache)) # non-zip_safe pex will be written to install cache - with nested(yield_pex_builder(zip_safe=False), temporary_dir(), temporary_file()) as ( + with nested(yield_pex_builder(zip_safe=False), temporary_dir(), temporary_filename()) as ( pb, pex_root, pex_file): pb.info.pex_root = pex_root - pb.build(pex_file.name) + pb.build(pex_file) - existing, new, zip_safe = PEXEnvironment.write_zipped_internal_cache(pex_file.name, pb.info) + existing, new, zip_safe = PEXEnvironment.write_zipped_internal_cache(pex_file, pb.info) assert len(new) == 1 assert normalize(new[0].location).startswith(normalize(pb.info.install_cache)) original_location = normalize(new[0].location) # do the second time to validate idempotence of caching - existing, new, zip_safe = PEXEnvironment.write_zipped_internal_cache(pex_file.name, pb.info) + existing, new, zip_safe = PEXEnvironment.write_zipped_internal_cache(pex_file, pb.info) assert len(existing) == 1 assert normalize(existing[0].location) == original_location diff --git a/tests/test_http.py b/tests/test_http.py index e5ab82b0d..b07f207eb 100644 --- a/tests/test_http.py +++ b/tests/test_http.py @@ -6,11 +6,11 @@ from io import BytesIO import pytest -from twitter.common.contextutil import temporary_file from pex.compatibility import PY2 from pex.http import Context, RequestsContext, StreamFilelike, UrllibContext from pex.link import Link +from pex.util import named_temporary_file from pex.variables import Variables try: @@ -107,7 +107,7 @@ def test_requests_context(): assert fp.read() == BLOB # test local reading - with temporary_file() as tf: + with named_temporary_file() as tf: tf.write(b'goop') tf.flush() assert context.read(Link.wrap(tf.name)) == b'goop' @@ -225,7 +225,7 @@ def test_requests_context_retries_read_timeout_retries_exhausted(): def test_urllib_context_utf8_encoding(): BYTES = b'this is a decoded utf8 string' - with temporary_file() as tf: + with named_temporary_file() as tf: tf.write(BYTES) tf.flush() local_link = Link.wrap(tf.name) diff --git a/tests/test_integration.py b/tests/test_integration.py index f53b8f5bc..81386a7bf 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -4,9 +4,12 @@ import os import sys -from twitter.common.contextutil import environment_as, temporary_dir, temporary_file +import pytest +from twitter.common.contextutil import environment_as, temporary_dir +from pex.compatibility import WINDOWS from pex.testing import run_simple_pex_test +from pex.util import named_temporary_file def test_pex_execute(): @@ -21,7 +24,7 @@ def test_pex_raise(): def test_pex_interpreter(): - with temporary_file() as fp: + with named_temporary_file() as fp: fp.write(b"print('Hello world')") fp.flush() @@ -33,6 +36,7 @@ def test_pex_interpreter(): assert rc == 0 +@pytest.mark.skipif(WINDOWS, reason='No symlinks on windows') def test_pex_python_symlink(): with temporary_dir() as td: with environment_as(HOME=td): diff --git a/tests/test_pex.py b/tests/test_pex.py index 7fbe589a1..c923b49de 100644 --- a/tests/test_pex.py +++ b/tests/test_pex.py @@ -9,7 +9,7 @@ import pytest from twitter.common.contextutil import temporary_dir -from pex.compatibility import nested, to_bytes +from pex.compatibility import WINDOWS, nested, to_bytes from pex.installer import EggInstaller, WheelInstaller from pex.pex import PEX from pex.testing import make_installer, run_simple_pex_test @@ -137,6 +137,7 @@ def test_site_libs(): assert site_packages in site_libs +@pytest.mark.skipif(WINDOWS, reason='No symlinks on windows') def test_site_libs_symlink(): with nested(mock.patch.object(PEX, '_get_site_packages'), temporary_dir()) as ( mock_site_packages, tempdir): diff --git a/tests/test_pex_builder.py b/tests/test_pex_builder.py index 5f2da3ffa..91553dd24 100644 --- a/tests/test_pex_builder.py +++ b/tests/test_pex_builder.py @@ -6,10 +6,11 @@ import zipfile from contextlib import closing +import pytest from twitter.common.contextutil import temporary_dir from twitter.common.dirutil import safe_mkdir -from pex.compatibility import nested +from pex.compatibility import WINDOWS, nested from pex.pex import PEX from pex.pex_builder import PEXBuilder from pex.testing import write_simple_pex as write_pex @@ -102,6 +103,7 @@ def build_and_check(path, precompile): build_and_check(td3, True) +@pytest.mark.skipif(WINDOWS, reason='No hardlinks on windows') def test_pex_builder_copy_or_link(): with nested(temporary_dir(), temporary_dir(), temporary_dir()) as (td1, td2, td3): src = os.path.join(td1, 'exe.py') diff --git a/tests/test_pex_info.py b/tests/test_pex_info.py index 032b221da..0e6a01a7f 100644 --- a/tests/test_pex_info.py +++ b/tests/test_pex_info.py @@ -1,6 +1,8 @@ # Copyright 2015 Pants project contributors (see CONTRIBUTORS.md). # Licensed under the Apache License, Version 2.0 (see LICENSE). +import os.path + import pytest from pex.orderedset import OrderedSet @@ -46,7 +48,8 @@ def test_from_empty_env(): def test_from_env(): - environ = dict(PEX_ROOT='/pex_root', + pex_root = os.path.realpath('/pex_root') + environ = dict(PEX_ROOT=pex_root, PEX_MODULE='entry:point', PEX_SCRIPT='script.sh', PEX_FORCE_LOCAL='true', @@ -54,7 +57,7 @@ def test_from_env(): PEX_IGNORE_ERRORS='true', PEX_ALWAYS_CACHE='true') - info = dict(pex_root='/pex_root', + info = dict(pex_root=pex_root, entry_point='entry:point', script='script.sh', zip_safe=False, diff --git a/tests/test_util.py b/tests/test_util.py index a03d4a02c..9ffc5e979 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -4,18 +4,17 @@ import contextlib import functools import os -import subprocess import zipfile from hashlib import sha1 from textwrap import dedent -from twitter.common.contextutil import temporary_dir, temporary_file +from twitter.common.contextutil import temporary_dir from pex.common import safe_mkdir from pex.compatibility import nested from pex.installer import EggInstaller, WheelInstaller from pex.pex_builder import PEXBuilder -from pex.testing import make_bdist, temporary_content, write_zipfile +from pex.testing import make_bdist, run_simple_pex, temporary_content, write_zipfile from pex.util import CacheHelper, DistributionHelper, named_temporary_file try: @@ -27,17 +26,17 @@ def test_hash(): empty_hash = sha1().hexdigest() - with temporary_file() as fp: + with named_temporary_file() as fp: fp.flush() assert empty_hash == CacheHelper.hash(fp.name) - with temporary_file() as fp: + with named_temporary_file() as fp: string = b'asdf' * 1024 * sha1().block_size + b'extra padding' fp.write(string) fp.flush() assert sha1(string).hexdigest() == CacheHelper.hash(fp.name) - with temporary_file() as fp: + with named_temporary_file() as fp: empty_hash = sha1() fp.write(b'asdf') fp.flush() @@ -59,7 +58,7 @@ def test_hash_consistency(): for reverse in (False, True): with temporary_content(CONTENT) as td: dir_hash = CacheHelper.dir_hash(td) - with temporary_file() as tf: + with named_temporary_file() as tf: write_zipfile(td, tf.name, reverse=reverse) with contextlib.closing(zipfile.ZipFile(tf.name, 'r')) as zf: zip_hash = CacheHelper.zip_hash(zf) @@ -147,18 +146,13 @@ def test_access_zipped_assets_integration(): pex = os.path.join(td2, 'app.pex') pb.build(pex) - po = subprocess.Popen( - [pex], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - po.wait() - output = po.stdout.read() + output, returncode = run_simple_pex(pex) try: output = output.decode('UTF-8') except ValueError: pass assert output == 'accessed\n' - assert po.returncode == 0 + assert returncode == 0 def test_named_temporary_file(): diff --git a/tests/test_variables.py b/tests/test_variables.py index 447efb5dd..3a33fbede 100644 --- a/tests/test_variables.py +++ b/tests/test_variables.py @@ -1,10 +1,9 @@ # Copyright 2015 Pants project contributors (see CONTRIBUTORS.md). # Licensed under the Apache License, Version 2.0 (see LICENSE). -import tempfile - import pytest +from pex.util import named_temporary_file from pex.variables import Variables @@ -85,7 +84,7 @@ def test_pex_get_kv(): def test_pex_from_rc(): - with tempfile.NamedTemporaryFile(mode='w') as pexrc: + with named_temporary_file(mode='w') as pexrc: pexrc.write('HELLO=42') pexrc.flush() v = Variables(rc=pexrc.name) @@ -93,7 +92,7 @@ def test_pex_from_rc(): def test_pexrc_precedence(): - with tempfile.NamedTemporaryFile(mode='w') as pexrc: + with named_temporary_file(mode='w') as pexrc: pexrc.write('HELLO=FORTYTWO') pexrc.flush() v = Variables(environ={'HELLO': 42}, rc=pexrc.name) @@ -101,7 +100,7 @@ def test_pexrc_precedence(): def test_rc_ignore(): - with tempfile.NamedTemporaryFile(mode='w') as pexrc: + with named_temporary_file(mode='w') as pexrc: pexrc.write('HELLO=FORTYTWO') pexrc.flush() v = Variables(environ={'PEX_IGNORE_RCFILES': 'True'}, rc=pexrc.name)