Skip to content

Commit ad65d30

Browse files
Drop django 1.4 to 1.7 support (#8)
- Removed reference to django.db.models.fields.subclassing.SubfieldBase (resolves #7) and conditional import for `django.core.checks`. - Removed the `timezone_utils/models.py` and `timezone_utils/migrations`. This means that only Django 1.8+ is now supported. - Removed support for Python versions < 2.6. The Django 1.6 series was the last to support Python 2.6. - Added testing support for Django 1.10. - Coverage fix: calling the super(DateTimeField, self).to_python(value) will convert a naive datetime, so the is_naive condition would never be reached. - Changed development status from `Beta` to `Production/Stable`. - Added contributor Alex Kamedov. - Updated documentation copyright year to 2016. - Version bump to `0.11`. - Minor PEP8 changes.
1 parent 2dfe03e commit ad65d30

File tree

9 files changed

+62
-96
lines changed

9 files changed

+62
-96
lines changed

.travis.yml

Lines changed: 21 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,21 @@ language:
22
python
33

44
python:
5-
- "2.6"
65
- "2.7"
6+
# https://docs.djangoproject.com/en/dev/releases/1.8/#python-compatibility
7+
# Due to the end of upstream support for Python 3.2 in February 2016, we
8+
# won’t test Django 1.8.x on Python 3.2 after the end of 2016.
79
- "3.2"
810
- "3.3"
911
- "3.4"
1012
- "3.5"
11-
- "3.5-dev"
1213
- "nightly"
1314

1415
env:
1516
- DJANGO="https://github.com/django/django/archive/master.tar.gz"
16-
- DJANGO="django>=1.9.0,<1.10.0"
17-
- DJANGO="django>=1.8.0,<1.9.0"
18-
- DJANGO="django>=1.7.0,<1.8.0"
19-
- DJANGO="django>=1.6.0,<1.7.0"
20-
- DJANGO="django>=1.5.0,<1.6.0"
21-
- DJANGO="django>=1.4.0,<1.5.0"
17+
- DJANGO="django>=1.10,<1.11"
18+
- DJANGO="django>=1.9,<1.10"
19+
- DJANGO="django>=1.8,<1.9"
2220

2321
install:
2422
- travis_retry pip install $DJANGO
@@ -38,40 +36,27 @@ notifications:
3836

3937
matrix:
4038
exclude:
39+
# https://docs.djangoproject.com/en/dev/releases/1.9/#python-compatibility
40+
# Django 1.9 requires Python 2.7, 3.4, or 3.5
4141
- python: "3.2"
42-
env: DJANGO="django>=1.4.0,<1.5.0"
43-
- python: "3.2"
44-
env: DJANGO="django>=1.9.0,<1.10.0"
42+
env: DJANGO="django>=1.9,<1.10"
4543
- python: "3.3"
46-
env: DJANGO="django>=1.4.0,<1.5.0"
44+
env: DJANGO="django>=1.9,<1.10"
45+
# https://docs.djangoproject.com/en/dev/releases/1.10/#python-compatibility
46+
# Django 1.10 requires Python 2.7, 3.4, or 3.5
47+
- python: "3.2"
48+
env: DJANGO="django>=1.10,<1.11"
4749
- python: "3.3"
48-
env: DJANGO="django>=1.9.0,<1.10.0"
49-
- python: "3.4"
50-
env: DJANGO="django>=1.4.0,<1.5.0"
51-
- python: "3.5"
52-
env: DJANGO="django>=1.4.0,<1.5.0"
53-
- python: "3.5"
54-
env: DJANGO="django>=1.5.0,<1.6.0"
55-
- python: "3.5"
56-
env: DJANGO="django>=1.6.0,<1.7.0"
57-
- python: "3.5"
58-
env: DJANGO="django>=1.7.0,<1.8.0"
59-
# - python: "pypy"
60-
# env: DJANGO="django>=1.4.0,<1.5.0"
61-
# - python: "pypy3"
62-
# env: DJANGO="django>=1.4.0,<1.5.0"
63-
- python: "2.6"
64-
env: DJANGO="django>=1.7.0,<1.8.0"
65-
- python: "2.6"
66-
env: DJANGO="django>=1.8.0,<1.9.0"
67-
- python: "2.6"
68-
env: DJANGO="django>=1.9.0,<1.10.0"
69-
- python: "2.6"
50+
env: DJANGO="django>=1.10,<1.11"
51+
# https://docs.djangoproject.com/en/dev/releases/1.11/#python-compatibility
52+
# Django 1.11 requires Python 2.7, 3.4, or 3.5.
53+
# The Django 1.11.x series is the last to support Python 2.
54+
# The next major release, Django 2.0, will only support Python 3.5+
55+
- python: "3.2"
7056
env: DJANGO="https://github.com/django/django/archive/master.tar.gz"
71-
- python: "2.6"
57+
- python: "3.3"
7258
env: DJANGO="https://github.com/django/django/archive/master.tar.gz"
7359
allow_failures:
7460
- env: DJANGO="https://github.com/django/django/archive/master.tar.gz"
75-
- python: "3.5-dev"
7661
- python: "nightly"
7762
fast_finish: true

README.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ Django Timezone Utils: Time Zone Utilities For Models
3333
**django-timezone-utils** adds automatic time zone conversions and support
3434
utilities to Django.
3535

36-
Please note that this project is currently marked as a development status of
37-
*Beta*. Suggestions, constructive criticism, and feedback are certainly
36+
Suggestions, constructive criticism, and feedback are certainly
3837
welcomed and appreciated.
3938

4039
Documentation
@@ -51,7 +50,7 @@ ever had to deal with this, you will know how complicated this can be.
5150

5251
I created these fields to ease the process of manipulating times based on
5352
another field's or models timezone choice. Instead of having to remember to use
54-
``Model.clean_fields``, we can now create the models with the validation built
53+
``Model.clean``, we can now create the models with the validation built
5554
into the model field.
5655

5756

@@ -105,9 +104,11 @@ Contributors
105104

106105
* `Michael Barr <http://github.com/michaeljohnbarr>`_
107106
* `Kosei Kitahara <https://github.com/Surgo>`_
107+
* `Alex Kamedov <https://github.com/alekam>`_
108108

109109
Changelog
110110
---------
111+
- 0.11 Removed reference to django.db.models.fields.subclassing.SubfieldBase, which means that only Django 1.8+ is now supported. Removed support for Python versions < 2.6. The Django 1.6 series was the last to support Python 2.6. Added testing support for Django 1.10. Changed development status from Beta to Production/Stable.
111112
- 0.10 Added testing support for Python 3.5 and Django 1.9.
112113
- 0.9 Corrected a bug to where ``time_override`` caused invalid date due to not converting to the correct timezone first. Refactored conversion code. Added testing support for Django 1.8. Removed Django from setup requirements - the onus of having a supported version of Django is on the developer.
113114
- 0.8 Corrected a bug to where ``time_override`` caused invalid date due to not converting to the correct timezone first. Added choices ``GROUPED_ALL_TIMEZONES_CHOICES`` and ``GROUPED_COMMON_TIMEZONES_CHOICES`` to the documentation.

docs/conf.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
# If extensions (or modules to document with autodoc) are in another directory,
1919
# add these directories to sys.path here. If the directory is relative to the
2020
# documentation root, use os.path.abspath to make it absolute, like shown here.
21-
#sys.path.insert(0, os.path.abspath('.'))
21+
# sys.path.insert(0, os.path.abspath('.'))
2222

2323
# -- General configuration ------------------------------------------------
2424

@@ -44,16 +44,16 @@
4444

4545
# General information about the project.
4646
project = u'Django Timezone Utils'
47-
copyright = u'2015, Michael Barr'
47+
copyright = u'2016, Michael Barr'
4848

4949
# The version info for the project you're documenting, acts as replacement for
5050
# |version| and |release|, also used in various other places throughout the
5151
# built documents.
5252
#
5353
# The short X.Y version.
54-
version = '0.10'
54+
version = '0.11'
5555
# The full version, including alpha/beta/rc tags.
56-
release = '0.10'
56+
release = '0.11'
5757

5858
# The language for content autogenerated by Sphinx. Refer to documentation
5959
# for a list of supported languages.

docs/setup.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ modify your ``INSTALLED_APPS`` setting.
1717
Dependencies
1818
============
1919

20-
* Supports `Django`_ 1.4+ on Python 2.6, 2.7, 3.2, 3.3, and 3.4.
20+
* Supports `Django`_ 1.8+ on Python 2.7, 3.2, 3.3, 3.4, and 3.5.
2121
* Requires `pytz`_ for time zone conversions.
2222

2323
.. _Django: http://www.djangoproject.com/

run_tests.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,10 @@
4343
TIME_ZONE='UTC',
4444
SECRET_KEY='secret',
4545
LANGUAGE_CODE = 'en-us',
46-
# TIME_ZONE = 'UTC',
47-
USE_I18N = True,
48-
USE_L10N = True,
49-
# USE_TZ = True,
50-
51-
SITE_ID = 1,
52-
TEST_DATETIME = timezone.make_aware(
46+
USE_I18N=True,
47+
USE_L10N=True,
48+
SITE_ID=1,
49+
TEST_DATETIME=timezone.make_aware(
5350
datetime(2014, 1, 1), pytz.timezone('UTC')
5451
),
5552
# SILENCED_SYSTEM_CHECKS=['1_7.W001'],

setup.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,20 @@
2121
packages=['timezone_utils'],
2222
install_requires=[
2323
'pytz',
24-
'django>=1.4,<1.10'
24+
'django>=1.8'
2525
],
2626
zip_safe=False,
2727
platforms='any',
2828
include_package_data=True,
2929
classifiers=[
30-
'Development Status :: 4 - Beta',
30+
'Development Status :: 5 - Production/Stable',
3131
'Framework :: Django',
3232
'Intended Audience :: Developers',
3333
'License :: OSI Approved :: MIT License',
3434
'Natural Language :: English',
3535
'Operating System :: OS Independent',
3636
'Programming Language :: Python',
3737
'Programming Language :: Python :: 2',
38-
'Programming Language :: Python :: 2.6',
3938
'Programming Language :: Python :: 2.7',
4039
'Programming Language :: Python :: 3',
4140
'Programming Language :: Python :: 3.2',

timezone_utils/fields.py

Lines changed: 26 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,30 @@
1-
# ==============================================================================
1+
# =============================================================================
22
# IMPORTS
3-
# ==============================================================================
3+
# =============================================================================
44
# Python
55
from __future__ import unicode_literals
66
from datetime import datetime, tzinfo, time as datetime_time
77
import pytz
88
import warnings
99

1010
# Django
11-
import django
12-
try:
13-
from django.core import checks
14-
except ImportError: # pragma: no cover
15-
pass
11+
from django.core import checks
1612
from django.core.exceptions import ValidationError
17-
from django.db import models
1813
from django.db.models.fields import DateTimeField, CharField
19-
from django.utils.six import with_metaclass
2014
from django.utils.timezone import get_default_timezone, is_naive, make_aware
2115
from django.utils.translation import ugettext_lazy as _
2216

2317
# App
2418
from timezone_utils import forms
2519

2620

27-
TimeZoneFieldBase = type if django.VERSION >= (1, 8) else models.SubfieldBase
28-
2921
__all__ = ('TimeZoneField', 'LinkedTZDateTimeField')
3022

3123

32-
# ==============================================================================
24+
# =============================================================================
3325
# MODEL FIELDS
34-
# ==============================================================================
35-
class TimeZoneField( # pylint: disable=E0239
36-
with_metaclass(TimeZoneFieldBase, CharField)
37-
):
26+
# =============================================================================
27+
class TimeZoneField(CharField):
3828
# Enforce the minimum length of max_length to be the length of the longest
3929
# pytz timezone string
4030
MIN_LENGTH = max(map(len, pytz.all_timezones))
@@ -128,9 +118,9 @@ def formfield(self, **kwargs):
128118
defaults.update(**kwargs)
129119
return super(TimeZoneField, self).formfield(**defaults)
130120

131-
# --------------------------------------------------------------------------
132-
# Django >= 1.7 Checks Framework
133-
# --------------------------------------------------------------------------
121+
# -------------------------------------------------------------------------
122+
# Django Checks Framework
123+
# -------------------------------------------------------------------------
134124
# pylint: disable=E0239
135125
def check(self, **kwargs): # pragma: no cover
136126
"""Calls the TimeZoneField's custom checks."""
@@ -142,8 +132,8 @@ def check(self, **kwargs): # pragma: no cover
142132

143133
def _check_timezone_max_length_attribute(self): # pragma: no cover
144134
"""
145-
Checks that the `max_length` attribute covers all possible pytz timezone
146-
lengths.
135+
Checks that the `max_length` attribute covers all possible pytz
136+
timezone lengths.
147137
"""
148138

149139
# Retrieve the maximum possible length for the time zone string
@@ -155,14 +145,14 @@ def _check_timezone_max_length_attribute(self): # pragma: no cover
155145
return [
156146
checks.Error(
157147
msg=(
158-
"'max_length' is too short to support all possible pytz"
159-
" time zones."
148+
"'max_length' is too short to support all possible "
149+
"pytz time zones."
160150
),
161151
hint=(
162-
"pytz {version}'s longest time zone string has a length"
163-
" of {value}, although it is recommended that you leave"
164-
" room for longer time zone strings to be added in the "
165-
"future.".format(
152+
"pytz {version}'s longest time zone string has a "
153+
"length of {value}, although it is recommended that "
154+
"you leave room for longer time zone strings to be "
155+
"added in the future.".format(
166156
version=pytz.VERSION,
167157
value=possible_max_length
168158
)
@@ -230,9 +220,7 @@ def _check_choices_attribute(self): # pragma: no cover
230220
return []
231221

232222

233-
class LinkedTZDateTimeField(
234-
with_metaclass(TimeZoneFieldBase, DateTimeField)
235-
): # pylint: disable=E0239
223+
class LinkedTZDateTimeField(DateTimeField):
236224
# pylint: disable=newstyle
237225
def __init__(self, *args, **kwargs):
238226
self.populate_from = kwargs.pop('populate_from', None)
@@ -246,7 +234,6 @@ def from_db_value(self, value, expression, connection, context):
246234
if value:
247235
value = self.to_python(value)
248236

249-
250237
return value
251238

252239
def to_python(self, value):
@@ -257,9 +244,6 @@ def to_python(self, value):
257244
if not value:
258245
return value
259246

260-
if is_naive(value):
261-
return make_aware(value=value, timezone=self.timezone)
262-
263247
return value.astimezone(self.timezone)
264248

265249
def pre_save(self, model_instance, add):
@@ -298,9 +282,9 @@ def deconstruct(self): # pragma: no cover
298282

299283
# Only include kwarg if it's not the default
300284
if self.populate_from is not None:
301-
# Since populate_from requires a model instance and Django does not,
302-
# allow lambda, we hope that we have been provided a function that
303-
# can be parsed
285+
# Since populate_from requires a model instance and Django does
286+
# not allow lambda, we hope that we have been provided a
287+
# function that can be parsed
304288
kwargs['populate_from'] = self.populate_from
305289

306290
# Only include kwarg if it's not the default
@@ -314,7 +298,9 @@ def deconstruct(self): # pragma: no cover
314298
return name, path, args, kwargs
315299

316300
def _get_populate_from(self, model_instance):
317-
"""Retrieves the timezone or None from the `populate_from` attribute."""
301+
"""
302+
Retrieves the timezone or None from the `populate_from` attribute.
303+
"""
318304

319305
if hasattr(self.populate_from, '__call__'):
320306
tz = self.populate_from(model_instance)
@@ -370,8 +356,8 @@ def _convert_value(self, value, model_instance, add):
370356
value = make_aware(value=value, timezone=tz)
371357

372358
# Convert the value to a datetime object in the correct timezone. This
373-
# insures that we will have the correct date if we are performing a time
374-
# override below.
359+
# insures that we will have the correct date if we are performing a
360+
# time override below.
375361
value = value.astimezone(tz)
376362

377363
# Do not convert the time to the time override if auto_now or

timezone_utils/migrations/__init__.py

Lines changed: 0 additions & 1 deletion
This file was deleted.

timezone_utils/models.py

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)