Skip to main content

A monkey-patching system to ease the transition between Django versions.

Project description

Compatibility Matters

DCP is a “magic” package which adds backward/forward compatibility patches to Django, so that your app ecosystem doesn’t get broken by trivial changes made to the core of the framework.

It injects compatibility shims like function/attribute aliases, restores data structures which were replaced by stdlib ones, extends the behaviour of callables (eg. referring to a view by object, by name, or by dotted path), and can even preserve deprecated module as “import aliases” (ex. keep importing from “django.contrib.comments” instead of the now external “django_comments”).

This allows to you upgrade your dependencies one at a time, to fork/patch them when you have a proper opportunity, and most importantly to not get stuck, when deadlines are tight and your dependencies suddenly have conflicting requirements. DCP will however not provide patches for changes related to security (permissions, html escaping, cookie parameters…), because of the risks involved. Also, changes that only impact project-level code (eg. settings module) will often not get patches, since it’s easier and cleaner to simply update your project code.

Technically, DCP manages a set of “fixers”, small utilities which advertise the change that they make, the versions of Django that they support, and which monkey-patch the Django framework on demand. By applying these fixers in a proper order (sometimes before, sometimes after django.setup()), DCP can work around multiple breaking changes which target the same part of the code (eg. a tag library being added and then removed).

Note that DCP is aimed at project maintainers. If you are developing a reusable Django application, you can’t expect all your users to integrate DCP as well. In this case, to support a wide range of Django versions, you should rather use a toolkit like Django-compat. You may think of DCP as a “runtime 2to3 for Django’, whereas Django-Compat is rather a “six module for Django”.

Feel free to contribute new fixers, for backwards or forwards compatibility, depending on the compatibility troubles you encounter on your projects (see CONTRIBUTE.rst)

1 How to install

Django-compat-patcher is currently tested on python2.7/3.4/3.5/3.6/3.7, with Django versions 1.8/1.9/1.10/1.11/2.0/2.1/2.2, where these combinations make sense (eg. Django2+ dropped support for Python2).

Add django-compat-patcher to your pip requirements, install it, and then activate it with:

import django_compat_patcher
django_compat_patcher.patch()

This code should be placed before any use of Django (eg. in your manage.py or your wsgi.py script), but after the DJANGO_SETTINGS_MODULE environment variable has been set.

In particular, some fixers only work if they are applied before the loading of INSTALLED_APPS (so before django.setup() gets called).

The Django settings of your project are not altered by compatibility shims, so they should be kept up-to-date with your installed Django version (eg. now use TEMPLATES, MIDDLEWARE, and not deprecated settings…). In particular, always put real package names in INSTALLED_APPS, not their potential “import aliases”.

2 Django settings

By default, DCP emits logs and warnings when patching the code, and applies all “relevant” fixers, i.e all that support your currently installed django version.

This behaviour can be customized via the Django settings below.

Note however, that some fixers depend on other fixers, so it’s advised to be consistent and always include contiguous series of fixers around your current version (ex. if you use Django1.10, apply fixers from Django1.8 up to Django1.10, or up to Django2.X if yo want some forward compatibility as well). DCP filters out, by himself, fixers which are useless for your Django version.

“Families” identify the Django version where the breaking change was introduced (for backwards compatibility fixers), or where the new feature was introduced (for forwards compatibility fixers). It is not related to the appearance of corresponding PendingDeprecationWarnings in the framework.

You may provide a “settings” dictionary directly to the patch() method, in which case your DCP django settings will be completely ignored (only library defaults will be used as fallbacks):

django_compat_patcher.patch(settings=dict(DCP_INCLUDE_FIXER_IDS=["my_fixer_id"]))

Note that exclusion filters have precedence over inclusion ones.

2.1 DCP_INCLUDE_FIXER_IDS

List of fixer identifiers to include. If "*" is used, then all fixers are included.

Default: "*"
Type: List of strings, or "*"
Example: DCP_INCLUDE_FIXER_IDS = ['fix_deletion_templatetags_future_url']

2.2 DCP_INCLUDE_FIXER_FAMILIES

List of fixer families to include. If "*" is used, then all families are included.

Note: If you want to include only specific families, remember to replace the value "*" from :code:`DCP_INCLUDE_FIXER_IDS by, for example, an empty list.

Default: []
Type: List of strings, or "*"
Choices: ("djangoX.Y") where X and Y are respectively the major and minor versions
Example: DCP_INCLUDE_FIXER_FAMILIES = ["django1.9"]

2.3 DCP_EXCLUDE_FIXER_IDS

List of fixer identifiers to exclude. If "*" is used, then all fixers are excluded.

Note: The “EXCLUDE” filters are applied AFTER the “INCLUDE” ones, and so take precedence.

Default: []
Type: List of strings, or "*"
Example: DCP_EXCLUDE_FIXER_IDS = ['fix_deletion_templatetags_future_url']

2.4 DCP_EXCLUDE_FIXER_FAMILIES

List of fixer families to exclude. If "*" is used, then all families are excluded.

Note: The “EXCLUDE” filters are applied AFTER the “INCLUDE” ones, and so take precedence.

Default: []
Type: List of strings, or "*"
Choices: ("djangoX.Y") where X and Y are respectively the major and minor versions
Example: DCP_EXCLUDE_FIXER_FAMILIES = ["django1.6", "django1.9"]

2.5 DCP_PATCH_INJECTED_OBJECTS

If True, the patcher adds a __dcp_injected__ = True attribute to the injected objects (callables, classes, modules, attributes…), when possible, to differentiate them from original ones.

Default: True
Type: Boolean
Example: DCP_PATCH_INJECTED_OBJECTS = False

2.6 DCP_ENABLE_WARNINGS

If True, compatibility shims emit python warnings (warnings.warn(...)) when they are imported/used, to help detect deprecated code. These warnings are mostly subclasses of DeprecationWarning (ex. RemovedInDjango19Warning).

Once emitted, the handling of warnings depends on your setup (python command line flags, logging config…), see the official doc on warnings for more information.

Default: True
Type: Boolean
Example: DCP_ENABLE_WARNINGS = False

2.7 DCP_LOGGING_LEVEL

The patch() system of DCP can output to STDERR which fixers are getting applied, and provide debug information (ex. for which reason a specific fixer was discarded).

This setting sets the logging level of that information stream, which is typically only viewed at django startup. A value None disables DCP logging entirely.

Note that DCP does NOT actually use stdlib loggers, because it mostly performs operations before Django logging has been setup (ex. using the LOGGING setting), so log entries would most probably get discarded.

Default: "INFO"
Type: Logging level string, or None
Example: DCP_LOGGING_LEVEL = "DEBUG"

3 Table of fixers

There are currently 36 available fixers.

Fixer and its ID

Fixer family

Min version

Max version

Preserve the request.raw_post_data alias for request.body. (fix_deletion_http_request_HttpRequest_raw_post_data)

django1.6

1.6

Keep ‘django.contrib.comments’ as an import alias for the now external package ‘django_comments’ (django-contrib-comments on pypi) ; the latter must be installed separately. (fix_outsourcing_contrib_comments)

django1.8

1.8

Preserve the MergeDict util datastructure (fix_deletion_utils_datastructures_MergeDict)

django1.9

1.9

Preserve the SortedDict util datastructure (fix_deletion_utils_datastructures_SortedDict)

django1.9

1.9

Preserve the dictconfig util file (fix_deletion_utils_dictconfig)

django1.9

1.9

Preserve utils.functional.memoize() utility (fix_deletion_utils_functional_memoize)

django1.9

1.9

Preserve the importlib util file (fix_deletion_utils_importlib)

django1.9

1.9

Preserve the tzinfo util file (fix_deletion_utils_tzinfo)

django1.9

1.9

Preserve the unittest util file (fix_deletion_utils_unittest)

django1.9

1.9

Preserve the `request.REQUEST` attribute, merging parameters from GET (fix_deletion_core_handlers_wsgi_WSGIRequest_REQUEST)

django1.9

1.9

Preserve the get_formsets method of ModelAdmin (fix_deletion_contrib_admin_ModelAdmin_get_formsets)

django1.9

1.9

Preserve the `url` tag in the `future` templatetags library. (fix_deletion_templatetags_future_url)

django1.9

1.9

Preserve the `ssi` tag in the `future` templatetags library. (fix_deletion_templatetags_future_ssi)

django1.9

1.9

Preserve the IPAddressField form field, now superseded by GenericIPAddressField (fix_deletion_forms_fields_IPAddressField)

django1.9

1.9

Preserve the fallback to AppCommand.handle_app() method in django management commands. (fix_deletion_core_management_base_AppCommand_handle_app)

django1.9

1.9

Preserve contrib.sites.models.RequestSite alias. (fix_deletion_contrib_sites_models_RequestSite)

django1.9

1.9

Preserve contrib.sites.models.get_current_site alias. (fix_deletion_contrib_sites_models_get_current_site)

django1.9

1.9

Put a forward compatibility import path for django.urls, which replaces django.core.urlresolvers (fix_incoming_urls_submodule)

django1.10

1.10

Preserve the “future” templatetags library, with its improved `firstof` and `cycle` tags. (fix_deletion_templatetags_future)

django1.10

1.10

Preserve the “ssi” default template tag. (fix_deletion_template_defaulttags_ssi)

django1.10

1.10

Restore support for dotted-string view parameter in RegexURLPattern, instead passing a view object. (fix_behaviour_urls_resolvers_RegexURLPattern)

django1.10

1.10

Preserve the ability to call urlresolver on dotted string view, instead of explicit view name. (fix_behaviour_core_urlresolvers_reverse_with_prefix)

django1.10

1.10

Support passing views to url() as dotted strings instead of view objects. (fix_behaviour_conf_urls_url)

django1.10

1.10

Preserve the patterns() builder for django urls. (fix_deletion_conf_urls_patterns)

django1.10

1.10

Preserve support for a single ‘=’ sign in {% if %} tag. (fix_behaviour_template_smartif_OPERATORS_equals)

django1.10

1.10

Preserve the “future” templatetags library, with its improved `firstof` and `cycle` tags. (fix_behaviour_widget_build_attrs)

django1.11

1.11

Preserve RegexURLPattern and RegexURLResolver in django.urls, which disappeared due to DEP 0201. (fix_deletion_urls_RegexURLPattern_RegexURLResolver)

django2.0

2.0

Preserve django.core.urlresolvers module, now replaced by django.urls. (fix_deletion_core_urlresolvers)

django2.0

2.0

Preserve the assignment_tag() helper, superseded by simple_tag(). (fix_deletion_template_library_assignment_tag)

django2.0

2.0

Preserve the allow_lazy() utility, superseded by keep_lazy(). (fix_deletion_utils_functional_allow_lazy)

django2.0

2.0

Preserve the Context.has_key() utility, replaced by “in” operator use. (fix_deletion_template_context_Context_has_key)

django2.0

2.0

Preserve the javascript_catalog() and json_catalog() i18n views, superseded by class-based views. (fix_deletion_views_i18n_javascript_and_json_catalog)

django2.0

2.0

Let “on_delete” parameter of ForeignKey and OneToOneField be optional, defaulting to CASCADE. (fix_behaviour_db_models_fields_related_ForeignKey_OneToOneField)

django2.0

2.0

Keep accepting a 3-tuple (urlconf_module, app_name, namespace) as first argument of include(), instead of providing namespace argument directly to include() (fix_behaviour_conf_urls_include_3tuples)

django2.0

2.0

Preserve django.utils.translation.string_concat(), superseded by django.utils.text.format_lazy(). (fix_deletion_utils_translation_string_concat)

django2.1

2.1

Restore the behaviour where the “renderer” parameter of Widget.render() may not be supported by subclasses. (fix_behaviour_widget_render_forced_renderer)

django2.1

2.1

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-compat-patcher-0.6.tar.gz (58.9 kB view details)

Uploaded Source

Built Distributions

django_compat_patcher-0.6-py3-none-any.whl (113.2 kB view details)

Uploaded Python 3

django_compat_patcher-0.6-py2-none-any.whl (113.2 kB view details)

Uploaded Python 2

File details

Details for the file django-compat-patcher-0.6.tar.gz.

File metadata

  • Download URL: django-compat-patcher-0.6.tar.gz
  • Upload date:
  • Size: 58.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.12.1 pkginfo/1.5.0.1 requests/2.18.4 setuptools/40.6.3 requests-toolbelt/0.8.0 tqdm/4.29.1 CPython/2.7.12

File hashes

Hashes for django-compat-patcher-0.6.tar.gz
Algorithm Hash digest
SHA256 d7b2db02dcb5b51c7be192fd9e1131b54e43c05d115be8c55c12796ad9e5308f
MD5 a7c7af92b3969af1cd5c2f2dbf6fa37e
BLAKE2b-256 ac4b59ceadd0c1e023a9a4b32003176cba5dffd8f2cab37483a8d181ae0814e2

See more details on using hashes here.

File details

Details for the file django_compat_patcher-0.6-py3-none-any.whl.

File metadata

  • Download URL: django_compat_patcher-0.6-py3-none-any.whl
  • Upload date:
  • Size: 113.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.6.0 setuptools/19.2 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.4.1

File hashes

Hashes for django_compat_patcher-0.6-py3-none-any.whl
Algorithm Hash digest
SHA256 7135bb6d0a15ae2e77cece33d71638fb884fc9d707a64539312cfc56c8a41aee
MD5 32412788fc7e82755f928206fb2a02d8
BLAKE2b-256 02c46cf70211720fcee39480882f2c3ff1b0ea8a55f3362d9ff09de35109015a

See more details on using hashes here.

File details

Details for the file django_compat_patcher-0.6-py2-none-any.whl.

File metadata

  • Download URL: django_compat_patcher-0.6-py2-none-any.whl
  • Upload date:
  • Size: 113.2 kB
  • Tags: Python 2
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.12.1 pkginfo/1.5.0.1 requests/2.18.4 setuptools/40.6.3 requests-toolbelt/0.8.0 tqdm/4.29.1 CPython/2.7.12

File hashes

Hashes for django_compat_patcher-0.6-py2-none-any.whl
Algorithm Hash digest
SHA256 7e3d391d42d840900dd4883339eadfdf9835cd332f08719c9d406494e2b220a0
MD5 eb2a6b33e3166e3aa43f8aadf7075b46
BLAKE2b-256 d9aaf4c9fe09aed6aa138b54e5302393b6bbcf231ec818f4fe1f5bf0a00e1fb5

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page