diff --git a/pip/commands/install.py b/pip/commands/install.py index 35c5d86ca..5b4489019 100644 --- a/pip/commands/install.py +++ b/pip/commands/install.py @@ -15,6 +15,7 @@ from pip.exceptions import ( InstallationError, CommandError, PreviousBuildDirError, ) from pip import cmdoptions +from pip.utils import ensure_dir from pip.utils.build import BuildDirectory from pip.utils.deprecation import RemovedInPip8Warning @@ -302,8 +303,7 @@ class InstallCommand(RequirementCommand): requirement_set.cleanup_files() if options.target_dir: - if not os.path.exists(options.target_dir): - os.makedirs(options.target_dir) + ensure_dir(options.target_dir) lib_dir = distutils_scheme('', home=temp_target_dir)['purelib'] diff --git a/pip/commands/wheel.py b/pip/commands/wheel.py index a3a580f7a..1e38c6a2f 100644 --- a/pip/commands/wheel.py +++ b/pip/commands/wheel.py @@ -9,7 +9,7 @@ from pip.basecommand import RequirementCommand from pip.index import PackageFinder from pip.exceptions import CommandError, PreviousBuildDirError from pip.req import RequirementSet -from pip.utils import import_or_raise, normalize_path +from pip.utils import import_or_raise, ensure_dir, normalize_path from pip.utils.build import BuildDirectory from pip.utils.deprecation import RemovedInPip8Warning from pip.wheel import WheelBuilder @@ -170,8 +170,7 @@ class WheelCommand(RequirementCommand): # make the wheelhouse options.wheel_dir = normalize_path(options.wheel_dir) - if not os.path.exists(options.wheel_dir): - os.makedirs(options.wheel_dir) + ensure_dir(options.wheel_dir) self.populate_requirement_set( requirement_set, args, options, finder, session, self.name, diff --git a/pip/req/req_install.py b/pip/req/req_install.py index 3c2638a51..7dab72f5c 100644 --- a/pip/req/req_install.py +++ b/pip/req/req_install.py @@ -30,7 +30,7 @@ from pip.locations import ( from pip.utils import ( display_path, rmtree, ask_path_exists, backup_dir, is_installable_dir, dist_in_usersite, dist_in_site_packages, egg_link_path, make_path_relative, - call_subprocess, read_text_file, FakeFile, _make_build_dir, + call_subprocess, read_text_file, FakeFile, _make_build_dir, ensure_dir, ) from pip.utils.deprecation import RemovedInPip8Warning from pip.utils.logging import indent_log @@ -384,8 +384,7 @@ class InstallRequirement(object): egg_base_option = [] else: egg_info_dir = os.path.join(self.source_dir, 'pip-egg-info') - if not os.path.exists(egg_info_dir): - os.makedirs(egg_info_dir) + ensure_dir(egg_info_dir) egg_base_option = ['--egg-base', 'pip-egg-info'] cwd = self.source_dir if self.editable_options and \ diff --git a/pip/utils/__init__.py b/pip/utils/__init__.py index b3e0c81a3..79ab2047f 100644 --- a/pip/utils/__init__.py +++ b/pip/utils/__init__.py @@ -1,6 +1,7 @@ from __future__ import absolute_import import contextlib +import errno import locale import logging import re @@ -38,7 +39,7 @@ __all__ = ['rmtree', 'display_path', 'backup_dir', 'make_path_relative', 'normalize_path', 'renames', 'get_terminal_size', 'get_prog', 'unzip_file', 'untar_file', 'unpack_file', 'call_subprocess', - 'captured_stdout', 'remove_tracebacks', + 'captured_stdout', 'remove_tracebacks', 'ensure_dir', 'ARCHIVE_EXTENSIONS', 'SUPPORTED_EXTENSIONS'] @@ -64,6 +65,15 @@ def import_or_raise(pkg_or_module_string, ExceptionType, *args, **kwargs): raise ExceptionType(*args, **kwargs) +def ensure_dir(path): + """os.path.makedirs without EEXIST.""" + try: + os.makedirs(path) + except OSError as e: + if e.errno != errno.EEXIST: + raise + + def get_prog(): try: if os.path.basename(sys.argv[0]) in ('__main__.py', '-c'): @@ -515,8 +525,7 @@ def unzip_file(filename, location, flatten=True): written. Note that for windows, any execute changes using os.chmod are no-ops per the python docs. """ - if not os.path.exists(location): - os.makedirs(location) + ensure_dir(location) zipfp = open(filename, 'rb') try: zip = zipfile.ZipFile(zipfp, allowZip64=True) @@ -529,13 +538,11 @@ def unzip_file(filename, location, flatten=True): fn = split_leading_dir(name)[1] fn = os.path.join(location, fn) dir = os.path.dirname(fn) - if not os.path.exists(dir): - os.makedirs(dir) if fn.endswith('/') or fn.endswith('\\'): # A directory - if not os.path.exists(fn): - os.makedirs(fn) + ensure_dir(fn) else: + ensure_dir(dir) fp = open(fn, 'wb') try: fp.write(data) @@ -561,8 +568,7 @@ def untar_file(filename, location): written. Note that for windows, any execute changes using os.chmod are no-ops per the python docs. """ - if not os.path.exists(location): - os.makedirs(location) + ensure_dir(location) if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'): mode = 'r:gz' elif filename.lower().endswith(BZ2_EXTENSIONS): @@ -589,8 +595,7 @@ def untar_file(filename, location): fn = split_leading_dir(fn)[1] path = os.path.join(location, fn) if member.isdir(): - if not os.path.exists(path): - os.makedirs(path) + ensure_dir(path) elif member.issym(): try: tar._extract_member(member, path) @@ -613,8 +618,7 @@ def untar_file(filename, location): filename, member.name, exc, ) continue - if not os.path.exists(os.path.dirname(path)): - os.makedirs(os.path.dirname(path)) + ensure_dir(os.path.dirname(path)) destfp = open(path, 'wb') try: shutil.copyfileobj(fp, destfp) diff --git a/pip/utils/logging.py b/pip/utils/logging.py index f5c1521a8..1025fbac8 100644 --- a/pip/utils/logging.py +++ b/pip/utils/logging.py @@ -11,6 +11,7 @@ except ImportError: import dummy_threading as threading from pip.compat import WINDOWS +from pip.utils import ensure_dir try: from pip._vendor import colorama @@ -114,10 +115,7 @@ class ColorizedStreamHandler(logging.StreamHandler): class BetterRotatingFileHandler(logging.handlers.RotatingFileHandler): def _open(self): - # Ensure the directory exists - if not os.path.exists(os.path.dirname(self.baseFilename)): - os.makedirs(os.path.dirname(self.baseFilename)) - + ensure_dir(os.path.dirname(self.baseFilename)) return logging.handlers.RotatingFileHandler._open(self) diff --git a/pip/utils/outdated.py b/pip/utils/outdated.py index f995cf718..6eb46054f 100644 --- a/pip/utils/outdated.py +++ b/pip/utils/outdated.py @@ -1,7 +1,6 @@ from __future__ import absolute_import import datetime -import errno import json import logging import os.path @@ -13,6 +12,7 @@ from pip._vendor import pkg_resources from pip.compat import total_seconds from pip.index import PyPI from pip.locations import USER_CACHE_DIR, running_under_virtualenv +from pip.utils import ensure_dir from pip.utils.filesystem import check_path_owner @@ -65,11 +65,7 @@ class GlobalSelfCheckState(object): # Now that we've ensured the directory is owned by this user, we'll go # ahead and make sure that all our directories are created. - try: - os.makedirs(os.path.dirname(self.statefile_path)) - except OSError as exc: - if exc.errno != errno.EEXIST: - raise + ensure_dir(os.path.dirname(self.statefile_path)) # Attempt to write out our version check file with lockfile.LockFile(self.statefile_path): diff --git a/pip/wheel.py b/pip/wheel.py index 57246cae7..0148b0318 100644 --- a/pip/wheel.py +++ b/pip/wheel.py @@ -23,8 +23,10 @@ from pip._vendor.six import StringIO from pip.exceptions import InvalidWheelFilename, UnsupportedWheel from pip.locations import distutils_scheme from pip import pep425tags -from pip.utils import (call_subprocess, normalize_path, make_path_relative, - captured_stdout) +from pip.utils import ( + call_subprocess, ensure_dir, normalize_path, make_path_relative, + captured_stdout, +) from pip.utils.logging import indent_log from pip._vendor.distlib.scripts import ScriptMaker from pip._vendor import pkg_resources @@ -175,8 +177,7 @@ def move_wheel_files(name, req, wheeldir, user=False, home=None, root=None, changed.add(destfile) def clobber(source, dest, is_base, fixer=None, filter=None): - if not os.path.exists(dest): # common for the 'include' path - os.makedirs(dest) + ensure_dir(dest) # common for the 'include' path for dir, subdirs, files in os.walk(source): basedir = dir[len(source):].lstrip(os.path.sep) @@ -204,8 +205,7 @@ def move_wheel_files(name, req, wheeldir, user=False, home=None, root=None, # directory creation is lazy and after the file filtering above # to ensure we don't install empty dirs; empty dirs can't be # uninstalled. - if not os.path.exists(destdir): - os.makedirs(destdir) + ensure_dir(destdir) # We use copyfile (not move, copy, or copy2) to be extra sure # that we are not moving directories over (copyfile fails for