diff --git a/django/contrib/staticfiles/management/commands/collectstatic.py b/django/contrib/staticfiles/management/commands/collectstatic.py index 7f5bbbf39b..cccaf1b9c2 100644 --- a/django/contrib/staticfiles/management/commands/collectstatic.py +++ b/django/contrib/staticfiles/management/commands/collectstatic.py @@ -310,10 +310,7 @@ class Command(BaseCommand): else: self.log("Linking '%s'" % source_path, level=2) full_path = self.storage.path(prefixed_path) - try: - os.makedirs(os.path.dirname(full_path)) - except OSError: - pass + os.makedirs(os.path.dirname(full_path), exist_ok=True) try: if os.path.lexists(full_path): os.unlink(full_path) diff --git a/django/core/cache/backends/filebased.py b/django/core/cache/backends/filebased.py index ca8b006577..f507011050 100644 --- a/django/core/cache/backends/filebased.py +++ b/django/core/cache/backends/filebased.py @@ -113,11 +113,7 @@ class FileBasedCache(BaseCache): self._delete(fname) def _createdir(self): - if not os.path.exists(self._dir): - try: - os.makedirs(self._dir, 0o700) - except FileExistsError: - pass + os.makedirs(self._dir, 0o700, exist_ok=True) def _key_to_file(self, key, version=None): """ diff --git a/django/core/files/storage.py b/django/core/files/storage.py index db0d311209..cbdab1de47 100644 --- a/django/core/files/storage.py +++ b/django/core/files/storage.py @@ -228,24 +228,18 @@ class FileSystemStorage(Storage): # Create any intermediate directories that do not exist. directory = os.path.dirname(full_path) - if not os.path.exists(directory): - try: - if self.directory_permissions_mode is not None: - # os.makedirs applies the global umask, so we reset it, - # for consistency with file_permissions_mode behavior. - old_umask = os.umask(0) - try: - os.makedirs(directory, self.directory_permissions_mode) - finally: - os.umask(old_umask) - else: - os.makedirs(directory) - except FileExistsError: - # There's a race between os.path.exists() and os.makedirs(). - # If os.makedirs() fails with FileExistsError, the directory - # was created concurrently. - pass - if not os.path.isdir(directory): + try: + if self.directory_permissions_mode is not None: + # os.makedirs applies the global umask, so we reset it, + # for consistency with file_permissions_mode behavior. + old_umask = os.umask(0) + try: + os.makedirs(directory, self.directory_permissions_mode, exist_ok=True) + finally: + os.umask(old_umask) + else: + os.makedirs(directory, exist_ok=True) + except FileExistsError: raise FileExistsError('%s exists and is not a directory.' % directory) # There's a potential race condition between get_available_name and diff --git a/django/core/mail/backends/filebased.py b/django/core/mail/backends/filebased.py index ddcd9ed97b..b30bb67e92 100644 --- a/django/core/mail/backends/filebased.py +++ b/django/core/mail/backends/filebased.py @@ -21,19 +21,16 @@ class EmailBackend(ConsoleEmailBackend): if not isinstance(self.file_path, str): raise ImproperlyConfigured('Path for saving emails is invalid: %r' % self.file_path) self.file_path = os.path.abspath(self.file_path) - # Make sure that self.file_path is a directory if it exists. - if os.path.exists(self.file_path) and not os.path.isdir(self.file_path): + try: + os.makedirs(self.file_path, exist_ok=True) + except FileExistsError: raise ImproperlyConfigured( 'Path for saving email messages exists, but is not a directory: %s' % self.file_path ) - # Try to create it, if it not exists. - elif not os.path.exists(self.file_path): - try: - os.makedirs(self.file_path) - except OSError as err: - raise ImproperlyConfigured( - 'Could not create directory for saving email messages: %s (%s)' % (self.file_path, err) - ) + except OSError as err: + raise ImproperlyConfigured( + 'Could not create directory for saving email messages: %s (%s)' % (self.file_path, err) + ) # Make sure that self.file_path is writable. if not os.access(self.file_path, os.W_OK): raise ImproperlyConfigured('Could not write to directory: %s' % self.file_path) diff --git a/django/core/management/commands/makemessages.py b/django/core/management/commands/makemessages.py index 6fc2028688..6c1e8248ce 100644 --- a/django/core/management/commands/makemessages.py +++ b/django/core/management/commands/makemessages.py @@ -356,8 +356,7 @@ class Command(BaseCommand): self.locale_paths.append(os.path.abspath('locale')) if self.locale_paths: self.default_locale_path = self.locale_paths[0] - if not os.path.exists(self.default_locale_path): - os.makedirs(self.default_locale_path) + os.makedirs(self.default_locale_path, exist_ok=True) # Build locale list looks_like_locale = re.compile(r'[a-z]{2}') @@ -598,8 +597,7 @@ class Command(BaseCommand): Use msgmerge and msgattrib GNU gettext utilities. """ basedir = os.path.join(os.path.dirname(potfile), locale, 'LC_MESSAGES') - if not os.path.isdir(basedir): - os.makedirs(basedir) + os.makedirs(basedir, exist_ok=True) pofile = os.path.join(basedir, '%s.po' % self.domain) if os.path.exists(pofile): diff --git a/django/core/management/commands/makemigrations.py b/django/core/management/commands/makemigrations.py index 5782b58398..3382887ca3 100644 --- a/django/core/management/commands/makemigrations.py +++ b/django/core/management/commands/makemigrations.py @@ -210,8 +210,7 @@ class Command(BaseCommand): # Write the migrations file to the disk. migrations_directory = os.path.dirname(writer.path) if not directory_created.get(app_label): - if not os.path.isdir(migrations_directory): - os.mkdir(migrations_directory) + os.makedirs(migrations_directory, exist_ok=True) init_path = os.path.join(migrations_directory, "__init__.py") if not os.path.isfile(init_path): open(init_path, "w").close() diff --git a/django/core/management/templates.py b/django/core/management/templates.py index f261a9235e..299b36b6df 100644 --- a/django/core/management/templates.py +++ b/django/core/management/templates.py @@ -120,8 +120,7 @@ class TemplateCommand(BaseCommand): relative_dir = path_rest.replace(base_name, name) if relative_dir: target_dir = path.join(top_dir, relative_dir) - if not path.exists(target_dir): - os.mkdir(target_dir) + os.makedirs(target_dir, exist_ok=True) for dirname in dirs[:]: if dirname.startswith('.') or dirname == '__pycache__': diff --git a/django/db/migrations/writer.py b/django/db/migrations/writer.py index 047436ffab..4918261fb0 100644 --- a/django/db/migrations/writer.py +++ b/django/db/migrations/writer.py @@ -1,3 +1,4 @@ + import os import re from importlib import import_module @@ -249,8 +250,7 @@ class MigrationWriter: migrations_package_name) final_dir = os.path.join(base_dir, *missing_dirs) - if not os.path.isdir(final_dir): - os.makedirs(final_dir) + os.makedirs(final_dir, exist_ok=True) for missing_dir in missing_dirs: base_dir = os.path.join(base_dir, missing_dir) with open(os.path.join(base_dir, "__init__.py"), "w"): diff --git a/django/utils/archive.py b/django/utils/archive.py index 5b9998f89c..b26924cc2a 100644 --- a/django/utils/archive.py +++ b/django/utils/archive.py @@ -157,8 +157,8 @@ class TarArchive(BaseArchive): name = self.split_leading_dir(name)[1] filename = os.path.join(to_path, name) if member.isdir(): - if filename and not os.path.exists(filename): - os.makedirs(filename) + if filename: + os.makedirs(filename, exist_ok=True) else: try: extracted = self._archive.extractfile(member) @@ -169,8 +169,8 @@ class TarArchive(BaseArchive): (name, member.name, exc)) else: dirname = os.path.dirname(filename) - if dirname and not os.path.exists(dirname): - os.makedirs(dirname) + if dirname: + os.makedirs(dirname, exist_ok=True) with open(filename, 'wb') as outfile: shutil.copyfileobj(extracted, outfile) self._copy_permissions(member.mode, filename) @@ -199,14 +199,13 @@ class ZipArchive(BaseArchive): if leading: name = self.split_leading_dir(name)[1] filename = os.path.join(to_path, name) - dirname = os.path.dirname(filename) - if dirname and not os.path.exists(dirname): - os.makedirs(dirname) if filename.endswith(('/', '\\')): # A directory - if not os.path.exists(filename): - os.makedirs(filename) + os.makedirs(filename, exist_ok=True) else: + dirname = os.path.dirname(filename) + if dirname: + os.makedirs(dirname, exist_ok=True) with open(filename, 'wb') as outfile: outfile.write(data) # Convert ZipInfo.external_attr to mode diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py index 8e00a86071..7b41c40199 100644 --- a/tests/admin_scripts/tests.py +++ b/tests/admin_scripts/tests.py @@ -48,8 +48,7 @@ class AdminScriptTestCase(SimpleTestCase): cls.__name__, 'test_project', )) - if not os.path.exists(cls.test_dir): - os.makedirs(cls.test_dir) + os.makedirs(cls.test_dir) with open(os.path.join(cls.test_dir, '__init__.py'), 'w'): pass diff --git a/tests/file_storage/tests.py b/tests/file_storage/tests.py index 991f1ff8cd..434869554c 100644 --- a/tests/file_storage/tests.py +++ b/tests/file_storage/tests.py @@ -410,12 +410,13 @@ class FileStorageTests(SimpleTestCase): # Monkey-patch os.makedirs, to simulate a normal call, a raced call, # and an error. - def fake_makedirs(path): + def fake_makedirs(path, mode=0o777, exist_ok=False): if path == os.path.join(self.temp_dir, 'normal'): - real_makedirs(path) + real_makedirs(path, mode, exist_ok) elif path == os.path.join(self.temp_dir, 'raced'): - real_makedirs(path) - raise FileExistsError() + real_makedirs(path, mode, exist_ok) + if not exist_ok: + raise FileExistsError() elif path == os.path.join(self.temp_dir, 'error'): raise PermissionError() else: diff --git a/tests/file_uploads/tests.py b/tests/file_uploads/tests.py index 07a9d9b647..2824b6eb42 100644 --- a/tests/file_uploads/tests.py +++ b/tests/file_uploads/tests.py @@ -29,8 +29,7 @@ class FileUploadTests(TestCase): @classmethod def setUpClass(cls): super().setUpClass() - if not os.path.isdir(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) + os.makedirs(MEDIA_ROOT, exist_ok=True) @classmethod def tearDownClass(cls): @@ -528,8 +527,7 @@ class DirectoryCreationTests(SimpleTestCase): @classmethod def setUpClass(cls): super().setUpClass() - if not os.path.isdir(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) + os.makedirs(MEDIA_ROOT, exist_ok=True) @classmethod def tearDownClass(cls):