diff --git a/.gitignore b/.gitignore index 33defe4..fe2cebe 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,6 @@ .tox/ +/.coverage +/.idea +db.sqlite +__pycache__ +/django_mobile.egg-info diff --git a/README.rst b/README.rst index 289705e..bc0600c 100644 --- a/README.rst +++ b/README.rst @@ -43,8 +43,6 @@ is enabled and working. 6. Add ``django_mobile.context_processors.flavour`` to your ``context_processors`` list for ``TEMPLATES`` setting. You can read more about ``loaders`` and ``context_processors`` in `Django docs`_. -*Note:* If you are using Django 1.7 or older, you need to change step 5 and 6 slightly. Use the ``TEMPLATE_LOADERS`` and ``TEMPLATE_CONTEXT_PROCESSORS`` settings instead of ``TEMPLATES``. - Now you should be able to use **django-mobile** in its glory. Read below of how things work and which settings can be tweaked to modify **django-mobile**'s behaviour. @@ -99,8 +97,7 @@ This will add ``(mobile version)`` to the title of your site if viewed with the mobile flavour enabled. *Note:* The ``flavour`` template variable is only available if you have set up the -``django_mobile.context_processors.flavour`` context processor and used -django's ``RequestContext`` as context instance to render the template. +``django_mobile.context_processors.flavour`` context processor. Changing the current flavour ---------------------------- diff --git a/django_mobile/__init__.py b/django_mobile/__init__.py index 99d0dcd..f677f38 100644 --- a/django_mobile/__init__.py +++ b/django_mobile/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- __author__ = u'Gregor Müllegger' -__version__ = '0.7.0.dev1' +__version__ = '1.0.0.RC1' import threading diff --git a/django_mobile/cache/middleware.py b/django_mobile/cache/middleware.py index ecfc4f5..488bae6 100644 --- a/django_mobile/cache/middleware.py +++ b/django_mobile/cache/middleware.py @@ -1,11 +1,13 @@ import warnings +from django.utils.deprecation import MiddlewareMixin from django.utils.cache import patch_vary_headers from django_mobile import get_flavour, _set_request_header -class CacheFlavourMiddleware(object): - def __init__(self): +class CacheFlavourMiddleware(MiddlewareMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) warnings.warn('CacheFlavourMiddleware does nothing and should be abandoned.' 'The intended behavior cannot be implemented using one middleware.' 'Use separate FetchFromCacheFlavourMiddleware and UpdateCacheFlavourMiddleware instead.' @@ -13,12 +15,12 @@ def __init__(self): category=DeprecationWarning) -class FetchFromCacheFlavourMiddleware(object): +class FetchFromCacheFlavourMiddleware(MiddlewareMixin): def process_request(self, request): _set_request_header(request, get_flavour(request)) -class UpdateCacheFlavourMiddleware(object): +class UpdateCacheFlavourMiddleware(MiddlewareMixin): def process_response(self, request, response): patch_vary_headers(response, ['X-Flavour']) return response diff --git a/django_mobile/compat.py b/django_mobile/compat.py deleted file mode 100644 index 4404aa9..0000000 --- a/django_mobile/compat.py +++ /dev/null @@ -1,27 +0,0 @@ -try: - from django.template.engine import Engine - from django.template.loaders.base import Loader as BaseLoader -except ImportError: # Django < 1.8 - Engine = None - from django.template.loader import BaseLoader, find_template_loader, get_template_from_string - - -def template_loader(loader_name): - if Engine: - return Engine.get_default().find_template_loader(loader_name) - else: # Django < 1.8 - return find_template_loader(loader_name) - - -def template_from_string(template_code): - if Engine: - return Engine().from_string(template_code) - else: # Django < 1.8 - return get_template_from_string(template_code) - - -def get_engine(): - if Engine: - return Engine.get_default() - else: # Django < 1.8 - return None diff --git a/django_mobile/conf.py b/django_mobile/conf.py index 3ffc804..c404006 100644 --- a/django_mobile/conf.py +++ b/django_mobile/conf.py @@ -6,8 +6,8 @@ class SettingsProxy(object): - def __init__(self, settings, defaults): - self.settings = settings + def __init__(self, proxied, defaults): + self.settings = proxied self.defaults = defaults def __getattr__(self, attr): @@ -17,26 +17,31 @@ def __getattr__(self, attr): try: return getattr(self.defaults, attr) except AttributeError: - raise AttributeError(u'settings object has no attribute "%s"' % attr) + raise AttributeError('settings object has no attribute "%s"' % attr) -class defaults(object): - FLAVOURS = (u'full', u'mobile',) - DEFAULT_MOBILE_FLAVOUR = u'mobile' - FLAVOURS_TEMPLATE_PREFIX = u'' - FLAVOURS_GET_PARAMETER = u'flavour' - FLAVOURS_STORAGE_BACKEND = u'cookie' - FLAVOURS_COOKIE_KEY = u'flavour' +class Defaults: + FLAVOURS = ('full', 'mobile',) + DEFAULT_MOBILE_FLAVOUR = 'mobile' + FLAVOURS_TEMPLATE_PREFIX = '' + FLAVOURS_GET_PARAMETER = 'flavour' + FLAVOURS_STORAGE_BACKEND = 'cookie' + FLAVOURS_COOKIE_KEY = 'flavour' FLAVOURS_COOKIE_HTTPONLY = False - FLAVOURS_SESSION_KEY = u'flavour' + FLAVOURS_SESSION_KEY = 'flavour' FLAVOURS_TEMPLATE_LOADERS = [] - for loader in django_settings.TEMPLATE_LOADERS: - if isinstance(loader, (tuple, list)) and loader[0] == CACHE_LOADER_NAME: - for cached_loader in loader[1]: - if cached_loader != DJANGO_MOBILE_LOADER: - FLAVOURS_TEMPLATE_LOADERS.append(cached_loader) - elif loader != DJANGO_MOBILE_LOADER: - FLAVOURS_TEMPLATE_LOADERS.append(loader) + for template in django_settings.TEMPLATES: + try: + for loader in template['OPTIONS'].get('loaders', []): + if isinstance(loader, (tuple, list)) and loader[0] == CACHE_LOADER_NAME: + for cached_loader in loader[1]: + if cached_loader != DJANGO_MOBILE_LOADER: + FLAVOURS_TEMPLATE_LOADERS.append(cached_loader) + elif loader != DJANGO_MOBILE_LOADER: + FLAVOURS_TEMPLATE_LOADERS.append(loader) + except KeyError: + pass FLAVOURS_TEMPLATE_LOADERS = tuple(FLAVOURS_TEMPLATE_LOADERS) -settings = SettingsProxy(django_settings, defaults) + +settings = SettingsProxy(django_settings, Defaults) diff --git a/django_mobile/loader.py b/django_mobile/loader.py index f617671..de9aeba 100644 --- a/django_mobile/loader.py +++ b/django_mobile/loader.py @@ -1,10 +1,10 @@ -import hashlib -from django.template import TemplateDoesNotExist +from django.template.exceptions import TemplateDoesNotExist from django.template.loaders.cached import Loader as DjangoCachedLoader from django_mobile import get_flavour from django_mobile.conf import settings -from django_mobile.compat import BaseLoader, template_loader, template_from_string -from django.utils.encoding import force_bytes + +from django.template.engine import Engine +from django.template.loaders.base import Loader as BaseLoader class Loader(BaseLoader): @@ -14,21 +14,17 @@ class Loader(BaseLoader): def get_contents(self, origin): return origin.loader.get_contents(origin) - def get_template_sources(self, template_name, template_dirs=None): + def get_template_sources(self, template_name): template_name = self.prepare_template_name(template_name) for loader in self.template_source_loaders: - if hasattr(loader, 'get_template_sources'): - try: - for result in loader.get_template_sources(template_name, template_dirs): - yield result - except UnicodeDecodeError: - # The template dir name was a bytestring that wasn't valid UTF-8. - raise - except ValueError: - # The joined path was located outside of this particular - # template_dir (it might be inside another one, so this isn't - # fatal). - pass + try: + for result in loader.get_template_sources(template_name): + yield result + except ValueError: + # The joined path was located outside this particular + # template_dir (it might be inside another one, so this isn't + # fatal). + pass def prepare_template_name(self, template_name): template_name = u'%s/%s' % (get_flavour(), template_name) @@ -36,33 +32,21 @@ def prepare_template_name(self, template_name): template_name = settings.FLAVOURS_TEMPLATE_PREFIX + template_name return template_name - def load_template(self, template_name, template_dirs=None): + def get_template(self, template_name, skip=None): template_name = self.prepare_template_name(template_name) for loader in self.template_source_loaders: try: - return loader(template_name, template_dirs) + return loader.get_template(template_name, skip=skip) except TemplateDoesNotExist: pass raise TemplateDoesNotExist("Tried %s" % template_name) - def load_template_source(self, template_name, template_dirs=None): - template_name = self.prepare_template_name(template_name) - for loader in self.template_source_loaders: - if hasattr(loader, 'load_template_source'): - try: - return loader.load_template_source( - template_name, - template_dirs) - except TemplateDoesNotExist: - pass - raise TemplateDoesNotExist("Tried %s" % template_name) - @property def template_source_loaders(self): if not self._template_source_loaders: loaders = [] for loader_name in settings.FLAVOURS_TEMPLATE_LOADERS: - loader = template_loader(loader_name) + loader = Engine.get_default().find_template_loader(loader_name) if loader is not None: loaders.append(loader) self._template_source_loaders = tuple(loaders) @@ -72,38 +56,32 @@ def template_source_loaders(self): class CachedLoader(DjangoCachedLoader): is_usable = True - def cache_key(self, template_name, template_dirs, *args): + def cache_key(self, template_name, *args, **kwargs): if len(args) > 0: # Django >= 1.9 - key = super(CachedLoader, self).cache_key(template_name, template_dirs, *args) + key = super(CachedLoader, self).cache_key(template_name, *args, **kwargs) else: - if template_dirs: - key = '-'.join([ - template_name, - hashlib.sha1(force_bytes('|'.join(template_dirs))).hexdigest() - ]) - else: - key = template_name + key = template_name return '{0}:{1}'.format(get_flavour(), key) - def load_template(self, template_name, template_dirs=None): - key = self.cache_key(template_name, template_dirs) - template_tuple = self.template_cache.get(key) + def get_template(self, template_name, skip=None): + key = self.cache_key(template_name) + template_tuple = self.get_template_cache.get(key) if template_tuple is TemplateDoesNotExist: raise TemplateDoesNotExist('Template not found: %s' % template_name) elif template_tuple is None: - template, origin = self.find_template(template_name, template_dirs) + template, origin = self.get_template(template_name, skip=skip) if not hasattr(template, 'render'): try: - template = template_from_string(template) + template = Engine.get_default().from_string(template) except TemplateDoesNotExist: # If compiling the template we found raises TemplateDoesNotExist, # back off to returning the source and display name for the template # we were asked to load. This allows for correct identification (later) # of the actual template that does not exist. - self.template_cache[key] = (template, origin) + self.get_template_cache[key] = (template, origin) - self.template_cache[key] = (template, None) + self.get_template_cache[key] = (template, None) - return self.template_cache[key] + return self.get_template_cache[key] diff --git a/django_mobile/middleware.py b/django_mobile/middleware.py index 9ce62bd..d76bb5d 100644 --- a/django_mobile/middleware.py +++ b/django_mobile/middleware.py @@ -1,10 +1,11 @@ import re +from django.utils.deprecation import MiddlewareMixin from django_mobile import flavour_storage from django_mobile import set_flavour, _init_flavour from django_mobile.conf import settings -class SetFlavourMiddleware(object): +class SetFlavourMiddleware(MiddlewareMixin): def process_request(self, request): _init_flavour(request) @@ -18,7 +19,7 @@ def process_response(self, request, response): return response -class MobileDetectionMiddleware(object): +class MobileDetectionMiddleware(MiddlewareMixin): user_agents_test_match = ( "w3c ", "acs-", "alav", "alca", "amoi", "audi", "avan", "benq", "bird", "blac", "blaz", "brew", @@ -42,9 +43,10 @@ class MobileDetectionMiddleware(object): user_agents_exception_search = u"(?:%s)" % u'|'.join(( 'ipad', )) - http_accept_regex = re.compile("application/vnd\.wap\.xhtml\+xml", re.IGNORECASE) + http_accept_regex = re.compile(r'application/vnd\.wap\.xhtml\+xml', re.IGNORECASE) - def __init__(self): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) user_agents_test_match = r'^(?:%s)' % '|'.join(self.user_agents_test_match) self.user_agents_test_match_regex = re.compile(user_agents_test_match, re.IGNORECASE) self.user_agents_test_search_regex = re.compile(self.user_agents_test_search, re.IGNORECASE) @@ -64,7 +66,7 @@ def process_request(self, request): # Nokia like test for WAP browsers. # http://www.developershome.com/wap/xhtmlmp/xhtml_mp_tutorial.asp?page=mimeTypesFileExtension - if 'HTTP_ACCEPT' in request.META : + if 'HTTP_ACCEPT' in request.META: http_accept = request.META['HTTP_ACCEPT'] if self.http_accept_regex.search(http_accept): is_mobile = True diff --git a/django_mobile_tests/manage.py b/django_mobile_tests/manage.py index 6cd2f10..a029b53 100755 --- a/django_mobile_tests/manage.py +++ b/django_mobile_tests/manage.py @@ -1,5 +1,6 @@ #!/usr/bin/env python -import os, sys +import sys +import os os.environ['DJANGO_SETTINGS_MODULE'] = 'django_mobile_tests.settings' parent = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) diff --git a/django_mobile_tests/settings.py b/django_mobile_tests/settings.py index 53c8c54..60cba0d 100644 --- a/django_mobile_tests/settings.py +++ b/django_mobile_tests/settings.py @@ -21,7 +21,8 @@ # If you set this to False, Django will make some optimizations so as not # to load the internationalization machinery. USE_I18N = True -USE_L10N = True + +DEBUG = True # Absolute path to the directory that holds media. # Example: "/home/media/media.lawrence.com/" @@ -51,10 +52,11 @@ )), ) -MIDDLEWARE_CLASSES = ( +MIDDLEWARE = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', 'django_mobile.middleware.MobileDetectionMiddleware', 'django_mobile.middleware.SetFlavourMiddleware', ) @@ -68,21 +70,40 @@ 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', + 'django.contrib.messages', 'django.contrib.admin', 'django_mobile', 'django_mobile_tests', ) -TEMPLATE_CONTEXT_PROCESSORS = ( - "django.contrib.auth.context_processors.auth", - "django.core.context_processors.debug", - "django.core.context_processors.i18n", - "django.core.context_processors.media", - "django_mobile.context_processors.flavour", - "django_mobile.context_processors.is_mobile", -) +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(PROJECT_ROOT, 'django_mobile_tests', 'templates')], + 'OPTIONS': { + 'debug': False, + 'loaders': [ + 'django_mobile.loader.Loader', + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + ], + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.template.context_processors.i18n', + 'django.template.context_processors.media', + 'django.template.context_processors.static', + 'django.template.context_processors.tz', + 'django.contrib.messages.context_processors.messages', + 'django.contrib.auth.context_processors.auth', + 'django_mobile.context_processors.flavour', + 'django_mobile.context_processors.is_mobile', + ], + }, + } +] import django if django.VERSION < (1, 6): diff --git a/django_mobile_tests/test_base.py b/django_mobile_tests/test_base.py index a952d62..30ba677 100644 --- a/django_mobile_tests/test_base.py +++ b/django_mobile_tests/test_base.py @@ -1,35 +1,40 @@ import threading import sys from django.contrib.sessions.models import Session -from django.template import RequestContext, TemplateDoesNotExist +from django.template import Engine +from django.template.loader import render_to_string + +from django.template.exceptions import TemplateDoesNotExist from django.test import Client, TestCase from mock import MagicMock, Mock, patch + from django_mobile import get_flavour, set_flavour from django_mobile.conf import settings -from django_mobile.compat import get_engine -from django_mobile.middleware import MobileDetectionMiddleware, \ - SetFlavourMiddleware +from django_mobile.middleware import MobileDetectionMiddleware, SetFlavourMiddleware IS_PYTHON_3 = sys.version > '3' + def _reset(): - ''' + """ Reset the thread local. - ''' + """ import django_mobile del django_mobile._local django_mobile._local = threading.local() -def str_p3_response( string ) : + +def str_p3_response(string): """ Since response.content is a binary string in python 3, we decode it to make it comparable to str objects ( python 2 compatibility ) """ - if IS_PYTHON_3 : - return string.decode( 'ASCII' ) + if IS_PYTHON_3: + return string.decode('ASCII') return string + class BaseTestCase(TestCase): def setUp(self): _reset() @@ -94,80 +99,63 @@ class TemplateLoaderTests(BaseTestCase): def test_load_template_on_filesystem(self): from django.template.loaders import app_directories, filesystem - @patch.object(app_directories.Loader, 'load_template') - @patch.object(filesystem.Loader, 'load_template') - def testing(filesystem_loader, app_directories_loader): + @patch.object(app_directories.Loader, 'get_template') + @patch.object(filesystem.Loader, 'get_template') + def testing(filesystem_loader, app_directories_loader, flavour=None): filesystem_loader.side_effect = TemplateDoesNotExist('error') app_directories_loader.side_effect = TemplateDoesNotExist('error') from django_mobile.loader import Loader - loader = Loader(get_engine()) - - set_flavour('mobile') - try: - loader.load_template('base.html', template_dirs=None) - except TemplateDoesNotExist: - pass - self.assertEqual(filesystem_loader.call_args[0][0], 'mobile/base.html') - self.assertEqual(app_directories_loader.call_args[0][0], 'mobile/base.html') + loader = Loader(Engine.get_default()) - set_flavour('full') + set_flavour(flavour) try: - loader.load_template('base.html', template_dirs=None) + loader.get_template('base.html') except TemplateDoesNotExist: pass - self.assertEqual(filesystem_loader.call_args[0][0], 'full/base.html') - self.assertEqual(app_directories_loader.call_args[0][0], 'full/base.html') + self.assertEqual(filesystem_loader.call_args[0][0], f'{flavour}/base.html') + self.assertEqual(app_directories_loader.call_args[0][0], f'{flavour}/base.html') - testing() + testing(flavour='mobile') + testing(flavour='full') - def test_load_template_source_on_filesystem(self): + def test_get_template_sources_on_filesystem(self): from django.template.loaders import app_directories, filesystem - @patch.object(app_directories.Loader, 'load_template_source') - @patch.object(filesystem.Loader, 'load_template_source') - def testing(filesystem_loader, app_directories_loader): - filesystem_loader.side_effect = TemplateDoesNotExist('error') - app_directories_loader.side_effect = TemplateDoesNotExist('error') + @patch.object(app_directories.Loader, 'get_template_sources') + @patch.object(filesystem.Loader, 'get_template_sources') + def testing(filesystem_loader, app_directories_loader, flavour=None): + filesystem_loader.return_value = iter([]) + app_directories_loader.return_value = iter([]) from django_mobile.loader import Loader - loader = Loader(get_engine()) - - set_flavour('mobile') - try: - loader.load_template_source('base.html', template_dirs=None) - except TemplateDoesNotExist: - pass - self.assertEqual(filesystem_loader.call_args[0][0], 'mobile/base.html') - self.assertEqual(app_directories_loader.call_args[0][0], 'mobile/base.html') + loader = Loader(Engine.get_default()) - set_flavour('full') + set_flavour(flavour) try: - loader.load_template_source('base.html', template_dirs=None) - except TemplateDoesNotExist: + for _ in loader.get_template_sources('base.html'): + pass + except RuntimeError: pass - self.assertEqual(filesystem_loader.call_args[0][0], 'full/base.html') - self.assertEqual(app_directories_loader.call_args[0][0], 'full/base.html') + self.assertEqual(filesystem_loader.call_args[0][0], f'{flavour}/base.html') + self.assertEqual(app_directories_loader.call_args[0][0], f'{flavour}/base.html') - testing() + testing(flavour='mobile') + testing(flavour='full') - def test_functional(self): - from django.template.loader import render_to_string + def test_functional_full(self): set_flavour('full') result = render_to_string('index.html') result = result.strip() self.assertEqual(result, 'Hello .') - # simulate RequestContext - result = render_to_string('index.html', context_instance=RequestContext(Mock())) - result = result.strip() - self.assertEqual(result, 'Hello full.') + + def test_functional_mobile(self): set_flavour('mobile') result = render_to_string('index.html') result = result.strip() self.assertEqual(result, 'Mobile!') def test_loading_unexisting_template(self): - from django.template.loader import render_to_string try: render_to_string('not_existent.html') except TemplateDoesNotExist as e: @@ -183,7 +171,7 @@ def test_mobile_browser_agent(self, set_flavour): request.META = { 'HTTP_USER_AGENT': 'My Mobile Browser', } - middleware = MobileDetectionMiddleware() + middleware = MobileDetectionMiddleware(lambda: None) middleware.process_request(request) self.assertEqual(set_flavour.call_args, (('mobile', request), {})) @@ -193,7 +181,7 @@ def test_desktop_browser_agent(self, set_flavour): request.META = { 'HTTP_USER_AGENT': 'My Desktop Browser', } - middleware = MobileDetectionMiddleware() + middleware = MobileDetectionMiddleware(lambda: None) middleware.process_request(request) self.assertEqual(set_flavour.call_args, (('full', request), {})) @@ -203,7 +191,7 @@ def test_set_default_flavour(self): request = Mock() request.META = MagicMock() request.GET = {} - middleware = SetFlavourMiddleware() + middleware = SetFlavourMiddleware(lambda: None) middleware.process_request(request) # default flavour is set self.assertEqual(get_flavour(), 'full') @@ -213,7 +201,7 @@ def test_set_flavour_through_get_parameter(self, set_flavour): request = Mock() request.META = MagicMock() request.GET = {'flavour': 'mobile'} - middleware = SetFlavourMiddleware() + middleware = SetFlavourMiddleware(lambda: None) middleware.process_request(request) self.assertEqual(set_flavour.call_args, (('mobile', request), {'permanent': True})) @@ -223,29 +211,29 @@ class RealAgentNameTests(BaseTestCase): def assertFullFlavour(self, agent): client = Client(HTTP_USER_AGENT=agent) response = client.get('/') - if str_p3_response( response.content.strip() ) != 'Hello full.': - self.fail(u'Agent is matched as mobile: %s' % agent) + if str_p3_response(response.content).strip() != 'Hello full.': + self.fail('Agent is matched as mobile: %s' % agent) def assertMobileFlavour(self, agent): client = Client(HTTP_USER_AGENT=agent) response = client.get('/') - if str_p3_response( response.content.strip() ) != 'Mobile!': - self.fail(u'Agent is not matched as mobile: %s' % agent) + if str_p3_response(response.content).strip() != 'Mobile!': + self.fail('Agent is not matched as mobile: %s' % agent) def test_ipad(self): - self.assertFullFlavour(u'Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10') + self.assertFullFlavour('Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10') def test_iphone(self): - self.assertMobileFlavour(u'Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3') + self.assertMobileFlavour('Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3') def test_motorola_xoom(self): - self.assertFullFlavour(u'Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13') + self.assertFullFlavour('Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13') def test_opera_mobile_on_android(self): - ''' + """ Regression test of issue #9 - ''' - self.assertMobileFlavour(u'Opera/9.80 (Android 2.3.3; Linux; Opera Mobi/ADR-1111101157; U; en) Presto/2.9.201 Version/11.50') + """ + self.assertMobileFlavour('Opera/9.80 (Android 2.3.3; Linux; Opera Mobi/ADR-1111101157; U; en) Presto/2.9.201 Version/11.50') class RegressionTests(BaseTestCase): @@ -255,30 +243,30 @@ def setUp(self): self.mobile = Client(HTTP_USER_AGENT='wap') def test_multiple_browser_access(self): - ''' + """ Regression test of issue #2 - ''' + """ response = self.desktop.get('/') - self.assertEqual( str_p3_response( response.content.strip() ), 'Hello full.') + self.assertEqual(str_p3_response(response.content).strip(), 'Hello full.') response = self.mobile.get('/') - self.assertEqual( str_p3_response( response.content.strip() ), 'Mobile!') + self.assertEqual(str_p3_response(response.content).strip(), 'Mobile!') response = self.desktop.get('/') - self.assertEqual( str_p3_response( response.content.strip() ), 'Hello full.') + self.assertEqual(str_p3_response(response.content).strip(), 'Hello full.') response = self.mobile.get('/') - self.assertEqual( str_p3_response( response.content.strip() ), 'Mobile!') + self.assertEqual(str_p3_response(response.content).strip(), 'Mobile!') def test_cache_page_decorator(self): response = self.mobile.get('/cached/') - self.assertEqual( str_p3_response( response.content.strip() ), 'Mobile!') + self.assertEqual(str_p3_response(response.content).strip(), 'Mobile!') response = self.desktop.get('/cached/') - self.assertEqual( str_p3_response( response.content.strip() ), 'Hello full.') + self.assertEqual(str_p3_response(response.content).strip(), 'Hello full.') response = self.mobile.get('/cached/') - self.assertEqual( str_p3_response( response.content.strip() ), 'Mobile!') + self.assertEqual(str_p3_response(response.content).strip(), 'Mobile!') response = self.desktop.get('/cached/') - self.assertEqual( str_p3_response( response.content.strip() ), 'Hello full.') + self.assertEqual(str_p3_response(response.content).strip(), 'Hello full.') diff --git a/django_mobile_tests/urls.py b/django_mobile_tests/urls.py index 9e5f5a9..f93ff83 100644 --- a/django_mobile_tests/urls.py +++ b/django_mobile_tests/urls.py @@ -1,18 +1,16 @@ try: from django.conf.urls.defaults import * except ImportError: - from django.conf.urls import * -from django.shortcuts import render_to_response -from django.template import RequestContext + from django.urls import * +from django.shortcuts import render from django_mobile.cache import cache_page def index(request): - return render_to_response('index.html', { - }, context_instance=RequestContext(request)) + return render(request, 'index.html', {}) -urlpatterns = patterns('', - url(r'^$', index), - url(r'^cached/$', cache_page(60*10)(index)), -) +urlpatterns = [ + path('', index), + path('cached/', cache_page(60*10)(index)), +] diff --git a/examples/middleware.py b/examples/middleware.py index aa5c5f8..b7201bb 100644 --- a/examples/middleware.py +++ b/examples/middleware.py @@ -9,12 +9,12 @@ class MobileTabletDetectionMiddleware(MobileDetectionMiddleware): # Example how default middleware could be expanded to provide possibility to detect # tablet devices. - user_agents_android_search = u"(?:android)" - user_agents_mobile_search = u"(?:mobile)" - user_agents_tablets_search = u"(?:%s)" % u'|'.join(('ipad', 'tablet', )) + user_agents_android_search = r"(?:android)" + user_agents_mobile_search = r"(?:mobile)" + user_agents_tablets_search = r"(?:%s)" % '|'.join(('ipad', 'tablet', )) - def __init__(self): - super(MobileTabletDetectionMiddleware, self).__init__() + def __init__(self, *args, **kwargs): + super(MobileTabletDetectionMiddleware, self).__init__(*args, **kwargs) self.user_agents_android_search_regex = re.compile(self.user_agents_android_search, re.IGNORECASE) self.user_agents_mobile_search_regex = re.compile(self.user_agents_mobile_search, diff --git a/runtests.py b/runtests.py index 254e513..2ae95ab 100755 --- a/runtests.py +++ b/runtests.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import argparse -import os, sys +import os +import sys os.environ['DJANGO_SETTINGS_MODULE'] = 'django_mobile_tests.settings' @@ -39,7 +40,7 @@ def runtests(*argv): argparser = argparse.ArgumentParser(description='Process some integers.') argparser.add_argument('appname', nargs='*') argparser.add_argument('--no-coverage', dest='coverage', action='store_const', - const=False, default=True, help='Do not collect coverage data.') + const=False, default=True, help='Do not collect coverage data.') if __name__ == '__main__':