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]