From ec899d70b725d8f74c971cc21018ec24a8586ad5 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 28 Dec 2017 18:03:13 +0100 Subject: [PATCH] Removed Python 2.6 support * Travis CI doesn't support it anymore. * It had EOL more than 4 years ago --- CHANGELOG.rst | 3 + README.rst | 10 +-- httpie/compat.py | 141 +------------------------------------------ httpie/input.py | 4 +- httpie/utils.py | 5 +- setup.py | 2 - tests/test_httpie.py | 5 -- tox.ini | 2 +- 8 files changed, 13 insertions(+), 159 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4e3a7d76..48d4552e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,9 +8,12 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (unreleased) ------------------------- + +* Removed Python 2.6 support. * ``--verify`` now accepts ``true``/``false`` in addition to ``yes``/``no`` and the boolean value is case-insensitive. + `0.9.8`_ (2016-12-08) --------------------- diff --git a/README.rst b/README.rst index 322d09d8..245f8ccb 100644 --- a/README.rst +++ b/README.rst @@ -41,7 +41,7 @@ Main features * Custom headers * Persistent sessions * Wget-like downloads -* Python 2.6, 2.7 and 3.x support +* Python 2.7 and 3.x support * Linux, macOS and Windows support * Plugins * Documentation @@ -119,10 +119,10 @@ and always provides the latest version) is to use `pip`_: Python version -------------- -Although Python 2.6 and 2.7 are supported as well, it is recommended to install -HTTPie against the latest Python 3.x whenever possible. That will ensure that -some of the newer HTTP features, such as `SNI (Server Name Indication)`_, -work out of the box. +Although Python 2.7 is supported as well, it is strongly recommended to +install HTTPie against the latest Python 3.x whenever possible. That will +ensure that some of the newer HTTP features, such as +`SNI (Server Name Indication)`_, work out of the box. Python 3 is the default for Homebrew installations starting with version 0.9.4. To see which version HTTPie uses, run ``http --debug``. diff --git a/httpie/compat.py b/httpie/compat.py index d626e984..d81e508b 100644 --- a/httpie/compat.py +++ b/httpie/compat.py @@ -1,12 +1,11 @@ """ -Python 2.6, 2.7, and 3.x compatibility. +Python 2.7, and 3.x compatibility. """ import sys is_py2 = sys.version_info[0] == 2 -is_py26 = sys.version_info[:2] == (2, 6) is_py27 = sys.version_info[:2] == (2, 7) is_py3 = sys.version_info[0] == 3 is_pypy = 'pypy' in sys.version.lower() @@ -38,141 +37,3 @@ try: # pragma: no cover except ImportError: # pragma: no cover # noinspection PyCompatibility,PyUnresolvedReferences from urllib2 import urlopen - -try: # pragma: no cover - from collections import OrderedDict -except ImportError: # pragma: no cover - # Python 2.6 OrderedDict class, needed for headers, parameters, etc .### - # - # noinspection PyCompatibility,PyUnresolvedReferences - from UserDict import DictMixin - - # noinspection PyShadowingBuiltins,PyCompatibility - class OrderedDict(dict, DictMixin): - # Copyright (c) 2009 Raymond Hettinger - # - # Permission is hereby granted, free of charge, to any person - # obtaining a copy of this software and associated documentation files - # (the "Software"), to deal in the Software without restriction, - # including without limitation the rights to use, copy, modify, merge, - # publish, distribute, sublicense, and/or sell copies of the Software, - # and to permit persons to whom the Software is furnished to do so, - # subject to the following conditions: - # - # The above copyright notice and this permission notice shall be - # included in all copies or substantial portions of the Software. - # - # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - # OTHER DEALINGS IN THE SOFTWARE. - # noinspection PyMissingConstructor - def __init__(self, *args, **kwds): - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' - % len(args)) - try: - self.__end - except AttributeError: - self.clear() - self.update(*args, **kwds) - - def clear(self): - self.__end = end = [] - # noinspection PyUnusedLocal - end += [None, end, end] # sentinel node for doubly linked list - self.__map = {} # key --> [key, prev, next] - dict.clear(self) - - def __setitem__(self, key, value): - if key not in self: - end = self.__end - curr = end[1] - curr[2] = end[1] = self.__map[key] = [key, curr, end] - dict.__setitem__(self, key, value) - - def __delitem__(self, key): - dict.__delitem__(self, key) - key, prev, next = self.__map.pop(key) - prev[2] = next - next[1] = prev - - def __iter__(self): - end = self.__end - curr = end[2] - while curr is not end: - yield curr[0] - curr = curr[2] - - def __reversed__(self): - end = self.__end - curr = end[1] - while curr is not end: - yield curr[0] - curr = curr[1] - - def popitem(self, last=True): - if not self: - raise KeyError('dictionary is empty') - if last: - # noinspection PyUnresolvedReferences - key = reversed(self).next() - else: - key = iter(self).next() - value = self.pop(key) - return key, value - - def __reduce__(self): - items = [[k, self[k]] for k in self] - tmp = self.__map, self.__end - del self.__map, self.__end - inst_dict = vars(self).copy() - self.__map, self.__end = tmp - if inst_dict: - return self.__class__, (items,), inst_dict - return self.__class__, (items,) - - def keys(self): - return list(self) - - setdefault = DictMixin.setdefault - update = DictMixin.update - pop = DictMixin.pop - values = DictMixin.values - items = DictMixin.items - iterkeys = DictMixin.iterkeys - itervalues = DictMixin.itervalues - iteritems = DictMixin.iteritems - - def __repr__(self): - if not self: - return '%s()' % (self.__class__.__name__,) - return '%s(%r)' % (self.__class__.__name__, self.items()) - - def copy(self): - return self.__class__(self) - - # noinspection PyMethodOverriding - @classmethod - def fromkeys(cls, iterable, value=None): - d = cls() - for key in iterable: - d[key] = value - return d - - def __eq__(self, other): - if isinstance(other, OrderedDict): - if len(self) != len(other): - return False - for p, q in zip(self.items(), other.items()): - if p != q: - return False - return True - return dict.__eq__(self, other) - - def __ne__(self, other): - return not self == other diff --git a/httpie/input.py b/httpie/input.py index de402b05..978b4b44 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -9,7 +9,7 @@ import errno import mimetypes import getpass from io import BytesIO -from collections import namedtuple, Iterable +from collections import namedtuple, Iterable, OrderedDict # noinspection PyCompatibility from argparse import ArgumentParser, ArgumentTypeError, ArgumentError @@ -18,7 +18,7 @@ from argparse import ArgumentParser, ArgumentTypeError, ArgumentError from httpie.plugins import plugin_manager from requests.structures import CaseInsensitiveDict -from httpie.compat import OrderedDict, urlsplit, str, is_pypy, is_py27 +from httpie.compat import urlsplit, str, is_pypy, is_py27 from httpie.sessions import VALID_SESSION_NAME_PATTERN from httpie.utils import load_json_preserve_order diff --git a/httpie/utils.py b/httpie/utils.py index c3b01258..e5d9766d 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -1,12 +1,9 @@ from __future__ import division import json - -from httpie.compat import is_py26, OrderedDict +from collections import OrderedDict def load_json_preserve_order(s): - if is_py26: - return json.loads(s) return json.loads(s, object_pairs_hook=OrderedDict) diff --git a/setup.py b/setup.py index ec071a2d..bf66f062 100644 --- a/setup.py +++ b/setup.py @@ -93,8 +93,6 @@ setup( classifiers=[ 'Development Status :: 5 - Production/Stable', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.1', diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 36a856f7..a3717470 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -6,7 +6,6 @@ from utils import TestEnvironment, http, HTTP_OK from fixtures import FILE_PATH, FILE_CONTENT import httpie -from httpie.compat import is_py26 def test_debug(): @@ -107,10 +106,6 @@ def test_headers_empty_value_with_value_gives_error(httpbin): http('GET', httpbin + '/headers', 'Accept;SYNTAX_ERROR') -@pytest.mark.skipif( - is_py26, - reason='the `object_pairs_hook` arg for `json.loads()` is Py>2.6 only' -) def test_json_input_preserve_order(httpbin_both): r = http('PATCH', httpbin_both + '/patch', 'order:={"map":{"1":"first","2":"second"}}') diff --git a/tox.ini b/tox.ini index aaa231f6..834e3362 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ [tox] -envlist = py26, py27, py35, py36, pypy, codestyle +envlist = py27, py35, py36, pypy, codestyle [testenv]