pax_global_header00006660000000000000000000000064132112106050014501gustar00rootroot0000000000000052 comment=597bd81a635dec7fdfcccf09b5c95df63615dbf2 django-compat-1.0.15/000077500000000000000000000000001321121060500143105ustar00rootroot00000000000000django-compat-1.0.15/.coveragerc000066400000000000000000000000761321121060500164340ustar00rootroot00000000000000[run] source = compat omit = compat/tests/* compat/docs/* django-compat-1.0.15/.gitignore000066400000000000000000000012511321121060500162770ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] # C extensions *.so # Distribution / packaging .Python env/ env?/ build/ develop-eggs/ dist/ downloads/ eggs/ lib/ lib64/ parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .cache nosetests.xml coverage.xml # Translations *.mo *.pot # Django stuff: *.log # Sphinx documentation docs/_build/ # PyBuilder target/ django-compat-1.0.15/.travis.yml000066400000000000000000000023541321121060500164250ustar00rootroot00000000000000language: python # this list can be easily generated py running `tox -l` env: - TOX_ENV=py27-django18 - TOX_ENV=py27-django19 - TOX_ENV=py27-django110 - TOX_ENV=py27-django111 # Currently, Python 3.5 Interpreter is only available when it is specified # in the travis python section. So we have to work around this with this include # GitHub issue: https://github.com/travis-ci/travis-ci/issues/4794 matrix: include: - python: "3.5" env: - TOX_ENV=py35-django18 - python: "3.5" env: - TOX_ENV=py35-django19 - python: "3.5" env: - TOX_ENV=py35-django110 - python: "3.5" env: - TOX_ENV=py35-django111 - python: "3.5" env: TOX_ENV=py35-django20 - python: "3.6" env: - TOX_ENV=py36-django18 - python: "3.6" env: - TOX_ENV=py36-django19 - python: "3.6" env: - TOX_ENV=py36-django110 - python: "3.6" env: - TOX_ENV=py36-django111 - python: "3.6" env: TOX_ENV=py36-django20 allow_failures: - python: "3.5" env: TOX_ENV=py35-django20 - python: "3.6" env: TOX_ENV=py36-django20 install: - pip install tox-travis - pip install coveralls script: - tox -e $TOX_ENV sudo: false after_success: coveralls django-compat-1.0.15/AUTHORS.txt000066400000000000000000000005351321121060500162010ustar00rootroot00000000000000Brad Pitcher (@brad) Low Kian Seong (@lowks) Philippe O. Wagner (@philippeowagner) Walter Renner (@walterrenner) Yannik Ammann (@yannik-ammann) Sergey Fursov (@GeyseR) Ryan P. Kilby (@rpkilby) Alex Willmer (@moreati) Eugena Mihailikova (@eugena) Luke Plant (@spookylukey) Senthil Kumaran (@stylesen) Bruno Alla (@browniebroke) David D Lowe (@Flimm) django-compat-1.0.15/LICENSE000066400000000000000000000020661321121060500153210ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2016 arteria GmbH Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. django-compat-1.0.15/MANIFEST.in000066400000000000000000000001171321121060500160450ustar00rootroot00000000000000include README.md include LICENSE include AUTHORS.txt include requirements.txt django-compat-1.0.15/README.md000066400000000000000000000332271321121060500155760ustar00rootroot00000000000000django-compat ============= [![Build Status](https://travis-ci.org/arteria/django-compat.svg?branch=master)](https://travis-ci.org/arteria/django-compat) [![Stories in Ready](https://badge.waffle.io/arteria/django-compat.png?label=ready&title=Ready)](https://waffle.io/arteria/django-compat) [![Coverage Status](https://coveralls.io/repos/arteria/django-compat/badge.svg?branch=master&service=github)](https://coveralls.io/github/arteria/django-compat?branch=master) [![PyPI](https://img.shields.io/pypi/v/django-compat.svg)](https://pypi.python.org/pypi/django-compat) Forward and backwards compatibility layer for Django ~~1.4~~, ~~1.7~~, 1.8, 1.9, 1.10 and 1.11 ~~Consider [django-compat](https://github.com/arteria/django-compat) as an experiment based on the discussion [on reddit](http://redd.it/2jrr4l). Let's see where it goes.~~ What started as an experiment based on [this discussion on reddit](http://redd.it/2jrr4l) has proven to be true in real life. django-compat is under active development. To learn about other features, bug fixes, and changes, please refer to the [changelog](https://github.com/arteria/django-compat#changelog). # Who uses django-compat Two popular examples of open source reusable app that uses django-compat are [django-hijack](https://github.com/arteria/django-hijack/) and [django-background-tasks](https://github.com/arteria/django-background-tasks). Want to have yours listed here? Send us a PR. # Why use django-compat * Be able to use the LTS versions of Django and support newer versions in your app * Use features from newer Django versions in an old one * Manage and master the gap between different framework versions # How to use django-compat Install compat from the [PyPI](https://pypi.python.org/pypi/django-compat) or download and install manually. All relevant releases are listed [here under releases](https://github.com/arteria/django-compat/releases). Using one of the compatible objects is easy. For example from compat import patterns, url urlpatterns = patterns('ABC.views', url(r'^abc/$', 'abc', name='abc-link'), ... See a full example [here](https://github.com/arteria/django-hijack/blob/4966d8865e7e829a562ff2724771628c6590f841/hijack/urls.py#L1). | django-compat is free software. If you find it useful and would like to give back, please consider to make a donation using [Bitcoin](https://blockchain.info/payment_request?address=1AJkbQdcNkrHzxi91mB1kkPxh4t4BJ4hu4) or [PayPal](https://www.paypal.me/arteriagmbh). Thank you! | | ----- | # Compatible objects |Compatible object|Specifically tested|1.8|1.9|1.10|1.11|Notes| |---|---|---|---|---|---|---| |`BytesIO`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`DjangoJSONEncoder`|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`EmailValidator`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`GenericForeignKey`|:heavy_multiplication_x:|:heavy_check_mark:|:x:|:x:|:x:|| |`models.GenericForeignKey`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`HttpResponseBase`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`JsonResponse`|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`LocaleRegexProvider`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`LocaleRegexURLResolver`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`NoReverseMatch`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`RegexURLPattern`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`RegexURLResolver`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`Resolver404`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`ResolverMatch`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`SortedDict`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`StringIO`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`URLValidator`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`VariableNode`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`View`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`add_to_builtins`|:heavy_multiplication_x:|:heavy_check_mark:|:x:|:x:|:x:|| |`admin_utils`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`atomic`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`clean_manytomany_helptext`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`clear_url_caches`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`close_connection`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`commit`|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`commit_on_success`|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|`:heavy_check_mark:|`commit_on_success` replaced by `atomic` in Django >= 1.8| |`force_text`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`format_html`|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`get_callable`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`get_current_site`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`get_ident`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`get_mod_func`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`get_model`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`get_model_name`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`get_ns_resolver`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`get_resolver`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`get_script_prefix`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`get_template_loaders`|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`get_urlconf`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`get_user_model`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`get_username_field`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`handler404`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`handler500`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`import_module`|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`import_string`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`include`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`is_valid_path`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`parse_qs`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`patterns`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:x:|:x:|| |`python_2_unicode_compatible`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`render_to_string`|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|The new function signature (https://docs.djangoproject.com/en/1.9/releases/1.8/#dictionary-and-context-instance-arguments-of-rendering-functions) is backported to pre-1.8.| |`resolve`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`resolve_url`|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:warning:|:warning:|1.10: Reversing by dotted path has been removed| |`reverse`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`reverse_lazy`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`rollback`|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|Transaction savepoint (sid) is required for Django < 1.8| |`set_script_prefix`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`set_urlconf`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`simplejson`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`slugify`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`smart_text`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`unquote_plus`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`url`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_multiplication_x:|:heavy_multiplication_x:|Function used in `urlpatterns`| |`tempat.url`|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|Templatetag; import with `{% load url from compat %}`| |`uravy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`urlparse`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`urlresolvers`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`urlunparse`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`user_model_label`|:heavy_multiplication_x:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|| |`templatetags.compat.verbatim`|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|Templatetag; import with `{% load verbatim from compat %}`. 1.4: Does not allow specific closing tags, e.g. `{% endverbatim myblock %}`, and does not preserve whitespace inside tags.| # Resources and references ## Resources * https://github.com/ubernostrum/django-compat-lint * https://docs.djangoproject.com/en/dev/misc/api-stability/ * https://docs.djangoproject.com/en/dev/topics/python3/ * http://andrewsforge.com/presentation/upgrading-django-to-17/ ## compat.py Bits and bites of the following projects were re-used to build [django-compat](https://github.com/arteria/django-compat). - [x] https://github.com/lukaszb/django-guardian/blob/devel/guardian/compat.py - [X] https://github.com/evonove/django-oauth-toolkit/blob/master/oauth2_provider/compat.py - [X] https://github.com/toastdriven/django-tastypie/blob/master/tastypie/compat.py - [X] https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/compat.py - [ ] TODO: MinValueValidator, MaxValueValidator et al. (other relevant bits are included) Django 1.8 - [X] https://gist.github.com/theskumar/ff8de60ff6a33bdacaa8 - [X] https://github.com/evonove/django-oauth-toolkit/blob/master/oauth2_provider/templatetags/compat.py - [ ] https://github.com/kennethreitz/requests/blob/master/requests/compat.py - [ ] https://github.com/mitsuhiko/jinja2/blob/master/jinja2/_compat.py - [ ] https://github.com/jaraco/setuptools/blob/master/setuptools/compat.py - [ ] https://github.com/mariocesar/sorl-thumbnail/blob/master/sorl/thumbnail/compat.py # Changelog ### 2017/04/07 * Update existing patches for Django 1.10 ### 2016/08/02 * Update existing patches for Django 1.10 ### 2016/06/01 * Add ``get_current_site`` and ``admin_utils`` ### 2016/05/11 * Fix error when installing package under python 3.4 ### 2015/11/12 * Backport new render_to_string function signature to Django < 1.8 * Backport verbatim tag to Django 1.4 * Add get_template_loaders * Add close_connection * Improve JsonResponse backport to Django 1.4 * Add tests for import_module, get_model and add_to_builtins * Anticipate renaming of django.core.urlresolvers to django.urls in 1.10 * Avoid warnings in setup.py ### 2015/11/11 * 1.9 compatibility for existing objects with the following changes: * ``add_to_builtins`` was removed for Django >= 1.9 * ``GenericForeignKey` was moved to ``compat.models`` for Django >= 1.9 ### 2015/07/15 * ``add_to_builtins`` was added ### 2015/07/08 * ``get_query_set``/``get_queryset`` support was dropped again (see [#29](https://github.com/arteria/django-compat/issues/29)) django-compat-1.0.15/compat/000077500000000000000000000000001321121060500155735ustar00rootroot00000000000000django-compat-1.0.15/compat/__init__.py000066400000000000000000000433201321121060500177060ustar00rootroot00000000000000# flake8: noqa from __future__ import unicode_literals import sys import django from django.conf import settings # removed get_queryset <> get_query_set see, #29 #from django.db.models import Manager ## Monkey patch: # #try: # Manager.get_query_set = Manager.get_queryset #except AttributeError: # Manager.get_queryset = Manager.get_query_set from django.core.exceptions import ImproperlyConfigured if django.VERSION < (1, 8): from django.template import add_to_builtins elif django.VERSION < (1, 9): from django.template.base import add_to_builtins else: pass # Removed in 1.9. Use template settings instead try: from importlib import import_module except ImportError: # Fallback for Python 2.6 & Django < 1.7 from django.utils.importlib import import_module try: # django 1.4.2+ , https://docs.djangoproject.com/en/1.5/topics/python3/#philosophy from django.utils import six except ImportError: import six # get_indent try: from threading import get_ident except ImportError: from six.moves._thread import get_ident # noqa try: from django.conf.urls import url, include, handler404, handler500 except ImportError: from django.conf.urls.defaults import url, include, handler404, handler500 # pyflakes:ignore try: from django.conf.urls import patterns except ImportError: try: from django.conf.urls.defaults import patterns # pyflakes:ignore except ImportError: pass # Handle django.utils.encoding rename in 1.5 onwards. # smart_unicode -> smart_text # force_unicode -> force_text try: from django.utils.encoding import smart_text except ImportError: from django.utils.encoding import smart_unicode as smart_text try: from django.utils.encoding import force_text except ImportError: from django.utils.encoding import force_unicode as force_text if django.VERSION >= (1, 6): def clean_manytomany_helptext(text): return text else: # Up to version 1.5 many to many fields automatically suffix # the `help_text` attribute with hardcoded text. def clean_manytomany_helptext(text): if text.endswith(' Hold down "Control", or "Command" on a Mac, to select more than one.'): text = text[:-69] return text # cStringIO only if it's available, otherwise StringIO try: import cStringIO.StringIO as StringIO except ImportError: StringIO = six.StringIO BytesIO = six.BytesIO try: # Django 1.7 or over use the new application loading system from django.apps import apps get_model = apps.get_model except ImportError: from django.db.models.loading import get_model def get_model_name(model_cls): try: return model_cls._meta.model_name except AttributeError: # < 1.6 used module_name instead of model_name return model_cls._meta.module_name # View._allowed_methods only present from 1.5 onwards if django.VERSION >= (1, 5): from django.views.generic import View else: from django.views.generic import View as DjangoView class View(DjangoView): def _allowed_methods(self): return [m.upper() for m in self.http_method_names if hasattr(self, m)] # URLValidator only accepts `message` in 1.6+ if django.VERSION >= (1, 6): from django.core.validators import URLValidator else: from django.core.validators import URLValidator as DjangoURLValidator class URLValidator(DjangoURLValidator): def __init__(self, *args, **kwargs): self.message = kwargs.pop('message', self.message) super(URLValidator, self).__init__(*args, **kwargs) # EmailValidator requires explicit regex prior to 1.6+ if django.VERSION >= (1, 6): from django.core.validators import EmailValidator else: from django.core.validators import EmailValidator as DjangoEmailValidator from django.core.validators import email_re class EmailValidator(DjangoEmailValidator): def __init__(self, *args, **kwargs): super(EmailValidator, self).__init__(email_re, *args, **kwargs) try: from django.utils.encoding import python_2_unicode_compatible except ImportError: def python_2_unicode_compatible(klass): """ A decorator that defines __unicode__ and __str__ methods under Python 2. Under Python 3 it does nothing. To support Python 2 and 3 with a single code base, define a __str__ method returning text and apply this decorator to the class. """ if '__str__' not in klass.__dict__: raise ValueError("@python_2_unicode_compatible cannot be applied " "to %s because it doesn't define __str__()." % klass.__name__) klass.__unicode__ = klass.__str__ klass.__str__ = lambda self: self.__unicode__().encode('utf-8') return klass try: import unittest2 as unittest except ImportError: import unittest # pyflakes:ignore try: from unittest import mock # Since Python 3.3 mock is is in stdlib except ImportError: try: import mock # pyflakes:ignore except ImportError: # mock is used for tests only however it is hard to check if user is # running tests or production code so we fail silently here; mock is # still required for tests at setup.py (See PR #193) pass # Django 1.5 compatibility utilities, providing support for custom User models. # Since get_user_model() causes a circular import if called when app models are # being loaded, the user_model_label should be used when possible, with calls # to get_user_model deferred to execution time user_model_label = getattr(settings, 'AUTH_USER_MODEL', 'auth.User') # get_username_field if django.VERSION >= (1, 5): def get_username_field(): return get_user_model().USERNAME_FIELD else: def get_username_field(): return 'username' try: from django.contrib.auth import get_user_model except ImportError: from django.contrib.auth.models import User get_user_model = lambda: User def get_user_model_path(): """ Returns 'app_label.ModelName' for User model. Basically if ``AUTH_USER_MODEL`` is set at settings it would be returned, otherwise ``auth.User`` is returned. """ return getattr(settings, 'AUTH_USER_MODEL', 'auth.User') def get_user_permission_full_codename(perm): """ Returns 'app_label._'. If standard ``auth.User`` is used, for 'change' perm this would return ``auth.change_user`` and if ``myapp.CustomUser`` is used it would return ``myapp.change_customuser``. """ User = get_user_model() return '%s.%s_%s' % (User._meta.app_label, perm, User._meta.module_name) def get_user_permission_codename(perm): """ Returns '_'. If standard ``auth.User`` is used, for 'change' perm this would return ``change_user`` and if ``myapp.CustomUser`` is used it would return ``change_customuser``. """ return get_user_permission_full_codename(perm).split('.')[1] def import_string(dotted_path): """ Import a dotted module path and return the attribute/class designated by the last name in the path. Raise ImportError if the import failed. Backported from Django 1.7 """ try: module_path, class_name = dotted_path.rsplit('.', 1) except ValueError: msg = "%s doesn't look like a module path" % dotted_path six.reraise(ImportError, ImportError(msg), sys.exc_info()[2]) module = import_module(module_path) try: return getattr(module, class_name) except AttributeError: msg = 'Module "%s" does not define a "%s" attribute/class' % ( dotted_path, class_name) six.reraise(ImportError, ImportError(msg), sys.exc_info()[2]) def commit(using=None): """ Possibility of calling transaction.commit() in new Django versions (in atomic block). """ try: django.db.transaction.commit(using) except django.db.transaction.TransactionManagementError: pass def rollback(using=None, sid=None): """ Possibility of calling transaction.rollback() in new Django versions (in atomic block). Important: transaction savepoint (sid) is required for Django < 1.8 """ if sid: django.db.transaction.savepoint_rollback(sid) else: try: django.db.transaction.rollback(using) except django.db.transaction.TransactionManagementError: django.db.transaction.set_rollback(True, using) # HttpResponseBase only exists from 1.5 onwards try: from django.http.response import HttpResponseBase except ImportError: from django.http import HttpResponse as HttpResponseBase # Python 3 try: unicode = unicode # pyflakes:ignore basestring = basestring # pyflakes:ignore str = str # pyflakes:ignore except NameError: basestring = unicode = str = str # urlparse in python3 has been renamed to urllib.parse try: from urlparse import urlparse, parse_qs, urlunparse except ImportError: from urllib.parse import urlparse, parse_qs, urlunparse try: from urllib import urlencode, unquote_plus except ImportError: from urllib.parse import urlencode, unquote_plus def create_permissions(*args, **kwargs): # create_permission API changed: skip the create_models (second # positional argument) if we have django 1.7+ and 2+ positional # arguments with the second one being a list/tuple from django.contrib.auth.management import create_permissions as original_create_permissions if django.VERSION < (1, 7) and len(args) > 1 and isinstance(args[1], (list, tuple)): args = args[:1] + args[2:] return original_create_permissions(*args, **kwargs) # Requires django < 1.5 or python >= 2.6 if django.VERSION < (1, 5): from django.utils import simplejson else: import json as simplejson try: from collections import OrderedDict as SortedDict except ImportError: from django.utils.datastructures import SortedDict # Backporting from 1.8 if django.VERSION < (1, 8): from compat.json_response import DjangoJSONEncoder else: from django.core.serializers.json import DjangoJSONEncoder if django.VERSION < (1, 8): from compat.json_response import JsonResponse else: from django.http import JsonResponse # format_html (django 1.6) try: from django.utils.html import format_html, conditional_escape except ImportError: # support django < 1.5. Taken from django.utils.html from django.utils import html def format_html(format_string, *args, **kwargs): """ Similar to str.format, but passes all arguments through conditional_escape, and calls 'mark_safe' on the result. This function should be used instead of str.format or % interpolation to build up small HTML fragments. """ args_safe = map(html.conditional_escape, args) kwargs_safe = dict([(k, html.conditional_escape(v)) for (k, v) in six.iteritems(kwargs)]) return html.mark_safe(format_string.format(*args_safe, **kwargs_safe)) try: from django.db import close_old_connections as close_connection except ImportError: # django < 1.8 from django.db import close_connection def get_template_loaders(): """ Compatibility method to fetch the template loaders. Source: https://github.com/django-debug-toolbar/django-debug-toolbar/blob/ece1c2775af108a92a0ef59636266b49e286e916/debug_toolbar/compat.py """ try: from django.template.engine import Engine except ImportError: # Django < 1.8 Engine = None if Engine: try: engine = Engine.get_default() except ImproperlyConfigured: loaders = [] else: loaders = engine.template_loaders else: # Django < 1.8 from django.template.loader import find_template_loader loaders = [ find_template_loader(loader_name) for loader_name in settings.TEMPLATE_LOADERS] return loaders if django.VERSION >= (2, 0): from django.urls import ( clear_url_caches, get_script_prefix, get_urlconf, is_valid_path, resolve, reverse, reverse_lazy, set_script_prefix, set_urlconf, NoReverseMatch, URLPattern, URLResolver, Resolver404, ResolverMatch, get_ns_resolver, get_resolver, get_callable, get_mod_func ) RegexURLPattern = URLPattern RegexURLResolver = URLResolver elif django.VERSION >= (1, 10): import django.urls as urlresolvers from django.urls import ( clear_url_caches, get_script_prefix, get_urlconf, is_valid_path, resolve, reverse, reverse_lazy, set_script_prefix, set_urlconf, LocaleRegexProvider, LocaleRegexURLResolver, NoReverseMatch, RegexURLPattern, RegexURLResolver, Resolver404, ResolverMatch, get_ns_resolver, get_resolver, get_callable, get_mod_func ) URLPattern = RegexURLPattern URLResolver = RegexURLResolver else: import django.core.urlresolvers as urlresolvers from django.core.urlresolvers import ( clear_url_caches, get_script_prefix, get_urlconf, is_valid_path, resolve, reverse, reverse_lazy, set_script_prefix, set_urlconf, LocaleRegexProvider, LocaleRegexURLResolver, NoReverseMatch, RegexURLPattern, RegexURLResolver, Resolver404, ResolverMatch, get_ns_resolver, get_resolver, get_callable, get_mod_func ) URLPattern = RegexURLPattern URLResolver = RegexURLResolver try: from django.shortcuts import resolve_url except ImportError: # django < 1.5 from .shortcuts import resolve_url from django.template.loader import render_to_string as render_to_string_django _context_instance_undefined = object() _dictionary_undefined = object() _dirs_undefined = object() def render_to_string(template_name, context=None, context_instance=_context_instance_undefined, dirs=_dirs_undefined, dictionary=_dictionary_undefined, request=None, using=None): if (context_instance is _context_instance_undefined and dirs is _dirs_undefined and dictionary is _dictionary_undefined): if django.VERSION >= (1, 8): # Call new render_to_string with new arguments return render_to_string_django(template_name, context, request, using) else: # Call legacy render_to_string with new arguments from django.template import RequestContext context_instance = RequestContext(request) if request else None return render_to_string_django(template_name, context, context_instance) else: if django.VERSION >= (1, 10): # Call new render_to_string with legacy arguments raise NotImplementedError('Django compat does not support calling post-1.8 render_to_string with pre-1.8 ' 'keyword arguments') else: # Call legacy render_to_string with legacy arguments if dictionary is _dictionary_undefined: dictionary = {} if context_instance is _context_instance_undefined: context_instance = None return render_to_string_django(template_name, dictionary, context_instance) ### Undocumented ### try: from django.template import VariableNode except: from django.template.base import VariableNode # slugify template filter is available as a standard python function at django.utils.text since django 1.5 try: from django.utils.text import slugify except: from django.template.defaultfilters import slugify if django.VERSION < (1, 7): from django.contrib.contenttypes.generic import GenericForeignKey elif django.VERSION < (1, 9): from django.contrib.contenttypes.fields import GenericForeignKey else: pass # Loading models from __init__ is deprecated from 1.9. Import from compat.models instead # commit_on_success replaced by atomic in Django >=1.8 atomic = commit_on_success = getattr(django.db.transaction, 'atomic', None) or getattr(django.db.transaction, 'commit_on_success') # Removed from django.contrib.sites.models in Django 1.9 try: from django.contrib.sites.shortcuts import get_current_site except ImportError: from django.contrib.sites.models import get_current_site # Renamed utils and removed in Django 1.9 try: from django.contrib.admin import utils as admin_utils except ImportError: from django.contrib.admin import util as admin_utils # the tests will try to import these __all__ = [ 'add_to_builtins', 'get_model', 'get_model_name', 'get_user_model', 'get_username_field', 'import_string', 'commit', 'rollback', 'user_model_label', 'url', 'patterns', 'include', 'handler404', 'handler500', 'get_ident', # 'mock', # 'unittest', 'urlparse', 'parse_qs', 'urlunparse', 'urlencode', 'unquote_plus', 'DjangoJSONEncoder', 'JsonResponse', 'HttpResponseBase', 'python_2_unicode_compatible', 'URLValidator', 'EmailValidator', 'View', 'StringIO', 'BytesIO', 'clean_manytomany_helptext', 'smart_text', 'force_text', 'simplejson', 'import_module', 'VariableNode', 'slugify', 'GenericForeignKey', 'SortedDict', 'atomic', 'commit_on_success', # alias 'format_html', 'resolve_url', 'close_connection', 'get_template_loaders', 'LocaleRegexProvider', 'LocaleRegexURLResolver', 'NoReverseMatch', 'RegexURLPattern', 'RegexURLResolver', # Old names before 2.0, alias after 'URLPattern', 'URLResolver', # New names in 2.0, alias before 'Resolver404', 'ResolverMatch', 'clear_url_caches', 'get_callable', 'get_mod_func', 'get_ns_resolver', 'get_resolver', 'get_script_prefix', 'get_urlconf', 'is_valid_path', 'resolve', 'reverse', 'reverse_lazy', 'set_script_prefix', 'set_urlconf', 'render_to_string', 'get_current_site', 'admin_utils' ] django-compat-1.0.15/compat/docs/000077500000000000000000000000001321121060500165235ustar00rootroot00000000000000django-compat-1.0.15/compat/docs/__init__.py000066400000000000000000000000001321121060500206220ustar00rootroot00000000000000django-compat-1.0.15/compat/docs/compatibility.py000066400000000000000000000361641321121060500217600ustar00rootroot00000000000000 COMPATIBLE_VERSIONS = ( (1, 4), (1, 7), (1, 8), (1, 9), (1, 10), ) COMPATIBLE_OBJECTS = [ { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'get_model', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'get_model_name', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'get_user_model', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'get_username_field', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'import_string', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': True, 'name': 'commit', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': True, 'name': 'rollback', 'notes': 'Transaction savepoint (sid) is required for Django < 1.8' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'url', 'notes': 'Function used in `urlpatterns`', }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'user_model_label', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [(1, 10)], 'issues_versions': [], 'is_tested': False, 'name': 'patterns', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'include', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'handler404', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'handler500', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'get_ident', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'urlparse', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'parse_qs', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'urlunparse', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'urlencode', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'unquote_plus', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': True, 'name': 'DjangoJSONEncoder', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': True, 'name': 'JsonResponse', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'HttpResponseBase', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'python_2_unicode_compatible', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'URLValidator', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'EmailValidator', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'View', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'StringIO', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'BytesIO', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'clean_manytomany_helptext', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'smart_text', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'force_text', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'simplejson', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': True, 'name': 'import_module', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'VariableNode', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'slugify', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'SortedDict', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'atomic', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': True, 'name': 'commit_on_success', 'notes': '`commit_on_success` replaced by `atomic` in Django >= 1.8' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': True, 'name': 'format_html', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [(1, 10)], 'is_tested': True, 'name': 'resolve_url', 'notes': '1.10: Reversing by dotted path has been removed' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'close_connection', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8),], 'incompatible_versions': [(1, 9), (1, 10)], 'issues_versions': [], 'is_tested': False, 'name': 'add_to_builtins', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': True, 'name': 'get_template_loaders', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': True, 'name': 'render_to_string', 'notes': 'The new function signature (https://docs.djangoproject.com/en/1.9/releases/1.8/#dictionary-and-context-instance-arguments-of-rendering-functions) is backported to pre-1.8.', }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8),], 'incompatible_versions': [(1, 9), (1, 10)], 'issues_versions': [], 'is_tested': False, 'name': 'GenericForeignKey', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'module': 'models', 'name': 'GenericForeignKey', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': True, 'module': 'templatetags.compat', 'name': 'url', 'notes': 'Templatetag; import with `{% load url from compat %}`', }, { 'compatible_versions': [(1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [(1, 4)], 'is_tested': True, 'module': 'templatetags.compat', 'name': 'verbatim', 'notes': 'Templatetag; import with `{% load verbatim from compat %}`. 1.4: Does not allow specific closing ' 'tags, e.g. `{% endverbatim myblock %}`, and does not preserve whitespace inside tags.', }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'urlresolvers', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'get_current_site', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'admin_utils', 'notes': '' } ] # django.core.urlresolvers will be moved to django.urls in 1.10 for urlresolvers_import in [ 'LocaleRegexProvider', 'LocaleRegexURLResolver', 'NoReverseMatch', 'RegexURLPattern', 'RegexURLResolver', 'Resolver404', 'ResolverMatch', 'clear_url_caches', 'get_callable', 'get_mod_func', 'get_ns_resolver', 'get_resolver', 'get_script_prefix', 'get_urlconf', 'is_valid_path', 'resolve', 'reverse', 'reverse_lazy', 'set_script_prefix', 'set_urlconf', ]: COMPATIBLE_OBJECTS.append({ 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9), (1, 10)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': urlresolvers_import, 'notes': '' }) def is_compatible(object_name, version, module=''): for object in COMPATIBLE_OBJECTS: if (object['name'] == object_name and version in object['compatible_versions'] and object.get('module', '') == module): return True return False # https://guides.github.com/features/mastering-markdown/#GitHub-flavored-markdown def get_compatible_objects_as_markdown(): def _version_str(version): return '.'.join(map(lambda n:str(n), version)) def _render_row(row): return '|' + '|'.join(row) + '|' def _get_row(object): name = object['module'] + '.' + object['name'] if 'module' in object else object['name'] row = ['`' + name + '`'] if object['is_tested']: row.append(':heavy_check_mark:') else: row.append(':heavy_multiplication_x:') for version in COMPATIBLE_VERSIONS: if version in object['compatible_versions']: row.append(':heavy_check_mark:') elif version in object['issues_versions']: row.append(':warning:') elif version in object['incompatible_versions']: row.append(':x:') else: row.append(':heavy_multiplication_x:') row += [object['notes']] return _render_row(row) def _get_header_line(num_columns): return '|' + '|'.join(['---' for i in range(num_columns)]) + '|' header_row = (['Compatible object', 'Specifically tested'] + [_version_str(v) for v in COMPATIBLE_VERSIONS] + ['Notes']) num_columns = len(header_row) rows = ([_render_row(header_row), _get_header_line(num_columns)] + [_get_row(o) for o in sorted(COMPATIBLE_OBJECTS, key=lambda o: o['name'])]) return '\n'.join(rows) if __name__ == '__main__': print(get_compatible_objects_as_markdown()) django-compat-1.0.15/compat/json_response.py000066400000000000000000000042531321121060500210400ustar00rootroot00000000000000from __future__ import unicode_literals import datetime import decimal import uuid from django.http import HttpResponse from django.utils.timezone import is_aware from compat import simplejson class DjangoJSONEncoder(simplejson.JSONEncoder): """ JSONEncoder subclass that knows how to encode date/time, decimal types and UUIDs. """ def default(self, o): # See "Date Time String Format" in the ECMA-262 specification. if isinstance(o, datetime.datetime): r = o.isoformat() if o.microsecond: r = r[:23] + r[26:] if r.endswith('+00:00'): r = r[:-6] + 'Z' return r elif isinstance(o, datetime.date): return o.isoformat() elif isinstance(o, datetime.time): if is_aware(o): raise ValueError("JSON can't represent timezone-aware times.") r = o.isoformat() if o.microsecond: r = r[:12] return r elif isinstance(o, decimal.Decimal): return str(o) elif isinstance(o, uuid.UUID): return str(o) else: return super(DjangoJSONEncoder, self).default(o) class JsonResponse(HttpResponse): """ An HTTP response class that consumes data to be serialized to JSON. :param data: Data to be dumped into json. By default only ``dict`` objects are allowed to be passed due to a security flaw before EcmaScript 5. See the ``safe`` parameter for more information. :param encoder: Should be an json encoder class. Defaults to ``django.core.serializers.json.DjangoJSONEncoder``. :param safe: Controls if only ``dict`` objects may be serialized. Defaults to ``True``. """ def __init__(self, data, encoder=DjangoJSONEncoder, safe=True, **kwargs): if safe and not isinstance(data, dict): raise TypeError('In order to allow non-dict objects to be ' 'serialized set the safe parameter to False') kwargs.setdefault('content_type', 'application/json') data = simplejson.dumps(data, cls=encoder) super(JsonResponse, self).__init__(content=data, **kwargs) django-compat-1.0.15/compat/models.py000066400000000000000000000003461321121060500174330ustar00rootroot00000000000000 try: from compat import GenericForeignKey except ImportError: # Django >= 1.9 from django.contrib.contenttypes.fields import GenericForeignKey # the tests will try to import these __all__ = [ 'GenericForeignKey', ] django-compat-1.0.15/compat/shortcuts.py000066400000000000000000000025751321121060500202140ustar00rootroot00000000000000 from compat import urlresolvers from django.utils.functional import Promise def resolve_url(to, *args, **kwargs): """ Return a URL appropriate for the arguments passed. The arguments could be: * A model: the model's `get_absolute_url()` function will be called. * A view name, possibly with arguments: `urlresolvers.reverse()` will be used to reverse-resolve the name. * A URL, which will be returned as-is. """ from compat import six, force_text # If it's a model, use get_absolute_url() if hasattr(to, 'get_absolute_url'): return to.get_absolute_url() if isinstance(to, Promise): # Expand the lazy instance, as it can cause issues when it is passed # further to some Python functions like urlparse. to = force_text(to) if isinstance(to, six.string_types): # Handle relative URLs if any(to.startswith(path) for path in ('./', '../')): return to # Next try a reverse URL resolution. try: return urlresolvers.reverse(to, args=args, kwargs=kwargs) except urlresolvers.NoReverseMatch: # If this is a callable, re-raise. if callable(to): raise # If this doesn't "feel" like a URL, re-raise. if '/' not in to and '.' not in to: raise # Finally, fall back and assume it's a URL return to django-compat-1.0.15/compat/templatetags/000077500000000000000000000000001321121060500202655ustar00rootroot00000000000000django-compat-1.0.15/compat/templatetags/__init__.py000066400000000000000000000000001321121060500223640ustar00rootroot00000000000000django-compat-1.0.15/compat/templatetags/compat.py000066400000000000000000000026301321121060500221230ustar00rootroot00000000000000import django from django import template register = template.Library() @register.tag def url(parser, token): # Django 1.5 adds support of context variables for the url template tag if django.VERSION >= (1, 5): from django.template.defaulttags import url as url_defaulttag else: from django.templatetags.future import url as url_defaulttag return url_defaulttag(parser, token) @register.tag def verbatim(parser, token): if django.VERSION >= (1, 5): from django.template.defaulttags import verbatim as verbatim_defaulttag return verbatim_defaulttag(parser, token) # 1.4; not available from django # Source: https://github.com/aljosa/django-verbatim class VerbatimNode(template.Node): def __init__(self, content): self.content = content def render(self, context): return self.content text = [] while 1: token = parser.tokens.pop(0) if token.contents == 'endverbatim': break if token.token_type == template.TOKEN_VAR: text.append('{{ ') elif token.token_type == template.TOKEN_BLOCK: text.append('{% ') text.append(token.contents) if token.token_type == template.TOKEN_VAR: text.append(' }}') elif token.token_type == template.TOKEN_BLOCK: text.append(' %}') return VerbatimNode(''.join(text)) django-compat-1.0.15/compat/tests/000077500000000000000000000000001321121060500167355ustar00rootroot00000000000000django-compat-1.0.15/compat/tests/__init__.py000066400000000000000000000000011321121060500210350ustar00rootroot00000000000000 django-compat-1.0.15/compat/tests/settings.py000066400000000000000000000030761321121060500211550ustar00rootroot00000000000000# -*- coding: utf-8 -*- import os PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) SECRET_KEY = 'notsosecret' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:' } } INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'compat', 'compat.tests.test_app', ] MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.contrib.redirects.middleware.RedirectFallbackMiddleware', ) TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [ os.path.join(PROJECT_ROOT, 'templates/'), ], 'OPTIONS': { 'context_processors': [ 'django.contrib.auth.context_processors.auth', 'django.template.context_processors.debug', 'django.template.context_processors.i18n', 'django.template.context_processors.tz', 'django.template.context_processors.request', ], 'loaders': [ 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader' ] }, }, ] ROOT_URLCONF = 'compat.tests.urls' django-compat-1.0.15/compat/tests/south_settings.py000066400000000000000000000010541321121060500223710ustar00rootroot00000000000000""" These settings are used by the ``manage.py`` command. With normal tests we want to use the fastest possible way which is an in-memory sqlite database but if you want to create South migrations you need a persistent database. Unfortunately there seems to be an issue with either South or syncdb so that defining two routers ("default" and "south") does not work. """ from .test_settings import * # NOQA DATABASES = { 'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': 'db.sqlite', } } INSTALLED_APPS.append('south', ) django-compat-1.0.15/compat/tests/templates/000077500000000000000000000000001321121060500207335ustar00rootroot00000000000000django-compat-1.0.15/compat/tests/templates/test_context.html000066400000000000000000000000151321121060500243400ustar00rootroot00000000000000obj:{{ obj }}django-compat-1.0.15/compat/tests/test_app/000077500000000000000000000000001321121060500205545ustar00rootroot00000000000000django-compat-1.0.15/compat/tests/test_app/__init__.py000066400000000000000000000000001321121060500226530ustar00rootroot00000000000000django-compat-1.0.15/compat/tests/test_app/models.py000066400000000000000000000003731321121060500224140ustar00rootroot00000000000000""" Regression tests for the resolve_url function. """ from django.db import models class UnimportantThing(models.Model): importance = models.IntegerField() def get_absolute_url(self): return '/importance/%d/' % (self.importance,) django-compat-1.0.15/compat/tests/test_app/templates/000077500000000000000000000000001321121060500225525ustar00rootroot00000000000000django-compat-1.0.15/compat/tests/test_app/templates/400.html000066400000000000000000000000001321121060500237310ustar00rootroot00000000000000django-compat-1.0.15/compat/tests/test_app/templates/500.html000066400000000000000000000000001321121060500237320ustar00rootroot00000000000000django-compat-1.0.15/compat/tests/test_app/templatetags/000077500000000000000000000000001321121060500232465ustar00rootroot00000000000000django-compat-1.0.15/compat/tests/test_app/templatetags/__init__.py000066400000000000000000000000001321121060500253450ustar00rootroot00000000000000django-compat-1.0.15/compat/tests/test_app/templatetags/test_app_tags.py000066400000000000000000000002041321121060500264510ustar00rootroot00000000000000from django import template register = template.Library() @register.simple_tag def my_tag(): return "Return value of my_tag" django-compat-1.0.15/compat/tests/test_compat.py000066400000000000000000000354461321121060500216450ustar00rootroot00000000000000# -*- encoding: utf-8 -*- from __future__ import unicode_literals import json import uuid import django from django.contrib.admin.models import LogEntry from django.core.serializers.json import DjangoJSONEncoder from django.test import TestCase, SimpleTestCase from django.test.client import RequestFactory from django.contrib.auth.views import logout try: from django.urls import NoReverseMatch except ImportError: from django.core.urlresolvers import NoReverseMatch from django.template import Template, Context, TemplateSyntaxError, RequestContext import compat from compat import (import_module, resolve_url, JsonResponse, get_model, render_to_string, get_template_loaders, get_current_site) from compat.docs.compatibility import is_compatible from compat.tests.test_app.models import UnimportantThing class CompatTests(TestCase): def test_is_compatible(self): self.assertTrue(is_compatible('get_model', (1, 4))) self.assertFalse(is_compatible('get_model', (1, 3))) self.assertFalse(is_compatible('Eyjafjallajoekull', (1, 4))) self.assertTrue(is_compatible('GenericForeignKey', (1, 4), module='models')) self.assertFalse(is_compatible('Eyjafjallajoekull', (1, 4), module='models')) def test_compat(self): compat = import_module('compat') for attribute in compat.__all__: if is_compatible(attribute, django.VERSION[:2]): self.assertTrue(hasattr(compat, attribute)) def test_compat_models(self): compat_models = import_module('compat.models') for attribute in compat_models.__all__: if is_compatible(attribute, django.VERSION[:2], 'models'): self.assertTrue(hasattr(compat_models, attribute)) def test_format_html(self): """ Test: format_html url: https://github.com/django/django/blob/stable/1.8.x/tests/utils_tests/test_html.py#L44-L53 """ from django.utils import html from compat import format_html self.assertEqual( format_html("{0} {1} {third} {fourth}", "< Dangerous >", html.mark_safe("safe"), third="< dangerous again", fourth=html.mark_safe("safe again") ), "< Dangerous > safe < dangerous again safe again" ) def test_resolve_url__url_path(self): """ Tests that passing a URL path to ``resolve_url`` will result in the same url. """ self.assertEqual('/something/', resolve_url('/something/')) def test_resolve_url__relative_path(self): """ Tests that passing a relative URL path to ``resolve_url`` will result in the same url. """ self.assertEqual('../', resolve_url('../')) self.assertEqual('../relative/', resolve_url('../relative/')) self.assertEqual('./', resolve_url('./')) self.assertEqual('./relative/', resolve_url('./relative/')) def test_resolve_url__full_url(self): """ Tests that passing a full URL to ``resolve_url`` will result in the same url. """ url = 'http://example.com/' self.assertEqual(url, resolve_url(url)) def test_resolve_url__model(self): """ Tests that passing a model to ``resolve_url`` will result in ``get_absolute_url`` being called on that model instance. """ m = UnimportantThing(importance=1) self.assertEqual(m.get_absolute_url(), resolve_url(m)) def test_resolve_url__view_function(self): """ Tests that passing a view name to ``resolve_url`` will result in the URL path mapping to that view name. """ resolved_url = resolve_url(logout) self.assertEqual('/accounts/logout/', resolved_url) ''' incompatible with lower django versions def test_resolve_url__lazy_reverse(self): """ Tests that passing the result of reverse_lazy is resolved to a real URL string. """ from django.utils import six resolved_url = resolve_url(reverse_lazy('logout')) self.assertIsInstance(resolved_url, six.text_type) self.assertEqual('/accounts/logout/', resolved_url) ''' if django.VERSION < (1, 10): def test_resolve_url__valid_view_name(self): """ Tests that passing a view function to ``resolve_url`` will result in the URL path mapping to that view. """ resolved_url = resolve_url('django.contrib.auth.views.logout') self.assertEqual('/accounts/logout/', resolved_url) def test_resolve_url__domain(self): """ Tests that passing a domain to ``resolve_url`` returns the same domain. """ self.assertEqual(resolve_url('example.com'), 'example.com') def test_resolve_url__non_view_callable_raises_no_reverse_match(self): """ Tests that passing a non-view callable into ``resolve_url`` raises a ``NoReverseMatch`` exception. """ with self.assertRaises(NoReverseMatch): resolve_url(lambda: 'asdf') def test_commit_on_success(self): """ Test of commit_on_success """ @compat.commit_on_success def db_action(): m = UnimportantThing(pk=1, importance=1) m.save() db_action() self.assertEqual(UnimportantThing.objects.get(pk=1).importance, 1) def test_commit(self): """ Test of commit """ m = UnimportantThing(pk=2, importance=2) m.save() compat.commit() self.assertEqual(UnimportantThing.objects.get(pk=2).importance, 2) def test_rollback__with_sid(self): """ Test of rollback with transaction savepoint """ @compat.commit_on_success def db_action(): m = UnimportantThing(pk=3, importance=3) m.save() return m @compat.commit_on_success def db_action_with_rollback(m): m.importance = 5 sid = django.db.transaction.savepoint() m.save() compat.rollback(None, sid) if django.VERSION < (1, 5): # Rollback doesn't work with SQLite return m = db_action() db_action_with_rollback(m) self.assertEqual(UnimportantThing.objects.get(pk=3).importance, 3) def test_rollback__without_sid(self): """ Test of rollback without transaction savepoint """ @compat.commit_on_success def db_action(): m = UnimportantThing(pk=4, importance=4) m.save() return m @compat.commit_on_success def db_action_with_rollback(m): m.importance = 5 m.save() compat.rollback() if django.VERSION < (1, 8): # Rollback doesn't work after .save() if an exception isn't thrown return m = db_action() db_action_with_rollback(m) self.assertEqual(UnimportantThing.objects.get(pk=4).importance, 4) def test_url_template_tag(self): template = Template( '{% load url from compat %}' 'Log out' ) html = template.render(Context({})) self.assertEqual( html, 'Log out' ) if django.VERSION < (1, 9): def test_add_to_builtins(self): from compat import add_to_builtins # Explicit import of tags template = Template( '{% load test_app_tags %}' '{% my_tag %}' ) self.assertIn('Return value of my_tag', template.render(Context({}))) # No import with self.assertRaises(TemplateSyntaxError): template = Template( '{% my_tag %}' ) template.render(Context({})) # No import but add_to_builtins call add_to_builtins('compat.tests.test_app.templatetags.test_app_tags') template = Template( '{% my_tag %}' ) self.assertIn('Return value of my_tag', template.render(Context({}))) def test_get_template_loaders(self): template_loaders = get_template_loaders() self.assertEqual(len(template_loaders), 2) self.assertIsInstance(template_loaders[0], django.template.loaders.filesystem.Loader) self.assertIsInstance(template_loaders[1], django.template.loaders.app_directories.Loader) class GetModelsTest(SimpleTestCase): """ Sources: * https://github.com/django/django/blob/stable/1.9.x/tests/app_loading/tests.py * https://github.com/django/django/blob/stable/1.9.x/tests/apps/tests.py """ def setUp(self): from compat.tests.utils_tests.not_installed import models self.not_installed_module = models def test_get_model_only_returns_installed_models(self): with self.assertRaises(LookupError): get_model("not_installed", "NotInstalledModel") def test_get_model(self): self.assertEqual(get_model('admin', 'LogEntry'), LogEntry) with self.assertRaises(LookupError): get_model('admin', 'LogExit') # App label is case-sensitive, Model name is case-insensitive. self.assertEqual(get_model('admin', 'loGentrY'), LogEntry) with self.assertRaises(LookupError): get_model('Admin', 'LogEntry') # A single argument is accepted. self.assertEqual(get_model('admin.LogEntry'), LogEntry) with self.assertRaises(LookupError): get_model('admin.LogExit') with self.assertRaises(ValueError): get_model('admin_LogEntry') class VerbatimTagTestCase(TestCase): """ Source: https://github.com/django/django/blob/master/tests/template_tests/syntax_tests/test_verbatim.py """ def setUp(self): self.import_tag = '{% load verbatim from compat %}' def test_verbatim_tag01(self): template = Template(self.import_tag + '{% verbatim %}{{ bare }}{% endverbatim %}' ) html = template.render(Context({})) self.assertEqual(html, '{{ bare }}' ) def test_verbatim_tag02(self): template = Template(self.import_tag + '{% verbatim %}{% endif %}{% endverbatim %}' ) html = template.render(Context({})) self.assertEqual(html, '{% endif %}' ) def test_verbatim_tag03(self): template = Template(self.import_tag + '{% verbatim %}It\'s the {% verbatim %} tag{% endverbatim %}' ) html = template.render(Context({})) self.assertEqual(html, 'It\'s the {% verbatim %} tag' ) def test_verbatim_tag04(self): with self.assertRaises(TemplateSyntaxError): Template(self.import_tag + '{% verbatim %}{% verbatim %}{% endverbatim %}{% endverbatim %}' ) def test_verbatim_tag05(self): template = Template(self.import_tag + '{% verbatim %}{% endverbatim %}{% verbatim %}{% endverbatim %}' ) html = template.render(Context({})) self.assertEqual(html, '') if django.VERSION >= (1, 5): # Not implemented in 1.4 def test_verbatim_tag06(self): template = Template(self.import_tag + '{% verbatim special %}' 'Don\'t {% endverbatim %} just yet{% endverbatim special %}' ) html = template.render(Context({})) self.assertEqual(html, 'Don\'t {% endverbatim %} just yet' ) class JsonResponseTests(SimpleTestCase): """ Source: https://github.com/django/django/blob/master/tests/httpwrappers/tests.py """ def test_json_response_non_ascii(self): data = {'key': 'łóżko'} response = JsonResponse(data) self.assertEqual(json.loads(response.content.decode()), data) def test_json_response_raises_type_error_with_default_setting(self): with self.assertRaises(TypeError): JsonResponse([1, 2, 3]) def test_json_response_text(self): response = JsonResponse('foobar', safe=False) self.assertEqual(json.loads(response.content.decode()), 'foobar') def test_json_response_list(self): response = JsonResponse(['foo', 'bar'], safe=False) self.assertEqual(json.loads(response.content.decode()), ['foo', 'bar']) def test_json_response_uuid(self): u = uuid.uuid4() response = JsonResponse(u, safe=False) self.assertEqual(json.loads(response.content.decode()), str(u)) def test_json_response_custom_encoder(self): class CustomDjangoJSONEncoder(DjangoJSONEncoder): def encode(self, o): return json.dumps({'foo': 'bar'}) response = JsonResponse({}, encoder=CustomDjangoJSONEncoder) self.assertEqual(json.loads(response.content.decode()), {'foo': 'bar'}) if django.VERSION >= (1, 9): def test_json_response_passing_arguments_to_json_dumps(self): response = JsonResponse({'foo': 'bar'}, json_dumps_params={'indent': 2}) self.assertEqual(response.content.decode(), '{\n "foo": "bar"\n}') def test_get_current_site(self): """ Test of get_current_site """ rf = RequestFactory() request = rf.get('/hello/') site = get_current_site(request) assert site class RenderToStringTest(TestCase): template_name = 'test_context.html' def test_basic(self): self.assertEqual(render_to_string(self.template_name), 'obj:') def test_positional_arg(self): self.assertEqual(render_to_string(self.template_name, {'obj': 'test'}), 'obj:test') if django.VERSION < (1, 10): def test_dictionary_kwarg(self): self.assertEqual(render_to_string(self.template_name, dictionary={'obj': 'test'}), 'obj:test') def test_context_instance_kwarg(self): self.assertEqual(render_to_string(self.template_name, context_instance=Context({'obj': 'test'})), 'obj:test') def test_request_context(self): self.assertEqual(render_to_string(self.template_name, context_instance=RequestContext(None, {'obj': 'test'})), 'obj:test') def test_dictionary_and_context_instance_kwarg(self): self.assertEqual(render_to_string(self.template_name, dictionary={'obj': '1'}, context_instance=Context({'obj': '2'})), 'obj:1') # Fails 1.4 def test_context_kwarg(self): self.assertEqual(render_to_string(self.template_name, context={'obj': 'test'}), 'obj:test') django-compat-1.0.15/compat/tests/test_module_loading.py000066400000000000000000000055671321121060500233450ustar00rootroot00000000000000import sys import imp from django.test import TestCase from django.utils.module_loading import module_has_submodule from compat import import_module class DefaultLoader(TestCase): def setUp(self): sys.meta_path.insert(0, ProxyFinder()) def tearDown(self): sys.meta_path.pop(0) def test_loader(self): "Normal module existence can be tested" test_module = import_module('compat.tests.utils_tests.test_module') test_no_submodule = import_module( 'compat.tests.utils_tests.test_no_submodule') # An importable child self.assertTrue(module_has_submodule(test_module, 'good_module')) mod = import_module('compat.tests.utils_tests.test_module.good_module') self.assertEqual(mod.content, 'Good Module') # A child that exists, but will generate an import error if loaded self.assertTrue(module_has_submodule(test_module, 'bad_module')) with self.assertRaises(ImportError): import_module('compat.tests.utils_tests.test_module.bad_module') # A child that doesn't exist self.assertFalse(module_has_submodule(test_module, 'no_such_module')) with self.assertRaises(ImportError): import_module('compat.tests.utils_tests.test_module.no_such_module') # A child that doesn't exist, but is the name of a package on the path self.assertFalse(module_has_submodule(test_module, 'django')) with self.assertRaises(ImportError): import_module('compat.tests.utils_tests.test_module.django') # Don't be confused by caching of import misses import types # NOQA: causes attempted import of utils_tests.types self.assertFalse(module_has_submodule(sys.modules['compat.tests.utils_tests'], 'types')) # A module which doesn't have a __path__ (so no submodules) self.assertFalse(module_has_submodule(test_no_submodule, 'anything')) with self.assertRaises(ImportError): import_module('compat.tests.utils_tests.test_no_submodule.anything') class ProxyFinder(object): def __init__(self): self._cache = {} def find_module(self, fullname, path=None): tail = fullname.rsplit('.', 1)[-1] try: fd, fn, info = imp.find_module(tail, path) if fullname in self._cache: old_fd = self._cache[fullname][0] if old_fd: old_fd.close() self._cache[fullname] = (fd, fn, info) except ImportError: return None else: return self # this is a loader as well def load_module(self, fullname): if fullname in sys.modules: return sys.modules[fullname] fd, fn, info = self._cache[fullname] try: return imp.load_module(fullname, fd, fn, info) finally: if fd: fd.close() django-compat-1.0.15/compat/tests/urls.py000066400000000000000000000002271321121060500202750ustar00rootroot00000000000000from django.conf.urls import url from django.contrib.auth import views urlpatterns = [ url(r'^accounts/logout/$', views.logout, name='logout'), ] django-compat-1.0.15/compat/tests/utils_tests/000077500000000000000000000000001321121060500213175ustar00rootroot00000000000000django-compat-1.0.15/compat/tests/utils_tests/__init__.py000066400000000000000000000000001321121060500234160ustar00rootroot00000000000000django-compat-1.0.15/compat/tests/utils_tests/not_installed/000077500000000000000000000000001321121060500241565ustar00rootroot00000000000000django-compat-1.0.15/compat/tests/utils_tests/not_installed/__init__.py000066400000000000000000000000001321121060500262550ustar00rootroot00000000000000django-compat-1.0.15/compat/tests/utils_tests/not_installed/models.py000066400000000000000000000006711321121060500260170ustar00rootroot00000000000000from django.db import models class NotInstalledModel(models.Model): class Meta: app_label = 'not_installed' class RelatedModel(models.Model): class Meta: app_label = 'not_installed' not_installed = models.ForeignKey(NotInstalledModel, models.CASCADE) class M2MRelatedModel(models.Model): class Meta: app_label = 'not_installed' not_installed = models.ManyToManyField(NotInstalledModel) django-compat-1.0.15/compat/tests/utils_tests/test_module/000077500000000000000000000000001321121060500236435ustar00rootroot00000000000000django-compat-1.0.15/compat/tests/utils_tests/test_module/__init__.py000066400000000000000000000002311321121060500257500ustar00rootroot00000000000000# Source: https://github.com/django/django/tree/stable/1.9.x/tests/utils_tests/test_module class SiteMock(object): _registry = {} site = SiteMock() django-compat-1.0.15/compat/tests/utils_tests/test_module/another_bad_module.py000066400000000000000000000002141321121060500300250ustar00rootroot00000000000000from . import site content = 'Another Bad Module' site._registry.update({ 'foo': 'bar', }) raise Exception('Some random exception.') django-compat-1.0.15/compat/tests/utils_tests/test_module/another_good_module.py000066400000000000000000000001461321121060500302330ustar00rootroot00000000000000from . import site content = 'Another Good Module' site._registry.update({ 'lorem': 'ipsum', }) django-compat-1.0.15/compat/tests/utils_tests/test_module/bad_module.py000066400000000000000000000001121321121060500263020ustar00rootroot00000000000000import a_package_name_that_does_not_exist # NOQA content = 'Bad Module' django-compat-1.0.15/compat/tests/utils_tests/test_module/good_module.py000066400000000000000000000000301321121060500265030ustar00rootroot00000000000000content = 'Good Module' django-compat-1.0.15/compat/tests/utils_tests/test_no_submodule.py000066400000000000000000000000701321121060500254200ustar00rootroot00000000000000# Used to test for modules which don't have submodules. django-compat-1.0.15/requirements-test.txt000066400000000000000000000000111321121060500205410ustar00rootroot00000000000000coverage django-compat-1.0.15/requirements.txt000066400000000000000000000000141321121060500175670ustar00rootroot00000000000000six>=1.10.0 django-compat-1.0.15/runtests.py000066400000000000000000000006171321121060500165550ustar00rootroot00000000000000#!/usr/bin/env python import os import sys import django from django.conf import settings from django.test.utils import get_runner if __name__ == "__main__": os.environ['DJANGO_SETTINGS_MODULE'] = 'compat.tests.settings' django.setup() TestRunner = get_runner(settings) test_runner = TestRunner() failures = test_runner.run_tests(["compat.tests"]) sys.exit(bool(failures)) django-compat-1.0.15/setup.cfg000066400000000000000000000003751321121060500161360ustar00rootroot00000000000000[bdist_wheel] # This flag says that the code is written to work on both Python 2 and Python # 3. If at all possible, it is good practice to do this. If you cannot, you # will need to generate wheels for each Python version that you support. universal=1 django-compat-1.0.15/setup.py000066400000000000000000000045061321121060500160270ustar00rootroot00000000000000# -*- encoding: utf-8 -*- import os, sys from setuptools import setup from setuptools import find_packages # Make the open function accept encodings in python < 3.x if sys.version_info[0] < 3: import codecs open = codecs.open # pylint: disable=redefined-builtin # Utility function to read the README file. # Used for the long_description. It's nice, because now 1) we have a top level # README file and 2) it's easier to type in the README file than to put a raw # string in below ... def get_path(fname): return os.path.join(os.path.dirname(os.path.abspath(__file__)), fname) def read(fname): return open(get_path(fname), 'r', encoding='utf8').read() if sys.argv[-1] == 'genreadme': try: import pypandoc long_description = pypandoc.convert(get_path('README.md'), 'rst') long_description = long_description.split('')[0] f = open(get_path('README.rst'), 'w') f.write(long_description) f.close() print("Successfully converted README.md to README.rst") except (IOError, ImportError): pass sys.exit() try: long_description=read('README.rst') except (OSError, IOError): try: long_description=read('README.md') except (OSError, IOError): long_description = "" setup( name="django-compat", version="1.0.15", author='arteria GmbH', author_email="admin@arteria.ch", packages=find_packages(), include_package_data=True, description="For- and backwards compatibility layer for Django 1.4, 1.7, 1.8, 1.9, 1.10, and 1.11", long_description=long_description, license='MIT', install_requires=open('requirements.txt').read().splitlines(), url="https://github.com/arteria/django-compat", classifiers=[ 'Development Status :: 5 - Production/Stable', 'Framework :: Django', 'License :: OSI Approved :: MIT License', 'Framework :: Django', 'Framework :: Django :: 1.4', 'Framework :: Django :: 1.6', 'Framework :: Django :: 1.7', 'Framework :: Django :: 1.8', 'Framework :: Django :: 1.9', 'Framework :: Django :: 1.10', 'Framework :: Django :: 1.11', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', ], ) django-compat-1.0.15/tox.ini000066400000000000000000000007001321121060500156200ustar00rootroot00000000000000[tox] envlist = py{27,35,36}-django{18,19,110,111,20}, [testenv] deps = django18: Django>=1.8,<1.9 django19: Django>=1.1,<1.10 django110: Django>=1.10,<1.11 django111: Django>=1.11,<2.0 django20: Django>=2.0a1,<2.1 -r{toxinidir}/requirements-test.txt -r{toxinidir}/requirements.txt commands = pip freeze coverage erase # delete excisting coverage reports coverage run ./runtests.py coverage report