Feature proposal: Target API version

107 views
Skip to first unread message

Patryk Zawadzki

unread,
Nov 12, 2015, 7:48:28 AM11/12/15
to django-d...@googlegroups.com
Hello everyone,

I have spent quite a while thinking about this and am still not sure
what the best approach would be or even if there are enough benefits
to justify the change.

If you've ever worked with compiled code, you're probably familiar
with ABI versioning in dynamic libraries. This is somewhat similar.


The idea is to allow a project to specify that is _assumes_ Django to
behave like a particular version or release. It could do so by
specifying a TARGET_DJANGO_VERSION (better name needed) setting that
is a valid semantic version tuple.

Example:

TARGET_DJANGO_VERSION = (1, 8, 6)

New projects would start with the variable set to whatever Django
version was used to create them. If the variable is not set, Django
could raise an ImproperlyConfiguredError telling the user what to put
in the settings file or it could simply issue a warning and assume the
current version.


Now what that gives us:

* Django version Y could outright tell you that the project that
targets version X is not compatible and point you to the *relevant*
upgrade instructions (since we know both the old and the new version).

* Setting the target version to a higher value could turn deprecation
warnings to exceptions for all features deprecated in the target
version and earlier (which could make future-proofing your code
easier).

* Django could introduce A/B feature switches that introduce
backwards-incompatible behaviour if a high-enough target version is
specified without breaking existing projects. It would also make it
theoretically possible for the latest stable version to support the
last LTS version from the same code tree (although it would probably
require an enormous legacy/compat module).


Is that something that was discussed in the past? Does it make any sense?

Cheers,

--
Patryk Zawadzki
I solve problems.

Collin Anderson

unread,
Nov 12, 2015, 9:34:20 AM11/12/15
to Django developers (Contributions to Django itself), pat...@room-303.com
Hi,

"It would also make it theoretically possible for the latest stable version to support the 
last LTS version from the same code tree".

Have you seen the latest changes to the deprecation policy? We hope we've done exactly that (having the latest version of Django support code that was written for the last LTS.)

Collin

Carl Meyer

unread,
Nov 12, 2015, 11:40:40 AM11/12/15
to django-d...@googlegroups.com
Hi Patryk,

On 11/12/2015 05:48 AM, Patryk Zawadzki wrote:
> I have spent quite a while thinking about this and am still not sure
> what the best approach would be or even if there are enough benefits
> to justify the change.

I think the idea is interesting (and I know it's been at least briefly
discussed before, I think back when the system checks framework was
first introduced), but I'm not sure if there are enough benefits to
justify adding it. More comments below:

> If you've ever worked with compiled code, you're probably familiar
> with ABI versioning in dynamic libraries. This is somewhat similar.
>
>
> The idea is to allow a project to specify that is _assumes_ Django to
> behave like a particular version or release. It could do so by
> specifying a TARGET_DJANGO_VERSION (better name needed) setting that
> is a valid semantic version tuple.
>
> Example:
>
> TARGET_DJANGO_VERSION = (1, 8, 6)
>
> New projects would start with the variable set to whatever Django
> version was used to create them. If the variable is not set, Django
> could raise an ImproperlyConfiguredError telling the user what to put
> in the settings file or it could simply issue a warning and assume the
> current version.

I think the latter. Lack of this setting isn't a nearly serious enough
issue to prevent Django starting up (not to mention that in itself would
be a massive backwards-incompatible change).

> Now what that gives us:
>
> * Django version Y could outright tell you that the project that
> targets version X is not compatible and point you to the *relevant*
> upgrade instructions (since we know both the old and the new version).

Ok - I guess this could direct more people to the release notes who
otherwise might have tried to upgrade without reading them. This benefit
only applies if you first upgrade Django without touching your
TARGET_DJANGO_VERSION setting.

> * Setting the target version to a higher value could turn deprecation
> warnings to exceptions for all features deprecated in the target
> version and earlier (which could make future-proofing your code
> easier).

You're proposing this would only activate if your TARGET_DJANGO_VERSION
is higher than your actual Django version? I'm not sure how this feature
is even possible as you've described it, since if you have Django 1.8
installed and you set TARGET_DJANGO_VERSION to (1, 9, 0), that doesn't
magically give Django 1.8 knowledge of future deprecations! Perhaps I'm
misunderstanding.

Plus, it's not hard to use filterwarnings to turn all deprecation
warnings into exceptions (I often do this on my projects, at least for
the test suite). Perhaps this is a technique we should recommend and
demonstrate somewhere in our upgrade docs?

> * Django could introduce A/B feature switches that introduce
> backwards-incompatible behaviour if a high-enough target version is
> specified without breaking existing projects.

This is tempting at first blush, because it allows us to claim that
you've opted in to whatever backwards-incompatible changes we feel like
making by bumping your TARGET_DJANGO_VERSION. I think this is false,
though. You don't know what all you're opting into by bumping your
TARGET_DJANGO_VERSION unless you carefully read the release notes.
(Unlike other opt-ins which typically involve changing the use of
specific APIs in your code.) So how is it any different from us claiming
that you've already "opted in" to backwards incompatible changes simply
by upgrading Django? (In practice, we _do_ claim this already, but we
try to minimize such changes.)

I guess the idea is that you could first upgrade Django but leave your
TARGET_DJANGO_VERSION alone, and nothing would break, and then you could
at some point bump up your TARGET_DJANGO_VERSION when you're ready to
deal with the breaking changes? In the end I'm not sure that's any
better than today's story, which is just "upgrade Django when you're
ready to deal with the breaking changes."

> It would also make it
> theoretically possible for the latest stable version to support the
> last LTS version from the same code tree (although it would probably
> require an enormous legacy/compat module).

As Collin pointed out, this is something we already are attempting to
achieve with our latest deprecation and version-numbering policy.

> Is that something that was discussed in the past? Does it make any sense?

Figuring out backwards-compatibility issues is already a brain-bender
sometimes, when considering both upgrading projects and new projects
(the effects of changes in Django vs changes in the startproject
template, etc).

This proposal would add yet another axis to this matrix, as we'd have to
additionally consider the effects of pairing various
TARGET_DJANGO_VERSIONs with various actual Django versions. At this
point, I'm not seeing enough benefit to justify that complexity.

Happy to discuss further if I'm missing something, though.

Carl

signature.asc

Patryk Zawadzki

unread,
Nov 12, 2015, 12:10:16 PM11/12/15
to django-d...@googlegroups.com
2015-11-12 17:40 GMT+01:00 Carl Meyer <ca...@oddbird.net>:
> On 11/12/2015 05:48 AM, Patryk Zawadzki wrote:
>> * Setting the target version to a higher value could turn deprecation
>> warnings to exceptions for all features deprecated in the target
>> version and earlier (which could make future-proofing your code
>> easier).
> You're proposing this would only activate if your TARGET_DJANGO_VERSION
> is higher than your actual Django version? I'm not sure how this feature
> is even possible as you've described it, since if you have Django 1.8
> installed and you set TARGET_DJANGO_VERSION to (1, 9, 0), that doesn't
> magically give Django 1.8 knowledge of future deprecations! Perhaps I'm
> misunderstanding.

Consider Django version 1.9 that also happens to support API versions
1.7 and 1.8 and an application that originally targetted 1.7.

I could leave my target API at 1.7 and get the app to work. This
requires minimum resources. I would assume during normal operation
deprecations introduced in 1.8 and later would not show up since I'm
explicitly targetting 1.7.
I could also bump my target API to 1.8 and get some more deprecation
warnings for things deprecated in 1.8 (but not in 1.9). At this point
things deprecated since 1.7 should stop working so I can make sure
that I am actually targetting the "intended" APIs of 1.8.
I could finally go all the way up to 1.9 and possibly get different
behaviour when calling the same functions I did while targetting 1.8.
See below for discussion.

> Plus, it's not hard to use filterwarnings to turn all deprecation
> warnings into exceptions (I often do this on my projects, at least for
> the test suite). Perhaps this is a technique we should recommend and
> demonstrate somewhere in our upgrade docs?

Yes, this is how I imagine this to work. Specifying the target could
among other things configure which warnings are ignored and which are
explicitly turned into errors.

>> * Django could introduce A/B feature switches that introduce
>> backwards-incompatible behaviour if a high-enough target version is
>> specified without breaking existing projects.
> This is tempting at first blush, because it allows us to claim that
> you've opted in to whatever backwards-incompatible changes we feel like
> making by bumping your TARGET_DJANGO_VERSION. I think this is false,
> though. You don't know what all you're opting into by bumping your
> TARGET_DJANGO_VERSION unless you carefully read the release notes.
> (Unlike other opt-ins which typically involve changing the use of
> specific APIs in your code.) So how is it any different from us claiming
> that you've already "opted in" to backwards incompatible changes simply
> by upgrading Django? (In practice, we _do_ claim this already, but we
> try to minimize such changes.)
>
> I guess the idea is that you could first upgrade Django but leave your
> TARGET_DJANGO_VERSION alone, and nothing would break, and then you could
> at some point bump up your TARGET_DJANGO_VERSION when you're ready to
> deal with the breaking changes? In the end I'm not sure that's any
> better than today's story, which is just "upgrade Django when you're
> ready to deal with the breaking changes."

Yes, you could upgrade Django safely at least X times before having to
touch any code. You could also target a major version like 2.5 and not
experience potentially incompatible but more secure change to default
settings introduced in its point release, 2.5.7, while allowing new
projects to benefit from that change.

Shai Berger

unread,
Nov 12, 2015, 3:46:38 PM11/12/15
to django-d...@googlegroups.com
If I get this correctly, this has an interesting effect:

If Django 1.9 supports API Target Versions 1.7 and 1.8 at its launch, then it
must also support them for its lifetime (dropping them would be the kind of
change we don't introduce in minor versions). 1.7's API would need to be
supported as long as 1.9 lives. This, essentially, makes every Django release
an LTS.

I suppose many users would be happy about that outcome. Contributors, less so.

-1,

Shai.
Reply all
Reply to author
Forward
0 new messages