from __future__ import unicode_literals
from future.builtins import open, range, str
from _ast import PyCF_ONLY_AST
import os
from shutil import copyfile, copytree
from django.contrib.auth import get_user_model
from django.db import connection
from django.template import Context, Template
from django.test import TestCase as BaseTestCase
from django.test.client import RequestFactory
from mezzanine.conf import settings
from mezzanine.utils.importing import path_for_import
# Ignore these warnings in pyflakes - if added to, please comment why.
IGNORE_ERRORS = (
# Used to version subpackages.
".__version__' imported but unused",
# No caching fallback.
"redefinition of function 'nevercache'",
# Dummy fallback in templates for django-compressor.
"redefinition of function 'compress'",
# Fabic config fallback.
"redefinition of unused 'conf'",
# Fixing these would make the code ugiler IMO.
"continuation line",
"closing bracket does not match",
# Jython compatiblity.
"redefinition of unused 'Image",
# Django custom user compatibility.
"'get_user_model' imported but unused",
# lambdas are OK.
"do not assign a lambda",
# checks modules need to be imported to register check functions, they will
# be run by Django.
"'.checks' imported but unused"
)
[docs]class TestCase(BaseTestCase):
"""
This is the base test case providing common features for all tests
across the different apps in Mezzanine.
"""
[docs] def setUp(self):
"""
Creates an admin user, sets up the debug cursor, so that we can
track the number of queries used in various places, and creates
a request factory for views testing.
"""
self._username = "test"
self._password = "test"
self._emailaddress = "example@example.com"
args = (self._username, self._emailaddress, self._password)
self._user = get_user_model().objects.create_superuser(*args)
self._request_factory = RequestFactory()
self._debug_cursor = connection.force_debug_cursor
connection.force_debug_cursor = True
[docs] def tearDown(self):
"""
Clean up the admin user created and debug cursor.
"""
self._user.delete()
connection.force_debug_cursor = self._debug_cursor
[docs] def queries_used_for_template(self, template, **context):
"""
Return the number of queries used when rendering a template
string.
"""
connection.queries_log.clear()
t = Template(template)
t.render(Context(context))
return len(connection.queries)
[docs] def create_recursive_objects(self, model, parent_field, **kwargs):
"""
Create multiple levels of recursive objects.
"""
per_level = list(range(3))
for _ in per_level:
kwargs[parent_field] = None
level1 = model.objects.create(**kwargs)
for _ in per_level:
kwargs[parent_field] = level1
level2 = model.objects.create(**kwargs)
for _ in per_level:
kwargs[parent_field] = level2
model.objects.create(**kwargs)
def _run_checker_for_package(checker, package_name, extra_ignore=None):
"""
Runs the checker function across every Python module in the
given package.
"""
ignore_strings = IGNORE_ERRORS
if extra_ignore:
ignore_strings += extra_ignore
package_path = path_for_import(package_name)
for (root, dirs, files) in os.walk(str(package_path)):
for f in files:
if (f == "local_settings.py" or not f.endswith(".py") or
root.split(os.sep)[-1] in ["migrations"]):
# Ignore
continue
for warning in checker(os.path.join(root, f)):
for ignore in ignore_strings:
if ignore in warning:
break
else:
yield warning.replace(package_path, package_name, 1)
[docs]def run_pyflakes_for_package(package_name, extra_ignore=None):
"""
If pyflakes is installed, run it across the given package name
returning any warnings found.
"""
from pyflakes.checker import Checker
def pyflakes_checker(path):
with open(path, "U") as source_file:
source = source_file.read()
try:
tree = compile(source, path, "exec", PyCF_ONLY_AST)
except (SyntaxError, IndentationError) as value:
info = (path, value.lineno, value.args[0])
yield "Invalid syntax in %s:%d: %s" % info
else:
result = Checker(tree, path)
for warning in result.messages:
yield str(warning)
args = (pyflakes_checker, package_name, extra_ignore)
return _run_checker_for_package(*args)
[docs]def run_pep8_for_package(package_name, extra_ignore=None):
"""
If pep8 is installed, run it across the given package name
returning any warnings or errors found.
"""
import pep8
class Checker(pep8.Checker):
"""
Subclass pep8's Checker to hook into error reporting.
"""
def __init__(self, *args, **kwargs):
super(Checker, self).__init__(*args, **kwargs)
self.report_error = self._report_error
def _report_error(self, line_number, offset, text, check):
"""
Store pairs of line numbers and errors.
"""
self.errors.append((line_number, text.split(" ", 1)[1]))
def check_all(self, *args, **kwargs):
"""
Assign the errors attribute and return it after running.
"""
self.errors = []
super(Checker, self).check_all(*args, **kwargs)
return self.errors
style_guide = pep8.StyleGuide(config_file="setup.cfg")
def pep8_checker(path):
for line_number, text in Checker(path,
options=style_guide.options).check_all():
yield "%s:%s: %s" % (path, line_number, text)
args = (pep8_checker, package_name, extra_ignore)
return _run_checker_for_package(*args)