Refs #27656 -- Updated remaining docstring verbs according to PEP 257.

This commit is contained in:
Anton Samarchyan 2017-01-24 15:37:33 -05:00 committed by Tim Graham
parent 6ae1b04fb5
commit 86de930f41
21 changed files with 226 additions and 336 deletions

View File

@ -8,15 +8,13 @@ MODELS_MODULE_NAME = 'models'
class AppConfig: class AppConfig:
""" """Class representing a Django application and its configuration."""
Class representing a Django application and its configuration.
"""
def __init__(self, app_name, app_module): def __init__(self, app_name, app_module):
# Full Python path to the application eg. 'django.contrib.admin'. # Full Python path to the application e.g. 'django.contrib.admin'.
self.name = app_name self.name = app_name
# Root module for the application eg. <module 'django.contrib.admin' # Root module for the application e.g. <module 'django.contrib.admin'
# from 'django/contrib/admin/__init__.py'>. # from 'django/contrib/admin/__init__.py'>.
self.module = app_module self.module = app_module
@ -27,21 +25,21 @@ class AppConfig:
# The following attributes could be defined at the class level in a # The following attributes could be defined at the class level in a
# subclass, hence the test-and-set pattern. # subclass, hence the test-and-set pattern.
# Last component of the Python path to the application eg. 'admin'. # Last component of the Python path to the application e.g. 'admin'.
# This value must be unique across a Django project. # This value must be unique across a Django project.
if not hasattr(self, 'label'): if not hasattr(self, 'label'):
self.label = app_name.rpartition(".")[2] self.label = app_name.rpartition(".")[2]
# Human-readable name for the application eg. "Admin". # Human-readable name for the application e.g. "Admin".
if not hasattr(self, 'verbose_name'): if not hasattr(self, 'verbose_name'):
self.verbose_name = self.label.title() self.verbose_name = self.label.title()
# Filesystem path to the application directory eg. # Filesystem path to the application directory e.g.
# '/path/to/django/contrib/admin'. # '/path/to/django/contrib/admin'.
if not hasattr(self, 'path'): if not hasattr(self, 'path'):
self.path = self._path_from_module(app_module) self.path = self._path_from_module(app_module)
# Module containing models eg. <module 'django.contrib.admin.models' # Module containing models e.g. <module 'django.contrib.admin.models'
# from 'django/contrib/admin/models.py'>. Set by import_models(). # from 'django/contrib/admin/models.py'>. Set by import_models().
# None if the application doesn't have a models module. # None if the application doesn't have a models module.
self.models_module = None self.models_module = None
@ -155,9 +153,9 @@ class AppConfig:
def get_model(self, model_name, require_ready=True): def get_model(self, model_name, require_ready=True):
""" """
Returns the model with the given case-insensitive model_name. Return the model with the given case-insensitive model_name.
Raises LookupError if no model exists with this name. Raise LookupError if no model exists with this name.
""" """
if require_ready: if require_ready:
self.apps.check_models_ready() self.apps.check_models_ready()
@ -171,7 +169,7 @@ class AppConfig:
def get_models(self, include_auto_created=False, include_swapped=False): def get_models(self, include_auto_created=False, include_swapped=False):
""" """
Returns an iterable of models. Return an iterable of models.
By default, the following models aren't included: By default, the following models aren't included:

View File

@ -14,7 +14,7 @@ class Apps:
""" """
A registry that stores the configuration of installed applications. A registry that stores the configuration of installed applications.
It also keeps track of models eg. to provide reverse-relations. It also keeps track of models, e.g. to provide reverse relations.
""" """
def __init__(self, installed_apps=()): def __init__(self, installed_apps=()):
@ -58,11 +58,11 @@ class Apps:
def populate(self, installed_apps=None): def populate(self, installed_apps=None):
""" """
Loads application configurations and models. Load application configurations and models.
This method imports each application module and then each model module. Import each application module and then each model module.
It is thread safe and idempotent, but not reentrant. It is thread-safe and idempotent, but not reentrant.
""" """
if self.ready: if self.ready:
return return
@ -122,31 +122,25 @@ class Apps:
self.ready = True self.ready = True
def check_apps_ready(self): def check_apps_ready(self):
""" """Raise an exception if all apps haven't been imported yet."""
Raises an exception if all apps haven't been imported yet.
"""
if not self.apps_ready: if not self.apps_ready:
raise AppRegistryNotReady("Apps aren't loaded yet.") raise AppRegistryNotReady("Apps aren't loaded yet.")
def check_models_ready(self): def check_models_ready(self):
""" """Raise an exception if all models haven't been imported yet."""
Raises an exception if all models haven't been imported yet.
"""
if not self.models_ready: if not self.models_ready:
raise AppRegistryNotReady("Models aren't loaded yet.") raise AppRegistryNotReady("Models aren't loaded yet.")
def get_app_configs(self): def get_app_configs(self):
""" """Import applications and return an iterable of app configs."""
Imports applications and returns an iterable of app configs.
"""
self.check_apps_ready() self.check_apps_ready()
return self.app_configs.values() return self.app_configs.values()
def get_app_config(self, app_label): def get_app_config(self, app_label):
""" """
Imports applications and returns an app config for the given label. Import applications and returns an app config for the given label.
Raises LookupError if no application exists with this label. Raise LookupError if no application exists with this label.
""" """
self.check_apps_ready() self.check_apps_ready()
try: try:
@ -163,7 +157,7 @@ class Apps:
@functools.lru_cache(maxsize=None) @functools.lru_cache(maxsize=None)
def get_models(self, include_auto_created=False, include_swapped=False): def get_models(self, include_auto_created=False, include_swapped=False):
""" """
Returns a list of all installed models. Return a list of all installed models.
By default, the following models aren't included: By default, the following models aren't included:
@ -182,15 +176,14 @@ class Apps:
def get_model(self, app_label, model_name=None, require_ready=True): def get_model(self, app_label, model_name=None, require_ready=True):
""" """
Returns the model matching the given app_label and model_name. Return the model matching the given app_label and model_name.
As a shortcut, this function also accepts a single argument in the As a shortcut, app_label may be in the form <app_label>.<model_name>.
form <app_label>.<model_name>.
model_name is case-insensitive. model_name is case-insensitive.
Raises LookupError if no application exists with this label, or no Raise LookupError if no application exists with this label, or no
model exists with this name in the application. Raises ValueError if model exists with this name in the application. Raise ValueError if
called with a single argument that doesn't contain exactly one dot. called with a single argument that doesn't contain exactly one dot.
""" """
if require_ready: if require_ready:
@ -232,9 +225,9 @@ class Apps:
def is_installed(self, app_name): def is_installed(self, app_name):
""" """
Checks whether an application with this name exists in the registry. Check whether an application with this name exists in the registry.
app_name is the full name of the app eg. 'django.contrib.admin'. app_name is the full name of the app e.g. 'django.contrib.admin'.
""" """
self.check_apps_ready() self.check_apps_ready()
return any(ac.name == app_name for ac in self.app_configs.values()) return any(ac.name == app_name for ac in self.app_configs.values())
@ -245,8 +238,8 @@ class Apps:
object_name is the dotted Python path to the object. object_name is the dotted Python path to the object.
Returns the app config for the inner application in case of nesting. Return the app config for the inner application in case of nesting.
Returns None if the object isn't in any registered app config. Return None if the object isn't in any registered app config.
""" """
self.check_apps_ready() self.check_apps_ready()
candidates = [] candidates = []
@ -296,7 +289,7 @@ class Apps:
def set_available_apps(self, available): def set_available_apps(self, available):
""" """
Restricts the set of installed apps used by get_app_config[s]. Restrict the set of installed apps used by get_app_config[s].
available must be an iterable of application names. available must be an iterable of application names.
@ -304,7 +297,7 @@ class Apps:
Primarily used for performance optimization in TransactionTestCase. Primarily used for performance optimization in TransactionTestCase.
This method is safe is the sense that it doesn't trigger any imports. This method is safe in the sense that it doesn't trigger any imports.
""" """
available = set(available) available = set(available)
installed = set(app_config.name for app_config in self.get_app_configs()) installed = set(app_config.name for app_config in self.get_app_configs())
@ -322,15 +315,13 @@ class Apps:
self.clear_cache() self.clear_cache()
def unset_available_apps(self): def unset_available_apps(self):
""" """Cancel a previous call to set_available_apps()."""
Cancels a previous call to set_available_apps().
"""
self.app_configs = self.stored_app_configs.pop() self.app_configs = self.stored_app_configs.pop()
self.clear_cache() self.clear_cache()
def set_installed_apps(self, installed): def set_installed_apps(self, installed):
""" """
Enables a different set of installed apps for get_app_config[s]. Enable a different set of installed apps for get_app_config[s].
installed must be an iterable in the same format as INSTALLED_APPS. installed must be an iterable in the same format as INSTALLED_APPS.
@ -342,7 +333,7 @@ class Apps:
This method may trigger new imports, which may add new models to the This method may trigger new imports, which may add new models to the
registry of all imported models. They will stay in the registry even registry of all imported models. They will stay in the registry even
after unset_installed_apps(). Since it isn't possible to replay after unset_installed_apps(). Since it isn't possible to replay
imports safely (eg. that could lead to registering listeners twice), imports safely (e.g. that could lead to registering listeners twice),
models are registered when they're imported and never removed. models are registered when they're imported and never removed.
""" """
if not self.ready: if not self.ready:
@ -354,16 +345,14 @@ class Apps:
self.populate(installed) self.populate(installed)
def unset_installed_apps(self): def unset_installed_apps(self):
""" """Cancel a previous call to set_installed_apps()."""
Cancels a previous call to set_installed_apps().
"""
self.app_configs = self.stored_app_configs.pop() self.app_configs = self.stored_app_configs.pop()
self.apps_ready = self.models_ready = self.ready = True self.apps_ready = self.models_ready = self.ready = True
self.clear_cache() self.clear_cache()
def clear_cache(self): def clear_cache(self):
""" """
Clears all internal caches, for methods that alter the app registry. Clear all internal caches, for methods that alter the app registry.
This is mostly used in tests. This is mostly used in tests.
""" """
@ -419,7 +408,7 @@ class Apps:
def do_pending_operations(self, model): def do_pending_operations(self, model):
""" """
Take a newly-prepared model and pass it to each function waiting for Take a newly-prepared model and pass it to each function waiting for
it. This is called at the very end of `Apps.register_model()`. it. This is called at the very end of Apps.register_model().
""" """
key = model._meta.app_label, model._meta.model_name key = model._meta.app_label, model._meta.model_name
for function in self._pending_operations.pop(key, []): for function in self._pending_operations.pop(key, []):

View File

@ -1,9 +1,9 @@
""" """
Settings and configuration for Django. Settings and configuration for Django.
Values will be read from the module specified by the DJANGO_SETTINGS_MODULE environment Read values from the module specified by the DJANGO_SETTINGS_MODULE environment
variable, and then from django.conf.global_settings; see the global settings file for variable, and then from django.conf.global_settings; see the global_settings.py
a list of all possible variables. for a list of all possible variables.
""" """
import importlib import importlib
@ -28,8 +28,8 @@ class LazySettings(LazyObject):
def _setup(self, name=None): def _setup(self, name=None):
""" """
Load the settings module pointed to by the environment variable. This Load the settings module pointed to by the environment variable. This
is used the first time we need any settings at all, if the user has not is used the first time settings are needed, if the user hasn't
previously configured the settings manually. configured settings manually.
""" """
settings_module = os.environ.get(ENVIRONMENT_VARIABLE) settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
if not settings_module: if not settings_module:
@ -51,9 +51,7 @@ class LazySettings(LazyObject):
} }
def __getattr__(self, name): def __getattr__(self, name):
""" """Return the value of a setting and cache it in self.__dict__."""
Return the value of a setting and cache it in self.__dict__.
"""
if self._wrapped is empty: if self._wrapped is empty:
self._setup(name) self._setup(name)
val = getattr(self._wrapped, name) val = getattr(self._wrapped, name)
@ -72,9 +70,7 @@ class LazySettings(LazyObject):
super().__setattr__(name, value) super().__setattr__(name, value)
def __delattr__(self, name): def __delattr__(self, name):
""" """Delete a setting and clear it from cache if needed."""
Delete a setting and clear it from cache if needed.
"""
super().__delattr__(name) super().__delattr__(name)
self.__dict__.pop(name, None) self.__dict__.pop(name, None)
@ -93,9 +89,7 @@ class LazySettings(LazyObject):
@property @property
def configured(self): def configured(self):
""" """Return True if the settings have already been configured."""
Returns True if the settings have already been configured.
"""
return self._wrapped is not empty return self._wrapped is not empty
@ -156,9 +150,7 @@ class Settings:
class UserSettingsHolder: class UserSettingsHolder:
""" """Holder for user configured settings."""
Holder for user configured settings.
"""
# SETTINGS_MODULE doesn't make much sense in the manually configured # SETTINGS_MODULE doesn't make much sense in the manually configured
# (standalone) case. # (standalone) case.
SETTINGS_MODULE = None SETTINGS_MODULE = None

View File

@ -8,9 +8,8 @@ from django.views.i18n import set_language
def i18n_patterns(*urls, prefix_default_language=True): def i18n_patterns(*urls, prefix_default_language=True):
""" """
Adds the language code prefix to every URL pattern within this Add the language code prefix to every URL pattern within this function.
function. This may only be used in the root URLconf, not in an included This may only be used in the root URLconf, not in an included URLconf.
URLconf.
""" """
if not settings.USE_I18N: if not settings.USE_I18N:
return list(urls) return list(urls)

View File

@ -8,7 +8,7 @@ from django.views.static import serve
def static(prefix, view=serve, **kwargs): def static(prefix, view=serve, **kwargs):
""" """
Helper function to return a URL pattern for serving files in debug mode. Return a URL pattern for serving files in debug mode.
from django.conf import settings from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static

View File

@ -7,9 +7,9 @@ class SessionStore(SessionBase):
def load(self): def load(self):
""" """
We load the data from the key itself instead of fetching from Load the data from the key itself instead of fetching from some
some external data store. Opposite of _get_session_key(), external data store. Opposite of _get_session_key(), raise BadSignature
raises BadSignature if signature fails. if signature fails.
""" """
try: try:
return signing.loads( return signing.loads(

View File

@ -72,7 +72,7 @@ class UpdateCacheMiddleware(MiddlewareMixin):
return hasattr(request, '_cache_update_cache') and request._cache_update_cache return hasattr(request, '_cache_update_cache') and request._cache_update_cache
def process_response(self, request, response): def process_response(self, request, response):
"""Sets the cache, if needed.""" """Set the cache, if needed."""
if not self._should_update_cache(request, response): if not self._should_update_cache(request, response):
# We don't need to update the cache, just return. # We don't need to update the cache, just return.
return response return response
@ -122,7 +122,7 @@ class FetchFromCacheMiddleware(MiddlewareMixin):
def process_request(self, request): def process_request(self, request):
""" """
Checks whether the page is already cached and returns the cached Check whether the page is already cached and return the cached
version if available. version if available.
""" """
if request.method not in ('GET', 'HEAD'): if request.method not in ('GET', 'HEAD'):

View File

@ -11,21 +11,15 @@ from django.utils.deprecation import MiddlewareMixin
class XFrameOptionsMiddleware(MiddlewareMixin): class XFrameOptionsMiddleware(MiddlewareMixin):
""" """
Middleware that sets the X-Frame-Options HTTP header in HTTP responses. Set the X-Frame-Options HTTP header in HTTP responses.
Does not set the header if it's already set or if the response contains Do not set the header if it's already set or if the response contains
a xframe_options_exempt value set to True. a xframe_options_exempt value set to True.
By default, sets the X-Frame-Options header to 'SAMEORIGIN', meaning the By default, set the X-Frame-Options header to 'SAMEORIGIN', meaning the
response can only be loaded on a frame within the same site. To prevent the response can only be loaded on a frame within the same site. To prevent the
response from being loaded in a frame in any site, set X_FRAME_OPTIONS in response from being loaded in a frame in any site, set X_FRAME_OPTIONS in
your project's Django settings to 'DENY'. your project's Django settings to 'DENY'.
Note: older browsers will quietly ignore this header, thus other
clickjacking protection techniques should be used if protection in those
browsers is required.
https://en.wikipedia.org/wiki/Clickjacking#Server_and_client
""" """
def process_response(self, request, response): def process_response(self, request, response):
# Don't set it if it's already in the response # Don't set it if it's already in the response
@ -42,10 +36,8 @@ class XFrameOptionsMiddleware(MiddlewareMixin):
def get_xframe_options_value(self, request, response): def get_xframe_options_value(self, request, response):
""" """
Gets the value to set for the X_FRAME_OPTIONS header. Get the value to set for the X_FRAME_OPTIONS header. Use the value from
the X_FRAME_OPTIONS setting, or 'SAMEORIGIN' if not set.
By default this uses the value from the X_FRAME_OPTIONS Django
settings. If not found in settings, defaults to 'SAMEORIGIN'.
This method can be overridden if needed, allowing it to vary based on This method can be overridden if needed, allowing it to vary based on
the request or response. the request or response.

View File

@ -17,17 +17,16 @@ class CommonMiddleware(MiddlewareMixin):
""" """
"Common" middleware for taking care of some basic operations: "Common" middleware for taking care of some basic operations:
- Forbids access to User-Agents in settings.DISALLOWED_USER_AGENTS - Forbid access to User-Agents in settings.DISALLOWED_USER_AGENTS
- URL rewriting: Based on the APPEND_SLASH and PREPEND_WWW settings, - URL rewriting: Based on the APPEND_SLASH and PREPEND_WWW settings,
this middleware appends missing slashes and/or prepends missing append missing slashes and/or prepends missing "www."s.
"www."s.
- If APPEND_SLASH is set and the initial URL doesn't end with a - If APPEND_SLASH is set and the initial URL doesn't end with a
slash, and it is not found in urlpatterns, a new URL is formed by slash, and it is not found in urlpatterns, form a new URL by
appending a slash at the end. If this new URL is found in appending a slash at the end. If this new URL is found in
urlpatterns, then an HTTP-redirect is returned to this new URL; urlpatterns, return an HTTP redirect to this new URL; otherwise
otherwise the initial URL is processed as usual. process the initial URL as usual.
This behavior can be customized by subclassing CommonMiddleware and This behavior can be customized by subclassing CommonMiddleware and
overriding the response_redirect_class attribute. overriding the response_redirect_class attribute.
@ -140,9 +139,7 @@ class CommonMiddleware(MiddlewareMixin):
return response return response
def needs_etag(self, response): def needs_etag(self, response):
""" """Return True if an ETag header should be added to response."""
Return True if an ETag header should be added to response.
"""
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) cache_control_headers = cc_delim_re.split(response.get('Cache-Control', ''))
return all(header.lower() != 'no-store' for header in cache_control_headers) return all(header.lower() != 'no-store' for header in cache_control_headers)
@ -150,9 +147,7 @@ class CommonMiddleware(MiddlewareMixin):
class BrokenLinkEmailsMiddleware(MiddlewareMixin): class BrokenLinkEmailsMiddleware(MiddlewareMixin):
def process_response(self, request, response): def process_response(self, request, response):
""" """Send broken link emails for relevant 404 NOT FOUND responses."""
Send broken link emails for relevant 404 NOT FOUND responses.
"""
if response.status_code == 404 and not settings.DEBUG: if response.status_code == 404 and not settings.DEBUG:
domain = request.get_host() domain = request.get_host()
path = request.get_full_path() path = request.get_full_path()
@ -173,7 +168,8 @@ class BrokenLinkEmailsMiddleware(MiddlewareMixin):
def is_internal_request(self, domain, referer): def is_internal_request(self, domain, referer):
""" """
Returns True if the referring URL is the same domain as the current request. Return True if the referring URL is the same domain as the current
request.
""" """
# Different subdomains are treated as different domains. # Different subdomains are treated as different domains.
return bool(re.match("^https?://%s/" % re.escape(domain), referer)) return bool(re.match("^https?://%s/" % re.escape(domain), referer))

View File

@ -33,9 +33,7 @@ CSRF_SESSION_KEY = '_csrftoken'
def _get_failure_view(): def _get_failure_view():
""" """Return the view to be used for CSRF rejections."""
Returns the view to be used for CSRF rejections
"""
return get_callable(settings.CSRF_FAILURE_VIEW) return get_callable(settings.CSRF_FAILURE_VIEW)
@ -75,7 +73,7 @@ def _get_new_csrf_token():
def get_token(request): def get_token(request):
""" """
Returns the CSRF token required for a POST form. The token is an Return the CSRF token required for a POST form. The token is an
alphanumeric value. A new token is created if one is not already set. alphanumeric value. A new token is created if one is not already set.
A side effect of calling this function is to make the csrf_protect A side effect of calling this function is to make the csrf_protect
@ -94,7 +92,7 @@ def get_token(request):
def rotate_token(request): def rotate_token(request):
""" """
Changes the CSRF token in use for a request - should be done on login Change the CSRF token in use for a request - should be done on login
for security purposes. for security purposes.
""" """
request.META.update({ request.META.update({
@ -132,12 +130,11 @@ def _compare_salted_tokens(request_csrf_token, csrf_token):
class CsrfViewMiddleware(MiddlewareMixin): class CsrfViewMiddleware(MiddlewareMixin):
""" """
Middleware that requires a present and correct csrfmiddlewaretoken Require a present and correct csrfmiddlewaretoken for POST requests that
for POST requests that have a CSRF cookie, and sets an outgoing have a CSRF cookie, and set an outgoing CSRF cookie.
CSRF cookie.
This middleware should be used in conjunction with the csrf_token template This middleware should be used in conjunction with the {% csrf_token %}
tag. template tag.
""" """
# The _accept and _reject methods currently only exist for the sake of the # The _accept and _reject methods currently only exist for the sake of the
# requires_csrf_token decorator. # requires_csrf_token decorator.

View File

@ -9,8 +9,8 @@ re_accepts_gzip = re.compile(r'\bgzip\b')
class GZipMiddleware(MiddlewareMixin): class GZipMiddleware(MiddlewareMixin):
""" """
This middleware compresses content if the browser allows gzip compression. Compress content if the browser allows gzip compression.
It sets the Vary header accordingly, so that caches will base their storage Set the Vary header accordingly, so that caches will base their storage
on the Accept-Encoding header. on the Accept-Encoding header.
""" """
def process_response(self, request, response): def process_response(self, request, response):

View File

@ -7,10 +7,9 @@ from django.utils.http import parse_http_date_safe
class ConditionalGetMiddleware(MiddlewareMixin): class ConditionalGetMiddleware(MiddlewareMixin):
""" """
Handles conditional GET operations. If the response has an ETag or Handle conditional GET operations. If the response has an ETag or
Last-Modified header, and the request has If-None-Match or Last-Modified header and the request has If-None-Match or If-Modified-Since,
If-Modified-Since, the response is replaced by an HttpNotModified. An ETag replace the response with HttpNotModified. Add an ETag header if needed.
header is added if needed.
""" """
def process_response(self, request, response): def process_response(self, request, response):
# It's too late to prevent an unsafe request with a 412 response, and # It's too late to prevent an unsafe request with a 412 response, and
@ -38,8 +37,6 @@ class ConditionalGetMiddleware(MiddlewareMixin):
return response return response
def needs_etag(self, response): def needs_etag(self, response):
""" """Return True if an ETag header should be added to response."""
Return True if an ETag header should be added to response.
"""
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) cache_control_headers = cc_delim_re.split(response.get('Cache-Control', ''))
return all(header.lower() != 'no-store' for header in cache_control_headers) return all(header.lower() != 'no-store' for header in cache_control_headers)

View File

@ -1,5 +1,3 @@
"This is the locale selecting middleware that will look at accept headers"
from django.conf import settings from django.conf import settings
from django.conf.urls.i18n import is_language_prefix_patterns_used from django.conf.urls.i18n import is_language_prefix_patterns_used
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
@ -11,11 +9,9 @@ from django.utils.deprecation import MiddlewareMixin
class LocaleMiddleware(MiddlewareMixin): class LocaleMiddleware(MiddlewareMixin):
""" """
This is a very simple middleware that parses a request Parse a request and decide what translation object to install in the
and decides what translation object to install in the current current thread context. This allows pages to be dynamically translated to
thread context. This allows pages to be dynamically the language the user desires (if the language is available, of course).
translated to the language the user desires (if the language
is available, of course).
""" """
response_redirect_class = HttpResponseRedirect response_redirect_class = HttpResponseRedirect

View File

@ -17,7 +17,7 @@ from django.utils.functional import Promise
def render_to_response(template_name, context=None, content_type=None, status=None, using=None): def render_to_response(template_name, context=None, content_type=None, status=None, using=None):
""" """
Returns a HttpResponse whose content is filled with the result of calling Return a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments. django.template.loader.render_to_string() with the passed arguments.
""" """
warnings.warn( warnings.warn(
@ -31,7 +31,7 @@ def render_to_response(template_name, context=None, content_type=None, status=No
def render(request, template_name, context=None, content_type=None, status=None, using=None): def render(request, template_name, context=None, content_type=None, status=None, using=None):
""" """
Returns a HttpResponse whose content is filled with the result of calling Return a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments. django.template.loader.render_to_string() with the passed arguments.
""" """
content = loader.render_to_string(template_name, context, request, using=using) content = loader.render_to_string(template_name, context, request, using=using)
@ -40,7 +40,7 @@ def render(request, template_name, context=None, content_type=None, status=None,
def redirect(to, *args, permanent=False, **kwargs): def redirect(to, *args, permanent=False, **kwargs):
""" """
Returns an HttpResponseRedirect to the appropriate URL for the arguments Return an HttpResponseRedirect to the appropriate URL for the arguments
passed. passed.
The arguments could be: The arguments could be:
@ -74,7 +74,7 @@ def _get_queryset(klass):
def get_object_or_404(klass, *args, **kwargs): def get_object_or_404(klass, *args, **kwargs):
""" """
Uses get() to return an object, or raises a Http404 exception if the object Use get() to return an object, or raise a Http404 exception if the object
does not exist. does not exist.
klass may be a Model, Manager, or QuerySet object. All other passed klass may be a Model, Manager, or QuerySet object. All other passed
@ -98,7 +98,7 @@ def get_object_or_404(klass, *args, **kwargs):
def get_list_or_404(klass, *args, **kwargs): def get_list_or_404(klass, *args, **kwargs):
""" """
Uses filter() to return a list of objects, or raise a Http404 exception if Use filter() to return a list of objects, or raise a Http404 exception if
the list is empty. the list is empty.
klass may be a Model, Manager, or QuerySet object. All other passed klass may be a Model, Manager, or QuerySet object. All other passed

View File

@ -1,6 +1,4 @@
""" """Django Unit Test framework."""
Django Unit Test and Doctest framework.
"""
from django.test.client import Client, RequestFactory from django.test.client import Client, RequestFactory
from django.test.testcases import ( from django.test.testcases import (

View File

@ -36,9 +36,7 @@ JSON_CONTENT_TYPE_RE = re.compile(r'^application\/(vnd\..+\+)?json$')
class RedirectCycleError(Exception): class RedirectCycleError(Exception):
""" """The test client has been asked to follow a redirect loop."""
The test client has been asked to follow a redirect loop.
"""
def __init__(self, message, last_response): def __init__(self, message, last_response):
super().__init__(message) super().__init__(message)
self.last_response = last_response self.last_response = last_response
@ -50,7 +48,7 @@ class FakePayload:
A wrapper around BytesIO that restricts what can be read since data from A wrapper around BytesIO that restricts what can be read since data from
the network can't be seeked and cannot be read outside of its content the network can't be seeked and cannot be read outside of its content
length. This makes sure that views can't do anything under the test client length. This makes sure that views can't do anything under the test client
that wouldn't work in Real Life. that wouldn't work in real life.
""" """
def __init__(self, content=None): def __init__(self, content=None):
self.__content = BytesIO() self.__content = BytesIO()
@ -93,7 +91,7 @@ def closing_iterator_wrapper(iterable, close):
def conditional_content_removal(request, response): def conditional_content_removal(request, response):
""" """
Simulate the behavior of most Web servers by removing the content of Simulate the behavior of most Web servers by removing the content of
responses for HEAD requests, 1xx, 204, and 304 responses. Ensures responses for HEAD requests, 1xx, 204, and 304 responses. Ensure
compliance with RFC 7230, section 3.3.3. compliance with RFC 7230, section 3.3.3.
""" """
if 100 <= response.status_code < 200 or response.status_code in (204, 304): if 100 <= response.status_code < 200 or response.status_code in (204, 304):
@ -112,8 +110,8 @@ def conditional_content_removal(request, response):
class ClientHandler(BaseHandler): class ClientHandler(BaseHandler):
""" """
A HTTP Handler that can be used for testing purposes. Uses the WSGI A HTTP Handler that can be used for testing purposes. Use the WSGI
interface to compose requests, but returns the raw HttpResponse object with interface to compose requests, but return the raw HttpResponse object with
the originating WSGIRequest attached to its ``wsgi_request`` attribute. the originating WSGIRequest attached to its ``wsgi_request`` attribute.
""" """
def __init__(self, enforce_csrf_checks=True, *args, **kwargs): def __init__(self, enforce_csrf_checks=True, *args, **kwargs):
@ -146,8 +144,7 @@ class ClientHandler(BaseHandler):
# later retrieved. # later retrieved.
response.wsgi_request = request response.wsgi_request = request
# We're emulating a WSGI server; we must call the close method # Emulate a WSGI server by calling the close method on completion.
# on completion.
if response.streaming: if response.streaming:
response.streaming_content = closing_iterator_wrapper( response.streaming_content = closing_iterator_wrapper(
response.streaming_content, response.close) response.streaming_content, response.close)
@ -161,7 +158,7 @@ class ClientHandler(BaseHandler):
def store_rendered_templates(store, signal, sender, template, context, **kwargs): def store_rendered_templates(store, signal, sender, template, context, **kwargs):
""" """
Stores templates and contexts that are rendered. Store templates and contexts that are rendered.
The context is copied so that it is an accurate representation at the time The context is copied so that it is an accurate representation at the time
of rendering. of rendering.
@ -174,7 +171,7 @@ def store_rendered_templates(store, signal, sender, template, context, **kwargs)
def encode_multipart(boundary, data): def encode_multipart(boundary, data):
""" """
Encodes multipart POST data from a dictionary of form values. Encode multipart POST data from a dictionary of form values.
The key will be used as the form data name; the value will be transmitted The key will be used as the form data name; the value will be transmitted
as content. If the value is a file, the contents of the file will be sent as content. If the value is a file, the contents of the file will be sent
@ -326,8 +323,7 @@ class RequestFactory:
return path.decode('iso-8859-1') return path.decode('iso-8859-1')
def get(self, path, data=None, secure=False, **extra): def get(self, path, data=None, secure=False, **extra):
"Construct a GET request." """Construct a GET request."""
data = {} if data is None else data data = {} if data is None else data
r = { r = {
'QUERY_STRING': urlencode(data, doseq=True), 'QUERY_STRING': urlencode(data, doseq=True),
@ -337,8 +333,7 @@ class RequestFactory:
def post(self, path, data=None, content_type=MULTIPART_CONTENT, def post(self, path, data=None, content_type=MULTIPART_CONTENT,
secure=False, **extra): secure=False, **extra):
"Construct a POST request." """Construct a POST request."""
data = {} if data is None else data data = {} if data is None else data
post_data = self._encode_data(data, content_type) post_data = self._encode_data(data, content_type)
@ -346,8 +341,7 @@ class RequestFactory:
secure=secure, **extra) secure=secure, **extra)
def head(self, path, data=None, secure=False, **extra): def head(self, path, data=None, secure=False, **extra):
"Construct a HEAD request." """Construct a HEAD request."""
data = {} if data is None else data data = {} if data is None else data
r = { r = {
'QUERY_STRING': urlencode(data, doseq=True), 'QUERY_STRING': urlencode(data, doseq=True),
@ -356,7 +350,7 @@ class RequestFactory:
return self.generic('HEAD', path, secure=secure, **r) return self.generic('HEAD', path, secure=secure, **r)
def trace(self, path, secure=False, **extra): def trace(self, path, secure=False, **extra):
"Construct a TRACE request." """Construct a TRACE request."""
return self.generic('TRACE', path, secure=secure, **extra) return self.generic('TRACE', path, secure=secure, **extra)
def options(self, path, data='', content_type='application/octet-stream', def options(self, path, data='', content_type='application/octet-stream',
@ -367,26 +361,26 @@ class RequestFactory:
def put(self, path, data='', content_type='application/octet-stream', def put(self, path, data='', content_type='application/octet-stream',
secure=False, **extra): secure=False, **extra):
"Construct a PUT request." """Construct a PUT request."""
return self.generic('PUT', path, data, content_type, return self.generic('PUT', path, data, content_type,
secure=secure, **extra) secure=secure, **extra)
def patch(self, path, data='', content_type='application/octet-stream', def patch(self, path, data='', content_type='application/octet-stream',
secure=False, **extra): secure=False, **extra):
"Construct a PATCH request." """Construct a PATCH request."""
return self.generic('PATCH', path, data, content_type, return self.generic('PATCH', path, data, content_type,
secure=secure, **extra) secure=secure, **extra)
def delete(self, path, data='', content_type='application/octet-stream', def delete(self, path, data='', content_type='application/octet-stream',
secure=False, **extra): secure=False, **extra):
"Construct a DELETE request." """Construct a DELETE request."""
return self.generic('DELETE', path, data, content_type, return self.generic('DELETE', path, data, content_type,
secure=secure, **extra) secure=secure, **extra)
def generic(self, method, path, data='', def generic(self, method, path, data='',
content_type='application/octet-stream', secure=False, content_type='application/octet-stream', secure=False,
**extra): **extra):
"""Constructs an arbitrary HTTP request.""" """Construct an arbitrary HTTP request."""
parsed = urlparse(str(path)) # path can be lazy parsed = urlparse(str(path)) # path can be lazy
data = force_bytes(data, settings.DEFAULT_CHARSET) data = force_bytes(data, settings.DEFAULT_CHARSET)
r = { r = {
@ -434,16 +428,12 @@ class Client(RequestFactory):
self.exc_info = None self.exc_info = None
def store_exc_info(self, **kwargs): def store_exc_info(self, **kwargs):
""" """Store exceptions when they are generated by a view."""
Stores exceptions when they are generated by a view.
"""
self.exc_info = sys.exc_info() self.exc_info = sys.exc_info()
@property @property
def session(self): def session(self):
""" """Return the current session variables."""
Obtains the current session variables.
"""
engine = import_module(settings.SESSION_ENGINE) engine = import_module(settings.SESSION_ENGINE)
cookie = self.cookies.get(settings.SESSION_COOKIE_NAME) cookie = self.cookies.get(settings.SESSION_COOKIE_NAME)
if cookie: if cookie:
@ -456,10 +446,10 @@ class Client(RequestFactory):
def request(self, **request): def request(self, **request):
""" """
The master request method. Composes the environment dictionary The master request method. Compose the environment dictionary and pass
and passes to the handler, returning the result of the handler. to the handler, return the result of the handler. Assume defaults for
Assumes defaults for the query environment, which can be overridden the query environment, which can be overridden using the arguments to
using the arguments to the request. the request.
""" """
environ = self._base_environ(**request) environ = self._base_environ(**request)
@ -523,9 +513,7 @@ class Client(RequestFactory):
got_request_exception.disconnect(dispatch_uid=exception_uid) got_request_exception.disconnect(dispatch_uid=exception_uid)
def get(self, path, data=None, follow=False, secure=False, **extra): def get(self, path, data=None, follow=False, secure=False, **extra):
""" """Request a response from the server using GET."""
Requests a response from the server using GET.
"""
response = super().get(path, data=data, secure=secure, **extra) response = super().get(path, data=data, secure=secure, **extra)
if follow: if follow:
response = self._handle_redirects(response, **extra) response = self._handle_redirects(response, **extra)
@ -533,18 +521,14 @@ class Client(RequestFactory):
def post(self, path, data=None, content_type=MULTIPART_CONTENT, def post(self, path, data=None, content_type=MULTIPART_CONTENT,
follow=False, secure=False, **extra): follow=False, secure=False, **extra):
""" """Request a response from the server using POST."""
Requests a response from the server using POST.
"""
response = super().post(path, data=data, content_type=content_type, secure=secure, **extra) response = super().post(path, data=data, content_type=content_type, secure=secure, **extra)
if follow: if follow:
response = self._handle_redirects(response, **extra) response = self._handle_redirects(response, **extra)
return response return response
def head(self, path, data=None, follow=False, secure=False, **extra): def head(self, path, data=None, follow=False, secure=False, **extra):
""" """Request a response from the server using HEAD."""
Request a response from the server using HEAD.
"""
response = super().head(path, data=data, secure=secure, **extra) response = super().head(path, data=data, secure=secure, **extra)
if follow: if follow:
response = self._handle_redirects(response, **extra) response = self._handle_redirects(response, **extra)
@ -552,9 +536,7 @@ class Client(RequestFactory):
def options(self, path, data='', content_type='application/octet-stream', def options(self, path, data='', content_type='application/octet-stream',
follow=False, secure=False, **extra): follow=False, secure=False, **extra):
""" """Request a response from the server using OPTIONS."""
Request a response from the server using OPTIONS.
"""
response = super().options(path, data=data, content_type=content_type, secure=secure, **extra) response = super().options(path, data=data, content_type=content_type, secure=secure, **extra)
if follow: if follow:
response = self._handle_redirects(response, **extra) response = self._handle_redirects(response, **extra)
@ -562,9 +544,7 @@ class Client(RequestFactory):
def put(self, path, data='', content_type='application/octet-stream', def put(self, path, data='', content_type='application/octet-stream',
follow=False, secure=False, **extra): follow=False, secure=False, **extra):
""" """Send a resource to the server using PUT."""
Send a resource to the server using PUT.
"""
response = super().put(path, data=data, content_type=content_type, secure=secure, **extra) response = super().put(path, data=data, content_type=content_type, secure=secure, **extra)
if follow: if follow:
response = self._handle_redirects(response, **extra) response = self._handle_redirects(response, **extra)
@ -572,9 +552,7 @@ class Client(RequestFactory):
def patch(self, path, data='', content_type='application/octet-stream', def patch(self, path, data='', content_type='application/octet-stream',
follow=False, secure=False, **extra): follow=False, secure=False, **extra):
""" """Send a resource to the server using PATCH."""
Send a resource to the server using PATCH.
"""
response = super().patch(path, data=data, content_type=content_type, secure=secure, **extra) response = super().patch(path, data=data, content_type=content_type, secure=secure, **extra)
if follow: if follow:
response = self._handle_redirects(response, **extra) response = self._handle_redirects(response, **extra)
@ -582,18 +560,14 @@ class Client(RequestFactory):
def delete(self, path, data='', content_type='application/octet-stream', def delete(self, path, data='', content_type='application/octet-stream',
follow=False, secure=False, **extra): follow=False, secure=False, **extra):
""" """Send a DELETE request to the server."""
Send a DELETE request to the server.
"""
response = super().delete(path, data=data, content_type=content_type, secure=secure, **extra) response = super().delete(path, data=data, content_type=content_type, secure=secure, **extra)
if follow: if follow:
response = self._handle_redirects(response, **extra) response = self._handle_redirects(response, **extra)
return response return response
def trace(self, path, data='', follow=False, secure=False, **extra): def trace(self, path, data='', follow=False, secure=False, **extra):
""" """Send a TRACE request to the server."""
Send a TRACE request to the server.
"""
response = super().trace(path, data=data, secure=secure, **extra) response = super().trace(path, data=data, secure=secure, **extra)
if follow: if follow:
response = self._handle_redirects(response, **extra) response = self._handle_redirects(response, **extra)
@ -601,9 +575,9 @@ class Client(RequestFactory):
def login(self, **credentials): def login(self, **credentials):
""" """
Sets the Factory to appear as if it has successfully logged into a site. Set the Factory to appear as if it has successfully logged into a site.
Returns True if login is possible; False if the provided credentials Return True if login is possible; False if the provided credentials
are incorrect. are incorrect.
""" """
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
@ -655,11 +629,7 @@ class Client(RequestFactory):
self.cookies[session_cookie].update(cookie_data) self.cookies[session_cookie].update(cookie_data)
def logout(self): def logout(self):
""" """Log out the user by removing the cookies and session object."""
Removes the authenticated user's cookies and session object.
Causes the authenticated user to be logged out.
"""
from django.contrib.auth import get_user, logout from django.contrib.auth import get_user, logout
request = HttpRequest() request = HttpRequest()
@ -683,8 +653,9 @@ class Client(RequestFactory):
return response._json return response._json
def _handle_redirects(self, response, **extra): def _handle_redirects(self, response, **extra):
"Follows any redirects by requesting responses from the server using GET." """
Follow any redirects by requesting responses from the server using GET.
"""
response.redirect_chain = [] response.redirect_chain = []
while response.status_code in (301, 302, 303, 307): while response.status_code in (301, 302, 303, 307):
response_url = response.url response_url = response.url

View File

@ -1,6 +1,4 @@
""" """Compare two HTML documents."""
Comparing two html documents.
"""
import re import re
@ -214,7 +212,7 @@ class Parser(HTMLParser):
def parse_html(html): def parse_html(html):
""" """
Takes a string that contains *valid* HTML and turns it into a Python object Take a string that contains *valid* HTML and turn it into a Python object
structure that can be easily compared against other HTML on semantic structure that can be easily compared against other HTML on semantic
equivalence. Syntactical differences like which quotation is used on equivalence. Syntactical differences like which quotation is used on
arguments will be ignored. arguments will be ignored.

View File

@ -253,9 +253,7 @@ class RemoteTestRunner:
def default_test_processes(): def default_test_processes():
""" """Default number of test processes when using the --parallel option."""
Default number of test processes when using the --parallel option.
"""
# The current implementation of the parallel test runner requires # The current implementation of the parallel test runner requires
# multiprocessing to start subprocesses with fork(). # multiprocessing to start subprocesses with fork().
if multiprocessing.get_start_method() != 'fork': if multiprocessing.get_start_method() != 'fork':
@ -389,9 +387,7 @@ class ParallelTestSuite(unittest.TestSuite):
class DiscoverRunner: class DiscoverRunner:
""" """A Django test runner that uses unittest2 test discovery."""
A Django test runner that uses unittest2 test discovery.
"""
test_suite = unittest.TestSuite test_suite = unittest.TestSuite
parallel_test_suite = ParallelTestSuite parallel_test_suite = ParallelTestSuite
@ -566,9 +562,7 @@ class DiscoverRunner:
return runner.run(suite) return runner.run(suite)
def teardown_databases(self, old_config, **kwargs): def teardown_databases(self, old_config, **kwargs):
""" """Destroy all the non-mirror databases."""
Destroys all the non-mirror databases.
"""
_teardown_databases( _teardown_databases(
old_config, old_config,
verbosity=self.verbosity, verbosity=self.verbosity,
@ -593,7 +587,7 @@ class DiscoverRunner:
A list of 'extra' tests may also be provided; these tests A list of 'extra' tests may also be provided; these tests
will be added to the test suite. will be added to the test suite.
Returns the number of tests that failed. Return the number of tests that failed.
""" """
self.setup_test_environment() self.setup_test_environment()
suite = self.build_suite(test_labels, extra_tests) suite = self.build_suite(test_labels, extra_tests)
@ -623,15 +617,15 @@ def is_discoverable(label):
def reorder_suite(suite, classes, reverse=False): def reorder_suite(suite, classes, reverse=False):
""" """
Reorders a test suite by test type. Reorder a test suite by test type.
`classes` is a sequence of types `classes` is a sequence of types
All tests of type classes[0] are placed first, then tests of type All tests of type classes[0] are placed first, then tests of type
classes[1], etc. Tests with no match in classes are placed last. classes[1], etc. Tests with no match in classes are placed last.
If `reverse` is True, tests within classes are sorted in opposite order, If `reverse` is True, sort tests within classes in opposite order but
but test classes are not reversed. don't reverse test classes.
""" """
class_count = len(classes) class_count = len(classes)
suite_class = type(suite) suite_class = type(suite)
@ -645,7 +639,7 @@ def reorder_suite(suite, classes, reverse=False):
def partition_suite_by_type(suite, classes, bins, reverse=False): def partition_suite_by_type(suite, classes, bins, reverse=False):
""" """
Partitions a test suite by test type. Also prevents duplicated tests. Partition a test suite by test type. Also prevent duplicated tests.
classes is a sequence of types classes is a sequence of types
bins is a sequence of TestSuites, one more than classes bins is a sequence of TestSuites, one more than classes
@ -670,9 +664,7 @@ def partition_suite_by_type(suite, classes, bins, reverse=False):
def partition_suite_by_case(suite): def partition_suite_by_case(suite):
""" """Partition a test suite by test case, preserving the order of tests."""
Partitions a test suite by test case, preserving the order of tests.
"""
groups = [] groups = []
suite_class = type(suite) suite_class = type(suite)
for test_type, test_group in itertools.groupby(suite, type): for test_type, test_group in itertools.groupby(suite, type):

View File

@ -73,7 +73,7 @@ class SeleniumTestCase(LiveServerTestCase, metaclass=SeleniumTestCaseBase):
@contextmanager @contextmanager
def disable_implicit_wait(self): def disable_implicit_wait(self):
"""Context manager that disables the default implicit wait.""" """Disable the default implicit wait."""
self.selenium.implicitly_wait(0) self.selenium.implicitly_wait(0)
try: try:
yield yield

View File

@ -43,8 +43,8 @@ __all__ = ('TestCase', 'TransactionTestCase',
def to_list(value): def to_list(value):
""" """
Puts value into a list if it's not already one. Put value into a list if it's not already one. Return an empty list if
Returns an empty list if value is None. value is None.
""" """
if value is None: if value is None:
value = [] value = []
@ -212,21 +212,22 @@ class SimpleTestCase(unittest.TestCase):
return return
def _pre_setup(self): def _pre_setup(self):
"""Performs any pre-test setup. This includes: """
Perform pre-test setup:
* Creating a test client. * Create a test client.
* Clearing the mail test outbox. * Clear the mail test outbox.
""" """
self.client = self.client_class() self.client = self.client_class()
mail.outbox = [] mail.outbox = []
def _post_teardown(self): def _post_teardown(self):
"""Perform any post-test things.""" """Perform post-test things."""
pass pass
def settings(self, **kwargs): def settings(self, **kwargs):
""" """
A context manager that temporarily sets a setting and reverts to the original value when exiting the context. A context manager that temporarily sets a setting and reverts to the
original value when exiting the context.
""" """
return override_settings(**kwargs) return override_settings(**kwargs)
@ -240,12 +241,13 @@ class SimpleTestCase(unittest.TestCase):
def assertRedirects(self, response, expected_url, status_code=302, def assertRedirects(self, response, expected_url, status_code=302,
target_status_code=200, msg_prefix='', target_status_code=200, msg_prefix='',
fetch_redirect_response=True): fetch_redirect_response=True):
"""Asserts that a response redirected to a specific URL, and that the """
Assert that a response redirected to a specific URL and that the
redirect URL can be loaded. redirect URL can be loaded.
Note that assertRedirects won't work for external links since it uses Won't work for external links since it uses TestClient to do a request
TestClient to do a request (use fetch_redirect_response=False to check (use fetch_redirect_response=False to check such links without fetching
such links without fetching them). them).
""" """
if msg_prefix: if msg_prefix:
msg_prefix += ": " msg_prefix += ": "
@ -349,8 +351,8 @@ class SimpleTestCase(unittest.TestCase):
def assertContains(self, response, text, count=None, status_code=200, msg_prefix='', html=False): def assertContains(self, response, text, count=None, status_code=200, msg_prefix='', html=False):
""" """
Asserts that a response indicates that some content was retrieved Assert that a response indicates that some content was retrieved
successfully, (i.e., the HTTP status code was as expected), and that successfully, (i.e., the HTTP status code was as expected) and that
``text`` occurs ``count`` times in the content of the response. ``text`` occurs ``count`` times in the content of the response.
If ``count`` is None, the count doesn't matter - the assertion is true If ``count`` is None, the count doesn't matter - the assertion is true
if the text occurs at least once in the response. if the text occurs at least once in the response.
@ -368,8 +370,8 @@ class SimpleTestCase(unittest.TestCase):
def assertNotContains(self, response, text, status_code=200, msg_prefix='', html=False): def assertNotContains(self, response, text, status_code=200, msg_prefix='', html=False):
""" """
Asserts that a response indicates that some content was retrieved Assert that a response indicates that some content was retrieved
successfully, (i.e., the HTTP status code was as expected), and that successfully, (i.e., the HTTP status code was as expected) and that
``text`` doesn't occurs in the content of the response. ``text`` doesn't occurs in the content of the response.
""" """
text_repr, real_count, msg_prefix = self._assert_contains( text_repr, real_count, msg_prefix = self._assert_contains(
@ -379,7 +381,7 @@ class SimpleTestCase(unittest.TestCase):
def assertFormError(self, response, form, field, errors, msg_prefix=''): def assertFormError(self, response, form, field, errors, msg_prefix=''):
""" """
Asserts that a form used to render the response has a specific field Assert that a form used to render the response has a specific field
error. error.
""" """
if msg_prefix: if msg_prefix:
@ -435,7 +437,7 @@ class SimpleTestCase(unittest.TestCase):
def assertFormsetError(self, response, formset, form_index, field, errors, def assertFormsetError(self, response, formset, form_index, field, errors,
msg_prefix=''): msg_prefix=''):
""" """
Asserts that a formset used to render the response has a specific error. Assert that a formset used to render the response has a specific error.
For field errors, specify the ``form_index`` and the ``field``. For field errors, specify the ``form_index`` and the ``field``.
For non-field errors, specify the ``form_index`` and the ``field`` as For non-field errors, specify the ``form_index`` and the ``field`` as
@ -538,7 +540,7 @@ class SimpleTestCase(unittest.TestCase):
def assertTemplateUsed(self, response=None, template_name=None, msg_prefix='', count=None): def assertTemplateUsed(self, response=None, template_name=None, msg_prefix='', count=None):
""" """
Asserts that the template with the provided name was used in rendering Assert that the template with the provided name was used in rendering
the response. Also usable as context manager. the response. Also usable as context manager.
""" """
context_mgr_template, template_names, msg_prefix = self._assert_template_used( context_mgr_template, template_names, msg_prefix = self._assert_template_used(
@ -567,7 +569,7 @@ class SimpleTestCase(unittest.TestCase):
def assertTemplateNotUsed(self, response=None, template_name=None, msg_prefix=''): def assertTemplateNotUsed(self, response=None, template_name=None, msg_prefix=''):
""" """
Asserts that the template with the provided name was NOT used in Assert that the template with the provided name was NOT used in
rendering the response. Also usable as context manager. rendering the response. Also usable as context manager.
""" """
context_mgr_template, template_names, msg_prefix = self._assert_template_used( context_mgr_template, template_names, msg_prefix = self._assert_template_used(
@ -590,7 +592,7 @@ class SimpleTestCase(unittest.TestCase):
def assertRaisesMessage(self, expected_exception, expected_message, *args, **kwargs): def assertRaisesMessage(self, expected_exception, expected_message, *args, **kwargs):
""" """
Asserts that expected_message is found in the the message of a raised Assert that expected_message is found in the the message of a raised
exception. exception.
Args: Args:
@ -615,7 +617,7 @@ class SimpleTestCase(unittest.TestCase):
def assertFieldOutput(self, fieldclass, valid, invalid, field_args=None, def assertFieldOutput(self, fieldclass, valid, invalid, field_args=None,
field_kwargs=None, empty_value=''): field_kwargs=None, empty_value=''):
""" """
Asserts that a form field behaves correctly with various inputs. Assert that a form field behaves correctly with various inputs.
Args: Args:
fieldclass: the class of the field to be tested. fieldclass: the class of the field to be tested.
@ -660,9 +662,9 @@ class SimpleTestCase(unittest.TestCase):
def assertHTMLEqual(self, html1, html2, msg=None): def assertHTMLEqual(self, html1, html2, msg=None):
""" """
Asserts that two HTML snippets are semantically the same. Assert that two HTML snippets are semantically the same.
Whitespace in most cases is ignored, and attribute ordering is not Whitespace in most cases is ignored, and attribute ordering is not
significant. The passed-in arguments must be valid HTML. significant. The arguments must be valid HTML.
""" """
dom1 = assert_and_parse_html(self, html1, msg, 'First argument is not valid HTML:') dom1 = assert_and_parse_html(self, html1, msg, 'First argument is not valid HTML:')
dom2 = assert_and_parse_html(self, html2, msg, 'Second argument is not valid HTML:') dom2 = assert_and_parse_html(self, html2, msg, 'Second argument is not valid HTML:')
@ -677,7 +679,7 @@ class SimpleTestCase(unittest.TestCase):
self.fail(self._formatMessage(msg, standardMsg)) self.fail(self._formatMessage(msg, standardMsg))
def assertHTMLNotEqual(self, html1, html2, msg=None): def assertHTMLNotEqual(self, html1, html2, msg=None):
"""Asserts that two HTML snippets are not semantically equivalent.""" """Assert that two HTML snippets are not semantically equivalent."""
dom1 = assert_and_parse_html(self, html1, msg, 'First argument is not valid HTML:') dom1 = assert_and_parse_html(self, html1, msg, 'First argument is not valid HTML:')
dom2 = assert_and_parse_html(self, html2, msg, 'Second argument is not valid HTML:') dom2 = assert_and_parse_html(self, html2, msg, 'Second argument is not valid HTML:')
@ -700,7 +702,7 @@ class SimpleTestCase(unittest.TestCase):
def assertJSONEqual(self, raw, expected_data, msg=None): def assertJSONEqual(self, raw, expected_data, msg=None):
""" """
Asserts that the JSON fragments raw and expected_data are equal. Assert that the JSON fragments raw and expected_data are equal.
Usual JSON non-significant whitespace rules apply as the heavyweight Usual JSON non-significant whitespace rules apply as the heavyweight
is delegated to the json library. is delegated to the json library.
""" """
@ -717,7 +719,7 @@ class SimpleTestCase(unittest.TestCase):
def assertJSONNotEqual(self, raw, expected_data, msg=None): def assertJSONNotEqual(self, raw, expected_data, msg=None):
""" """
Asserts that the JSON fragments raw and expected_data are not equal. Assert that the JSON fragments raw and expected_data are not equal.
Usual JSON non-significant whitespace rules apply as the heavyweight Usual JSON non-significant whitespace rules apply as the heavyweight
is delegated to the json library. is delegated to the json library.
""" """
@ -734,9 +736,9 @@ class SimpleTestCase(unittest.TestCase):
def assertXMLEqual(self, xml1, xml2, msg=None): def assertXMLEqual(self, xml1, xml2, msg=None):
""" """
Asserts that two XML snippets are semantically the same. Assert that two XML snippets are semantically the same.
Whitespace in most cases is ignored, and attribute ordering is not Whitespace in most cases is ignored and attribute ordering is not
significant. The passed-in arguments must be valid XML. significant. The arguments must be valid XML.
""" """
try: try:
result = compare_xml(xml1, xml2) result = compare_xml(xml1, xml2)
@ -754,9 +756,9 @@ class SimpleTestCase(unittest.TestCase):
def assertXMLNotEqual(self, xml1, xml2, msg=None): def assertXMLNotEqual(self, xml1, xml2, msg=None):
""" """
Asserts that two XML snippets are not semantically equivalent. Assert that two XML snippets are not semantically equivalent.
Whitespace in most cases is ignored, and attribute ordering is not Whitespace in most cases is ignored and attribute ordering is not
significant. The passed-in arguments must be valid XML. significant. The arguments must be valid XML.
""" """
try: try:
result = compare_xml(xml1, xml2) result = compare_xml(xml1, xml2)
@ -795,12 +797,12 @@ class TransactionTestCase(SimpleTestCase):
allow_database_queries = True allow_database_queries = True
def _pre_setup(self): def _pre_setup(self):
"""Performs any pre-test setup. This includes: """
Perform pre-test setup:
* If the class has an 'available_apps' attribute, restricting the app * If the class has an 'available_apps' attribute, restrict the app
registry to these applications, then firing post_migrate -- it must registry to these applications, then fire the post_migrate signal --
run with the correct set of applications for the test case. it must run with the correct set of applications for the test case.
* If the class has a 'fixtures' attribute, installing these fixtures. * If the class has a 'fixtures' attribute, install those fixtures.
""" """
super()._pre_setup() super()._pre_setup()
if self.available_apps is not None: if self.available_apps is not None:
@ -876,11 +878,11 @@ class TransactionTestCase(SimpleTestCase):
return True return True
def _post_teardown(self): def _post_teardown(self):
"""Performs any post-test things. This includes: """
Perform post-test things:
* Flushing the contents of the database, to leave a clean slate. If * Flush the contents of the database to leave a clean slate. If the
the class has an 'available_apps' attribute, post_migrate isn't fired. class has an 'available_apps' attribute, don't fire post_migrate.
* Force-closing the connection, so the next test gets a clean cursor. * Force-close the connection so the next test gets a clean cursor.
""" """
try: try:
self._fixture_teardown() self._fixture_teardown()
@ -944,16 +946,13 @@ class TransactionTestCase(SimpleTestCase):
def connections_support_transactions(): def connections_support_transactions():
""" """Return True if all connections support transactions."""
Returns True if all connections support transactions. return all(conn.features.supports_transactions for conn in connections.all())
"""
return all(conn.features.supports_transactions
for conn in connections.all())
class TestCase(TransactionTestCase): class TestCase(TransactionTestCase):
""" """
Similar to TransactionTestCase, but uses `transaction.atomic()` to achieve Similar to TransactionTestCase, but use `transaction.atomic()` to achieve
test isolation. test isolation.
In most situations, TestCase should be preferred to TransactionTestCase as In most situations, TestCase should be preferred to TransactionTestCase as
@ -966,7 +965,7 @@ class TestCase(TransactionTestCase):
""" """
@classmethod @classmethod
def _enter_atomics(cls): def _enter_atomics(cls):
"""Helper method to open atomic blocks for multiple databases""" """Open atomic blocks for multiple databases."""
atomics = {} atomics = {}
for db_name in cls._databases_names(): for db_name in cls._databases_names():
atomics[db_name] = transaction.atomic(using=db_name) atomics[db_name] = transaction.atomic(using=db_name)
@ -975,7 +974,7 @@ class TestCase(TransactionTestCase):
@classmethod @classmethod
def _rollback_atomics(cls, atomics): def _rollback_atomics(cls, atomics):
"""Rollback atomic blocks opened through the previous method""" """Rollback atomic blocks opened by the previous method."""
for db_name in reversed(cls._databases_names()): for db_name in reversed(cls._databases_names()):
transaction.set_rollback(True, using=db_name) transaction.set_rollback(True, using=db_name)
atomics[db_name].__exit__(None, None, None) atomics[db_name].__exit__(None, None, None)
@ -1014,7 +1013,7 @@ class TestCase(TransactionTestCase):
@classmethod @classmethod
def setUpTestData(cls): def setUpTestData(cls):
"""Load initial data for the TestCase""" """Load initial data for the TestCase."""
pass pass
def _should_reload_connections(self): def _should_reload_connections(self):
@ -1050,7 +1049,7 @@ class TestCase(TransactionTestCase):
class CheckCondition: class CheckCondition:
"""Descriptor class for deferred condition checking""" """Descriptor class for deferred condition checking."""
def __init__(self, *conditions): def __init__(self, *conditions):
self.conditions = conditions self.conditions = conditions
@ -1095,9 +1094,7 @@ def _deferredSkip(condition, reason):
def skipIfDBFeature(*features): def skipIfDBFeature(*features):
""" """Skip a test if a database has at least one of the named features."""
Skip a test if a database has at least one of the named features.
"""
return _deferredSkip( return _deferredSkip(
lambda: any(getattr(connection.features, feature, False) for feature in features), lambda: any(getattr(connection.features, feature, False) for feature in features),
"Database has feature(s) %s" % ", ".join(features) "Database has feature(s) %s" % ", ".join(features)
@ -1105,9 +1102,7 @@ def skipIfDBFeature(*features):
def skipUnlessDBFeature(*features): def skipUnlessDBFeature(*features):
""" """Skip a test unless a database has all the named features."""
Skip a test unless a database has all the named features.
"""
return _deferredSkip( return _deferredSkip(
lambda: not all(getattr(connection.features, feature, False) for feature in features), lambda: not all(getattr(connection.features, feature, False) for feature in features),
"Database doesn't support feature(s): %s" % ", ".join(features) "Database doesn't support feature(s): %s" % ", ".join(features)
@ -1115,9 +1110,7 @@ def skipUnlessDBFeature(*features):
def skipUnlessAnyDBFeature(*features): def skipUnlessAnyDBFeature(*features):
""" """Skip a test unless a database has any of the named features."""
Skip a test unless a database has any of the named features.
"""
return _deferredSkip( return _deferredSkip(
lambda: not any(getattr(connection.features, feature, False) for feature in features), lambda: not any(getattr(connection.features, feature, False) for feature in features),
"Database doesn't support any of the feature(s): %s" % ", ".join(features) "Database doesn't support any of the feature(s): %s" % ", ".join(features)
@ -1126,11 +1119,9 @@ def skipUnlessAnyDBFeature(*features):
class QuietWSGIRequestHandler(WSGIRequestHandler): class QuietWSGIRequestHandler(WSGIRequestHandler):
""" """
Just a regular WSGIRequestHandler except it doesn't log to the standard A WSGIRequestHandler that doesn't log to standard output any of the
output any of the requests received, so as to not clutter the output for requests received, so as to not clutter the test result output.
the tests' results.
""" """
def log_message(*args): def log_message(*args):
pass pass
@ -1147,17 +1138,14 @@ class FSFilesHandler(WSGIHandler):
def _should_handle(self, path): def _should_handle(self, path):
""" """
Checks if the path should be handled. Ignores the path if: Check if the path should be handled. Ignore the path if:
* the host is provided as part of the base_url * the host is provided as part of the base_url
* the request's path isn't under the media path (or equal) * the request's path isn't under the media path (or equal)
""" """
return path.startswith(self.base_url[2]) and not self.base_url[1] return path.startswith(self.base_url[2]) and not self.base_url[1]
def file_path(self, url): def file_path(self, url):
""" """Return the relative path to the file on disk for the given URL."""
Returns the relative path to the file on disk for the given URL.
"""
relative_url = url[len(self.base_url[2]):] relative_url = url[len(self.base_url[2]):]
return url2pathname(relative_url) return url2pathname(relative_url)
@ -1191,7 +1179,6 @@ class _StaticFilesHandler(FSFilesHandler):
Handler for serving static files. A private class that is meant to be used Handler for serving static files. A private class that is meant to be used
solely as a convenience by LiveServerThread. solely as a convenience by LiveServerThread.
""" """
def get_base_dir(self): def get_base_dir(self):
return settings.STATIC_ROOT return settings.STATIC_ROOT
@ -1204,7 +1191,6 @@ class _MediaFilesHandler(FSFilesHandler):
Handler for serving the media files. A private class that is meant to be Handler for serving the media files. A private class that is meant to be
used solely as a convenience by LiveServerThread. used solely as a convenience by LiveServerThread.
""" """
def get_base_dir(self): def get_base_dir(self):
return settings.MEDIA_ROOT return settings.MEDIA_ROOT
@ -1213,9 +1199,7 @@ class _MediaFilesHandler(FSFilesHandler):
class LiveServerThread(threading.Thread): class LiveServerThread(threading.Thread):
""" """Thread for running a live http server while the tests are running."""
Thread for running a live http server while the tests are running.
"""
def __init__(self, host, static_handler, connections_override=None): def __init__(self, host, static_handler, connections_override=None):
self.host = host self.host = host
@ -1228,8 +1212,8 @@ class LiveServerThread(threading.Thread):
def run(self): def run(self):
""" """
Sets up the live server and databases, and then loops over handling Set up the live server and databases, and then loop over handling
http requests. HTTP requests.
""" """
if self.connections_override: if self.connections_override:
# Override this thread's database connections with the ones # Override this thread's database connections with the ones
@ -1263,14 +1247,14 @@ class LiveServerThread(threading.Thread):
class LiveServerTestCase(TransactionTestCase): class LiveServerTestCase(TransactionTestCase):
""" """
Does basically the same as TransactionTestCase but also launches a live Do basically the same as TransactionTestCase but also launch a live HTTP
http server in a separate thread so that the tests may use another testing server in a separate thread so that the tests may use another testing
framework, such as Selenium for example, instead of the built-in dummy framework, such as Selenium for example, instead of the built-in dummy
client. client.
Note that it inherits from TransactionTestCase instead of TestCase because It inherits from TransactionTestCase instead of TestCase because the
the threads do not share the same transactions (unless if using in-memory threads don't share the same transactions (unless if using in-memory sqlite)
sqlite) and each thread needs to commit all their transactions so that the and each thread needs to commit all their transactions so that the other
other thread can see the changes. thread can see the changes.
""" """
host = 'localhost' host = 'localhost'
server_thread_class = LiveServerThread server_thread_class = LiveServerThread
@ -1338,14 +1322,13 @@ class LiveServerTestCase(TransactionTestCase):
class SerializeMixin: class SerializeMixin:
""" """
Mixin to enforce serialization of TestCases that share a common resource. Enforce serialization of TestCases that share a common resource.
Define a common 'lockfile' for each set of TestCases to serialize. This Define a common 'lockfile' for each set of TestCases to serialize. This
file must exist on the filesystem. file must exist on the filesystem.
Place it early in the MRO in order to isolate setUpClass / tearDownClass. Place it early in the MRO in order to isolate setUpClass()/tearDownClass().
""" """
lockfile = None lockfile = None
@classmethod @classmethod

View File

@ -55,7 +55,8 @@ class Approximate:
class ContextList(list): class ContextList(list):
"""A wrapper that provides direct key access to context items contained """
A wrapper that provides direct key access to context items contained
in a list of context objects. in a list of context objects.
""" """
def __getitem__(self, key): def __getitem__(self, key):
@ -93,8 +94,8 @@ class ContextList(list):
def instrumented_test_render(self, context): def instrumented_test_render(self, context):
""" """
An instrumented Template render method, providing a signal An instrumented Template render method, providing a signal that can be
that can be intercepted by the test system Client intercepted by the test Client.
""" """
template_rendered.send(sender=self, template=self, context=context) template_rendered.send(sender=self, template=self, context=context)
return self.nodelist.render(context) return self.nodelist.render(context)
@ -157,9 +158,7 @@ def teardown_test_environment():
def setup_databases(verbosity, interactive, keepdb=False, debug_sql=False, parallel=0, **kwargs): def setup_databases(verbosity, interactive, keepdb=False, debug_sql=False, parallel=0, **kwargs):
""" """Create the test databases."""
Create the test databases.
"""
test_databases, mirrored_aliases = get_unique_databases_and_mirrors() test_databases, mirrored_aliases = get_unique_databases_and_mirrors()
old_names = [] old_names = []
@ -290,9 +289,7 @@ def get_unique_databases_and_mirrors():
def teardown_databases(old_config, verbosity, parallel=0, keepdb=False): def teardown_databases(old_config, verbosity, parallel=0, keepdb=False):
""" """Destroy all the non-mirror databases."""
Destroy all the non-mirror databases.
"""
for connection, old_name, destroy in old_config: for connection, old_name, destroy in old_config:
if destroy: if destroy:
if parallel > 1: if parallel > 1:
@ -387,10 +384,10 @@ class TestContextDecorator:
class override_settings(TestContextDecorator): class override_settings(TestContextDecorator):
""" """
Acts as either a decorator or a context manager. If it's a decorator it Act as either a decorator or a context manager. If it's a decorator, take a
takes a function and returns a wrapped function. If it's a contextmanager function and return a wrapped function. If it's a contextmanager, use it
it's used with the ``with`` statement. In either event entering/exiting with the ``with`` statement. In either event, entering/exiting are called
are called before and after, respectively, the function/block is executed. before and after, respectively, the function/block is executed.
""" """
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.options = kwargs self.options = kwargs
@ -444,7 +441,7 @@ class override_settings(TestContextDecorator):
class modify_settings(override_settings): class modify_settings(override_settings):
""" """
Like override_settings, but makes it possible to append, prepend or remove Like override_settings, but makes it possible to append, prepend, or remove
items instead of redefining the entire list. items instead of redefining the entire list.
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -492,7 +489,7 @@ class modify_settings(override_settings):
class override_system_checks(TestContextDecorator): class override_system_checks(TestContextDecorator):
""" """
Acts as a decorator. Overrides list of registered system checks. Act as a decorator. Override list of registered system checks.
Useful when you override `INSTALLED_APPS`, e.g. if you exclude `auth` app, Useful when you override `INSTALLED_APPS`, e.g. if you exclude `auth` app,
you also need to exclude its system checks. you also need to exclude its system checks.
""" """
@ -516,10 +513,10 @@ class override_system_checks(TestContextDecorator):
def compare_xml(want, got): def compare_xml(want, got):
"""Tries to do a 'xml-comparison' of want and got. Plain string """
comparison doesn't always work because, for example, attribute Try to do a 'xml-comparison' of want and got. Plain string comparison
ordering should not be important. Comment nodes are not considered in the doesn't always work because, for example, attribute ordering should not be
comparison. Leading and trailing whitespace is ignored on both chunks. important. Ignore comment nodes and leading and trailing whitespace.
Based on https://github.com/lxml/lxml/blob/master/src/lxml/doctestcompare.py Based on https://github.com/lxml/lxml/blob/master/src/lxml/doctestcompare.py
""" """
@ -794,9 +791,7 @@ def require_jinja2(test_func):
class override_script_prefix(TestContextDecorator): class override_script_prefix(TestContextDecorator):
""" """Decorator or context manager to temporary override the script prefix."""
Decorator or context manager to temporary override the script prefix.
"""
def __init__(self, prefix): def __init__(self, prefix):
self.prefix = prefix self.prefix = prefix
super().__init__() super().__init__()
@ -840,7 +835,6 @@ class isolate_apps(TestContextDecorator):
`kwarg_name`: keyword argument passing the isolated registry if used as a `kwarg_name`: keyword argument passing the isolated registry if used as a
function decorator. function decorator.
""" """
def __init__(self, *installed_apps, **kwargs): def __init__(self, *installed_apps, **kwargs):
self.installed_apps = installed_apps self.installed_apps = installed_apps
super().__init__(**kwargs) super().__init__(**kwargs)
@ -856,9 +850,7 @@ class isolate_apps(TestContextDecorator):
def tag(*tags): def tag(*tags):
""" """Decorator to add tags to a test class or method."""
Decorator to add tags to a test class or method.
"""
def decorator(obj): def decorator(obj):
setattr(obj, 'tags', set(tags)) setattr(obj, 'tags', set(tags))
return obj return obj