Skip to content

Commit

Permalink
Drop python 2.7 and django 1.11 support. (#666)
Browse files Browse the repository at this point in the history
* Remove python 2.7 support

* Remove ucfirst utility function in favour of django.utils.text.capfirst

* Start compiling a changelog for 2.1.0

* Cleanup super() calls

* Update tutorial to use django 2.0 url syntax and CBV's

* Upgrade to xenial to include sqlite 3.8.3

* Do not install django-master on py35

* No need to inherit from object anymore

* Use new url syntax in example/urls.py, some more cleanups

* Drop py34 support

* Update requirements and drop django 1.11
  • Loading branch information
jieter authored Jul 22, 2019
1 parent cf7bed5 commit 95513e5
Show file tree
Hide file tree
Showing 77 changed files with 215 additions and 449 deletions.
15 changes: 6 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
dist: xenial
language: python
cache:
pip: true
Expand All @@ -8,21 +9,14 @@ addons:
- myspell-en-us

install:
- pip install tox python-coveralls
- pip install tox coverage

script:
- tox

matrix:
include:
- { python: 2.7, env: TOXENV=py27-1.11 }
- { python: 3.4, env: TOXENV=py34-1.11 }
- { python: 3.4, env: TOXENV=py34-2.0 }
- { python: 3.5, env: TOXENV=py35-1.11 }
- { python: 3.5, env: TOXENV=py35-2.0 }
- { python: 3.5, env: TOXENV=py35-2.1 }
- { python: 3.5, env: TOXENV=py35-master }
- { python: 3.6, env: TOXENV=py36-2.0 }
- { python: 3.6, env: TOXENV=py36-2.1 }
- { python: 3.6, env: TOXENV=py36-master }
- { python: 3.7-dev, env: TOXENV=py37-2.1 }
Expand All @@ -39,4 +33,7 @@ matrix:
- env: TOXENV=py37-master

after_success:
coveralls
- pip combine --amend
- pip report -m
- pip install codecov
- codecov
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Change log

## 2.1.0 (not yet released)
- Dropped support for python 2.7. Django==1.11 is still supported on python 3.
- Removed `django_tables2.utils.ucfirst`, use `django.utils.text.capfirst` instead.


## 2.0.6 (2019-03-26)
- Add optional 'table' kwarg to `row_attrs` callables

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ has native support for pagination and sorting. It does for HTML tables what

- Available on pypi as [django-tables2](https://pypi.python.org/pypi/django-tables2)
- Tested against currently supported versions of Django
[and the python versions Django supports](https://docs.djangoproject.com/en/dev/faq/install/#what-python-version-can-i-use-with-django)
[and supported python 3 versions Django supports](https://docs.djangoproject.com/en/dev/faq/install/#what-python-version-can-i-use-with-django) No python 2.7 support anymore
(see [Travis CI](https://travis-ci.org/jieter/django-tables2)
- [Documentation on readthedocs.org](https://django-tables2.readthedocs.io/en/latest/)
- [Bug tracker](http://github.com/jieter/django-tables2/issues)
Expand Down
1 change: 0 additions & 1 deletion django_tables2/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# coding: utf-8
from .tables import Table, TableBase, table_factory
from .columns import (
BooleanColumn,
Expand Down
35 changes: 15 additions & 20 deletions django_tables2/columns/base.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
# coding: utf-8
from __future__ import absolute_import, unicode_literals

from collections import OrderedDict
from itertools import islice

from django.core.exceptions import ImproperlyConfigured
from django.urls import reverse
from django.utils import six
from django.utils.html import format_html
from django.utils.safestring import SafeData
from django.utils.text import capfirst

from django_tables2.utils import (
from ..utils import (
Accessor,
AttributeDict,
OrderBy,
OrderByTuple,
call_with_appropriate,
computed_values,
ucfirst,
)


class Library(object):
class Library:
"""
A collection of columns.
"""
Expand Down Expand Up @@ -64,7 +60,7 @@ def column_for_field(self, field):
library = Library()


class LinkTransform(object):
class LinkTransform:
"""
Object used to generate attributes for the `<a>`-tag to wrap the cell content in.
"""
Expand Down Expand Up @@ -160,7 +156,7 @@ def __call__(self, content, **kwargs):


@library.register
class Column(object):
class Column:
"""
Represents a single column of a table.
Expand Down Expand Up @@ -275,7 +271,7 @@ def __init__(
linkify=False,
initial_sort_descending=False,
):
if not (accessor is None or isinstance(accessor, six.string_types) or callable(accessor)):
if not (accessor is None or isinstance(accessor, str) or callable(accessor)):
raise TypeError(
"accessor must be a string or callable, not %s" % type(accessor).__name__
)
Expand All @@ -289,7 +285,7 @@ def __init__(
self.attrs = attrs or getattr(self, "attrs", {})

# massage order_by into an OrderByTuple or None
order_by = (order_by,) if isinstance(order_by, six.string_types) else order_by
order_by = (order_by,) if isinstance(order_by, str) else order_by
self.order_by = OrderByTuple(order_by) if order_by is not None else None
if empty_values is not None:
self.empty_values = empty_values
Expand Down Expand Up @@ -424,11 +420,10 @@ def from_field(cls, field):
else:
verbose_name = getattr(field, "verbose_name", field.name)

return cls(verbose_name=ucfirst(verbose_name))
return cls(verbose_name=capfirst(verbose_name))


@six.python_2_unicode_compatible
class BoundColumn(object):
class BoundColumn:
"""
A *run-time* version of `.Column`. The difference between
`.BoundColumn` and `.Column`, is that `.BoundColumn` objects include the
Expand Down Expand Up @@ -456,7 +451,7 @@ def __init__(self, table, column, name):
self.current_value = None

def __str__(self):
return six.text_type(self.header)
return str(self.header)

@property
def accessor(self):
Expand Down Expand Up @@ -707,7 +702,7 @@ def verbose_name(self):
if isinstance(name, SafeData):
return name

return ucfirst(name)
return capfirst(name)

@property
def visible(self):
Expand All @@ -724,7 +719,7 @@ def localize(self):
return self.column.localize


class BoundColumns(object):
class BoundColumns:
"""
Container for spawning `.BoundColumn` objects.
Expand All @@ -748,7 +743,7 @@ class BoundColumns(object):
def __init__(self, table, base_columns):
self._table = table
self.columns = OrderedDict()
for name, column in six.iteritems(base_columns):
for name, column in base_columns.items():
self.columns[name] = bc = BoundColumn(table, column, name)
bc.render = getattr(table, "render_" + name, column.render)
# How the value is defined: 1. value_<name> 2. render_<name> 3. column.value.
Expand Down Expand Up @@ -846,7 +841,7 @@ def __contains__(self, item):
*item* can either be a `~.BoundColumn` object, or the name of a column.
"""
if isinstance(item, six.string_types):
if isinstance(item, str):
return item in self.iternames()
else:
# let's assume we were given a column
Expand Down Expand Up @@ -875,7 +870,7 @@ def __getitem__(self, index):
return next(islice(self.iterall(), index, index + 1))
except StopIteration:
raise IndexError
elif isinstance(index, six.string_types):
elif isinstance(index, str):
for column in self.iterall():
if column.name == index:
return column
Expand Down
18 changes: 7 additions & 11 deletions django_tables2/columns/booleancolumn.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
# coding: utf-8
from __future__ import absolute_import, unicode_literals

from django.db import models
from django.utils import six
from django.utils.html import escape, format_html
from django.utils.text import capfirst

from django_tables2.utils import AttributeDict, ucfirst

from ..utils import AttributeDict
from .base import Column, library


Expand All @@ -30,10 +26,10 @@ class BooleanColumn(Column):
"""

def __init__(self, null=False, yesno="✔,✘", **kwargs):
self.yesno = yesno.split(",") if isinstance(yesno, six.string_types) else tuple(yesno)
self.yesno = yesno.split(",") if isinstance(yesno, str) else tuple(yesno)
if not null:
kwargs["empty_values"] = ()
super(BooleanColumn, self).__init__(**kwargs)
super().__init__(**kwargs)

def _get_bool_value(self, record, value, bound_column):
# If record is a model, we need to check if it has choices defined.
Expand All @@ -51,7 +47,7 @@ def _get_bool_value(self, record, value, bound_column):
def render(self, value, record, bound_column):
value = self._get_bool_value(record, value, bound_column)
text = self.yesno[int(not value)]
attrs = {"class": six.text_type(value).lower()}
attrs = {"class": str(value).lower()}
attrs.update(self.attrs.get("span", {}))

return format_html("<span {}>{}</span>", AttributeDict(attrs).as_html(), escape(text))
Expand All @@ -66,8 +62,8 @@ def value(self, record, value, bound_column):
@classmethod
def from_field(cls, field):
if isinstance(field, models.NullBooleanField):
return cls(verbose_name=ucfirst(field.verbose_name), null=True)
return cls(verbose_name=capfirst(field.verbose_name), null=True)

if isinstance(field, models.BooleanField):
null = getattr(field, "null", False)
return cls(verbose_name=ucfirst(field.verbose_name), null=null)
return cls(verbose_name=capfirst(field.verbose_name), null=null)
5 changes: 1 addition & 4 deletions django_tables2/columns/checkboxcolumn.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# coding: utf-8
from __future__ import absolute_import, unicode_literals

from django.utils.safestring import mark_safe

from django_tables2.utils import Accessor, AttributeDict
Expand Down Expand Up @@ -51,7 +48,7 @@ def __init__(self, attrs=None, checked=None, **extra):
self.checked = checked
kwargs = {"orderable": False, "attrs": attrs}
kwargs.update(extra)
super(CheckBoxColumn, self).__init__(**kwargs)
super().__init__(**kwargs)

@property
def header(self):
Expand Down
10 changes: 3 additions & 7 deletions django_tables2/columns/datecolumn.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
# coding: utf-8
from __future__ import absolute_import, unicode_literals

from django.db import models

from django_tables2.utils import ucfirst
from django.utils.text import capfirst

from .base import library
from .templatecolumn import TemplateColumn
Expand All @@ -25,9 +21,9 @@ def __init__(self, format=None, short=True, *args, **kwargs):
if format is None:
format = "SHORT_DATE_FORMAT" if short else "DATE_FORMAT"
template = '{{ value|date:"%s"|default:default }}' % format
super(DateColumn, self).__init__(template_code=template, *args, **kwargs)
super().__init__(template_code=template, *args, **kwargs)

@classmethod
def from_field(cls, field):
if isinstance(field, models.DateField):
return cls(verbose_name=ucfirst(field.verbose_name))
return cls(verbose_name=capfirst(field.verbose_name))
10 changes: 3 additions & 7 deletions django_tables2/columns/datetimecolumn.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
# coding: utf-8
from __future__ import absolute_import, unicode_literals

from django.db import models

from django_tables2.utils import ucfirst
from django.utils.text import capfirst

from .base import library
from .templatecolumn import TemplateColumn
Expand All @@ -25,9 +21,9 @@ def __init__(self, format=None, short=True, *args, **kwargs):
if format is None:
format = "SHORT_DATETIME_FORMAT" if short else "DATETIME_FORMAT"
template = '{{ value|date:"%s"|default:default }}' % format
super(DateTimeColumn, self).__init__(template_code=template, *args, **kwargs)
super().__init__(template_code=template, *args, **kwargs)

@classmethod
def from_field(cls, field):
if isinstance(field, models.DateTimeField):
return cls(verbose_name=ucfirst(field.verbose_name))
return cls(verbose_name=capfirst(field.verbose_name))
8 changes: 2 additions & 6 deletions django_tables2/columns/emailcolumn.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
# coding: utf-8
from __future__ import absolute_import, unicode_literals

from django.db import models

from django_tables2.utils import ucfirst
from django.utils.text import capfirst

from .base import library
from .linkcolumn import BaseLinkColumn
Expand Down Expand Up @@ -42,4 +38,4 @@ def get_url(self, value):
@classmethod
def from_field(cls, field):
if isinstance(field, models.EmailField):
return cls(verbose_name=ucfirst(field.verbose_name))
return cls(verbose_name=capfirst(field.verbose_name))
13 changes: 5 additions & 8 deletions django_tables2/columns/filecolumn.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
# coding: utf-8
from __future__ import absolute_import, unicode_literals

import os

from django.db import models
from django.utils.html import format_html
from django.utils.text import capfirst

from django_tables2.utils import AttributeDict, ucfirst

from ..utils import AttributeDict
from .base import library
from .linkcolumn import BaseLinkColumn

Expand Down Expand Up @@ -40,7 +37,7 @@ class FileColumn(BaseLinkColumn):

def __init__(self, verify_exists=True, **kwargs):
self.verify_exists = verify_exists
super(FileColumn, self).__init__(**kwargs)
super().__init__(**kwargs)

def get_url(self, value, record):
storage = getattr(value, "storage", None)
Expand All @@ -52,7 +49,7 @@ def get_url(self, value, record):
def text_value(self, record, value):
if self.text is None:
return os.path.basename(value.name)
return super(FileColumn, self).text_value(record, value)
return super().text_value(record, value)

def render(self, record, value):
attrs = AttributeDict(self.attrs.get("span", {}))
Expand Down Expand Up @@ -86,4 +83,4 @@ def render(self, record, value):
@classmethod
def from_field(cls, field):
if isinstance(field, models.FileField):
return cls(verbose_name=ucfirst(field.verbose_name))
return cls(verbose_name=capfirst(field.verbose_name))
11 changes: 4 additions & 7 deletions django_tables2/columns/jsoncolumn.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
# coding: utf-8
from __future__ import absolute_import, unicode_literals

import json

from django.utils.html import format_html
from django.utils.text import capfirst

from django_tables2.utils import AttributeDict, ucfirst

from ..utils import AttributeDict
from .base import library
from .linkcolumn import BaseLinkColumn

Expand Down Expand Up @@ -48,7 +45,7 @@ def __init__(self, json_dumps_kwargs=None, **kwargs):
json_dumps_kwargs if json_dumps_kwargs is not None else {"indent": 2}
)

super(JSONColumn, self).__init__(**kwargs)
super().__init__(**kwargs)

def render(self, record, value):
return format_html(
Expand All @@ -61,4 +58,4 @@ def render(self, record, value):
def from_field(cls, field):
if POSTGRES_AVAILABLE:
if isinstance(field, JSONField) or isinstance(field, HStoreField):
return cls(verbose_name=ucfirst(field.verbose_name))
return cls(verbose_name=capfirst(field.verbose_name))
Loading

0 comments on commit 95513e5

Please sign in to comment.