mirror of
https://github.com/django/django.git
synced 2025-10-23 21:59:11 +00:00
Merge branch 'master' into schema-alteration
Conflicts: django/db/backends/mysql/introspection.py django/db/backends/oracle/creation.py django/db/backends/postgresql_psycopg2/creation.py django/db/models/base.py django/db/models/loading.py
This commit is contained in:
@@ -180,7 +180,11 @@ def encode_multipart(boundary, data):
|
||||
|
||||
def encode_file(boundary, key, file):
|
||||
to_bytes = lambda s: force_bytes(s, settings.DEFAULT_CHARSET)
|
||||
content_type = mimetypes.guess_type(file.name)[0]
|
||||
if hasattr(file, 'content_type'):
|
||||
content_type = file.content_type
|
||||
else:
|
||||
content_type = mimetypes.guess_type(file.name)[0]
|
||||
|
||||
if content_type is None:
|
||||
content_type = 'application/octet-stream'
|
||||
return [
|
||||
|
||||
@@ -238,6 +238,7 @@ def setup_databases(verbosity, interactive, **kwargs):
|
||||
mirrored_aliases = {}
|
||||
test_databases = {}
|
||||
dependencies = {}
|
||||
default_sig = connections[DEFAULT_DB_ALIAS].creation.test_db_signature()
|
||||
for alias in connections:
|
||||
connection = connections[alias]
|
||||
if connection.settings_dict['TEST_MIRROR']:
|
||||
@@ -259,7 +260,7 @@ def setup_databases(verbosity, interactive, **kwargs):
|
||||
dependencies[alias] = (
|
||||
connection.settings_dict['TEST_DEPENDENCIES'])
|
||||
else:
|
||||
if alias != DEFAULT_DB_ALIAS:
|
||||
if alias != DEFAULT_DB_ALIAS and connection.creation.test_db_signature() != default_sig:
|
||||
dependencies[alias] = connection.settings_dict.get(
|
||||
'TEST_DEPENDENCIES', [DEFAULT_DB_ALIAS])
|
||||
|
||||
@@ -271,15 +272,16 @@ def setup_databases(verbosity, interactive, **kwargs):
|
||||
test_databases.items(), dependencies):
|
||||
test_db_name = None
|
||||
# Actually create the database for the first connection
|
||||
|
||||
for alias in aliases:
|
||||
connection = connections[alias]
|
||||
old_names.append((connection, db_name, True))
|
||||
if test_db_name is None:
|
||||
test_db_name = connection.creation.create_test_db(
|
||||
verbosity, autoclobber=not interactive)
|
||||
destroy = True
|
||||
else:
|
||||
connection.settings_dict['NAME'] = test_db_name
|
||||
destroy = False
|
||||
old_names.append((connection, db_name, destroy))
|
||||
|
||||
for alias, mirror_alias in mirrored_aliases.items():
|
||||
mirrors.append((alias, connections[alias].settings_dict['NAME']))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import os
|
||||
import time
|
||||
import warnings
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import connections
|
||||
@@ -9,11 +10,14 @@ from django.utils.functional import empty
|
||||
|
||||
template_rendered = Signal(providing_args=["template", "context"])
|
||||
|
||||
setting_changed = Signal(providing_args=["setting", "value"])
|
||||
setting_changed = Signal(providing_args=["setting", "value", "enter"])
|
||||
|
||||
# Most setting_changed receivers are supposed to be added below,
|
||||
# except for cases where the receiver is related to a contrib app.
|
||||
|
||||
# Settings that may not work well when using 'override_settings' (#19031)
|
||||
COMPLEX_OVERRIDE_SETTINGS = set(['DATABASES'])
|
||||
|
||||
|
||||
@receiver(setting_changed)
|
||||
def update_connections_time_zone(**kwargs):
|
||||
@@ -74,8 +78,15 @@ def language_changed(**kwargs):
|
||||
if kwargs['setting'] == 'LOCALE_PATHS':
|
||||
trans_real._translations = {}
|
||||
|
||||
|
||||
@receiver(setting_changed)
|
||||
def file_storage_changed(**kwargs):
|
||||
if kwargs['setting'] in ('MEDIA_ROOT', 'DEFAULT_FILE_STORAGE'):
|
||||
from django.core.files.storage import default_storage
|
||||
default_storage._wrapped = empty
|
||||
|
||||
|
||||
@receiver(setting_changed)
|
||||
def complex_setting_changed(**kwargs):
|
||||
if kwargs['enter'] and kwargs['setting'] in COMPLEX_OVERRIDE_SETTINGS:
|
||||
warnings.warn("Overriding setting %s can lead to unexpected behaviour." % kwargs['setting'])
|
||||
|
||||
@@ -8,7 +8,6 @@ import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import select
|
||||
import socket
|
||||
import threading
|
||||
import unittest
|
||||
@@ -880,10 +879,19 @@ class TestCase(TransactionTestCase):
|
||||
self.atomics[db_name].__exit__(None, None, None)
|
||||
|
||||
|
||||
class CheckCondition(object):
|
||||
"""Descriptor class for deferred condition checking"""
|
||||
def __init__(self, cond_func):
|
||||
self.cond_func = cond_func
|
||||
|
||||
def __get__(self, obj, objtype):
|
||||
return self.cond_func()
|
||||
|
||||
|
||||
def _deferredSkip(condition, reason):
|
||||
def decorator(test_func):
|
||||
if not (isinstance(test_func, type) and
|
||||
issubclass(test_func, TestCase)):
|
||||
issubclass(test_func, unittest.TestCase)):
|
||||
@wraps(test_func)
|
||||
def skip_wrapper(*args, **kwargs):
|
||||
if condition():
|
||||
@@ -891,7 +899,9 @@ def _deferredSkip(condition, reason):
|
||||
return test_func(*args, **kwargs)
|
||||
test_item = skip_wrapper
|
||||
else:
|
||||
# Assume a class is decorated
|
||||
test_item = test_func
|
||||
test_item.__unittest_skip__ = CheckCondition(condition)
|
||||
test_item.__unittest_skip_why__ = reason
|
||||
return test_item
|
||||
return decorator
|
||||
@@ -924,104 +934,6 @@ class QuietWSGIRequestHandler(WSGIRequestHandler):
|
||||
pass
|
||||
|
||||
|
||||
if sys.version_info >= (3, 3, 0):
|
||||
_ImprovedEvent = threading.Event
|
||||
elif sys.version_info >= (2, 7, 0):
|
||||
_ImprovedEvent = threading._Event
|
||||
else:
|
||||
class _ImprovedEvent(threading._Event):
|
||||
"""
|
||||
Does the same as `threading.Event` except it overrides the wait() method
|
||||
with some code borrowed from Python 2.7 to return the set state of the
|
||||
event (see: http://hg.python.org/cpython/rev/b5aa8aa78c0f/). This allows
|
||||
to know whether the wait() method exited normally or because of the
|
||||
timeout. This class can be removed when Django supports only Python >= 2.7.
|
||||
"""
|
||||
|
||||
def wait(self, timeout=None):
|
||||
self._Event__cond.acquire()
|
||||
try:
|
||||
if not self._Event__flag:
|
||||
self._Event__cond.wait(timeout)
|
||||
return self._Event__flag
|
||||
finally:
|
||||
self._Event__cond.release()
|
||||
|
||||
|
||||
class StoppableWSGIServer(WSGIServer):
|
||||
"""
|
||||
The code in this class is borrowed from the `SocketServer.BaseServer` class
|
||||
in Python 2.6. The important functionality here is that the server is non-
|
||||
blocking and that it can be shut down at any moment. This is made possible
|
||||
by the server regularly polling the socket and checking if it has been
|
||||
asked to stop.
|
||||
Note for the future: Once Django stops supporting Python 2.6, this class
|
||||
can be removed as `WSGIServer` will have this ability to shutdown on
|
||||
demand and will not require the use of the _ImprovedEvent class whose code
|
||||
is borrowed from Python 2.7.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(StoppableWSGIServer, self).__init__(*args, **kwargs)
|
||||
self.__is_shut_down = _ImprovedEvent()
|
||||
self.__serving = False
|
||||
|
||||
def serve_forever(self, poll_interval=0.5):
|
||||
"""
|
||||
Handle one request at a time until shutdown.
|
||||
|
||||
Polls for shutdown every poll_interval seconds.
|
||||
"""
|
||||
self.__serving = True
|
||||
self.__is_shut_down.clear()
|
||||
while self.__serving:
|
||||
r, w, e = select.select([self], [], [], poll_interval)
|
||||
if r:
|
||||
self._handle_request_noblock()
|
||||
self.__is_shut_down.set()
|
||||
|
||||
def shutdown(self):
|
||||
"""
|
||||
Stops the serve_forever loop.
|
||||
|
||||
Blocks until the loop has finished. This must be called while
|
||||
serve_forever() is running in another thread, or it will
|
||||
deadlock.
|
||||
"""
|
||||
self.__serving = False
|
||||
if not self.__is_shut_down.wait(2):
|
||||
raise RuntimeError(
|
||||
"Failed to shutdown the live test server in 2 seconds. The "
|
||||
"server might be stuck or generating a slow response.")
|
||||
|
||||
def handle_request(self):
|
||||
"""Handle one request, possibly blocking.
|
||||
"""
|
||||
fd_sets = select.select([self], [], [], None)
|
||||
if not fd_sets[0]:
|
||||
return
|
||||
self._handle_request_noblock()
|
||||
|
||||
def _handle_request_noblock(self):
|
||||
"""
|
||||
Handle one request, without blocking.
|
||||
|
||||
I assume that select.select has returned that the socket is
|
||||
readable before this function was called, so there should be
|
||||
no risk of blocking in get_request().
|
||||
"""
|
||||
try:
|
||||
request, client_address = self.get_request()
|
||||
except socket.error:
|
||||
return
|
||||
if self.verify_request(request, client_address):
|
||||
try:
|
||||
self.process_request(request, client_address)
|
||||
except Exception:
|
||||
self.handle_error(request, client_address)
|
||||
self.close_request(request)
|
||||
|
||||
|
||||
class _MediaFilesHandler(StaticFilesHandler):
|
||||
"""
|
||||
Handler for serving the media files. This is a private class that is
|
||||
@@ -1071,7 +983,7 @@ class LiveServerThread(threading.Thread):
|
||||
# one that is free to use for the WSGI server.
|
||||
for index, port in enumerate(self.possible_ports):
|
||||
try:
|
||||
self.httpd = StoppableWSGIServer(
|
||||
self.httpd = WSGIServer(
|
||||
(self.host, port), QuietWSGIRequestHandler)
|
||||
except WSGIServerException as e:
|
||||
if (index + 1 < len(self.possible_ports) and
|
||||
@@ -1128,7 +1040,7 @@ class LiveServerTestCase(TransactionTestCase):
|
||||
for conn in connections.all():
|
||||
# If using in-memory sqlite databases, pass the connections to
|
||||
# the server thread.
|
||||
if (conn.settings_dict['ENGINE'].rsplit('.', 1)[-1] in ('sqlite3', 'spatialite')
|
||||
if (conn.vendor == 'sqlite'
|
||||
and conn.settings_dict['NAME'] == ':memory:'):
|
||||
# Explicitly enable thread-shareability for this connection
|
||||
conn.allow_thread_sharing = True
|
||||
@@ -1180,7 +1092,7 @@ class LiveServerTestCase(TransactionTestCase):
|
||||
|
||||
# Restore sqlite connections' non-sharability
|
||||
for conn in connections.all():
|
||||
if (conn.settings_dict['ENGINE'].rsplit('.', 1)[-1] in ('sqlite3', 'spatialite')
|
||||
if (conn.vendor == 'sqlite'
|
||||
and conn.settings_dict['NAME'] == ':memory:'):
|
||||
conn.allow_thread_sharing = False
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ class override_settings(object):
|
||||
settings._wrapped = override
|
||||
for key, new_value in self.options.items():
|
||||
setting_changed.send(sender=settings._wrapped.__class__,
|
||||
setting=key, value=new_value)
|
||||
setting=key, value=new_value, enter=True)
|
||||
|
||||
def disable(self):
|
||||
settings._wrapped = self.wrapped
|
||||
@@ -236,7 +236,7 @@ class override_settings(object):
|
||||
for key in self.options:
|
||||
new_value = getattr(settings, key, None)
|
||||
setting_changed.send(sender=settings._wrapped.__class__,
|
||||
setting=key, value=new_value)
|
||||
setting=key, value=new_value, enter=False)
|
||||
|
||||
|
||||
def compare_xml(want, got):
|
||||
|
||||
Reference in New Issue
Block a user