PYTHON-1467 - PyMongo no longer supports Python 2.6

This commit is contained in:
Bernie Hackett 2018-07-02 10:56:43 -07:00
parent c2fde81d60
commit 749c1a2f0b
31 changed files with 141 additions and 333 deletions

View File

@ -855,10 +855,11 @@ axes:
- id: os-fully-featured
display_name: OS
values:
- id: linux-64-amzn-test
display_name: "Amazon Linux (Enterprise)"
run_on: linux-64-amzn-test
batchtime: 10080 # 7 days
# https://jira.mongodb.org/browse/BUILD-5453
#- id: linux-64-amzn-test
# display_name: "Amazon Linux (Enterprise)"
# run_on: linux-64-amzn-test
# batchtime: 10080 # 7 days
- id: ubuntu-14.04
display_name: "Ubuntu 14.04"
@ -1013,10 +1014,6 @@ axes:
- id: python-version
display_name: "Python"
values:
- id: "2.6"
display_name: "Python 2.6"
variables:
PYTHON_BINARY: "/opt/python/2.6/bin/python"
- id: "2.7"
display_name: "Python 2.7"
variables:
@ -1061,10 +1058,6 @@ axes:
- id: mod-wsgi-version
display_name: "mod_wsgi version"
values:
- id: "2"
display_name: "mod_wsgi 2.8"
variables:
MOD_WSGI_VERSION: "2"
- id: "3"
display_name: "mod_wsgi 3.5"
variables:
@ -1122,11 +1115,7 @@ axes:
values:
# There is (currently) no vs2008 distro. The Microsoft Visual
# C++ Compiler for Python 2.7 has been installed, with CPython
# 2.6 and 2.7, on the vs2015 distro.
- id: "2.6"
display_name: "Python 2.6"
variables:
PYTHON_BINARY: "/cygdrive/c/python/Python26/python.exe"
# 2.7, on the vs2015 distro.
- id: "2.7"
display_name: "Python 2.7"
variables:
@ -1339,9 +1328,6 @@ buildvariants:
# on Windows with the Microsoft Visual C++ Compiler for Python 2.7 or Visual Studio 2015.
- matrix_name: "tests-windows-vs2015-python-version-27plus"
matrix_spec: {windows-vs2015-python-version: "*", auth-ssl: "*"}
exclude_spec:
- windows-vs2015-python-version: "2.6"
auth-ssl: "*"
display_name: "Windows 64 Visual Studio 2015 ${windows-vs2015-python-version} ${auth-ssl}"
run_on: windows-64-vs2015-test
tasks:
@ -1353,51 +1339,6 @@ buildvariants:
- ".3.0"
- ".2.6"
# Test CPython 2.6 against all versions on MongoDB >= 2.6
# on Windows with the Microsoft Visual C++ Compiler for Python 2.7.
# Python 2.6.6 (the last 2.6 version with Windows installers) bundles
# OpenSSL 0.9.8, which doesn't support TLS 1.1+. MongoDB 4.0+ requires
# TLS 1.1+ by default.
- matrix_name: "tests-windows-vs2015-python-version-26"
matrix_spec: {windows-vs2015-python-version: "2.6", auth: "*", ssl: "*"}
exclude_spec:
- windows-vs2015-python-version: "*"
auth: "noauth"
ssl: "ssl"
display_name: "Windows 64 Visual Studio 2015 ${windows-vs2015-python-version} ${auth} ${ssl}"
run_on: windows-64-vs2015-test
rules:
- if:
windows-vs2015-python-version: "*"
auth: "*"
ssl: "nossl"
then:
add_tasks:
- ".latest"
- ".4.0"
- if:
windows-vs2015-python-version: "*"
auth: "noauth"
ssl: "nossl"
then:
add_tasks:
- ".3.6"
- ".3.4"
- ".3.2"
- ".3.0"
- ".2.6"
- if:
windows-vs2015-python-version: "*"
auth: "auth"
ssl: "ssl"
then:
add_tasks:
- ".3.6"
- ".3.4"
- ".3.2"
- ".3.0"
- ".2.6"
# Storage engine tests on RHEL 6.2 (x86_64) with Python 2.7.
- matrix_name: "tests-storage-engines"
matrix_spec: {storage-engine: "*", python-version: "2.7"}
@ -1453,11 +1394,7 @@ buildvariants:
- name: "test-enterprise-auth"
- matrix_name: "tests-mod-wsgi"
matrix_spec: {"python-version": ["2.6", "2.7", "3.4", "3.6"], "mod-wsgi-version": "*"}
exclude_spec:
# mod_wsgi 2.8 segfaults with the toolchain python 2.7, regardless of distro
python-version: ["2.7", "3.4", "3.6"]
mod-wsgi-version: ["2"]
matrix_spec: {"python-version": ["2.7", "3.4", "3.6"], "mod-wsgi-version": "*"}
display_name: "${mod-wsgi-version} ${python-version}"
run_on: rhel62-small
tasks:
@ -1479,7 +1416,7 @@ buildvariants:
- name: "doctests"
- matrix_name: "cdecimal"
matrix_spec: {python-version: ["2.6", "2.7"]}
matrix_spec: {python-version: ["2.7"]}
display_name: "cdecimal ${python-version}"
batchtime: 10080 # 7 days
run_on:

View File

@ -7,24 +7,16 @@ export JAVA_HOME=/opt/java/jdk8
IMPL=$(${PYTHON_BINARY} -c "import platform, sys; sys.stdout.write(platform.python_implementation())")
PYTHON_VERSION=$(${PYTHON_BINARY} -c "import sys; print('.'.join(map(str, sys.version_info[:2])))")
if [ $PYTHON_VERSION = "2.6" -o $IMPL = "Jython" ]; then
# TODO - When Jython has its own virtualenv install use it instead.
/opt/python/2.6/bin/virtualenv -p ${PYTHON_BINARY} --never-download --no-wheel atlastest
. atlastest/bin/activate
trap "deactivate; rm -rf atlastest" EXIT HUP
pip install certifi
if [ $PYTHON_VERSION = "2.6" ]; then
pip install unittest2
fi
PYTHON=python
elif [ $IMPL = "PyPy" -a $PYTHON_VERSION = "3.2" ]; then
if [ $IMPL = "Jython" -o $IMPL = "PyPy" ]; then
$PYTHON_BINARY -m virtualenv --never-download --no-wheel atlastest
. atlastest/bin/activate
trap "deactivate; rm -rf atlastest" EXIT HUP
pip install certifi
# Portable pypy3.2 can't load CA certs from the system.
# https://github.com/squeaky-pl/portable-pypy/issues/15
export SSL_CERT_FILE=$(python -c "import certifi; print(certifi.where())")
if [ $PYTHON_VERSION = "3.2" ]; then
# Portable pypy3.2 can't load CA certs from the system.
# https://github.com/squeaky-pl/portable-pypy/issues/15
export SSL_CERT_FILE=$(python -c "import certifi; print(certifi.where())")
fi
PYTHON=python
else
PYTHON=$PYTHON_BINARY

View File

@ -44,10 +44,7 @@ if [ -z "$PYTHON_BINARY" ]; then
exit 1
fi
else
# wheel and pip are dropping support for Python 2.6. Avoid virtualenv
# automatically upgrading its bundled versions to new versions that
# might fail in 2.6.
$VIRTUALENV --no-download pymongotestvenv || $VIRTUALENV pymongotestvenv
$VIRTUALENV pymongotestvenv
. pymongotestvenv/bin/activate
PYTHON=python
trap "deactivate; rm -rf pymongotestvenv" EXIT HUP

View File

@ -1,7 +1,6 @@
language: python
python:
- 2.6
- 2.7
- 3.4
- 3.5

View File

@ -19,7 +19,7 @@ that might not be of interest or that has already been addressed.
Supported Interpreters
----------------------
PyMongo supports CPython 2.6, 2.7, 3.4+, PyPy, and PyPy3. Language
PyMongo supports CPython 2.7, 3.4+, PyPy, and PyPy3. Language
features not supported by all interpreters can not be used.
Style Guide

View File

@ -88,7 +88,7 @@ is incompatible with PyMongo.
Dependencies
============
PyMongo supports CPython 2.6, 2.7, 3.4+, PyPy, and PyPy3.
PyMongo supports CPython 2.7, 3.4+, PyPy, and PyPy3.
Optional dependencies:
@ -136,7 +136,6 @@ Other optional packages:
Additional dependencies are:
- (to generate documentation) sphinx_
- (to run the tests under Python 2.6) unittest2_
Examples
========
@ -188,8 +187,7 @@ Testing
=======
The easiest way to run the tests is to run **python setup.py test** in
the root of the distribution. Note that you will need unittest2_ to
run the tests under Python 2.6.
the root of the distribution.
To verify that PyMongo works with Gevent's monkey-patching::
@ -200,4 +198,3 @@ Or with Eventlet's::
$ python green_framework_test.py eventlet
.. _sphinx: http://sphinx.pocoo.org/
.. _unittest2: https://pypi.python.org/pypi/unittest2

View File

@ -31,9 +31,9 @@ that changes the major version number.
Doing a Release
---------------
1. Test releases on Python 2.6-2.7 and 3.4+ on Windows, Linux and OSX,
1. Test releases on Python 2.7 and 3.4+ on Windows, Linux and OSX,
with and without the C extensions. It's generally enough to just run the
tests on 2.6, 2.7, 3.4 and the latest 3.x version with and without the
tests on 2.7, 3.4 and the latest 3.x version with and without the
extensions on a single platform, and then just test any version on the
other platforms as a sanity check. `python setup.py test` will build the
extensions and test. `python tools/clean.py` will remove the extensions,

View File

@ -35,21 +35,6 @@ else:
"An implementation of int.from_bytes for python 2.x."
return _int(_hexlify(value), 16)
if sys.version_info[:2] == (2, 6):
def _bit_length(num):
"""bit_length for python 2.6"""
if num:
# bin() was new in 2.6. Note that this won't work
# for values less than 0, which we never have here.
return len(bin(num)) - 2
# bit_length(0) is 0, but len(bin(0)) - 2 is 1
return 0
else:
def _bit_length(num):
"""bit_length for python >= 2.7"""
# num could be int or long in python 2.7
return num.bit_length()
_PACK_64 = struct.Struct("<Q").pack
_UNPACK_64 = struct.Struct("<Q").unpack
@ -126,7 +111,7 @@ def _decimal_to_128(value):
return _NNAN if value.is_signed() else _PNAN
significand = int("".join([str(digit) for digit in digits]))
bit_length = _bit_length(significand)
bit_length = significand.bit_length()
high = 0
low = 0
@ -298,10 +283,9 @@ class Decimal128(object):
mask = 0x0001000000000000
arr[0] = (high & mask) >> 48
# Have to convert bytearray to bytes for python 2.6.
# cdecimal only accepts a tuple for digits.
digits = tuple(
int(digit) for digit in str(_from_bytes(bytes(arr), 'big')))
int(digit) for digit in str(_from_bytes(arr, 'big')))
with decimal.localcontext(_DEC128_CTX) as ctx:
return ctx.create_decimal((sign, digits, exponent))

View File

@ -107,21 +107,12 @@ but it will be faster as there is less recursion.
import base64
import datetime
import json
import math
import re
import sys
import uuid
if sys.version_info[:2] == (2, 6):
# In Python 2.6, json does not include object_pairs_hook. Use simplejson
# instead.
try:
import simplejson as json
except ImportError:
import json
else:
import json
from pymongo.errors import ConfigurationError
import bson
@ -143,13 +134,6 @@ from bson.timestamp import Timestamp
from bson.tz_util import utc
try:
json.loads("{}", object_pairs_hook=dict)
_HAS_OBJECT_PAIRS_HOOK = True
except TypeError:
_HAS_OBJECT_PAIRS_HOOK = False
_RE_OPT_TABLE = {
"i": re.I,
"l": re.L,
@ -245,10 +229,6 @@ class JSONMode:
class JSONOptions(CodecOptions):
"""Encapsulates JSON options for :func:`dumps` and :func:`loads`.
Raises :exc:`~pymongo.errors.ConfigurationError` on Python 2.6 if
`simplejson >= 2.1.0 <https://pypi.python.org/pypi/simplejson>`_ is not
installed and document_class is not the default (:class:`dict`).
:Parameters:
- `strict_number_long`: If ``True``, :class:`~bson.int64.Int64` objects
are encoded to MongoDB Extended JSON's *Strict mode* type
@ -301,11 +281,6 @@ class JSONOptions(CodecOptions):
"JSONOptions.datetime_representation must be one of LEGACY, "
"NUMBERLONG, or ISO8601 from DatetimeRepresentation.")
self = super(JSONOptions, cls).__new__(cls, *args, **kwargs)
if not _HAS_OBJECT_PAIRS_HOOK and self.document_class != dict:
raise ConfigurationError(
"Support for JSONOptions.document_class on Python 2.6 "
"requires simplejson >= 2.1.0"
"(https://pypi.python.org/pypi/simplejson) to be installed.")
if json_mode not in (JSONMode.LEGACY,
JSONMode.RELAXED,
JSONMode.CANONICAL):
@ -430,11 +405,8 @@ def loads(s, *args, **kwargs):
Accepts optional parameter `json_options`. See :class:`JSONOptions`.
"""
json_options = kwargs.pop("json_options", DEFAULT_JSON_OPTIONS)
if _HAS_OBJECT_PAIRS_HOOK:
kwargs["object_pairs_hook"] = lambda pairs: object_pairs_hook(
pairs, json_options)
else:
kwargs["object_hook"] = lambda obj: object_hook(obj, json_options)
kwargs["object_pairs_hook"] = lambda pairs: object_pairs_hook(
pairs, json_options)
return json.loads(s, *args, **kwargs)

View File

@ -36,7 +36,7 @@ if PY3:
def b(s):
# BSON and socket operations deal in binary data. In
# python 3 that means instances of `bytes`. In python
# 2.6 and 2.7 you can create an alias for `bytes` using
# 2.7 you can create an alias for `bytes` using
# the b prefix (e.g. b'foo').
# See http://python3porting.com/problems.html#nicer-solutions
return codecs.latin_1_encode(s)[0]

View File

@ -1,6 +1,23 @@
Changelog
=========
Changes in Version 3.8.0
------------------------
.. warning:: PyMongo no longer supports Python 2.6. RHEL 6 users should install
Python 2.7 or newer from `Red Hat Software Collections
<https://www.softwarecollections.org>`_. CentOS 6 users should install Python
2.7 or newer from `SCL
<https://wiki.centos.org/AdditionalResources/Repositories/SCL>`_
Issues Resolved
...............
See the `PyMongo 3.8 release notes in JIRA`_ for the list of resolved issues
in this release.
.. _PyMongo 3.8 release notes in JIRA: https://jira.mongodb.org/secure/ReleaseNote.jspa?projectId=10004&version=19904
Changes in Version 3.7.0
------------------------

View File

@ -45,7 +45,7 @@ To upgrade do::
Dependencies
------------
PyMongo supports CPython 2.6, 2.7, 3.4+, PyPy, and PyPy3.
PyMongo supports CPython 2.7, 3.4+, PyPy, and PyPy3.
Optional dependencies:
@ -135,13 +135,12 @@ OSX and Xcode versions.
**Snow Leopard (10.6)** - Xcode 3 with 'UNIX Development Support'.
**Snow Leopard Xcode 4**: The Python versions shipped with OSX 10.6.x
are universal binaries. They support i386, PPC, and (in the case of python2.6)
x86_64. Xcode 4 removed support for PPC, causing the distutils version shipped
with Apple's builds of Python to fail to build the C extensions if you have
Xcode 4 installed. There is a workaround::
are universal binaries. They support i386, PPC, and x86_64. Xcode 4 removed
support for PPC, causing the distutils version shipped with Apple's builds of
Python to fail to build the C extensions if you have Xcode 4 installed. There
is a workaround::
# For Apple-supplied Python2.6 (installed at /usr/bin/python2.6) and
# some builds from python.org
# For some Python builds from python.org
$ env ARCHFLAGS='-arch i386 -arch x86_64' python -m easy_install pymongo
See `http://bugs.python.org/issue11623 <http://bugs.python.org/issue11623>`_
@ -185,8 +184,8 @@ requirements apply to both CPython and ActiveState's ActivePython:
For Python 3.5 and newer install Visual Studio 2015. For Python 3.4
install Visual Studio 2010. You must use the full version of Visual Studio
2010 as Visual C++ Express does not provide 64-bit compilers. Make sure that
you check the "x64 Compilers and Tools" option under Visual C++. For Python 2.6
and 2.7 install the `Microsoft Visual C++ Compiler for Python 2.7`_.
you check the "x64 Compilers and Tools" option under Visual C++. For Python 2.7
install the `Microsoft Visual C++ Compiler for Python 2.7`_.
32-bit Windows
~~~~~~~~~~~~~~
@ -195,7 +194,7 @@ For Python 3.5 and newer install Visual Studio 2015.
For Python 3.4 install Visual C++ 2010 Express.
For Python 2.6 and 2.7 install the `Microsoft Visual C++ Compiler for Python 2.7`_
For Python 2.7 install the `Microsoft Visual C++ Compiler for Python 2.7`_
.. _`Microsoft Visual C++ Compiler for Python 2.7`: https://www.microsoft.com/en-us/download/details.aspx?id=44266

View File

@ -97,8 +97,8 @@ Python 3 you must pass ``encoding='latin-1'`` to pickle.loads::
If you need to pickle ObjectIds using Python 3 and unpickle them using Python 2
you must use ``protocol <= 2``::
Python 3.6.1 (v3.6.1:69c0db5050, Mar 21 2017, 01:21:04)
[GCC 4.9.3] on linux
Python 3.6.5 (default, Jun 21 2018, 15:09:09)
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> from bson.objectid import ObjectId
@ -108,8 +108,8 @@ you must use ``protocol <= 2``::
>>> pickle.dumps(oid, protocol=2)
b'\x80\x02cbson.objectid\nObjectId\nq\x00)\x81q\x01c_codecs\nencode\...'
Python 2.6.9 (unknown, Feb 26 2014, 12:39:10)
[GCC 4.7.3] on linux2
Python 2.7.15 (default, Jun 21 2018, 15:00:48)
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> pickle.loads('\x80\x02cbson.objectid\nObjectId\nq\x00)\x81q\x01c_codecs\nencode\...')

View File

@ -284,10 +284,7 @@ class ServerListener(_EventListener):
def _to_micros(dur):
"""Convert duration 'dur' to microseconds."""
if hasattr(dur, 'total_seconds'):
return int(dur.total_seconds() * 10e5)
# Python 2.6
return dur.microseconds + (dur.seconds + dur.days * 24 * 3600) * 1000000
return int(dur.total_seconds() * 10e5)
def _validate_event_listeners(option, listeners):

View File

@ -101,7 +101,7 @@ except ImportError:
# ':' is not a valid character for a hostname. If we get
# here a few things have to be true:
# - We're on a recent version of python 2.7 (2.7.9+).
# 2.6 and older 2.7 versions don't support SNI.
# Older 2.7 versions don't support SNI.
# - We're on Windows XP or some unusual Unix that doesn't
# have inet_pton.
# - The application is using IPv6 literals with TLS, which
@ -272,7 +272,7 @@ def _raise_connection_failure(address, error, msg_prefix=None):
if isinstance(error, socket.timeout):
raise NetworkTimeout(msg)
elif isinstance(error, SSLError) and 'timed out' in str(error):
# CPython 2.6, 2.7, PyPy 2.x, and PyPy3 do not distinguish network
# CPython 2.7, PyPy 2.x, and PyPy3 do not distinguish network
# timeouts from other SSLErrors (https://bugs.python.org/issue10272).
# Luckily, we can work around this limitation because the phrase
# 'timed out' appears in all the timeout related SSLErrors raised
@ -766,7 +766,7 @@ def _create_connection(address, options):
Can raise socket.error.
This is a modified version of create_connection from CPython >= 2.6.
This is a modified version of create_connection from CPython >= 2.7.
"""
host, port = address

View File

@ -20,16 +20,6 @@ from pymongo.ismaster import IsMaster
from pymongo.monotonic import time as _time
def _total_seconds(delta):
"""Total seconds in the duration."""
if hasattr(delta, 'total_seconds'):
return delta.total_seconds()
# Python 2.6.
return ((delta.days * 86400 + delta.seconds) * 10 ** 6 +
delta.microseconds) / 10.0 ** 6
class ServerDescription(object):
"""Immutable representation of one server.
@ -82,7 +72,7 @@ class ServerDescription(object):
if ismaster.last_write_date:
# Convert from datetime to seconds.
delta = ismaster.last_write_date - EPOCH_NAIVE
self._last_write_date = _total_seconds(delta)
self._last_write_date = delta.total_seconds()
else:
self._last_write_date = None

View File

@ -25,7 +25,7 @@ class SSLContext(object):
This implements an API similar to ssl.SSLContext from python 3.2
but does not implement methods or properties that would be
incompatible with ssl.wrap_socket from python 2.6.
incompatible with ssl.wrap_socket from python 2.7 < 2.7.9.
You must pass protocol which must be one of the PROTOCOL_* constants
defined in the ssl module. ssl.PROTOCOL_SSLv23 is recommended for maximum

View File

@ -1,11 +1,11 @@
# Backport of the match_hostname logic from python 3.5, with small
# changes to support IP address matching on python 2.6, 2.7, 3.3, and 3.4.
# changes to support IP address matching on python 2.7 and 3.4.
import re
import sys
try:
# Python 3.3+, or the ipaddress module from pypi.
# Python 3.4+, or the ipaddress module from pypi.
from ipaddress import ip_address
except ImportError:
ip_address = lambda address: None

View File

@ -123,7 +123,7 @@ if HAVE_SSL:
# up to date versions of MongoDB 2.4 and above already disable
# SSLv2 and SSLv3, python disables SSLv2 by default in >= 2.7.7
# and >= 3.3.4 and SSLv3 in >= 3.4.3. There is no way for us to do
# any of this explicitly for python 2.6 or 2.7 before 2.7.9.
# any of this explicitly for python 2.7 before 2.7.9.
ctx.options |= getattr(ssl, "OP_NO_SSLv2", 0)
ctx.options |= getattr(ssl, "OP_NO_SSLv3", 0)
# OpenSSL >= 1.0.0

View File

@ -97,21 +97,16 @@ class test(Command):
if self.distribution.tests_require:
self.distribution.fetch_build_eggs(self.distribution.tests_require)
if self.xunit_output:
if sys.version_info[:2] == (2, 6):
self.distribution.fetch_build_eggs(
["unittest-xml-reporting>=1.14.0,<2.0.0a0"])
else:
self.distribution.fetch_build_eggs(["unittest-xml-reporting"])
self.distribution.fetch_build_eggs(["unittest-xml-reporting"])
self.run_command('egg_info')
build_ext_cmd = self.reinitialize_command('build_ext')
build_ext_cmd.inplace = 1
self.run_command('build_ext')
# Construct a TextTestRunner directly from the unittest imported from
# test (this will be unittest2 under Python 2.6), which creates a
# TestResult that supports the 'addSkip' method. setuptools will by
# default create a TextTestRunner that uses the old TestResult class,
# resulting in DeprecationWarnings instead of skipping tests under 2.6.
# test, which creates a TestResult that supports the 'addSkip' method.
# setuptools will by default create a TextTestRunner that uses the old
# TestResult class.
from test import unittest, PymongoTestRunner, test_cases
if self.test_suite is None:
all_tests = unittest.defaultTestLoader.discover(self.test_module)
@ -223,8 +218,8 @@ class doc(Command):
" %s/\n" % (mode, path))
if sys.platform == 'win32' and sys.version_info > (2, 6):
# 2.6's distutils.msvc9compiler can raise an IOError when failing to
if sys.platform == 'win32':
# distutils.msvc9compiler can raise an IOError when failing to
# find the compiler
build_errors = (CCompilerError, DistutilsExecError,
DistutilsPlatformError, IOError)
@ -294,7 +289,7 @@ http://api.mongodb.org/python/current/installation.html#osx
def build_extension(self, ext):
name = ext.name
if sys.version_info[:3] >= (2, 6, 0):
if sys.version_info[:3] >= (2, 7, 0):
try:
build_ext.build_extension(self, ext)
except build_errors:
@ -310,7 +305,7 @@ http://api.mongodb.org/python/current/installation.html#osx
warnings.warn(self.warning_message % ("The %s extension "
"module" % (name,),
"PyMongo supports python "
">= 2.6."))
">= 2.7."))
ext_modules = [Extension('bson._cbson',
include_dirs=['bson'],
@ -343,15 +338,6 @@ else:
extra_opts = {
"packages": ["bson", "pymongo", "gridfs"]
}
if sys.version_info[:2] == (2, 6):
try:
import unittest2
except ImportError:
# The setuptools version on Solaris 11 is incapable
# of recognizing if unittest2 is already installed.
# It's also incapable of installing any version of
# unittest2 newer than 0.8.0
extra_opts['tests_require'] = "unittest2<=0.8.0"
if "--no_ext" in sys.argv:
sys.argv.remove("--no_ext")
@ -388,7 +374,6 @@ setup(
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",

View File

@ -20,6 +20,7 @@ import socket
import sys
import threading
import time
import unittest
import warnings
try:
@ -28,14 +29,8 @@ try:
except ImportError:
HAVE_IPADDRESS = False
if sys.version_info[:2] == (2, 6):
import unittest2 as unittest
from unittest2 import SkipTest
else:
import unittest
from unittest import SkipTest
from functools import wraps
from unittest import SkipTest
import pymongo
import pymongo.errors

View File

@ -17,13 +17,7 @@
import os
import ssl
import sys
# Don't drag in PyMongo's entire test suite
# just to get the right unittest module.
if sys.version_info[:2] == (2, 6):
import unittest2 as unittest
else:
import unittest
import unittest
sys.path[0:0] = [""]

View File

@ -38,7 +38,7 @@ Compile mod_wsgi
................
Compile mod_wsgi for each combination for Python and mod_wsgi version in the
test matrix. For example, to compile mod_wsgi 3.4 for Python 2.6 on a
test matrix. For example, to compile mod_wsgi 3.4 for Python 2.7 on a
RedHat-like Linux::
sudo yum install -y httpd httpd-devel

View File

@ -18,19 +18,12 @@ import binascii
import codecs
import functools
import glob
import json
import os
import sys
from decimal import DecimalException
if sys.version_info[:2] == (2, 6):
try:
import simplejson as json
except ImportError:
import json
else:
import json
sys.path[0:0] = [""]
from bson import BSON, json_util
@ -92,17 +85,11 @@ to_bson_uuid_04 = functools.partial(BSON.encode,
codec_options=codec_options_uuid_04)
to_bson = functools.partial(BSON.encode, codec_options=codec_options)
decode_bson = lambda bbytes: BSON(bbytes).decode(codec_options=codec_options)
if json_util._HAS_OBJECT_PAIRS_HOOK:
decode_extjson = functools.partial(
json_util.loads,
json_options=json_util.JSONOptions(json_mode=JSONMode.CANONICAL,
document_class=SON))
loads = functools.partial(json.loads, object_pairs_hook=SON)
else:
decode_extjson = functools.partial(
json_util.loads,
json_options=json_util.CANONICAL_JSON_OPTIONS)
loads = json.loads
decode_extjson = functools.partial(
json_util.loads,
json_options=json_util.JSONOptions(json_mode=JSONMode.CANONICAL,
document_class=SON))
loads = functools.partial(json.loads, object_pairs_hook=SON)
class TestBSONCorpus(unittest.TestCase):
@ -177,7 +164,7 @@ def create_test(case_spec):
# Test round-tripping canonical extended json.
decoded_json = decode_extjson(cEJ)
self.assertJsonEqual(encode_extjson(decoded_json), cEJ)
if not lossy and json_util._HAS_OBJECT_PAIRS_HOOK:
if not lossy:
self.assertEqual(encode_bson(decoded_json), cB)
# Test round-tripping degenerate bson.
@ -190,9 +177,6 @@ def create_test(case_spec):
decoded_json = decode_extjson(dEJ)
self.assertJsonEqual(encode_extjson(decoded_json), cEJ)
if not lossy:
# We don't need to check json_util._HAS_OBJECT_PAIRS_HOOK
# because degenerate_extjson is always a single key so
# the order cannot be changed.
self.assertEqual(encode_bson(decoded_json), cB)
# Test round-tripping relaxed extended json.

View File

@ -911,9 +911,6 @@ class TestClient(IntegrationTest):
@client_context.require_ipv6
def test_ipv6(self):
if client_context.ssl:
# http://bugs.python.org/issue13034
if sys.version_info[:2] == (2, 6):
raise SkipTest("Python 2.6 can't parse SANs")
if not HAVE_IPADDRESS:
raise SkipTest("Need the ipaddress module to test with SSL")

View File

@ -131,11 +131,9 @@ def run_operation(collection, test):
else:
for arg_name in list(arguments):
c2s = camel_to_snake(arg_name)
# PyMongo accepts sort as list of tuples. Asserting len=1
# because ordering dicts from JSON in 2.6 is unwieldy.
# PyMongo accepts sort as list of tuples.
if arg_name == "sort":
sort_dict = arguments[arg_name]
assert len(sort_dict) == 1, 'test can only have 1 sort key'
arguments[arg_name] = list(iteritems(sort_dict))
# Named "key" instead not fieldName.
if arg_name == "fieldName":

View File

@ -26,8 +26,7 @@ from pymongo.errors import ConfigurationError
from bson import json_util, EPOCH_AWARE, EPOCH_NAIVE, SON
from bson.json_util import (DatetimeRepresentation,
STRICT_JSON_OPTIONS,
_HAS_OBJECT_PAIRS_HOOK)
STRICT_JSON_OPTIONS)
from bson.binary import (ALL_UUID_REPRESENTATIONS, Binary, MD5_SUBTYPE,
USER_DEFINED_SUBTYPE, JAVA_LEGACY, CSHARP_LEGACY,
STANDARD)
@ -64,11 +63,10 @@ class TestJsonUtil(unittest.TestCase):
self.round_trip({"ref": DBRef("foo", 5, "db")})
self.round_trip({"ref": DBRef("foo", ObjectId())})
if _HAS_OBJECT_PAIRS_HOOK:
# Check order.
self.assertEqual(
'{"$ref": "collection", "$id": 1, "$db": "db"}',
json_util.dumps(DBRef('collection', 1, 'db')))
# Check order.
self.assertEqual(
'{"$ref": "collection", "$id": 1, "$db": "db"}',
json_util.dumps(DBRef('collection', 1, 'db')))
def test_datetime(self):
# only millis, not micros
@ -226,15 +224,14 @@ class TestJsonUtil(unittest.TestCase):
json_util.loads(
'{"r": {"$regex": ".*", "$options": "ilm"}}')['r'])
if _HAS_OBJECT_PAIRS_HOOK:
# Check order.
self.assertEqual(
'{"$regex": ".*", "$options": "mx"}',
json_util.dumps(Regex('.*', re.M | re.X)))
# Check order.
self.assertEqual(
'{"$regex": ".*", "$options": "mx"}',
json_util.dumps(Regex('.*', re.M | re.X)))
self.assertEqual(
'{"$regex": ".*", "$options": "mx"}',
json_util.dumps(re.compile(b'.*', re.M | re.X)))
self.assertEqual(
'{"$regex": ".*", "$options": "mx"}',
json_util.dumps(re.compile(b'.*', re.M | re.X)))
def test_minkey(self):
self.round_trip({"m": MinKey()})
@ -247,9 +244,7 @@ class TestJsonUtil(unittest.TestCase):
res = json_util.dumps(dct, default=json_util.default)
rtdct = json_util.loads(res)
self.assertEqual(dct, rtdct)
if _HAS_OBJECT_PAIRS_HOOK:
self.assertEqual('{"ts": {"$timestamp": {"t": 4, "i": 13}}}', res)
self.assertEqual('{"ts": {"$timestamp": {"t": 4, "i": 13}}}', res)
def test_uuid(self):
doc = {'uuid': uuid.UUID('f47ac10b-58cc-4372-a567-0e02b2c3d479')}
@ -257,33 +252,30 @@ class TestJsonUtil(unittest.TestCase):
self.assertEqual(
'{"uuid": {"$uuid": "f47ac10b58cc4372a5670e02b2c3d479"}}',
json_util.dumps(doc))
if _HAS_OBJECT_PAIRS_HOOK:
self.assertEqual(
self.assertEqual(
'{"uuid": '
'{"$binary": "9HrBC1jMQ3KlZw4CssPUeQ==", "$type": "03"}}',
json_util.dumps(
doc, json_options=json_util.STRICT_JSON_OPTIONS))
self.assertEqual(
'{"uuid": '
'{"$binary": "9HrBC1jMQ3KlZw4CssPUeQ==", "$type": "04"}}',
json_util.dumps(
doc, json_options=json_util.JSONOptions(
strict_uuid=True, uuid_representation=STANDARD)))
self.assertEqual(
doc, json_util.loads(
'{"uuid": '
'{"$binary": "9HrBC1jMQ3KlZw4CssPUeQ==", "$type": "03"}}',
json_util.dumps(
doc, json_options=json_util.STRICT_JSON_OPTIONS))
self.assertEqual(
'{"uuid": '
'{"$binary": "9HrBC1jMQ3KlZw4CssPUeQ==", "$type": "04"}}',
json_util.dumps(
doc, json_options=json_util.JSONOptions(
strict_uuid=True, uuid_representation=STANDARD)))
self.assertEqual(
doc, json_util.loads(
'{"uuid": '
'{"$binary": "9HrBC1jMQ3KlZw4CssPUeQ==", "$type": "03"}}'))
'{"$binary": "9HrBC1jMQ3KlZw4CssPUeQ==", "$type": "03"}}'))
for uuid_representation in ALL_UUID_REPRESENTATIONS:
options = json_util.JSONOptions(
strict_uuid=True, uuid_representation=uuid_representation)
self.round_trip(doc, json_options=options)
# Ignore UUID representation when decoding BSON binary subtype 4.
if _HAS_OBJECT_PAIRS_HOOK:
self.assertEqual(doc, json_util.loads(
'{"uuid": '
'{"$binary": "9HrBC1jMQ3KlZw4CssPUeQ==", "$type": "04"}}',
json_options=options))
self.assertEqual(doc, json_util.loads(
'{"uuid": '
'{"$binary": "9HrBC1jMQ3KlZw4CssPUeQ==", "$type": "04"}}',
json_options=options))
def test_binary(self):
if PY3:
@ -312,24 +304,22 @@ class TestJsonUtil(unittest.TestCase):
self.assertTrue('"$type": "00"' in json_bin_dump)
self.assertEqual(bin_type_dict,
json_util.loads('{"bin": {"$type": 0, "$binary": "AAECAwQ="}}'))
json_bin_dump = json_util.dumps(md5_type_dict)
# Check order.
self.assertEqual(
'{"md5": {"$binary": "IG43GK8JL9HRL4DK53HMrA==",'
+ ' "$type": "05"}}',
json_bin_dump)
if _HAS_OBJECT_PAIRS_HOOK:
json_bin_dump = json_util.dumps(md5_type_dict)
# Check order.
self.assertEqual(
'{"md5": {"$binary": "IG43GK8JL9HRL4DK53HMrA==",'
+ ' "$type": "05"}}',
json_bin_dump)
self.assertEqual(md5_type_dict,
json_util.loads('{"md5": {"$type": 5, "$binary":'
' "IG43GK8JL9HRL4DK53HMrA=="}}'))
self.assertEqual(md5_type_dict,
json_util.loads('{"md5": {"$type": 5, "$binary":'
' "IG43GK8JL9HRL4DK53HMrA=="}}'))
json_bin_dump = json_util.dumps(custom_type_dict)
self.assertTrue('"$type": "80"' in json_bin_dump)
self.assertEqual(custom_type_dict,
json_util.loads('{"custom": {"$type": 128, "$binary":'
' "aGVsbG8="}}'))
json_bin_dump = json_util.dumps(custom_type_dict)
self.assertTrue('"$type": "80"' in json_bin_dump)
self.assertEqual(custom_type_dict,
json_util.loads('{"custom": {"$type": 128, "$binary":'
' "aGVsbG8="}}'))
# Handle mongoexport where subtype >= 128
self.assertEqual(128,
@ -347,13 +337,12 @@ class TestJsonUtil(unittest.TestCase):
res = json_util.dumps(code)
self.assertEqual(code, json_util.loads(res))
if _HAS_OBJECT_PAIRS_HOOK:
# Check order.
self.assertEqual('{"$code": "return z", "$scope": {"z": 2}}', res)
# Check order.
self.assertEqual('{"$code": "return z", "$scope": {"z": 2}}', res)
no_scope = Code('function() {}')
self.assertEqual(
'{"$code": "function() {}"}', json_util.dumps(no_scope))
no_scope = Code('function() {}')
self.assertEqual(
'{"$code": "function() {}"}', json_util.dumps(no_scope))
def test_undefined(self):
jsn = '{"name": {"$undefined": true}}'
@ -375,13 +364,9 @@ class TestJsonUtil(unittest.TestCase):
self.assertEqual({"foo": "bar"}, json_util.loads(
'{"foo": "bar"}',
json_options=json_util.JSONOptions(document_class=dict)))
if not _HAS_OBJECT_PAIRS_HOOK:
self.assertRaises(
ConfigurationError, json_util.JSONOptions, document_class=SON)
else:
self.assertEqual(SON([("foo", "bar"), ("b", 1)]), json_util.loads(
'{"foo": "bar", "b": 1}',
json_options=json_util.JSONOptions(document_class=SON)))
self.assertEqual(SON([("foo", "bar"), ("b", 1)]), json_util.loads(
'{"foo": "bar", "b": 1}',
json_options=json_util.JSONOptions(document_class=SON)))
class TestJsonUtilRoundtrip(IntegrationTest):

View File

@ -196,9 +196,6 @@ class TestReplicaSetClient(TestReplicaSetClientBase):
@client_context.require_ipv6
def test_ipv6(self):
if client_context.ssl:
# http://bugs.python.org/issue13034
if sys.version_info[:2] == (2, 6):
raise SkipTest("Python 2.6 can't parse SANs")
if not HAVE_IPADDRESS:
raise SkipTest("Need the ipaddress module to test with SSL")

View File

@ -257,9 +257,7 @@ class TestSSL(IntegrationTest):
self.assertClientWorks(client)
# Python 2.6 often can't read SANs from the peer cert.
# http://bugs.python.org/issue13034
if HAVE_IPADDRESS and sys.version_info[:2] > (2, 6):
if HAVE_IPADDRESS:
client = MongoClient('127.0.0.1',
ssl=True,
ssl_certfile=CLIENT_PEM,

View File

@ -247,11 +247,9 @@ class TestTransactions(IntegrationTest):
for arg_name in list(arguments):
c2s = camel_to_snake(arg_name)
# PyMongo accepts sort as list of tuples. Asserting len=1
# because ordering dicts from JSON in 2.6 is unwieldy.
# PyMongo accepts sort as list of tuples.
if arg_name == "sort":
sort_dict = arguments[arg_name]
assert len(sort_dict) == 1, 'test can only have 1 sort key'
arguments[arg_name] = list(iteritems(sort_dict))
# Named "key" instead not fieldName.
if arg_name == "fieldName":

View File

@ -4,13 +4,9 @@
# and then run "tox" from this directory.
[tox]
envlist = py26, py27, py33, py34, py35, pypy, pypy3
envlist = py27, py34, py35, py36, pypy, pypy3
skip_missing_interpreters = True
[testenv]
commands =
{envpython} setup.py --no_ext test
[testenv:py26]
deps =
unittest2