Skip to content

Commit

Permalink
PYTHON-1022 - Drop support for Python 3.2
Browse files Browse the repository at this point in the history
This change removes the u() helper from bson.py3compat
and all of its uses in the driver and tests. PyPy3 continues
to be supported since, even though it is based on python 3.2.5,
it has always supported the u string prefix.

The README and install docs are now explicit about PyPy(3) support.
  • Loading branch information
behackett committed Jun 15, 2016
1 parent 7afca2f commit 53a7bea
Show file tree
Hide file tree
Showing 28 changed files with 143 additions and 217 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.2 and newer, and PyPy. Language
PyMongo supports CPython 2.6, 2.7, 3.3+, PyPy, and PyPy3. Language
features not supported by all interpreters can not be used.

Style Guide
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ with PyMongo.
Dependencies
============

PyMongo supports Python 2.6, 2.7, and 3.2+.
PyMongo supports CPython 2.6, 2.7, 3.3+, PyPy, and PyPy3.

Optional dependencies for GSSAPI and TLS:

Expand Down
8 changes: 0 additions & 8 deletions bson/py3compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ def b(s):
# See http://python3porting.com/problems.html#nicer-solutions
return codecs.latin_1_encode(s)[0]

def u(s):
# PY3 strings may already be treated as unicode literals
return s

def bytes_from_hex(h):
return bytes.fromhex(h)

Expand Down Expand Up @@ -71,10 +67,6 @@ def b(s):
# See comments above. In python 2.x b('foo') is just 'foo'.
return s

def u(s):
"""Replacement for unicode literal prefix."""
return unicode(s.replace('\\', '\\\\'), 'unicode_escape')

def bytes_from_hex(h):
return h.decode('hex')

Expand Down
2 changes: 1 addition & 1 deletion doc/faq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ thread, all sockets are closed.
Does PyMongo support Python 3?
------------------------------

PyMongo supports Python 3.x where x >= 2. See the :doc:`python3` for details.
PyMongo supports CPython 3.3+ and PyPy3. See the :doc:`python3` for details.

Does PyMongo support asynchronous frameworks like Gevent, asyncio, Tornado, or Twisted?
---------------------------------------------------------------------------------------
Expand Down
8 changes: 4 additions & 4 deletions doc/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ To upgrade do::
Dependencies
------------

PyMongo supports Python 2.6, 2.7, and 3.2+.
PyMongo supports CPython 2.6, 2.7, 3.3+, PyPy, and PyPy3.

Optional dependencies for GSSAPI and TLS:

Expand Down Expand Up @@ -132,7 +132,7 @@ See `http://bugs.python.org/issue11623 <http://bugs.python.org/issue11623>`_
for a more detailed explanation.

**Lion (10.7) and newer** - PyMongo's C extensions can be built against
versions of Python 2.7 >= 2.7.4 or Python 3.x >= 3.2.4 downloaded from
versions of Python 2.7 >= 2.7.4 or Python 3.3+ downloaded from
python.org. In all cases Xcode must be installed with 'UNIX Development
Support'.

Expand Down Expand Up @@ -167,7 +167,7 @@ requirements apply to both CPython and ActiveState's ActivePython:
~~~~~~~~~~~~~~

For Python 3.5 and newer install Visual Studio 2015. For Python 3.3 and 3.4
install Visual Studio 2010. For Python 3.2 and older install Visual Studio
install Visual Studio 2010. For Python 2.6 and 2.7 install Visual Studio
2008, or the Microsoft Visual C++ Compiler for Python 2.7. You must use the
full version of Visual Studio 2010 or 2008 as Visual C++ Express does not
provide 64-bit compilers. Make sure that you check the "x64 Compilers and
Expand All @@ -180,7 +180,7 @@ For Python 3.5 and newer install Visual Studio 2015.

For Python 3.3 and 3.4 install Visual C++ 2010 Express.

For Python 2.6 through 3.2 install Visual C++ 2008 Express SP1.
For Python 2.6 and 2.7 install Visual C++ 2008 Express SP1.

.. _install-no-c:

Expand Down
61 changes: 9 additions & 52 deletions doc/python3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Python 3 FAQ
What Python 3 versions are supported?
-------------------------------------

PyMongo supports Python 3.x where x >= 2.
PyMongo supports CPython 3.3+ and PyPy3.

Are there any PyMongo behavior changes with Python 3?
-----------------------------------------------------
Expand All @@ -20,8 +20,8 @@ with subtype 0.
For example, let's insert a :class:`bytes` instance using Python 3 then
read it back. Notice the byte string is decoded back to :class:`bytes`::

Python 3.2.5 (default, Feb 26 2014, 12:40:25)
[GCC 4.7.3] on linux2
Python 3.3.5 (default, Apr 29 2016, 11:04:32)
[GCC 4.9.3] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pymongo
>>> c = pymongo.MongoClient()
Expand All @@ -46,10 +46,7 @@ Why can't I share pickled ObjectIds between some versions of Python 2 and 3?
----------------------------------------------------------------------------

Instances of :class:`~bson.objectid.ObjectId` pickled using Python 2
can always be unpickled using Python 3. Due to
`http://bugs.python.org/issue13505 <http://bugs.python.org/issue13505>`_
you must use Python 3.2.3 or newer to pickle instances of ObjectId if you
need to unpickle them in Python 2.
can always be unpickled using Python 3.

If you pickled an ObjectId using Python 2 and want to unpickle it using
Python 3 you must pass ``encoding='latin-1'`` to pickle.loads::
Expand All @@ -65,19 +62,19 @@ Python 3 you must pass ``encoding='latin-1'`` to pickle.loads::
>>> pickle.dumps(oid)
'ccopy_reg\n_reconstructor\np0\n(cbson.objectid\...'

Python 3.2.5 (default, Feb 26 2014, 12:40:25)
[GCC 4.7.3] on linux2
Python 3.3.5 (default, Apr 29 2016, 11:04:32)
[GCC 4.9.3] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> pickle.loads(b'ccopy_reg\n_reconstructor\np0\n(cbson.objectid\...', encoding='latin-1')
ObjectId('4f919ba2fba5225b84000000')


If you need to pickle ObjectIds using Python 3 and unpickle them using Python 2
you must use Python 3.2.3 or newer and ``protocol <= 2``::
you must use ``protocol <= 2``::

Python 3.2.3 (v3.2.3:3d0686d90f55, Apr 10 2012, 11:25:50)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Python 3.3.5 (default, Apr 29 2016, 11:04:32)
[GCC 4.9.3] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> from bson.objectid import ObjectId
Expand All @@ -94,43 +91,3 @@ you must use Python 3.2.3 or newer and ``protocol <= 2``::
>>> pickle.loads('\x80\x02cbson.objectid\nObjectId\nq\x00)\x81q\x01c_codecs\nencode\...')
ObjectId('4f96f20c430ee6bd06000000')


Unfortunately this won't work if you pickled the ObjectId using a Python 3
version older than 3.2.3::

Python 3.2.2 (default, Mar 21 2012, 14:32:23)
[GCC 4.5.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> from bson.objectid import ObjectId
>>> oid = ObjectId()
>>> pickle.dumps(oid, protocol=2)
b'\x80\x02cbson.objectid\nObjectId\nq\x00)\x81q\x01c__builtin__\nbytes\...'

Python 2.4.6 (#1, Apr 12 2012, 14:48:24)
[GCC 4.5.3] on linux3
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> pickle.loads('\x80\x02cbson.objectid\nObjectId\nq\x00)\x81q\x01c__builtin__\nbytes\...')
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "/usr/lib/python2.4/pickle.py", line 1394, in loads
return Unpickler(file).load()
File "/usr/lib/python2.4/pickle.py", line 872, in load
dispatch[key](self)
File "/usr/lib/python2.4/pickle.py", line 1104, in load_global
klass = self.find_class(module, name)
File "/usr/lib/python2.4/pickle.py", line 1140, in find_class
klass = getattr(mod, name)
AttributeError: 'module' object has no attribute 'bytes'

.. warning::

Unpickling in Python 2.6 or 2.7 an ObjectId pickled in a Python 3 version
older than 3.2.3 will seem to succeed but the resulting ObjectId instance
will contain garbage data.

>>> pickle.loads('\x80\x02cbson.objectid\nObjectId\nq\x00)\x81q\x01c__builtin__\nbytes\...)
ObjectId('5b37392c203135302c203234362c2034352c203235312c203136352c2033342c203532...')


11 changes: 5 additions & 6 deletions pymongo/bulk.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
"""

from bson.objectid import ObjectId
from bson.py3compat import u
from bson.raw_bson import RawBSONDocument
from bson.son import SON
from pymongo.common import (validate_is_mapping,
Expand Down Expand Up @@ -50,11 +49,11 @@
# These string literals are used when we create fake server return
# documents client side. We use unicode literals in python 2.x to
# match the actual return values from the server.
_UID = u("_id")
_UCODE = u("code")
_UERRMSG = u("errmsg")
_UINDEX = u("index")
_UOP = u("op")
_UID = u"_id"
_UCODE = u"code"
_UERRMSG = u"errmsg"
_UINDEX = u"index"
_UOP = u"op"


class _Run(object):
Expand Down
5 changes: 2 additions & 3 deletions pymongo/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@
from bson.objectid import ObjectId
from bson.py3compat import (_unicode,
integer_types,
string_type,
u)
string_type)
from bson.raw_bson import RawBSONDocument
from bson.codec_options import CodecOptions
from bson.son import SON
Expand Down Expand Up @@ -52,7 +51,7 @@
_ORDERED_TYPES = (SON,)

_NO_OBJ_ERROR = "No matching object found"
_UJOIN = u("%s.%s")
_UJOIN = u"%s.%s"


class ReturnDocument(object):
Expand Down
4 changes: 2 additions & 2 deletions pymongo/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

import bson
from bson.codec_options import CodecOptions
from bson.py3compat import itervalues, string_type, iteritems, u
from bson.py3compat import itervalues, string_type, iteritems
from bson.son import SON
from pymongo import ASCENDING
from pymongo.errors import (CursorNotFound,
Expand All @@ -38,7 +38,7 @@
from pymongo.read_concern import DEFAULT_READ_CONCERN


_UUNDER = u("_")
_UUNDER = u"_"

_UNICODE_REPLACE_CODEC_OPTIONS = CodecOptions(
unicode_decode_error_handler='replace')
Expand Down
4 changes: 2 additions & 2 deletions pymongo/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

import bson
from bson.codec_options import DEFAULT_CODEC_OPTIONS
from bson.py3compat import b, StringIO, u
from bson.py3compat import b, StringIO
from bson.son import SON
try:
from pymongo import _cmessage
Expand Down Expand Up @@ -61,7 +61,7 @@
_DELETE: b'\x04deletes\x00\x00\x00\x00\x00',
}

_UJOIN = u("%s.%s")
_UJOIN = u"%s.%s"


def _randint():
Expand Down
4 changes: 2 additions & 2 deletions pymongo/pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import threading

from bson import DEFAULT_CODEC_OPTIONS
from bson.py3compat import u, itervalues
from bson.py3compat import itervalues
from pymongo import auth, helpers, thread_util
from pymongo.common import MAX_MESSAGE_SIZE
from pymongo.errors import (AutoReconnect,
Expand All @@ -42,7 +42,7 @@
# while the main thread holds the import lock, getaddrinfo deadlocks trying
# to import the IDNA codec. Import it here, where presumably we're on the
# main thread, to avoid the deadlock. See PYTHON-607.
u('foo').encode('idna')
u'foo'.encode('idna')

try:
from ssl import match_hostname, CertificateError
Expand Down
6 changes: 2 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,8 @@ def build_extension(self, ext):
else:
warnings.warn(self.warning_message % ("The %s extension "
"module" % (name,),
"Please use Python >= 2.6 "
"to take advantage of the "
"extension."))
"PyMongo supports python "
">= 2.6."))

ext_modules = [Extension('bson._cbson',
include_dirs=['bson'],
Expand Down Expand Up @@ -311,7 +310,6 @@ def build_extension(self, ext):
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.2",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
Expand Down
10 changes: 5 additions & 5 deletions test/qcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from bson.binary import Binary
from bson.dbref import DBRef
from bson.objectid import ObjectId
from bson.py3compat import MAXSIZE, PY3, iteritems, u
from bson.py3compat import MAXSIZE, PY3, iteritems
from bson.son import SON

if PY3:
Expand Down Expand Up @@ -91,9 +91,9 @@ def gen_unichar():


def gen_unicode(gen_length):
return lambda: u("").join([x for x in
gen_list(gen_unichar(), gen_length)() if
x not in ".$"])
return lambda: u"".join([x for x in
gen_list(gen_unichar(), gen_length)() if
x not in ".$"])


def gen_list(generator, gen_length):
Expand Down Expand Up @@ -124,7 +124,7 @@ def gen_regexp(gen_length):
# TODO our patterns only consist of one letter.
# this is because of a bug in CPython's regex equality testing,
# which I haven't quite tracked down, so I'm just ignoring it...
pattern = lambda: u("").join(gen_list(choose_lifted(u("a")), gen_length)())
pattern = lambda: u"".join(gen_list(choose_lifted(u"a"), gen_length)())

def gen_flags():
flags = 0
Expand Down
3 changes: 1 addition & 2 deletions test/test_binary.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@

from bson.binary import *
from bson.codec_options import CodecOptions
from bson.py3compat import u
from bson.son import SON
from test import client_context, unittest
from pymongo.mongo_client import MongoClient
Expand Down Expand Up @@ -81,7 +80,7 @@ def test_binary(self):

def test_exceptions(self):
self.assertRaises(TypeError, Binary, None)
self.assertRaises(TypeError, Binary, u("hello"))
self.assertRaises(TypeError, Binary, u"hello")
self.assertRaises(TypeError, Binary, 5)
self.assertRaises(TypeError, Binary, 10.2)
self.assertRaises(TypeError, Binary, b"hello", None)
Expand Down
Loading

0 comments on commit 53a7bea

Please sign in to comment.