Skip to content

Commit

Permalink
Drop python 2 support (#35)
Browse files Browse the repository at this point in the history
* Automated: run 2to3 across the codebase
* Remove contextlib2/six. Only test on python 3.4+
* Update docs to drop earlier pythons
* Fix trove classifiers
* Run buildkite tests on all supported pythons
* Fix tests on slim/alpine dockered python
  • Loading branch information
craigds authored May 24, 2020
1 parent 0859bb5 commit 1bab3d0
Show file tree
Hide file tree
Showing 21 changed files with 124 additions and 129 deletions.
16 changes: 14 additions & 2 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ steps:

- wait

- label: ":pytest: run tests (:python: 3.7)"
command:
- ./.buildkite/test.sh
plugins:
artifacts#v1.2.0:
download: "dist/*.whl"
docker#v1.4.0:
image: "python:3.7-alpine"
workdir: /app
shell: false
artifact_paths: "./pytest*.xml"

- label: ":pytest: run tests (:python: 3.6)"
command:
- ./.buildkite/test.sh
Expand All @@ -39,14 +51,14 @@ steps:
shell: false
artifact_paths: "./pytest*.xml"

- label: ":pytest: run tests (:python: 2.7)"
- label: ":pytest: run tests (:python: 3.4)"
command:
- ./.buildkite/test.sh
plugins:
artifacts#v1.2.0:
download: "dist/*.whl"
docker#v1.4.0:
image: "python:2.7-alpine"
image: "python:3.4-alpine"
workdir: /app
shell: false
artifact_paths: "./pytest*.xml"
Expand Down
6 changes: 3 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ Installation

To install the latest stable release of the library, simply::

$ pip install koordinates
$ pip install -U koordinates

The library is compatible with Python 2.7 & Python 3.3+.
The library is compatible with Python 3.4+.


Documentation
Expand All @@ -41,6 +41,6 @@ We use [Black](https://github.com/psf/black) to ensure consistent code formattin
* Sublime Text: install [sublack](https://packagecontrol.io/packages/sublack) via Package Control
* VSCode [instructions](https://code.visualstudio.com/docs/python/editing#_formatting)

We use the default settings, and target python 2.7 and 3.3+.
We use the default settings.

One easy solution is to install [pre-commit](https://pre-commit.com), run `pre-commit install --install-hooks` and it'll automatically validate your changes code as a git pre-commit hook.
14 changes: 7 additions & 7 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@
master_doc = "index"

# General information about the project.
project = u"Koordinates Python API Client"
copyright = u"Koordinates Limited."
author = u"Koordinates"
project = "Koordinates Python API Client"
copyright = "Koordinates Limited."
author = "Koordinates"

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
Expand Down Expand Up @@ -228,8 +228,8 @@
(
master_doc,
"KoordinatesPythonAPIClient.tex",
u"Koordinates Python API Client Documentation",
u"Koordinates",
"Koordinates Python API Client Documentation",
"Koordinates",
"manual",
),
]
Expand Down Expand Up @@ -263,7 +263,7 @@
(
master_doc,
"koordinatespythonapiclient",
u"Koordinates Python API Client Documentation",
"Koordinates Python API Client Documentation",
[author],
1,
)
Expand All @@ -282,7 +282,7 @@
(
master_doc,
"KoordinatesPythonAPIClient",
u"Koordinates Python API Client Documentation",
"Koordinates Python API Client Documentation",
author,
"KoordinatesPythonAPIClient",
"One line description of project.",
Expand Down
37 changes: 16 additions & 21 deletions koordinates/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import unicode_literals

import abc
import collections
import datetime
Expand All @@ -8,8 +6,7 @@
import logging
import re

import six
from six.moves import urllib
import urllib

from .exceptions import ClientValidationError
from .utils import make_date, is_bound
Expand All @@ -18,8 +15,7 @@
logger = logging.getLogger(__name__)


@six.add_metaclass(abc.ABCMeta)
class BaseManager(object):
class BaseManager(metaclass=abc.ABCMeta):
"""
Base class for Model Manager classes.
Expand Down Expand Up @@ -52,15 +48,13 @@ def _reverse_url(self, url):
return self.client.reverse_url(self._URL_KEY, url)


@six.add_metaclass(abc.ABCMeta)
class InnerManager(BaseManager):
class InnerManager(BaseManager, metaclass=abc.ABCMeta):
def __init__(self, client, parent_manager):
super(InnerManager, self).__init__(client)
self.parent = parent_manager


@six.add_metaclass(abc.ABCMeta)
class Manager(BaseManager):
class Manager(BaseManager, metaclass=abc.ABCMeta):
def list(self):
"""
Fetches a set of model objects
Expand Down Expand Up @@ -170,7 +164,7 @@ def _to_url(self):
params = collections.defaultdict(list, copy.deepcopy(self._filters))
if self._order_by is not None:
params["sort"] = self._order_by
for k, vl in self._extra.items():
for k, vl in list(self._extra.items()):
params[k] += vl

if params:
Expand Down Expand Up @@ -286,7 +280,7 @@ def extra(self, **params):
:rtype: Query
"""
q = self._clone()
for key, value in params.items():
for key, value in list(params.items()):
q._extra[key].append(value)
return q

Expand All @@ -299,7 +293,7 @@ def filter(self, **filters):
"""

q = self._clone()
for key, value in filters.items():
for key, value in list(filters.items()):
filter_key = re.split("__", key)
filter_attr = filter_key[0]
if filter_attr not in self._valid_filter_attrs:
Expand Down Expand Up @@ -416,7 +410,9 @@ def _getter(self):

return _getter

for ref_attr, ref_class in getattr(klass._meta, "relations", {}).items():
for ref_attr, ref_class in list(
getattr(klass._meta, "relations", {}).items()
):
if isinstance(ref_class, (list, tuple)) and len(ref_class) == 1:
# multiple relation
ref_method = "list_%s" % ref_attr
Expand Down Expand Up @@ -469,14 +465,14 @@ def _deserialize(self, data):
except AttributeError: # _meta not available
skip = []

for key, value in data.items():
for key, value in list(data.items()):
if key not in skip:
value = self._deserialize_value(key, value)
setattr(self, key, value)
return self

def _deserialize_value(self, key, value):
if key.endswith("_at") and isinstance(value, six.string_types):
if key.endswith("_at") and isinstance(value, str):
value = make_date(value)
return value

Expand All @@ -500,7 +496,7 @@ def _serialize(self, skip_empty=True):
skip = set(getattr(self._meta, "serialize_skip", []))

r = {}
for k, v in self.__dict__.items():
for k, v in list(self.__dict__.items()):
if k.startswith("_"):
continue
elif k in skip:
Expand All @@ -520,7 +516,7 @@ def _serialize_value(self, value):
if isinstance(value, (list, tuple, set)):
return [self._serialize_value(v) for v in value]
elif isinstance(value, dict):
return dict([(k, self._serialize_value(v)) for k, v in value.items()])
return dict([(k, self._serialize_value(v)) for k, v in list(value.items())])
elif isinstance(value, ModelBase):
return value._serialize()
elif isinstance(value, datetime.date): # includes datetime.datetime
Expand All @@ -529,8 +525,7 @@ def _serialize_value(self, value):
return value


@six.add_metaclass(ModelMeta)
class ModelBase(SerializableBase):
class ModelBase(SerializableBase, metaclass=ModelMeta):
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self)

Expand All @@ -543,7 +538,7 @@ def __str__(self):
def __init__(self, **kwargs):
self._manager = None
self.id = None
for k, v in kwargs.items():
for k, v in list(kwargs.items()):
setattr(self, k, v)

def __eq__(self, other):
Expand Down
7 changes: 3 additions & 4 deletions koordinates/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import pkg_resources
import requests
import requests_toolbelt
import six

from . import layers, licenses, publishing, sets, users, catalog, sources, exports
from . import exceptions
Expand Down Expand Up @@ -99,7 +98,7 @@ def _init_managers(self, public, private):
mgr = manager_class(self)
self._register_manager(mgr.model, mgr)

for alias, manager_class in public.items():
for alias, manager_class in list(public.items()):
mgr = manager_class(self)
self._register_manager(mgr.model, mgr)
setattr(self, alias, mgr)
Expand All @@ -113,9 +112,9 @@ def get_manager(self, model):
:param model: Model class to look up the manager instance for.
:return: Manager instance for the model associated with this client.
"""
if isinstance(model, six.string_types):
if isinstance(model, str):
# undocumented string lookup
for k, m in self._manager_map.items():
for k, m in list(self._manager_map.items()):
if k.__name__ == model:
return m
else:
Expand Down
10 changes: 2 additions & 8 deletions koordinates/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
# -*- coding: utf-8 -*-
from six import string_types


class KoordinatesException(Exception):
""" Base class for all koordinates module errors """

def __init__(self, message, **kwargs):
super(KoordinatesException, self).__init__(message)
for k, v in kwargs.items():
for k, v in list(kwargs.items()):
setattr(self, k, v)


Expand Down Expand Up @@ -82,9 +78,7 @@ def _get_message(self, error, response):
try:
messages = []
for field, errors in sorted(response.json().items()):
errors = (
errors if isinstance(errors, string_types) else "; ".join(errors)
)
errors = errors if isinstance(errors, str) else "; ".join(errors)
messages.append("%s: %s" % (field, errors))
return "\n".join(messages)
except Exception as e:
Expand Down
12 changes: 3 additions & 9 deletions koordinates/exports.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-

"""
koordinates.exports
===================
Expand All @@ -8,14 +6,10 @@
provides an interface to create exports and download data from a Koordinates site.
"""
import collections
import contextlib
import logging
import os
import six

if six.PY2:
import contextlib2 as contextlib
else:
import contextlib

from . import base
from . import exceptions
Expand Down Expand Up @@ -196,7 +190,7 @@ def get_formats(self):
"""
format_opts = self._options()["actions"]["POST"]["formats"]["children"]
r = {}
for kind, kind_opts in format_opts.items():
for kind, kind_opts in list(format_opts.items()):
r[kind] = {c["value"]: c["display_name"] for c in kind_opts["choices"]}
return r

Expand Down Expand Up @@ -264,7 +258,7 @@ def set_formats(self, **kinds):
if not hasattr(self, "formats"):
self.formats = {}

for kind, data_format in kinds.items():
for kind, data_format in list(kinds.items()):
if data_format:
self.formats[kind] = data_format
elif kind in self.formats:
Expand Down
5 changes: 2 additions & 3 deletions koordinates/sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import os

from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
import six

from . import base
from .exceptions import ClientValidationError
Expand Down Expand Up @@ -259,7 +258,7 @@ def wrapped_callback(monitor):
for i, (upload_path, (file_or_path, content_type)) in enumerate(
self._files.items()
):
if isinstance(file_or_path, six.string_types):
if isinstance(file_or_path, str):
# path
fp = open(file_or_path, "rb")
opened_files.append(fp)
Expand Down Expand Up @@ -310,7 +309,7 @@ def add_file(self, fp, upload_path=None, content_type=None):
:param str content_type: Content-Type of the file. By default it will attempt to auto-detect from the \
file/upload_path.
"""
if isinstance(fp, six.string_types):
if isinstance(fp, str):
# path
if not os.path.isfile(fp):
raise ClientValidationError("Invalid file: %s", fp)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[tool.black]
target-version = ['py27']
target-version = ['py34']
2 changes: 0 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,3 @@ python-dateutil~=2.4
pytz
requests~=2.18
requests-toolbelt~=0.4
six~=1.10
contextlib2~=0.5; python_version<'3.0'
7 changes: 2 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,21 @@
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Scientific/Engineering :: GIS",
],
python_requires=">=3.4",
install_requires=[
"python-dateutil>=2,<3",
"pytz",
"requests>=2.5,<3",
"requests-toolbelt>=0.4,<1",
"six>=1.10.0,<2",
],
extras_require={':python_version=="2.7"': ["contextlib2",],},
tests_require=["pytest>=3.3", "responses>=0.3", "coverage>=3.7,<4",],
zip_safe=False,
)
Loading

0 comments on commit 1bab3d0

Please sign in to comment.