pax_global_header00006660000000000000000000000064126223331150014510gustar00rootroot0000000000000052 comment=9a3cc469ac5aadaec09554ec56a1bf879c72b4c2 django-compat-1.0.8/000077500000000000000000000000001262233311500142415ustar00rootroot00000000000000django-compat-1.0.8/.gitignore000066400000000000000000000012511262233311500162300ustar00rootroot00000000000000# 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.8/.travis.yml000066400000000000000000000026001262233311500163500ustar00rootroot00000000000000language: python sudo: false cache: pip # Python versions supported by Django # 2.5 2.6 2.7 3.2 3.3 3.4 3.5 3.6 # 1.4 X X X # 1.6 X X X X # 1.7 X X X X # 1.8 X X X X # 1.9 X X X matrix: include: - python: 2.6 env: DJANGO=django==1.4.* - python: 2.6 env: DJANGO=django==1.6.* - python: 2.7 env: DJANGO=django==1.4.* - python: 2.7 env: DJANGO=django==1.6.* - python: 2.7 env: DJANGO=django==1.7.* - python: 2.7 env: DJANGO=django==1.8.* - python: 2.7 env: DJANGO=django==1.9b1 - python: 3.2 env: DJANGO=django==1.6.* - python: 3.2 env: DJANGO=django==1.7.* - python: 3.2 env: DJANGO=django==1.8.* - python: 3.3 env: DJANGO=django==1.6.* - python: 3.3 env: DJANGO=django==1.7.* - python: 3.3 env: DJANGO=django==1.8.* - python: 3.4 env: DJANGO=django==1.7.* - python: 3.4 env: DJANGO=django==1.8.* - python: 3.4 env: DJANGO=django==1.9b1 - python: 3.5 env: DJANGO=django==1.9b1 install: - pip install "pip>=7.0" wheel - pip install -r requirements.txt $DJANGO script: python runtests.py django-compat-1.0.8/AUTHORS.txt000066400000000000000000000004201262233311500161230ustar00rootroot00000000000000Brad 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) django-compat-1.0.8/MANIFEST000066400000000000000000000001351262233311500153710ustar00rootroot00000000000000include LICENSE include README.md include README.rst include README include requirements.txt django-compat-1.0.8/MANIFEST.in000066400000000000000000000001351262233311500157760ustar00rootroot00000000000000include LICENSE include README.md include README.rst include README include requirements.txt django-compat-1.0.8/README.md000066400000000000000000000216601262233311500155250ustar00rootroot00000000000000 django-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) Forward and backwards compatibility layer for Django 1.4, 1.7, 1.8, and 1.9 ~~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). # Compatible objects |Compatible object|Specifically tested|1.4|1.7|1.8|1.9|Notes| |---|---|---|---|---|---|---| |`BytesIO`|:heavy_multiplication_x:|: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:|:heavy_check_mark:|:heavy_check_mark:|: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_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:|:heavy_check_mark:|:heavy_check_mark:|:x:|| |`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:|| |`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_ident`|: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_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_multiplication_x:|: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:|| |`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:|:heavy_check_mark:|:heavy_check_mark:|| |`python_2_unicode_compatible`|: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:|: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| |`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_check_mark:|:heavy_check_mark:|Function used in `urlpatterns`| |`templatetags.compat.url`|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|Templatetag; import with `{% load url from compat %}`| |`urlencode`|:heavy_multiplication_x:|: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:|| |`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:|| # 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 ### 2015/11/12 * Added `{% load url from compat %}` ### 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.8/compat/000077500000000000000000000000001262233311500155245ustar00rootroot00000000000000django-compat-1.0.8/compat/__init__.py000066400000000000000000000307241262233311500176430ustar00rootroot00000000000000# 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 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, patterns, include, handler404, handler500 except ImportError: from django.conf.urls.defaults import url, patterns, include, handler404, handler500 # pyflakes:ignore # 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 # Django 1.7 compatibility try: from django.http import JsonResponse except: from .json_response 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.shortcuts import resolve_url except ImportError: # django < 1.5 from .shortcuts import resolve_url try: from django.shortcuts import resolve_url except ImportError: # django < 1.5 from .shortcuts import resolve_url ### 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') # 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', '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', ] django-compat-1.0.8/compat/docs/000077500000000000000000000000001262233311500164545ustar00rootroot00000000000000django-compat-1.0.8/compat/docs/__init__.py000066400000000000000000000000001262233311500205530ustar00rootroot00000000000000django-compat-1.0.8/compat/docs/compatibility.py000066400000000000000000000275221262233311500217070ustar00rootroot00000000000000 COMPATIBLE_VERSIONS = ( (1, 4), (1, 7), (1, 8), (1, 9), ) COMPATIBLE_OBJECTS = ( { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'get_model', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'get_model_name', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'get_user_model', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'get_username_field', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'import_string', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': True, 'name': 'commit', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], '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)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'user_model_label', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'patterns', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'include', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'handler404', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'handler500', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'get_ident', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'urlparse', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'parse_qs', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'urlunparse', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'urlencode', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'unquote_plus', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'JsonResponse', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'HttpResponseBase', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'python_2_unicode_compatible', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'URLValidator', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'EmailValidator', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'View', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'StringIO', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'BytesIO', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'clean_manytomany_helptext', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'smart_text', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'force_text', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'simplejson', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'import_module', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'VariableNode', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'slugify', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'SortedDict', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'name': 'atomic', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], '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)], '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': [], 'is_tested': True, 'name': 'resolve_url', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8),], 'incompatible_versions': [(1, 9),], 'issues_versions': [], 'is_tested': False, 'name': 'add_to_builtins', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8),], 'incompatible_versions': [(1, 9),], 'issues_versions': [], 'is_tested': False, 'name': 'GenericForeignKey', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': False, 'module': 'models', 'name': 'GenericForeignKey', 'notes': '' }, { 'compatible_versions': [(1, 4), (1, 7), (1, 8), (1, 9)], 'incompatible_versions': [], 'issues_versions': [], 'is_tested': True, 'module': 'templatetags.compat', 'name': 'url', 'notes': 'Templatetag; import with `{% load url from compat %}`', }, ) 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.8/compat/json_response.py000066400000000000000000000014061262233311500207660ustar00rootroot00000000000000""" A subclass of HttpResponse useful as a shortcut in views; it chooses the correct JSON serializer based on whether or not it is passed a QuerySet. Source: https://djangosnippets.org/snippets/154/ """ from django.core.serializers import json, serialize from django.db.models.query import QuerySet from django.http import HttpResponse from compat import simplejson class JsonResponse(HttpResponse): def __init__(self, object): if isinstance(object, QuerySet): content = serialize('json', object) else: content = simplejson.dumps( object, indent=2, cls=json.DjangoJSONEncoder, ensure_ascii=False) super(JsonResponse, self).__init__( content, content_type='application/json') django-compat-1.0.8/compat/models.py000066400000000000000000000003461262233311500173640ustar00rootroot00000000000000 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.8/compat/shortcuts.py000066400000000000000000000026021262233311500201340ustar00rootroot00000000000000 from django.core 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.8/compat/templatetags/000077500000000000000000000000001262233311500202165ustar00rootroot00000000000000django-compat-1.0.8/compat/templatetags/__init__.py000066400000000000000000000000001262233311500223150ustar00rootroot00000000000000django-compat-1.0.8/compat/templatetags/compat.py000066400000000000000000000006111262233311500220510ustar00rootroot00000000000000import django from django import template # 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 register = template.Library() @register.tag def url(parser, token): return url_defaulttag(parser, token) django-compat-1.0.8/compat/tests/000077500000000000000000000000001262233311500166665ustar00rootroot00000000000000django-compat-1.0.8/compat/tests/__init__.py000066400000000000000000000000011262233311500207660ustar00rootroot00000000000000 django-compat-1.0.8/compat/tests/manage_settings.py000066400000000000000000000002131262233311500224040ustar00rootroot00000000000000from .test_settings import * DATABASES = { 'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': 'test.db', } } django-compat-1.0.8/compat/tests/south_settings.py000066400000000000000000000010541262233311500223220ustar00rootroot00000000000000""" 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 persistant 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.8/compat/tests/test_app/000077500000000000000000000000001262233311500205055ustar00rootroot00000000000000django-compat-1.0.8/compat/tests/test_app/__init__.py000066400000000000000000000000001262233311500226040ustar00rootroot00000000000000django-compat-1.0.8/compat/tests/test_app/models.py000066400000000000000000000003731262233311500223450ustar00rootroot00000000000000""" 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.8/compat/tests/test_app/templates/000077500000000000000000000000001262233311500225035ustar00rootroot00000000000000django-compat-1.0.8/compat/tests/test_app/templates/400.html000066400000000000000000000000001262233311500236620ustar00rootroot00000000000000django-compat-1.0.8/compat/tests/test_app/templates/500.html000066400000000000000000000000001262233311500236630ustar00rootroot00000000000000django-compat-1.0.8/compat/tests/test_compat.py000066400000000000000000000156401262233311500215700ustar00rootroot00000000000000from django.test import TestCase import django from django.contrib.auth.views import logout from django.core.urlresolvers import NoReverseMatch from django.template import Template, Context import compat from compat import import_module, resolve_url 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) ''' 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' ) django-compat-1.0.8/compat/tests/urls.py000066400000000000000000000002271262233311500202260ustar00rootroot00000000000000from django.conf.urls import url from django.contrib.auth import views urlpatterns = [ url(r'^accounts/logout/$', views.logout, name='logout'), ] django-compat-1.0.8/requirements.txt000066400000000000000000000000251262233311500175220ustar00rootroot00000000000000six django-nose>=1.2 django-compat-1.0.8/runtests.py000066400000000000000000000030151262233311500165010ustar00rootroot00000000000000#!/usr/bin/env python """ This script is a trick to setup a fake Django environment, since this reusable app will be developed and tested outside any specifiv Django project. Via ``settings.configure`` you will be able to set all necessary settings for your app and run the tests as if you were calling ``./manage.py test``. """ import sys import django from django.conf import settings def setup(): DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:' } } INSTALLED_APPS = [ 'django.contrib.auth', 'django.contrib.contenttypes', 'compat', 'compat.tests.test_app', ] if django.VERSION < (1, 7): INSTALLED_APPS.append('compat.tests') MIDDLEWARE_CLASSES = [] if django.VERSION < (1, 7): MIDDLEWARE_CLASSES.append('django.middleware.transaction.TransactionMiddleware') from django.conf import settings if not settings.configured: settings.configure( INSTALLED_APPS=INSTALLED_APPS, DATABASES=DATABASES, ROOT_URLCONF='compat.tests.urls', MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES, ) def runtests(*test_args): if django.VERSION >= (1, 7): django.setup() from django_nose import NoseTestSuiteRunner failures = NoseTestSuiteRunner(verbosity=2, interactive=True).run_tests(test_args) sys.exit(failures) if __name__ == '__main__': setup() runtests(*sys.argv[1:])django-compat-1.0.8/setup.cfg000066400000000000000000000003751262233311500160670ustar00rootroot00000000000000[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.8/setup.py000066400000000000000000000037741262233311500157660ustar00rootroot00000000000000# -*- encoding: utf-8 -*- import os, sys from setuptools import setup from setuptools import find_packages # 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)).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 IOError: try: long_description=read('README.md') except IOError: long_description = "" install_requires = [ 'django>=1.4,<1.10', 'six>=1.10.0', ] setup( name="django-compat", version="1.0.8", 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, and 1.9", long_description=long_description, license='MIT', install_requires=install_requires, 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', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', ], ) django-compat-1.0.8/tox.ini000066400000000000000000000012201262233311500155470ustar00rootroot00000000000000# To run the unit tests against multiple python versions you will need # the necessary python versions installed, and Tox. # pip install tox # tox [tox] envlist = py26-django14, py26-django16, py27-django14, py27-django16, py27-django17, py27-django18, py32-django16, py32-django17, py32-django18, py33-django16, py33-django17, py33-django18, py34-django16, py34-django17, py34-django18, [testenv] deps = -rrequirements.txt django14: Django>=1.4,<1.5 django16: Django>=1.6,<1.7 django17: Django>=1.7,<1.8 django18: Django>=1.8,<1.9 commands = python runtests.py