Refs #29983 -- Added support for using pathlib.Path in all settings.

This commit is contained in:
Jon Dufresne 2019-11-07 01:26:22 -08:00 committed by Carlton Gibson
parent 367634f976
commit 77aa74cb70
18 changed files with 118 additions and 10 deletions

View File

@ -21,7 +21,7 @@ class Command(LabelCommand):
if verbosity >= 2:
searched_locations = (
"\nLooking in the following locations:\n %s" %
"\n ".join(finders.searched_locations)
"\n ".join([str(loc) for loc in finders.searched_locations])
)
else:
searched_locations = ''

View File

@ -174,7 +174,9 @@ class DatabaseWrapper(BaseDatabaseWrapper):
"settings.DATABASES is improperly configured. "
"Please supply the NAME value.")
kwargs = {
'database': settings_dict['NAME'],
# TODO: Remove str() when dropping support for PY36.
# https://bugs.python.org/issue33496
'database': str(settings_dict['NAME']),
'detect_types': Database.PARSE_DECLTYPES | Database.PARSE_COLNAMES,
**settings_dict['OPTIONS'],
}

View File

@ -1,6 +1,7 @@
import os
import shutil
import sys
from pathlib import Path
from django.db.backends.base.creation import BaseDatabaseCreation
@ -9,7 +10,9 @@ class DatabaseCreation(BaseDatabaseCreation):
@staticmethod
def is_in_memory_db(database_name):
return database_name == ':memory:' or 'mode=memory' in database_name
return not isinstance(database_name, Path) and (
database_name == ':memory:' or 'mode=memory' in database_name
)
def _get_test_db_name(self):
test_database_name = self.connection.settings_dict['TEST']['NAME'] or ':memory:'

View File

@ -39,7 +39,7 @@ class EngineMixin:
def engine(self):
return self.backend({
'APP_DIRS': True,
'DIRS': [str(ROOT / self.backend.app_dirname)],
'DIRS': [ROOT / self.backend.app_dirname],
'NAME': 'djangoforms',
'OPTIONS': {},
})

View File

@ -99,7 +99,7 @@ def get_app_template_dirs(dirname):
installed applications.
"""
template_dirs = [
str(Path(app_config.path) / dirname)
Path(app_config.path) / dirname
for app_config in apps.get_app_configs()
if app_config.path and (Path(app_config.path) / dirname).is_dir()
]

View File

@ -96,7 +96,7 @@ Minor features
:mod:`django.contrib.staticfiles`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ...
* The :setting:`STATICFILES_DIRS` setting now supports :class:`pathlib.Path`.
:mod:`django.contrib.syndication`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -226,6 +226,12 @@ Validators
* ...
Miscellaneous
~~~~~~~~~~~~~
* The SQLite backend now supports :class:`pathlib.Path` for the ``NAME``
setting.
.. _backwards-incompatible-3.1:
Backwards incompatible changes in 3.1

View File

@ -1,11 +1,14 @@
import os
import re
import tempfile
import threading
import unittest
from pathlib import Path
from sqlite3 import dbapi2
from unittest import mock
from django.core.exceptions import ImproperlyConfigured
from django.db import connection, transaction
from django.db import ConnectionHandler, connection, transaction
from django.db.models import Avg, StdDev, Sum, Variance
from django.db.models.aggregates import Aggregate
from django.db.models.fields import CharField
@ -89,6 +92,19 @@ class Tests(TestCase):
value = bool(value) if value in {0, 1} else value
self.assertIs(value, expected)
def test_pathlib_name(self):
with tempfile.TemporaryDirectory() as tmp:
settings_dict = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': Path(tmp) / 'test.db',
},
}
connections = ConnectionHandler(settings_dict)
connections['default'].ensure_connection()
connections['default'].close()
self.assertTrue(os.path.isfile(os.path.join(tmp, 'test.db')))
@unittest.skipUnless(connection.vendor == 'sqlite', 'SQLite tests')
@isolate_apps('backends')

View File

@ -227,3 +227,12 @@ class AppCompilationTest(ProjectAndAppTests):
call_command('compilemessages', locale=[self.LOCALE], stdout=StringIO())
self.assertTrue(os.path.exists(self.PROJECT_MO_FILE))
self.assertTrue(os.path.exists(self.APP_MO_FILE))
class PathLibLocaleCompilationTests(MessageCompilationTests):
work_subdir = 'exclude'
def test_locale_paths_pathlib(self):
with override_settings(LOCALE_PATHS=[Path(self.test_dir) / 'canned_locale']):
call_command('compilemessages', locale=['fr'], stdout=StringIO())
self.assertTrue(os.path.exists('canned_locale/fr/LC_MESSAGES/django.mo'))

View File

@ -5,6 +5,7 @@ import tempfile
import time
import warnings
from io import StringIO
from pathlib import Path
from unittest import mock, skipIf, skipUnless
from admin_scripts.tests import AdminScriptTestCase
@ -735,11 +736,17 @@ class CustomLayoutExtractionTests(ExtractorTests):
management.call_command('makemessages', locale=LOCALE, verbosity=0)
def test_project_locale_paths(self):
self._test_project_locale_paths(os.path.join(self.test_dir, 'project_locale'))
def test_project_locale_paths_pathlib(self):
self._test_project_locale_paths(Path(self.test_dir) / 'project_locale')
def _test_project_locale_paths(self, locale_path):
"""
* translations for an app containing a locale folder are stored in that folder
* translations outside of that app are in LOCALE_PATHS[0]
"""
with override_settings(LOCALE_PATHS=[os.path.join(self.test_dir, 'project_locale')]):
with override_settings(LOCALE_PATHS=[locale_path]):
management.call_command('makemessages', locale=[LOCALE], verbosity=0)
project_de_locale = os.path.join(
self.test_dir, 'project_locale', 'de', 'LC_MESSAGES', 'django.po')

View File

@ -1,6 +1,8 @@
import os
import sys
import tempfile
import unittest
from pathlib import Path
from django.core.files import temp
from django.core.files.base import ContentFile
@ -94,3 +96,10 @@ class FileFieldTests(TestCase):
# open() doesn't write to disk.
d.myfile.file = ContentFile(b'', name='bla')
self.assertEqual(d.myfile, d.myfile.open())
def test_media_root_pathlib(self):
with tempfile.TemporaryDirectory() as tmp_dir:
with override_settings(MEDIA_ROOT=Path(tmp_dir)):
with TemporaryUploadedFile('foo.txt', 'text/plain', 1, 'utf-8') as tmp_file:
Document.objects.create(myfile=tmp_file)
self.assertTrue(os.path.exists(os.path.join(tmp_dir, 'unused', 'foo.txt')))

View File

@ -6,6 +6,7 @@ import tempfile
import unittest
from datetime import timedelta
from http import cookies
from pathlib import Path
from django.conf import settings
from django.contrib.sessions.backends.base import UpdateError
@ -521,7 +522,7 @@ class FileSessionTests(SessionTestsMixin, unittest.TestCase):
def setUp(self):
# Do file session tests in an isolated directory, and kill it after we're done.
self.original_session_file_path = settings.SESSION_FILE_PATH
self.temp_session_store = settings.SESSION_FILE_PATH = tempfile.mkdtemp()
self.temp_session_store = settings.SESSION_FILE_PATH = self.mkdtemp()
# Reset the file session backend's internal caches
if hasattr(self.backend, '_storage_path'):
del self.backend._storage_path
@ -532,6 +533,9 @@ class FileSessionTests(SessionTestsMixin, unittest.TestCase):
settings.SESSION_FILE_PATH = self.original_session_file_path
shutil.rmtree(self.temp_session_store)
def mkdtemp(self):
return tempfile.mkdtemp()
@override_settings(
SESSION_FILE_PATH='/if/this/directory/exists/you/have/a/weird/computer',
)
@ -598,6 +602,12 @@ class FileSessionTests(SessionTestsMixin, unittest.TestCase):
self.assertEqual(1, count_sessions())
class FileSessionPathLibTests(FileSessionTests):
def mkdtemp(self):
tmp_dir = super().mkdtemp()
return Path(tmp_dir)
class CacheSessionTests(SessionTestsMixin, unittest.TestCase):
backend = CacheSession

View File

@ -64,7 +64,7 @@ class CollectionTestCase(BaseStaticFilesMixin, SimpleTestCase):
def setUp(self):
super().setUp()
temp_dir = tempfile.mkdtemp()
temp_dir = self.mkdtemp()
# Override the STATIC_ROOT for all tests from setUp to tearDown
# rather than as a context manager
self.patched_settings = self.settings(STATIC_ROOT=temp_dir)
@ -78,6 +78,9 @@ class CollectionTestCase(BaseStaticFilesMixin, SimpleTestCase):
self.patched_settings.disable()
super().tearDown()
def mkdtemp(self):
return tempfile.mkdtemp()
def run_collectstatic(self, *, verbosity=0, **kwargs):
call_command('collectstatic', interactive=False, verbosity=verbosity,
ignore_patterns=['*.ignoreme'], **kwargs)

View File

@ -0,0 +1 @@
pathlib

View File

@ -1,4 +1,5 @@
import os.path
from pathlib import Path
TEST_ROOT = os.path.dirname(__file__)
@ -10,6 +11,7 @@ TEST_SETTINGS = {
'STATICFILES_DIRS': [
os.path.join(TEST_ROOT, 'project', 'documents'),
('prefix', os.path.join(TEST_ROOT, 'project', 'prefixed')),
Path(TEST_ROOT) / 'project' / 'pathlib',
],
'STATICFILES_FINDERS': [
'django.contrib.staticfiles.finders.FileSystemFinder',

View File

@ -4,6 +4,7 @@ import shutil
import tempfile
import unittest
from io import StringIO
from pathlib import Path
from unittest import mock
from admin_scripts.tests import AdminScriptTestCase
@ -102,6 +103,7 @@ class TestFindStatic(TestDefaults, CollectionTestCase):
# FileSystemFinder searched locations
self.assertIn(TEST_SETTINGS['STATICFILES_DIRS'][1][1], searched_locations)
self.assertIn(TEST_SETTINGS['STATICFILES_DIRS'][0], searched_locations)
self.assertIn(str(TEST_SETTINGS['STATICFILES_DIRS'][2]), searched_locations)
# DefaultStorageFinder searched locations
self.assertIn(
os.path.join('staticfiles_tests', 'project', 'site_media', 'media'),
@ -174,6 +176,15 @@ class TestCollection(TestDefaults, CollectionTestCase):
self.assertFileNotFound('test/backup~')
self.assertFileNotFound('test/CVS')
def test_pathlib(self):
self.assertFileContains('pathlib.txt', 'pathlib')
class TestCollectionPathLib(TestCollection):
def mkdtemp(self):
tmp_dir = super().mkdtemp()
return Path(tmp_dir)
class TestCollectionVerbosity(CollectionTestCase):
copying_msg = 'Copying '

View File

@ -1,3 +1,5 @@
from pathlib import Path
from template_tests.test_response import test_processor_name
from django.template import Context, EngineHandler, RequestContext
@ -164,3 +166,13 @@ class DjangoTemplatesTests(TemplateStringsTests):
def test_debug_default_template_loaders(self):
engine = DjangoTemplates({'DIRS': [], 'APP_DIRS': True, 'NAME': 'django', 'OPTIONS': {}})
self.assertEqual(engine.engine.loaders, self.default_loaders)
def test_dirs_pathlib(self):
engine = DjangoTemplates({
'DIRS': [Path(__file__).parent / 'templates' / 'template_backends'],
'APP_DIRS': False,
'NAME': 'django',
'OPTIONS': {},
})
template = engine.get_template('hello.html')
self.assertEqual(template.render({'name': 'Joe'}), 'Hello Joe!\n')

View File

@ -1,3 +1,4 @@
from pathlib import Path
from unittest import skipIf
from django.template import TemplateSyntaxError
@ -85,3 +86,13 @@ class Jinja2Tests(TemplateStringsTests):
with self.settings(STATIC_URL='/s/'):
content = template.render(request=request)
self.assertEqual(content, 'Static URL: /s/')
def test_dirs_pathlib(self):
engine = Jinja2({
'DIRS': [Path(__file__).parent / 'templates' / 'template_backends'],
'APP_DIRS': False,
'NAME': 'jinja2',
'OPTIONS': {},
})
template = engine.get_template('hello.html')
self.assertEqual(template.render({'name': 'Joe'}), 'Hello Joe!')

View File

@ -1,4 +1,5 @@
import os
from pathlib import Path
from unittest import mock
from django.core.exceptions import ImproperlyConfigured
@ -52,3 +53,8 @@ class LocaleRegexDescriptorTests(SimpleTestCase):
def test_access_locale_regex_descriptor(self):
self.assertIsInstance(RegexPattern.regex, LocaleRegexDescriptor)
@override_settings(LOCALE_PATHS=[Path(here) / 'translations' / 'locale'])
class LocaleRegexDescriptorPathLibTests(LocaleRegexDescriptorTests):
pass