Hello community,

here is the log from the commit of package python3-pymongo for openSUSE:Factory 
checked in at 2015-04-25 09:54:20
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python3-pymongo (Old)
 and      /work/SRC/openSUSE:Factory/.python3-pymongo.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python3-pymongo"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python3-pymongo/python3-pymongo.changes  
2015-04-10 09:52:20.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.python3-pymongo.new/python3-pymongo.changes     
2015-04-25 11:26:29.000000000 +0200
@@ -1,0 +2,8 @@
+Fri Apr 24 16:35:07 UTC 2015 - [email protected]
+
+- update to version 3.0.1:
+  * OperationFailure iterating cursor with multiple mongoses
+  * GridFS.delete does not remove all chunks in PyMongo 3
+  * AssertionError: Result batch started from 101, expected 0
+
+-------------------------------------------------------------------

Old:
----
  pymongo-3.0.tar.gz

New:
----
  pymongo-3.0.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python3-pymongo.spec ++++++
--- /var/tmp/diff_new_pack.7OaZvQ/_old  2015-04-25 11:26:30.000000000 +0200
+++ /var/tmp/diff_new_pack.7OaZvQ/_new  2015-04-25 11:26:30.000000000 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           python3-pymongo
-Version:        3.0
+Version:        3.0.1
 Release:        0
 Url:            http://github.com/mongodb/mongo-python-driver
 Summary:        Python driver for MongoDB

++++++ pymongo-3.0.tar.gz -> pymongo-3.0.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/MANIFEST.in new/pymongo-3.0.1/MANIFEST.in
--- old/pymongo-3.0/MANIFEST.in 2015-04-02 00:41:30.000000000 +0200
+++ new/pymongo-3.0.1/MANIFEST.in       2015-04-21 17:58:36.000000000 +0200
@@ -3,6 +3,9 @@
 include ez_setup.py
 recursive-include doc *.rst
 recursive-include doc *.py
+recursive-include doc *.conf
+recursive-include doc *.css
+recursive-include doc *.js
 recursive-include tools *.py
 include tools/README.rst
 recursive-include test *.pem
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/PKG-INFO new/pymongo-3.0.1/PKG-INFO
--- old/pymongo-3.0/PKG-INFO    2015-04-08 00:10:46.000000000 +0200
+++ new/pymongo-3.0.1/PKG-INFO  2015-04-21 22:37:57.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: pymongo
-Version: 3.0
+Version: 3.0.1
 Summary: Python driver for MongoDB <http://www.mongodb.org>
 Home-page: http://github.com/mongodb/mongo-python-driver
 Author: Bernie Hackett
@@ -102,6 +102,18 @@
         - `Monotime <https://pypi.python.org/pypi/Monotime>`_ adds support for
           a monotonic clock, which improves reliability in environments
           where clock adjustments are frequent. Not needed in Python 3.3+.
+        - `wincertstore <https://pypi.python.org/pypi/wincertstore>`_ adds 
support
+          for verifying server SSL certificates using Windows provided CA
+          certificates on older versions of python. Not needed or used with 
versions
+          of Python 2 beginning with 2.7.9, or versions of Python 3 beginning 
with
+          3.4.0.
+        - `certifi <https://pypi.python.org/pypi/certifi>`_ adds support for
+          using the Mozilla CA bundle with SSL to verify server certificates. 
Not
+          needed or used with versions of Python 2 beginning with 2.7.9 on any 
OS,
+          versions of Python 3 beginning with Python 3.4.0 on Windows, or 
versions
+          of Python 3 beginning with Python 3.2.0 on operating systems other 
than
+          Windows.
+        
         
         Additional dependencies are:
         
@@ -165,7 +177,7 @@
         
             $ python green_framework_test.py gevent
         
-        Or with Eventlet's:
+        Or with Eventlet's::
         
             $ python green_framework_test.py eventlet
         
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/README.rst new/pymongo-3.0.1/README.rst
--- old/pymongo-3.0/README.rst  2015-04-02 00:41:30.000000000 +0200
+++ new/pymongo-3.0.1/README.rst        2015-04-21 01:03:45.000000000 +0200
@@ -94,6 +94,18 @@
 - `Monotime <https://pypi.python.org/pypi/Monotime>`_ adds support for
   a monotonic clock, which improves reliability in environments
   where clock adjustments are frequent. Not needed in Python 3.3+.
+- `wincertstore <https://pypi.python.org/pypi/wincertstore>`_ adds support
+  for verifying server SSL certificates using Windows provided CA
+  certificates on older versions of python. Not needed or used with versions
+  of Python 2 beginning with 2.7.9, or versions of Python 3 beginning with
+  3.4.0.
+- `certifi <https://pypi.python.org/pypi/certifi>`_ adds support for
+  using the Mozilla CA bundle with SSL to verify server certificates. Not
+  needed or used with versions of Python 2 beginning with 2.7.9 on any OS,
+  versions of Python 3 beginning with Python 3.4.0 on Windows, or versions
+  of Python 3 beginning with Python 3.2.0 on operating systems other than
+  Windows.
+
 
 Additional dependencies are:
 
@@ -157,7 +169,7 @@
 
     $ python green_framework_test.py gevent
 
-Or with Eventlet's:
+Or with Eventlet's::
 
     $ python green_framework_test.py eventlet
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/doc/changelog.rst 
new/pymongo-3.0.1/doc/changelog.rst
--- old/pymongo-3.0/doc/changelog.rst   2015-04-07 23:16:42.000000000 +0200
+++ new/pymongo-3.0.1/doc/changelog.rst 2015-04-21 01:22:42.000000000 +0200
@@ -1,6 +1,21 @@
 Changelog
 =========
 
+Changes in Version 3.0.1
+------------------------
+
+Version 3.0.1 fixes issues reported since the release of 3.0, most
+importantly a bug in GridFS.delete that could prevent file chunks from
+actually being deleted.
+
+Issues Resolved
+...............
+
+See the `PyMongo 3.0.1 release notes in JIRA`_ for the list of resolved issues
+in this release.
+
+.. _PyMongo 3.0.1 release notes in JIRA: 
https://jira.mongodb.org/browse/PYTHON/fixforversion/15322
+
 Changes in Version 3.0
 ----------------------
 
@@ -485,6 +500,38 @@
 
 .. _PyMongo 2.8 release notes in JIRA: 
https://jira.mongodb.org/browse/PYTHON/fixforversion/14223
 
+Changes in Version 2.7.2
+------------------------
+
+Version 2.7.2 includes fixes for upsert reporting in the bulk API for MongoDB
+versions previous to 2.6, a regression in how son manipulators are applied in
+:meth:`~pymongo.collection.Collection.insert`, a few obscure connection pool
+semaphore leaks, and a few other minor issues. See the list of issues resolved
+for full details.
+
+Issues Resolved
+...............
+
+See the `PyMongo 2.7.2 release notes in JIRA`_ for the list of resolved issues
+in this release.
+
+.. _PyMongo 2.7.2 release notes in JIRA: 
https://jira.mongodb.org/browse/PYTHON/fixforversion/14005
+
+Changes in Version 2.7.1
+------------------------
+
+Version 2.7.1 fixes a number of issues reported since the release of 2.7,
+most importantly a fix for creating indexes and manipulating users through
+mongos versions older than 2.4.0.
+
+Issues Resolved
+...............
+
+See the `PyMongo 2.7.1 release notes in JIRA`_ for the list of resolved issues
+in this release.
+
+.. _PyMongo 2.7.1 release notes in JIRA: 
https://jira.mongodb.org/browse/PYTHON/fixforversion/13823
+
 Changes in Version 2.7
 ----------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/doc/examples/aggregation.rst 
new/pymongo-3.0.1/doc/examples/aggregation.rst
--- old/pymongo-3.0/doc/examples/aggregation.rst        2015-04-02 
00:41:30.000000000 +0200
+++ new/pymongo-3.0.1/doc/examples/aggregation.rst      2015-04-20 
22:03:23.000000000 +0200
@@ -178,13 +178,13 @@
 
 .. doctest::
 
+  >>> from bson.code import Code
   >>> reducer = Code("""
   ...                function(obj, prev){
   ...                  prev.count++;
   ...                }
   ...                """)
   ...
-  >>> from bson.son import SON
   >>> results = db.things.group(key={"x":1}, condition={}, initial={"count": 
0}, reduce=reducer)
   >>> for doc in results:
   ...   print doc
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/doc/pydoctheme/static/pydoctheme.css 
new/pymongo-3.0.1/doc/pydoctheme/static/pydoctheme.css
--- old/pymongo-3.0/doc/pydoctheme/static/pydoctheme.css        1970-01-01 
01:00:00.000000000 +0100
+++ new/pymongo-3.0.1/doc/pydoctheme/static/pydoctheme.css      2015-04-14 
20:25:10.000000000 +0200
@@ -0,0 +1,178 @@
+@import url("default.css");
+
+body {
+    background-color: white;
+    margin-left: 1em;
+    margin-right: 1em;
+}
+
+div.related {
+    margin-bottom: 1.2em;
+    padding: 0.5em 0;
+    border-top: 1px solid #ccc;
+    margin-top: 0.5em;
+}
+
+div.related a:hover {
+    color: #0095C4;
+}
+
+div.related:first-child {
+    border-top: 0;
+    border-bottom: 1px solid #ccc;
+}
+
+div.sphinxsidebar {
+    background-color: #eeeeee;
+    border-radius: 5px;
+    line-height: 130%;
+    font-size: smaller;
+}
+
+div.sphinxsidebar h3, div.sphinxsidebar h4 {
+    margin-top: 1.5em;
+}
+
+div.sphinxsidebarwrapper > h3:first-child {
+    margin-top: 0.2em;
+}
+
+div.sphinxsidebarwrapper > ul > li > ul > li {
+    margin-bottom: 0.4em;
+}
+
+div.sphinxsidebar a:hover {
+    color: #0095C4;
+}
+
+div.sphinxsidebar input {
+    font-family: 'Lucida Grande',Arial,sans-serif;
+    border: 1px solid #999999;
+    font-size: smaller;
+    border-radius: 3px;
+}
+
+div.sphinxsidebar input[type=text] {
+    max-width: 150px;
+}
+
+div.body {
+    padding: 0 0 0 1.2em;
+}
+
+div.body p {
+    line-height: 140%;
+}
+
+div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 {
+    margin: 0;
+    border: 0;
+    padding: 0.3em 0;
+}
+
+div.body hr {
+    border: 0;
+    background-color: #ccc;
+    height: 1px;
+}
+
+div.body pre {
+    border-radius: 3px;
+    border: 1px solid #ac9;
+}
+
+div.body div.admonition, div.body div.impl-detail {
+    border-radius: 3px;
+}
+
+div.body div.impl-detail > p {
+    margin: 0;
+}
+
+div.body div.seealso {
+    border: 1px solid #dddd66;
+}
+
+div.body a {
+    color: #0072aa;
+}
+
+div.body a:visited {
+    color: #6363bb;
+}
+
+div.body a:hover {
+    color: #00B0E4;
+}
+
+tt, code, pre {
+    font-family: monospace, sans-serif;
+    font-size: 96.5%;
+}
+
+div.body tt, div.body code {
+    border-radius: 3px;
+}
+
+div.body tt.descname, div.body code.descname {
+    font-size: 120%;
+}
+
+div.body tt.xref, div.body a tt, div.body code.xref, div.body a code {
+    font-weight: normal;
+}
+
+.deprecated {
+    border-radius: 3px;
+}
+
+table.docutils {
+    border: 1px solid #ddd;
+    min-width: 20%;
+    border-radius: 3px;
+    margin-top: 10px;
+    margin-bottom: 10px;
+}
+
+table.docutils td, table.docutils th {
+    border: 1px solid #ddd !important;
+    border-radius: 3px;
+}
+
+table p, table li {
+    text-align: left !important;
+}
+
+table.docutils th {
+    background-color: #eee;
+    padding: 0.3em 0.5em;
+}
+
+table.docutils td {
+    background-color: white;
+    padding: 0.3em 0.5em;
+}
+
+table.footnote, table.footnote td {
+    border: 0 !important;
+}
+
+div.footer {
+    line-height: 150%;
+    margin-top: -2em;
+    text-align: right;
+    width: auto;
+    margin-right: 10px;
+}
+
+div.footer a:hover {
+    color: #0095C4;
+}
+
+.refcount {
+    color: #060;
+}
+
+.stableabi {
+    color: #229;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/doc/pydoctheme/theme.conf 
new/pymongo-3.0.1/doc/pydoctheme/theme.conf
--- old/pymongo-3.0/doc/pydoctheme/theme.conf   1970-01-01 01:00:00.000000000 
+0100
+++ new/pymongo-3.0.1/doc/pydoctheme/theme.conf 2015-04-14 20:25:10.000000000 
+0200
@@ -0,0 +1,23 @@
+[theme]
+inherit = default
+stylesheet = pydoctheme.css
+pygments_style = sphinx
+
+[options]
+bodyfont = 'Lucida Grande', Arial, sans-serif
+headfont = 'Lucida Grande', Arial, sans-serif
+footerbgcolor = white
+footertextcolor = #555555
+relbarbgcolor = white
+relbartextcolor = #666666
+relbarlinkcolor = #444444
+sidebarbgcolor = white
+sidebartextcolor = #444444
+sidebarlinkcolor = #444444
+bgcolor = white
+textcolor = #222222
+linkcolor = #0090c0
+visitedlinkcolor = #00608f
+headtextcolor = #1a1a1a
+headbgcolor = white
+headlinkcolor = #aaaaaa
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/doc/static/sidebar.js 
new/pymongo-3.0.1/doc/static/sidebar.js
--- old/pymongo-3.0/doc/static/sidebar.js       1970-01-01 01:00:00.000000000 
+0100
+++ new/pymongo-3.0.1/doc/static/sidebar.js     2015-04-14 20:25:10.000000000 
+0200
@@ -0,0 +1,193 @@
+/*
+ * sidebar.js
+ * ~~~~~~~~~~
+ *
+ * This script makes the Sphinx sidebar collapsible and implements intelligent
+ * scrolling.
+ *
+ * .sphinxsidebar contains .sphinxsidebarwrapper.  This script adds in
+ * .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton used to
+ * collapse and expand the sidebar.
+ *
+ * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden and the
+ * width of the sidebar and the margin-left of the document are decreased.
+ * When the sidebar is expanded the opposite happens.  This script saves a
+ * per-browser/per-session cookie used to remember the position of the sidebar
+ * among the pages.  Once the browser is closed the cookie is deleted and the
+ * position reset to the default (expanded).
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+$(function() {
+  // global elements used by the functions.
+  // the 'sidebarbutton' element is defined as global after its
+  // creation, in the add_sidebar_button function
+  var jwindow = $(window);
+  var jdocument = $(document);
+  var bodywrapper = $('.bodywrapper');
+  var sidebar = $('.sphinxsidebar');
+  var sidebarwrapper = $('.sphinxsidebarwrapper');
+
+  // original margin-left of the bodywrapper and width of the sidebar
+  // with the sidebar expanded
+  var bw_margin_expanded = bodywrapper.css('margin-left');
+  var ssb_width_expanded = sidebar.width();
+
+  // margin-left of the bodywrapper and width of the sidebar
+  // with the sidebar collapsed
+  var bw_margin_collapsed = '.8em';
+  var ssb_width_collapsed = '.8em';
+
+  // colors used by the current theme
+  var dark_color = '#AAAAAA';
+  var light_color = '#CCCCCC';
+
+  function get_viewport_height() {
+    if (window.innerHeight)
+      return window.innerHeight;
+    else
+      return jwindow.height();
+  }
+
+  function sidebar_is_collapsed() {
+    return sidebarwrapper.is(':not(:visible)');
+  }
+
+  function toggle_sidebar() {
+    if (sidebar_is_collapsed())
+      expand_sidebar();
+    else
+      collapse_sidebar();
+    // adjust the scrolling of the sidebar
+    scroll_sidebar();
+  }
+
+  function collapse_sidebar() {
+    sidebarwrapper.hide();
+    sidebar.css('width', ssb_width_collapsed);
+    bodywrapper.css('margin-left', bw_margin_collapsed);
+    sidebarbutton.css({
+        'margin-left': '0',
+        'height': bodywrapper.height(),
+        'border-radius': '5px'
+    });
+    sidebarbutton.find('span').text('»');
+    sidebarbutton.attr('title', _('Expand sidebar'));
+    document.cookie = 'sidebar=collapsed';
+  }
+
+  function expand_sidebar() {
+    bodywrapper.css('margin-left', bw_margin_expanded);
+    sidebar.css('width', ssb_width_expanded);
+    sidebarwrapper.show();
+    sidebarbutton.css({
+        'margin-left': ssb_width_expanded-12,
+        'height': bodywrapper.height(),
+        'border-radius': '0 5px 5px 0'
+    });
+    sidebarbutton.find('span').text('«');
+    sidebarbutton.attr('title', _('Collapse sidebar'));
+    //sidebarwrapper.css({'padding-top':
+    //  Math.max(window.pageYOffset - sidebarwrapper.offset().top, 10)});
+    document.cookie = 'sidebar=expanded';
+  }
+
+  function add_sidebar_button() {
+    sidebarwrapper.css({
+        'float': 'left',
+        'margin-right': '0',
+        'width': ssb_width_expanded - 28
+    });
+    // create the button
+    sidebar.append(
+      '<div id="sidebarbutton"><span>&laquo;</span></div>'
+    );
+    var sidebarbutton = $('#sidebarbutton');
+    // find the height of the viewport to center the '<<' in the page
+    var viewport_height = get_viewport_height();
+    var sidebar_offset = sidebar.offset().top;
+    var sidebar_height = Math.max(bodywrapper.height(), sidebar.height());
+    sidebarbutton.find('span').css({
+        'display': 'block',
+        'position': 'fixed',
+        'top': Math.min(viewport_height/2, sidebar_height/2 + sidebar_offset) 
- 10
+    });
+
+    sidebarbutton.click(toggle_sidebar);
+    sidebarbutton.attr('title', _('Collapse sidebar'));
+    sidebarbutton.css({
+        'border-radius': '0 5px 5px 0',
+        'color': '#444444',
+        'background-color': '#CCCCCC',
+        'font-size': '1.2em',
+        'cursor': 'pointer',
+        'height': sidebar_height,
+        'padding-top': '1px',
+        'padding-left': '1px',
+        'margin-left': ssb_width_expanded - 12
+    });
+
+    sidebarbutton.hover(
+      function () {
+          $(this).css('background-color', dark_color);
+      },
+      function () {
+          $(this).css('background-color', light_color);
+      }
+    );
+  }
+
+  function set_position_from_cookie() {
+    if (!document.cookie)
+      return;
+    var items = document.cookie.split(';');
+    for(var k=0; k<items.length; k++) {
+      var key_val = items[k].split('=');
+      var key = key_val[0];
+      if (key == 'sidebar') {
+        var value = key_val[1];
+        if ((value == 'collapsed') && (!sidebar_is_collapsed()))
+          collapse_sidebar();
+        else if ((value == 'expanded') && (sidebar_is_collapsed()))
+          expand_sidebar();
+      }
+    }
+  }
+
+  add_sidebar_button();
+  var sidebarbutton = $('#sidebarbutton');
+  set_position_from_cookie();
+
+
+  /* intelligent scrolling */
+  function scroll_sidebar() {
+    var sidebar_height = sidebarwrapper.height();
+    var viewport_height = get_viewport_height();
+    var offset = sidebar.position()['top'];
+    var wintop = jwindow.scrollTop();
+    var winbot = wintop + viewport_height;
+    var curtop = sidebarwrapper.position()['top'];
+    var curbot = curtop + sidebar_height;
+    // does sidebar fit in window?
+    if (sidebar_height < viewport_height) {
+      // yes: easy case -- always keep at the top
+      sidebarwrapper.css('top', $u.min([$u.max([0, wintop - offset - 10]),
+                            jdocument.height() - sidebar_height - 200]));
+    }
+    else {
+      // no: only scroll if top/bottom edge of sidebar is at
+      // top/bottom edge of window
+      if (curtop > wintop && curbot > winbot) {
+        sidebarwrapper.css('top', $u.max([wintop - offset - 10, 0]));
+      }
+      else if (curtop < wintop && curbot < winbot) {
+        sidebarwrapper.css('top', $u.min([winbot - sidebar_height - offset - 
20,
+                              jdocument.height() - sidebar_height - 200]));
+      }
+    }
+  }
+  jwindow.scroll(scroll_sidebar);
+});
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/gridfs/__init__.py 
new/pymongo-3.0.1/gridfs/__init__.py
--- old/pymongo-3.0/gridfs/__init__.py  2015-04-02 00:41:30.000000000 +0200
+++ new/pymongo-3.0.1/gridfs/__init__.py        2015-04-20 22:03:23.000000000 
+0200
@@ -41,15 +41,9 @@
         Raises :class:`TypeError` if `database` is not an instance of
         :class:`~pymongo.database.Database`.
 
-        The `connect` parameter ensures that the underlying
-        :class:`~pymongo.mongo_client.MongoClient` is connected to a server,
-        and creates an index on the "chunks" collection if needed.
-
         :Parameters:
           - `database`: database to use
           - `collection` (optional): root collection to use
-          - `connect` (optional): whether to begin connecting the client in
-            the background
 
         .. versionchanged:: 3.0
            `database` must use an acknowledged
@@ -235,8 +229,8 @@
           - `file_id`: ``"_id"`` of the file to delete
         """
         self.__ensure_index_files_id()
-        self.__files.delete_many({"_id": file_id})
-        self.__chunks.delete_one({"files_id": file_id})
+        self.__files.delete_one({"_id": file_id})
+        self.__chunks.delete_many({"files_id": file_id})
 
     def list(self):
         """List the names of all files stored in this instance of
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/pymongo/__init__.py 
new/pymongo-3.0.1/pymongo/__init__.py
--- old/pymongo-3.0/pymongo/__init__.py 2015-04-07 23:24:48.000000000 +0200
+++ new/pymongo-3.0.1/pymongo/__init__.py       2015-04-21 22:28:15.000000000 
+0200
@@ -70,7 +70,7 @@
 ALL = 2
 """Profile all operations."""
 
-version_tuple = (3, 0)
+version_tuple = (3, 0, 1)
 
 def get_version_string():
     if isinstance(version_tuple[-1], str):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/pymongo/collection.py 
new/pymongo-3.0.1/pymongo/collection.py
--- old/pymongo-3.0/pymongo/collection.py       2015-04-06 23:54:56.000000000 
+0200
+++ new/pymongo-3.0.1/pymongo/collection.py     2015-04-14 20:47:22.000000000 
+0200
@@ -870,8 +870,11 @@
             error.
           - `oplog_replay` (optional): If True, set the oplogReplay query
             flag.
-          - `modifiers` (optional): A dict specifying the MongoDB query
-            modifiers that should be used for this query.
+          - `modifiers` (optional): A dict specifying the MongoDB `query
+            modifiers`_ that should be used for this query. For example::
+
+              >>> db.test.find(modifiers={"$maxTimeMS": 500})
+
           - `batch_size` (optional): Limits the number of documents returned in
             a single batch.
           - `manipulate` (optional): **DEPRECATED** - If True (the default),
@@ -918,6 +921,8 @@
            The `tag_sets` and `secondary_acceptable_latency_ms` parameters.
 
         .. _PYTHON-500: https://jira.mongodb.org/browse/PYTHON-500
+        .. _query modifiers:
+          http://docs.mongodb.org/manual/reference/operator/query-modifier/
 
         .. mongodoc:: find
         """
@@ -975,6 +980,15 @@
         return [CommandCursor(self, cursor['cursor'], sock_info.address)
                 for cursor in result['cursors']]
 
+    def _count(self, cmd):
+        """Internal count helper."""
+        with self._socket_for_reads() as (sock_info, slave_ok):
+            res = self._command(sock_info, cmd, slave_ok,
+                                allowable_errors=["ns missing"])
+        if res.get("errmsg", "") == "ns missing":
+            return 0
+        return int(res["n"])
+
     def count(self, filter=None, **kwargs):
         """Get the number of documents in this collection.
 
@@ -1006,12 +1020,7 @@
         if "hint" in kwargs and not isinstance(kwargs["hint"], string_type):
             kwargs["hint"] = helpers._index_document(kwargs["hint"])
         cmd.update(kwargs)
-        with self._socket_for_reads() as (sock_info, slave_ok):
-            res = self._command(sock_info, cmd, slave_ok,
-                                allowable_errors=["ns missing"])
-        if res.get("errmsg", "") == "ns missing":
-            return 0
-        return int(res["n"])
+        return self._count(cmd)
 
     def create_indexes(self, indexes):
         """Create one or more indexes on this collection.
@@ -1255,23 +1264,31 @@
 
         .. versionadded:: 3.0
         """
+        codec_options = CodecOptions(SON)
+        coll = self.with_options(codec_options)
         with self._socket_for_primary_reads() as (sock_info, slave_ok):
             if sock_info.max_wire_version > 2:
                 cmd = SON([("listIndexes", self.__name), ("cursor", {})])
                 cursor = self._command(sock_info, cmd, slave_ok,
                                        ReadPreference.PRIMARY,
-                                       CodecOptions(SON))["cursor"]
+                                       codec_options)["cursor"]
+                return CommandCursor(coll, cursor, sock_info.address)
             else:
                 namespace = _UJOIN % (self.__database.name, "system.indexes")
                 res = helpers._first_batch(
                     sock_info, namespace, {"ns": self.__full_name},
-                    0, slave_ok, CodecOptions(SON), ReadPreference.PRIMARY)
+                    0, slave_ok, codec_options, ReadPreference.PRIMARY)
+                data = res["data"]
                 cursor = {
                     "id": res["cursor_id"],
-                    "firstBatch": res["data"],
+                    "firstBatch": data,
                     "ns": namespace,
                 }
-            return CommandCursor(self, cursor, sock_info.address)
+                # Note that a collection can only have 64 indexes, so we don't
+                # technically have to pass len(data) here. There will never be
+                # an OP_GET_MORE call.
+                return CommandCursor(
+                    coll, cursor, sock_info.address, len(data))
 
     def index_information(self):
         """Get information on this collection's indexes.
@@ -1887,6 +1904,7 @@
             else:
                 self._update(sock_info, {"_id": to_save["_id"]}, to_save, True,
                              check_keys, False, manipulate, write_concern)
+                return to_save.get("_id")
 
     def insert(self, doc_or_docs, manipulate=True,
                check_keys=True, continue_on_error=False, **kwargs):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/pymongo/command_cursor.py 
new/pymongo-3.0.1/pymongo/command_cursor.py
--- old/pymongo-3.0/pymongo/command_cursor.py   2015-04-02 00:41:30.000000000 
+0200
+++ new/pymongo-3.0.1/pymongo/command_cursor.py 2015-04-20 22:03:23.000000000 
+0200
@@ -35,7 +35,7 @@
         self.__data = deque(cursor_info['firstBatch'])
         self.__retrieved = retrieved
         self.__batch_size = 0
-        self.__killed = False
+        self.__killed = (self.__id == 0)
 
         if "ns" in cursor_info:
             self.__ns = cursor_info["ns"]
@@ -114,6 +114,8 @@
             client._reset_server_and_request_check(self.address)
             raise
         self.__id = doc["cursor_id"]
+        if self.__id == 0:
+            self.__killed = True
 
         assert doc["starting_from"] == self.__retrieved, (
             "Result batch started from %s, expected %s" % (
@@ -143,7 +145,14 @@
 
     @property
     def alive(self):
-        """Does this cursor have the potential to return more data?"""
+        """Does this cursor have the potential to return more data?
+
+        Even if :attr:`alive` is ``True``, :meth:`.next` can raise
+        :exc:`StopIteration`. Best to use a for loop::
+
+            for doc in collection.aggregate(pipeline):
+                print(doc)
+        """
         return bool(len(self.__data) or (not self.__killed))
 
     @property
@@ -167,7 +176,7 @@
         """
         if len(self.__data) or self._refresh():
             coll = self.__collection
-            return coll.database._fix_incoming(self.__data.popleft(), coll)
+            return coll.database._fix_outgoing(self.__data.popleft(), coll)
         else:
             raise StopIteration
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/pymongo/cursor.py 
new/pymongo-3.0.1/pymongo/cursor.py
--- old/pymongo-3.0/pymongo/cursor.py   2015-04-02 00:41:30.000000000 +0200
+++ new/pymongo-3.0.1/pymongo/cursor.py 2015-04-20 22:03:23.000000000 +0200
@@ -655,22 +655,23 @@
            The :meth:`~count` method now supports :meth:`~hint`.
         """
         validate_boolean("with_limit_and_skip", with_limit_and_skip)
-        options = {"query": self.__spec}
+        cmd = SON([("count", self.__collection.name),
+                   ("query", self.__spec)])
         if self.__max_time_ms is not None:
-            options["maxTimeMS"] = self.__max_time_ms
+            cmd["maxTimeMS"] = self.__max_time_ms
         if self.__comment:
-            options["$comment"] = self.__comment
+            cmd["$comment"] = self.__comment
 
         if self.__hint is not None:
-            options["hint"] = self.__hint
+            cmd["hint"] = self.__hint
 
         if with_limit_and_skip:
             if self.__limit:
-                options["limit"] = self.__limit
+                cmd["limit"] = self.__limit
             if self.__skip:
-                options["skip"] = self.__skip
+                cmd["skip"] = self.__skip
 
-        return self.__collection.count(**options)
+        return self.__collection._count(cmd)
 
     def distinct(self, key):
         """Get a list of distinct values for `key` among all documents
@@ -860,6 +861,8 @@
             client._reset_server_and_request_check(self.__address)
             raise
         self.__id = doc["cursor_id"]
+        if self.__id == 0:
+            self.__killed = True
 
         # starting from doesn't get set on getmore's for tailable cursors
         if not self.__query_flags & _QUERY_OPTIONS["tailable_cursor"]:
@@ -934,6 +937,11 @@
         <http://www.mongodb.org/display/DOCS/Tailable+Cursors>`_
         since they will stop iterating even though they *may* return more
         results in the future.
+
+        With regular cursors, simply use a for loop instead of :attr:`alive`::
+
+            for doc in collection.find():
+                print(doc)
         """
         return bool(len(self.__data) or (not self.__killed))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/pymongo/database.py 
new/pymongo-3.0.1/pymongo/database.py
--- old/pymongo-3.0/pymongo/database.py 2015-04-02 00:41:30.000000000 +0200
+++ new/pymongo-3.0.1/pymongo/database.py       2015-04-14 20:43:22.000000000 
+0200
@@ -462,17 +462,20 @@
                 cmd["filter"] = criteria
             coll = self["$cmd"]
             cursor = self._command(sock_info, cmd, slave_okay)["cursor"]
+            return CommandCursor(coll, cursor, sock_info.address)
         else:
             coll = self["system.namespaces"]
             res = _first_batch(sock_info, coll.full_name,
                                criteria, 0, slave_okay,
                                CodecOptions(), ReadPreference.PRIMARY)
+            data = res["data"]
             cursor = {
                 "id": res["cursor_id"],
-                "firstBatch": res["data"],
+                "firstBatch": data,
                 "ns": coll.full_name,
             }
-        return CommandCursor(coll, cursor, sock_info.address)
+            # Need to tell the cursor how many docs were in the first batch.
+            return CommandCursor(coll, cursor, sock_info.address, len(data))
 
     def collection_names(self, include_system_collections=True):
         """Get a list of all the collection names in this database.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/pymongo/message.py 
new/pymongo-3.0.1/pymongo/message.py
--- old/pymongo-3.0/pymongo/message.py  2015-04-02 00:41:30.000000000 +0200
+++ new/pymongo-3.0.1/pymongo/message.py        2015-04-20 22:07:00.000000000 
+0200
@@ -69,7 +69,7 @@
     if mode and (
         mode != ReadPreference.SECONDARY_PREFERRED.mode or tag_sets != [{}]):
 
-        if "query" not in spec:
+        if "$query" not in spec:
             spec = SON([("$query", spec)])
         spec["$readPreference"] = read_preference.document
     return spec
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/pymongo/mongo_client.py 
new/pymongo-3.0.1/pymongo/mongo_client.py
--- old/pymongo-3.0/pymongo/mongo_client.py     2015-04-02 20:32:45.000000000 
+0200
+++ new/pymongo-3.0.1/pymongo/mongo_client.py   2015-04-21 21:56:43.000000000 
+0200
@@ -118,12 +118,20 @@
             that the pool will open simultaneously. If this is set, operations
             will block if there are `maxPoolSize` outstanding connections
             from the pool. Defaults to 100.
-          - `socketTimeoutMS`: (integer or None) How long (in milliseconds) a
-            send or receive on a socket can take before timing out. Defaults to
-            ``None`` (no timeout).
-          - `connectTimeoutMS`: (integer or None) How long (in milliseconds) a
-            connection can take to be opened before timing out. Defaults to
-            ``20000``.
+          - `socketTimeoutMS`: (integer or None) Controls how long (in
+            milliseconds) the driver will wait for a response after sending an
+            ordinary (non-monitoring) database operation before concluding that
+            a network error has occurred. Defaults to ``None`` (no timeout).
+          - `connectTimeoutMS`: (integer or None) Controls how long (in
+            milliseconds) the driver will wait during server monitoring when
+            connecting a new socket to a server before concluding the server
+            is unavailable. Defaults to ``20000`` (20 seconds).
+          - `serverSelectionTimeoutMS`: (integer) Controls how long (in
+            milliseconds) the driver will wait to find an available,
+            appropriate server to carry out a database operation; while it is
+            waiting, multiple server monitoring operations may be carried out,
+            each controlled by `connectTimeoutMS`. Defaults to ``30000`` (30
+            seconds).
           - `waitQueueTimeoutMS`: (integer or None) How long (in milliseconds)
             a thread will wait for a socket from the pool if the pool has no
             free sockets. Defaults to ``None`` (no timeout).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/pymongo/server_selectors.py 
new/pymongo-3.0.1/pymongo/server_selectors.py
--- old/pymongo-3.0/pymongo/server_selectors.py 2015-04-02 00:41:30.000000000 
+0200
+++ new/pymongo-3.0.1/pymongo/server_selectors.py       2015-04-20 
22:03:23.000000000 +0200
@@ -21,10 +21,6 @@
     return server_descriptions
 
 
-def address_server_selector(address, server_descriptions):
-    return [s for s in server_descriptions if s.address == address]
-
-
 def writable_server_selector(server_descriptions):
     return [s for s in server_descriptions if s.is_writable]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/pymongo/topology.py 
new/pymongo-3.0.1/pymongo/topology.py
--- old/pymongo-3.0/pymongo/topology.py 2015-04-02 00:41:30.000000000 +0200
+++ new/pymongo-3.0.1/pymongo/topology.py       2015-04-20 22:03:23.000000000 
+0200
@@ -16,7 +16,6 @@
 
 import random
 import threading
-from functools import partial
 
 from bson.py3compat import itervalues
 from pymongo import common
@@ -27,7 +26,7 @@
 from pymongo.errors import ServerSelectionTimeoutError, InvalidOperation
 from pymongo.monotonic import time as _time
 from pymongo.server import Server
-from pymongo.server_selectors import (address_server_selector,
+from pymongo.server_selectors import (any_server_selector,
                                       apply_local_threshold,
                                       arbiter_server_selector,
                                       secondary_server_selector,
@@ -59,7 +58,10 @@
         with self._lock:
             self._ensure_opened()
 
-    def select_servers(self, selector, server_selection_timeout=None):
+    def select_servers(self,
+                       selector,
+                       server_selection_timeout=None,
+                       address=None):
         """Return a list of Servers matching selector, or time out.
 
         :Parameters:
@@ -68,6 +70,7 @@
           - `server_selection_timeout` (optional): maximum seconds to wait.
             If not provided, the default value common.SERVER_SELECTION_TIMEOUT
             is used.
+          - `address`: optional server address to select.
 
         Calls self.open() if needed.
 
@@ -84,7 +87,7 @@
 
             now = _time()
             end_time = now + server_timeout
-            server_descriptions = self._apply_selector(selector)
+            server_descriptions = self._apply_selector(selector, address)
 
             while not server_descriptions:
                 # No suitable servers.
@@ -102,15 +105,19 @@
                 self._condition.wait(common.MIN_HEARTBEAT_INTERVAL)
                 self._description.check_compatible()
                 now = _time()
-                server_descriptions = self._apply_selector(selector)
+                server_descriptions = self._apply_selector(selector, address)
 
             return [self.get_server_by_address(sd.address)
                     for sd in server_descriptions]
 
-    def select_server(self, selector, server_selection_timeout=None):
+    def select_server(self,
+                      selector,
+                      server_selection_timeout=None,
+                      address=None):
         """Like select_servers, but choose a random server if several match."""
         return random.choice(self.select_servers(selector,
-                                                 server_selection_timeout))
+                                                 server_selection_timeout,
+                                                 address))
 
     def select_server_by_address(self, address,
                                  server_selection_timeout=None):
@@ -131,8 +138,9 @@
         Raises exc:`ServerSelectionTimeoutError` after
         `server_selection_timeout` if no matching servers are found.
         """
-        selector = partial(address_server_selector, address)
-        return self.select_server(selector, server_selection_timeout)
+        return self.select_server(any_server_selector,
+                                  server_selection_timeout,
+                                  address)
 
     def on_change(self, server_description):
         """Process a new ServerDescription after an ismaster call completes."""
@@ -295,10 +303,13 @@
         for server in self._servers.values():
             server.request_check()
 
-    def _apply_selector(self, selector):
+    def _apply_selector(self, selector, address):
         if self._description.topology_type == TOPOLOGY_TYPE.Single:
             # Ignore the selector.
             return self._description.known_servers
+        elif address:
+            sd = self._description.server_descriptions().get(address)
+            return [sd] if sd else []
         elif self._description.topology_type == TOPOLOGY_TYPE.Sharded:
             return apply_local_threshold(self._settings.local_threshold_ms,
                                          self._description.known_servers)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/pymongo.egg-info/PKG-INFO 
new/pymongo-3.0.1/pymongo.egg-info/PKG-INFO
--- old/pymongo-3.0/pymongo.egg-info/PKG-INFO   2015-04-08 00:10:46.000000000 
+0200
+++ new/pymongo-3.0.1/pymongo.egg-info/PKG-INFO 2015-04-21 22:37:57.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: pymongo
-Version: 3.0
+Version: 3.0.1
 Summary: Python driver for MongoDB <http://www.mongodb.org>
 Home-page: http://github.com/mongodb/mongo-python-driver
 Author: Bernie Hackett
@@ -102,6 +102,18 @@
         - `Monotime <https://pypi.python.org/pypi/Monotime>`_ adds support for
           a monotonic clock, which improves reliability in environments
           where clock adjustments are frequent. Not needed in Python 3.3+.
+        - `wincertstore <https://pypi.python.org/pypi/wincertstore>`_ adds 
support
+          for verifying server SSL certificates using Windows provided CA
+          certificates on older versions of python. Not needed or used with 
versions
+          of Python 2 beginning with 2.7.9, or versions of Python 3 beginning 
with
+          3.4.0.
+        - `certifi <https://pypi.python.org/pypi/certifi>`_ adds support for
+          using the Mozilla CA bundle with SSL to verify server certificates. 
Not
+          needed or used with versions of Python 2 beginning with 2.7.9 on any 
OS,
+          versions of Python 3 beginning with Python 3.4.0 on Windows, or 
versions
+          of Python 3 beginning with Python 3.2.0 on operating systems other 
than
+          Windows.
+        
         
         Additional dependencies are:
         
@@ -165,7 +177,7 @@
         
             $ python green_framework_test.py gevent
         
-        Or with Eventlet's:
+        Or with Eventlet's::
         
             $ python green_framework_test.py eventlet
         
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/pymongo.egg-info/SOURCES.txt 
new/pymongo-3.0.1/pymongo.egg-info/SOURCES.txt
--- old/pymongo-3.0/pymongo.egg-info/SOURCES.txt        2015-04-08 
00:10:46.000000000 +0200
+++ new/pymongo-3.0.1/pymongo.egg-info/SOURCES.txt      2015-04-21 
22:37:57.000000000 +0200
@@ -88,6 +88,9 @@
 doc/examples/index.rst
 doc/examples/mod_wsgi.rst
 doc/examples/tls.rst
+doc/pydoctheme/theme.conf
+doc/pydoctheme/static/pydoctheme.css
+doc/static/sidebar.js
 gridfs/__init__.py
 gridfs/errors.py
 gridfs/grid_file.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/setup.py new/pymongo-3.0.1/setup.py
--- old/pymongo-3.0/setup.py    2015-04-07 23:24:36.000000000 +0200
+++ new/pymongo-3.0.1/setup.py  2015-04-21 22:28:25.000000000 +0200
@@ -26,7 +26,7 @@
 from distutils.errors import DistutilsPlatformError, DistutilsExecError
 from distutils.core import Extension
 
-version = "3.0"
+version = "3.0.1"
 
 f = open("README.rst")
 try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/test/__init__.py 
new/pymongo-3.0.1/test/__init__.py
--- old/pymongo-3.0/test/__init__.py    2015-04-02 00:41:30.000000000 +0200
+++ new/pymongo-3.0.1/test/__init__.py  2015-04-21 00:04:45.000000000 +0200
@@ -297,6 +297,12 @@
                              "Must be connected to a mongod, not a mongos",
                              func=func)
 
+    def require_mongos(self, func):
+        """Run a test only if the client is connected to a mongos."""
+        return self._require(self.is_mongos,
+                             "Must be connected to a mongos",
+                             func=func)
+
     def check_auth_with_sharding(self, func):
         """Skip a test when connected to mongos < 2.0 and running with auth."""
         condition = not (self.auth_enabled and
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/test/test_collection.py 
new/pymongo-3.0.1/test/test_collection.py
--- old/pymongo-3.0/test/test_collection.py     2015-04-02 00:41:30.000000000 
+0200
+++ new/pymongo-3.0.1/test/test_collection.py   2015-04-21 00:10:33.000000000 
+0200
@@ -1110,6 +1110,22 @@
         for doc in cursor:
             pass
 
+    @client_context.require_version_min(2, 5, 1)
+    def test_aggregation_cursor_alive(self):
+        self.db.test.delete_many({})
+        self.db.test.insert_many([{} for _ in range(3)])
+        self.addCleanup(self.db.test.delete_many, {})
+        cursor = self.db.test.aggregate(pipeline=[], cursor={'batchSize': 2})
+        n = 0
+        while True:
+            cursor.next()
+            n += 1
+            if 3 == n:
+                self.assertFalse(cursor.alive)
+                break
+
+            self.assertTrue(cursor.alive)
+
     @client_context.require_version_min(2, 5, 5)
     @client_context.require_no_mongos
     def test_parallel_scan(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/test/test_cursor.py 
new/pymongo-3.0.1/test/test_cursor.py
--- old/pymongo-3.0/test/test_cursor.py 2015-04-02 00:41:30.000000000 +0200
+++ new/pymongo-3.0.1/test/test_cursor.py       2015-04-21 00:10:46.000000000 
+0200
@@ -634,11 +634,16 @@
         if client_context.version.at_least(2, 6, 0):
             # Count supports hint
             self.assertEqual(0, collection.find({'i': 1}).hint("x_1").count())
+            self.assertEqual(
+                0, collection.find({'i': 1}).hint([("x", 1)]).count())
         else:
             # Hint is ignored
             self.assertEqual(1, collection.find({'i': 1}).hint("x_1").count())
+            self.assertEqual(
+                1, collection.find({'i': 1}).hint([("x", 1)]).count())
 
         self.assertEqual(2, collection.find().hint("x_1").count())
+        self.assertEqual(2, collection.find().hint([("x", 1)]).count())
 
     def test_where(self):
         db = self.db
@@ -1106,5 +1111,34 @@
         docs.extend(ccursor)
         self.assertEqual(len(docs), 200)
 
+    def test_modifiers(self):
+        cur = self.db.test.find()
+        self.assertTrue('$query' not in cur._Cursor__query_spec())
+        cur = self.db.test.find().comment("testing").max_time_ms(500)
+        self.assertTrue('$query' in cur._Cursor__query_spec())
+        self.assertEqual(cur._Cursor__query_spec()["$comment"], "testing")
+        self.assertEqual(cur._Cursor__query_spec()["$maxTimeMS"], 500)
+        cur = self.db.test.find(
+            modifiers={"$maxTimeMS": 500, "$comment": "testing"})
+        self.assertTrue('$query' in cur._Cursor__query_spec())
+        self.assertEqual(cur._Cursor__query_spec()["$comment"], "testing")
+        self.assertEqual(cur._Cursor__query_spec()["$maxTimeMS"], 500)
+
+    def test_alive(self):
+        self.db.test.delete_many({})
+        self.db.test.insert_many([{} for _ in range(3)])
+        self.addCleanup(self.db.test.delete_many, {})
+        cursor = self.db.test.find().batch_size(2)
+        n = 0
+        while True:
+            cursor.next()
+            n += 1
+            if 3 == n:
+                self.assertFalse(cursor.alive)
+                break
+
+            self.assertTrue(cursor.alive)
+
+
 if __name__ == "__main__":
     unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/test/test_database.py 
new/pymongo-3.0.1/test/test_database.py
--- old/pymongo-3.0/test/test_database.py       2015-04-02 00:41:30.000000000 
+0200
+++ new/pymongo-3.0.1/test/test_database.py     2015-04-14 20:43:22.000000000 
+0200
@@ -163,6 +163,16 @@
         for coll in colls_without_systems:
             self.assertTrue(not coll.startswith("system."))
 
+        # Force more than one batch.
+        db = self.client.many_collections
+        for i in range(101):
+            db["coll" + str(i)].insert_one({})
+        # No Error
+        try:
+            db.collection_names()
+        finally:
+            self.client.drop_database("many_collections")
+
     def test_drop_collection(self):
         db = Database(self.client, "pymongo_test")
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/test/test_gridfs.py 
new/pymongo-3.0.1/test/test_gridfs.py
--- old/pymongo-3.0/test/test_gridfs.py 2015-04-02 00:41:30.000000000 +0200
+++ new/pymongo-3.0.1/test/test_gridfs.py       2015-04-20 22:03:23.000000000 
+0200
@@ -117,6 +117,18 @@
         self.assertEqual("foo", oid)
         self.assertEqual(b"hello world", self.fs.get("foo").read())
 
+    def test_multi_chunk_delete(self):
+        self.db.fs.drop()
+        self.assertEqual(0, self.db.fs.files.count())
+        self.assertEqual(0, self.db.fs.chunks.count())
+        gfs = gridfs.GridFS(self.db)
+        oid = gfs.put(b"hello", chunkSize=1)
+        self.assertEqual(1, self.db.fs.files.count())
+        self.assertEqual(5, self.db.fs.chunks.count())
+        gfs.delete(oid)
+        self.assertEqual(0, self.db.fs.files.count())
+        self.assertEqual(0, self.db.fs.chunks.count())
+
     def test_list(self):
         self.assertEqual([], self.fs.list())
         self.fs.put(b"hello world")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/test/test_legacy_api.py 
new/pymongo-3.0.1/test/test_legacy_api.py
--- old/pymongo-3.0/test/test_legacy_api.py     2015-04-02 00:43:39.000000000 
+0200
+++ new/pymongo-3.0.1/test/test_legacy_api.py   2015-04-14 20:33:36.000000000 
+0200
@@ -615,6 +615,16 @@
         self.db.test.save(doc)
         self.assertTrue("_id" in doc)
 
+    def test_save_returns_id(self):
+        doc = {"hello": "jesse"}
+        _id = self.db.test.save(doc)
+        self.assertTrue(isinstance(_id, ObjectId))
+        self.assertEqual(_id, doc["_id"])
+        doc["hi"] = "bernie"
+        _id = self.db.test.save(doc)
+        self.assertTrue(isinstance(_id, ObjectId))
+        self.assertEqual(_id, doc["_id"])
+
     def test_remove_one(self):
         # Tests legacy remove.
         self.db.test.remove()
@@ -967,6 +977,33 @@
         out = db.test.find_one()
         self.assertEqual('value', out.get('value'))
 
+    def test_son_manipulator_outgoing(self):
+        class Thing(object):
+            def __init__(self, value):
+                self.value = value
+
+        class ThingTransformer(SONManipulator):
+            def transform_outgoing(self, doc, collection):
+                # We don't want this applied to the command return
+                # value in pymongo.cursor.Cursor.
+                if 'value' in doc:
+                    return Thing(doc['value'])
+                return doc
+
+        db = self.client.foo
+        db.add_son_manipulator(ThingTransformer())
+
+        db.test.delete_many({})
+        db.test.insert_one({'value': 'value'})
+        out = db.test.find_one()
+        self.assertTrue(isinstance(out, Thing))
+        self.assertEqual('value', out.value)
+
+        if client_context.version.at_least(2, 6):
+            out = next(db.test.aggregate([], cursor={}))
+            self.assertTrue(isinstance(out, Thing))
+            self.assertEqual('value', out.value)
+
     def test_son_manipulator_inheritance(self):
         # Tests legacy API elements.
         class Thing(object):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymongo-3.0/test/test_read_preferences.py 
new/pymongo-3.0.1/test/test_read_preferences.py
--- old/pymongo-3.0/test/test_read_preferences.py       2015-04-02 
00:41:30.000000000 +0200
+++ new/pymongo-3.0.1/test/test_read_preferences.py     2015-04-21 
01:17:13.000000000 +0200
@@ -21,8 +21,9 @@
 sys.path[0:0] = [""]
 
 from bson.py3compat import MAXSIZE
-from pymongo.cursor import _QUERY_OPTIONS
+from bson.son import SON
 from pymongo.errors import ConfigurationError
+from pymongo.message import _maybe_add_read_preference
 from pymongo.mongo_client import MongoClient
 from pymongo.read_preferences import (ReadPreference, MovingAverage,
                                       Primary, PrimaryPreferred,
@@ -33,15 +34,14 @@
 from pymongo.write_concern import WriteConcern
 
 from test.test_replica_set_client import TestReplicaSetClientBase
-from test import (client_context,
+from test import (SkipTest,
+                  client_context,
                   host,
                   port,
                   unittest,
-                  utils,
-                  IntegrationTest,
                   db_user,
                   db_pwd)
-from test.utils import connected, single_client, one, wait_until, rs_client
+from test.utils import single_client, one, wait_until, rs_client
 from test.version import Version
 
 
@@ -400,6 +400,95 @@
         avg.add_sample(30)
         self.assertAlmostEqual(15.6, avg.get())
 
+class TestMongosAndReadPreference(unittest.TestCase):
+
+    def test_maybe_add_read_preference(self):
+
+        # Primary doesn't add $readPreference
+        out = _maybe_add_read_preference({}, Primary())
+        self.assertEqual(out, {})
+
+        pref = PrimaryPreferred()
+        out = _maybe_add_read_preference({}, pref)
+        self.assertEqual(
+            out, SON([("$query", {}), ("$readPreference", pref.document)]))
+        pref = PrimaryPreferred(tag_sets=[{'dc': 'nyc'}])
+        out = _maybe_add_read_preference({}, pref)
+        self.assertEqual(
+            out, SON([("$query", {}), ("$readPreference", pref.document)]))
+
+        pref = Secondary()
+        out = _maybe_add_read_preference({}, pref)
+        self.assertEqual(
+            out, SON([("$query", {}), ("$readPreference", pref.document)]))
+        pref = Secondary(tag_sets=[{'dc': 'nyc'}])
+        out = _maybe_add_read_preference({}, pref)
+        self.assertEqual(
+            out, SON([("$query", {}), ("$readPreference", pref.document)]))
+
+        # SecondaryPreferred without tag_sets doesn't add $readPreference
+        pref = SecondaryPreferred()
+        out = _maybe_add_read_preference({}, pref)
+        self.assertEqual(out, {})
+        pref = SecondaryPreferred(tag_sets=[{'dc': 'nyc'}])
+        out = _maybe_add_read_preference({}, pref)
+        self.assertEqual(
+            out, SON([("$query", {}), ("$readPreference", pref.document)]))
+
+        pref = Nearest()
+        out = _maybe_add_read_preference({}, pref)
+        self.assertEqual(
+            out, SON([("$query", {}), ("$readPreference", pref.document)]))
+        pref = Nearest(tag_sets=[{'dc': 'nyc'}])
+        out = _maybe_add_read_preference({}, pref)
+        self.assertEqual(
+            out, SON([("$query", {}), ("$readPreference", pref.document)]))
+
+        criteria = SON([("$query", {}), ("$orderby", SON([("_id", 1)]))])
+        pref = Nearest()
+        out = _maybe_add_read_preference(criteria, pref)
+        self.assertEqual(
+            out,
+            SON([("$query", {}),
+                 ("$orderby", SON([("_id", 1)])),
+                 ("$readPreference", pref.document)]))
+        pref = Nearest(tag_sets=[{'dc': 'nyc'}])
+        out = _maybe_add_read_preference(criteria, pref)
+        self.assertEqual(
+            out,
+            SON([("$query", {}),
+                 ("$orderby", SON([("_id", 1)])),
+                 ("$readPreference", pref.document)]))
+
+    @client_context.require_mongos
+    def test_mongos(self):
+        shard = client_context.client.config.shards.find_one()['host']
+        num_members = shard.count(',') + 1
+        if num_members == 1:
+            raise SkipTest("Need a replica set shard to test.")
+        coll = client_context.client.pymongo_test.get_collection(
+            "test",
+            write_concern=WriteConcern(w=num_members))
+        coll.drop()
+        res = coll.insert_many([{} for _ in range(5)])
+        first_id = res.inserted_ids[0]
+        last_id = res.inserted_ids[-1]
+
+        # Note - this isn't a perfect test since there's no way to
+        # tell what shard member a query ran on.
+        for pref in (Primary(),
+                     PrimaryPreferred(),
+                     Secondary(),
+                     SecondaryPreferred(),
+                     Nearest()):
+            qcoll = coll.with_options(read_preference=pref)
+            results = list(qcoll.find().sort([("_id", 1)]))
+            self.assertEqual(first_id, results[0]["_id"])
+            self.assertEqual(last_id, results[-1]["_id"])
+            results = list(qcoll.find().sort([("_id", -1)]))
+            self.assertEqual(first_id, results[-1]["_id"])
+            self.assertEqual(last_id, results[0]["_id"])
+
 
 if __name__ == "__main__":
     unittest.main()


Reply via email to