django/tests/utils_tests/test_autoreload.py

187 lines
6.9 KiB
Python

import os
import shutil
import tempfile
from importlib import import_module
from django import conf
from django.contrib import admin
from django.test import SimpleTestCase, override_settings
from django.test.utils import extend_sys_path
from django.utils import autoreload
from django.utils._os import npath
LOCALE_PATH = os.path.join(os.path.dirname(__file__), 'locale')
class TestFilenameGenerator(SimpleTestCase):
def clear_autoreload_caches(self):
autoreload._cached_modules = set()
autoreload._cached_filenames = []
def assertFileFound(self, filename):
self.clear_autoreload_caches()
# Test uncached access
self.assertIn(npath(filename), autoreload.gen_filenames())
# Test cached access
self.assertIn(npath(filename), autoreload.gen_filenames())
def assertFileNotFound(self, filename):
self.clear_autoreload_caches()
# Test uncached access
self.assertNotIn(npath(filename), autoreload.gen_filenames())
# Test cached access
self.assertNotIn(npath(filename), autoreload.gen_filenames())
def assertFileFoundOnlyNew(self, filename):
self.clear_autoreload_caches()
# Test uncached access
self.assertIn(npath(filename), autoreload.gen_filenames(only_new=True))
# Test cached access
self.assertNotIn(npath(filename), autoreload.gen_filenames(only_new=True))
def test_django_locales(self):
"""
gen_filenames() yields the built-in Django locale files.
"""
django_dir = os.path.join(os.path.dirname(conf.__file__), 'locale')
django_mo = os.path.join(django_dir, 'nl', 'LC_MESSAGES', 'django.mo')
self.assertFileFound(django_mo)
@override_settings(LOCALE_PATHS=[LOCALE_PATH])
def test_locale_paths_setting(self):
"""
gen_filenames also yields from LOCALE_PATHS locales.
"""
locale_paths_mo = os.path.join(LOCALE_PATH, 'nl', 'LC_MESSAGES', 'django.mo')
self.assertFileFound(locale_paths_mo)
@override_settings(INSTALLED_APPS=[])
def test_project_root_locale(self):
"""
gen_filenames() also yields from the current directory (project root).
"""
old_cwd = os.getcwd()
os.chdir(os.path.dirname(__file__))
current_dir = os.path.join(os.path.dirname(__file__), 'locale')
current_dir_mo = os.path.join(current_dir, 'nl', 'LC_MESSAGES', 'django.mo')
try:
self.assertFileFound(current_dir_mo)
finally:
os.chdir(old_cwd)
@override_settings(INSTALLED_APPS=['django.contrib.admin'])
def test_app_locales(self):
"""
gen_filenames() also yields from locale dirs in installed apps.
"""
admin_dir = os.path.join(os.path.dirname(admin.__file__), 'locale')
admin_mo = os.path.join(admin_dir, 'nl', 'LC_MESSAGES', 'django.mo')
self.assertFileFound(admin_mo)
@override_settings(USE_I18N=False)
def test_no_i18n(self):
"""
If i18n machinery is disabled, there is no need for watching the
locale files.
"""
django_dir = os.path.join(os.path.dirname(conf.__file__), 'locale')
django_mo = os.path.join(django_dir, 'nl', 'LC_MESSAGES', 'django.mo')
self.assertFileNotFound(django_mo)
def test_paths_are_native_strings(self):
for filename in autoreload.gen_filenames():
self.assertIsInstance(filename, str)
def test_only_new_files(self):
"""
When calling a second time gen_filenames with only_new = True, only
files from newly loaded modules should be given.
"""
dirname = tempfile.mkdtemp()
filename = os.path.join(dirname, 'test_only_new_module.py')
self.addCleanup(shutil.rmtree, dirname)
with open(filename, 'w'):
pass
# Test uncached access
self.clear_autoreload_caches()
filenames = set(autoreload.gen_filenames(only_new=True))
filenames_reference = set(autoreload.gen_filenames())
self.assertEqual(filenames, filenames_reference)
# Test cached access: no changes
filenames = set(autoreload.gen_filenames(only_new=True))
self.assertEqual(filenames, set())
# Test cached access: add a module
with extend_sys_path(dirname):
import_module('test_only_new_module')
filenames = set(autoreload.gen_filenames(only_new=True))
self.assertEqual(filenames, {npath(filename)})
def test_deleted_removed(self):
"""
When a file is deleted, gen_filenames() no longer returns it.
"""
dirname = tempfile.mkdtemp()
filename = os.path.join(dirname, 'test_deleted_removed_module.py')
self.addCleanup(shutil.rmtree, dirname)
with open(filename, 'w'):
pass
with extend_sys_path(dirname):
import_module('test_deleted_removed_module')
self.assertFileFound(filename)
os.unlink(filename)
self.assertFileNotFound(filename)
def test_check_errors(self):
"""
When a file containing an error is imported in a function wrapped by
check_errors(), gen_filenames() returns it.
"""
dirname = tempfile.mkdtemp()
filename = os.path.join(dirname, 'test_syntax_error.py')
self.addCleanup(shutil.rmtree, dirname)
with open(filename, 'w') as f:
f.write("Ceci n'est pas du Python.")
with extend_sys_path(dirname):
with self.assertRaises(SyntaxError):
autoreload.check_errors(import_module)('test_syntax_error')
self.assertFileFound(filename)
def test_check_errors_only_new(self):
"""
When a file containing an error is imported in a function wrapped by
check_errors(), gen_filenames(only_new=True) returns it.
"""
dirname = tempfile.mkdtemp()
filename = os.path.join(dirname, 'test_syntax_error.py')
self.addCleanup(shutil.rmtree, dirname)
with open(filename, 'w') as f:
f.write("Ceci n'est pas du Python.")
with extend_sys_path(dirname):
with self.assertRaises(SyntaxError):
autoreload.check_errors(import_module)('test_syntax_error')
self.assertFileFoundOnlyNew(filename)
def test_check_errors_catches_all_exceptions(self):
"""
Since Python may raise arbitrary exceptions when importing code,
check_errors() must catch Exception, not just some subclasses.
"""
dirname = tempfile.mkdtemp()
filename = os.path.join(dirname, 'test_exception.py')
self.addCleanup(shutil.rmtree, dirname)
with open(filename, 'w') as f:
f.write("raise Exception")
with extend_sys_path(dirname):
with self.assertRaises(Exception):
autoreload.check_errors(import_module)('test_exception')
self.assertFileFound(filename)