Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare for pymongo 4 upgrade #60

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6ced711
fix deprecation; using log.warning instead of log.warn
dill0wn Jun 28, 2024
e1a36e7
Begin pymongo4 prep; enter fixmes for each pymongo item that needs up…
dill0wn Jun 18, 2024
d293843
migrated from insert to insert_one/insert_many. removed 'manipulate' …
dill0wn Jun 18, 2024
f9de9ec
switch from pymongo's update to update_one/many
dill0wn Jun 28, 2024
9a4595b
migrated pymongo from find_and_modify to find_one_and_update/replace/…
dill0wn Jun 18, 2024
0468abd
replace deprecated pymongo database_names() and collection_names() wi…
dill0wn Jun 19, 2024
7aa7d0f
remove deprecated pymongo group() method
dill0wn Jun 19, 2024
40b1d7e
remove references to map_reduce and inline_map_reduce; pymongo no longer
dill0wn Jun 28, 2024
3beb935
removed pymongo.collection.save but kept mapper/session's save()
dill0wn Jun 28, 2024
0f11289
maybe fixed nearly 10 year old issue with ming's replace_one
dill0wn Jun 20, 2024
f0ac56d
incremental improvements to ming's type hinting (while avoiding circu…
dill0wn Jun 20, 2024
1736d15
replaced pymongo 'remove' with delete_many or delete_one internally
dill0wn Jun 28, 2024
3d0b293
drop mongo's count() methods, but keep ming session and cursor count …
dill0wn Jun 28, 2024
f1bfbc1
internally switch from ensure_index to create_index
dill0wn Jun 28, 2024
50a1c88
Updated docs/news.rst with better notes on pymongo4 prep
dill0wn Jun 28, 2024
de453c9
update gh actions, fix codecov hopefully
brondsem Jul 1, 2024
1666e11
added one, basic real mongo test for Document / Foundation Layer
dill0wn Jul 2, 2024
d2bf051
Refactored mim to more natively internally use pymongo's result classes
dill0wn Jul 9, 2024
6637de0
add note about cursor's count() behavior
dill0wn Jul 10, 2024
48808a2
fixup! Refactored mim to more natively internally use pymongo's resul…
dill0wn Jul 10, 2024
69f9336
changed session's save() logic
dill0wn Jul 11, 2024
a751703
fixup! migrated pymongo from find_and_modify to find_one_and_update/r…
dill0wn Jul 12, 2024
e65fec5
fixup! changed session's save() logic
dill0wn Jul 12, 2024
518a185
allow pymongo4; add generative tox environments for py3.8-to-3.11 * p…
dill0wn Jul 15, 2024
53ba153
add missing `option` attribute to mim.Connection to mirror MongoClient
dill0wn Jul 16, 2024
f9d629d
update pymongo UUID handling to use 'pythonLegacy'
dill0wn Jul 16, 2024
ccf05df
mim create_index now accepts dict.items()
dill0wn Jul 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4

- uses: actions/setup-python@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
Expand All @@ -55,9 +55,9 @@ jobs:
run: tox --skip-missing-interpreters false -e py`echo ${{ matrix.python-version }} | sed s/\\\.// | sed s/pypy/py/ | sed s/-dev//`

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: true
fail_ci_if_error: false
flags: tests-${{ matrix.python-version }}
name: codecov-umbrella
verbose: true
Expand Down
20 changes: 20 additions & 0 deletions docs/news.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,26 @@ Ming News / Release Notes

The latest releases support PyMongo 3. The older 0.5.x releases support PyMongo 2 and Python 2.

Pre-Release
---------------------
* Prepare for PyMongo 4.0 support
* Replace ``find_and_modify()`` session methods with ``find_one_and_update()``, ``find_one_and_replace()``,
and ``find_one_and_delete()`` to closer match pymongo4's API
* Remove ``group()`` session methods as they are unsupported in pymongo4. Use the aggregation pipeline.
* Remove ``map_reduce()`` and ``inline_map_reduce()`` session methods as they are unsupported in pymongo4.
Use the aggregation pipeline.
* MIM: Replace ``mim.Collection.insert()`` with ``insert_one()`` and ``insert_many()`` to match pymongo4
* MIM: Remove deprecated ``manipulate`` and ``safe`` args from pymongo's ``insert_one`` and ``insert_many`` methods
* MIM: Replace ``mim.Collection.update()`` with ``update_one()`` and ``update_many()`` to match pymongo4
* MIM: Replace ``mim.Collection.count()`` and ``mim.Cursor.count()`` with
``mim.Collection.estimated_document_count()`` and ``mim.Collection.count_documents()`` to match pymongo4
* MIM: Replace ``mim.Collection.remove()`` with ``mim.Collection.delete_one()``
and ``mim.Collection.delete_many()`` to match pymongo4
* MIM: Rename ``collection_names()`` and ``database_names()`` to ``list_collection_names()``
and ``list_database_names``
* MIM: Remove ``mim.Collection.map_reduce()`` and ``mim.Collection.inline_map_reduce()`` to match pymongo4
* MIM: Replace ``ensure_index()`` with ``create_index()`` to match pymongo4

0.13.0 (Mar 16, 2023)
---------------------
* remove Python 3.6 support
Expand Down
6 changes: 3 additions & 3 deletions docs/presentations/pyatl-20100114/src/demo1.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@

pages = db.pages

pages.insert(page)
pages.insert_one(page)

db.collection_names()
db.list_collection_names()

page = pages.find_one()

page['author'] = 'Rick Copeland'

pages.save(page)
pages.replace_one(dict(_id=page._id), page)

pages.find_one()
4 changes: 2 additions & 2 deletions docs/src/ming_odm_migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def snippet1():
TAGS = ['foo', 'bar', 'snafu', 'mongodb']

# Insert the documents through PyMongo so that Ming is not involved
session.db.wiki_page.insert([
session.db.wiki_page.insert_many([
dict(title='Page %s' % idx, text='Text of Page %s' %idx, tags=random.sample(TAGS, 2)) for idx in range(10)
])

Expand All @@ -134,7 +134,7 @@ def snippet5():
next(session.db.wiki_page.find()).get('metadata')

def snippet6():
session.db.mymodel.insert(dict(name='desrever'))
session.db.mymodel.insert_one(dict(name='desrever'))
session.db.mymodel.find_one()

# Apply migration to version 1 and then to version 2
Expand Down
4 changes: 2 additions & 2 deletions docs/src/ming_odm_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ def snippet1_2():

def snippet1_3():
Contact.query.remove({})
session.db.contact.insert(dict(name='Invalid Contact',
email='this-is-invalid'))
session.db.contact.insert_one(dict(name='Invalid Contact',
email='this-is-invalid'))

try:
c1 = Contact.query.find().first()
Expand Down
6 changes: 3 additions & 3 deletions docs/src/ming_odm_tutorial.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ def snippet5_1():
session.flush()

def snippet5_3():
WikiPage.query.find_and_modify({'title': 'MyFirstPage'},
update={'$set': {'text': 'This is my first page'}},
new=True)
WikiPage.query.find_one_and_update({'title': 'MyFirstPage'},
update={'$set': {'text': 'This is my first page'}},
upsert=True)

def snippet5_4():
wp = WikiPage.query.get(title='MyFirstPage')
Expand Down
4 changes: 2 additions & 2 deletions docs/src/ming_welcome.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ class __mongometa__:


def snippet1():
session.db.wiki_page.insert({'title': 'FirstPage',
'text': 'This is my first page'})
session.db.wiki_page.insert_one({'title': 'FirstPage',
'text': 'This is my first page'})
session.db.wiki_page.find_one({'title': 'FirstPage'})


Expand Down
6 changes: 3 additions & 3 deletions docs/userguide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ Querying Objects
Once we have a `WikiPage` in the database, we can retrieve it using the `.query`
attribute. The query attribute is a proxy to the Session query features which expose
three methods that make possible to query objects :meth:`._ClassQuery.get`,
:meth:`.ODMSession.find` and :meth:`.ODMSession.find_and_modify`:
:meth:`.ODMSession.find` and :meth:`.ODMSession.find_one_and_update`:

.. run-pysnippet:: ming_odm_tutorial snippet2

Expand Down Expand Up @@ -340,7 +340,7 @@ will track that the object needs to be updated:
:skip: 1
:emphasize-lines: 17

Another option to edit an object is to actually rely on :meth:`.ODMSession.find_and_modify`
Another option to edit an object is to actually rely on :meth:`.ODMSession.find_one_and_update`
method which will query the object and update it atomically:

.. run-pysnippet:: ming_odm_tutorial snippet5_3
Expand All @@ -349,7 +349,7 @@ This is often used to increment counters or acquire global locks in mongodb

.. note::

``find_and_modify`` always refreshes the object in the IdentityMap, so the object
``find_one_and_update`` always refreshes the object in the IdentityMap, so the object
in your IdentityMap will always get replaced with the newly retrieved value. Make
sure you properly flushed any previous change to the object and use the ``new`` option
to avoid retrieving a stale version of the object if you plan to modify it.
Expand Down
10 changes: 8 additions & 2 deletions ming/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,12 @@ class Cursor:
def __bool__(self):
raise MingException('Cannot evaluate Cursor to a boolean')

def __init__(self, cls, cursor, allow_extra=True, strip_extra=True):
def __init__(self, cls, cursor, allow_extra=True, strip_extra=True, find_spec=None):
self.cls = cls
self.cursor = cursor
self._allow_extra = allow_extra
self._strip_extra = strip_extra
self.find_spec = find_spec

def __iter__(self):
return self
Expand All @@ -89,7 +90,12 @@ def next(self):
__next__ = next

def count(self):
return self.cursor.count()
"""
This method, although deprecated by pymongo, is kept for backcompat with existing code.
It is inaccurate when used with a cursor that has been limited or skipped. However,
this behavior is consistent with previous pymongo (3.X) and mongo shell (4.X) behavior.
"""
return self.cursor.collection.count_documents(self.find_spec)

def distinct(self, *args, **kwargs):
return self.cursor.distinct(*args, **kwargs)
Expand Down
7 changes: 4 additions & 3 deletions ming/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,9 @@ class _ClassManager(metaclass=_CurriedProxyClass):
_proxy_args=('cls',)
_proxy_methods = (
'get', 'find', 'find_by', 'remove', 'count', 'update_partial',
'group', 'ensure_index', 'ensure_indexes', 'index_information', 'drop_indexes',
'find_and_modify', 'aggregate', 'distinct', 'map_reduce', 'inline_map_reduce',
'create_index', 'ensure_index', 'ensure_indexes', 'index_information', 'drop_indexes',
'find_one_and_update', 'find_one_and_replace', 'find_one_and_delete',
'aggregate', 'distinct',
)
InstanceManagerClass=_InstanceManager

Expand Down Expand Up @@ -358,7 +359,7 @@ def _ensure_indexes(self):
try:
with self._lock:
for idx in self.manager.indexes:
collection.ensure_index(idx.index_spec, background=True,
collection.create_index(idx.index_spec, background=True,
brondsem marked this conversation as resolved.
Show resolved Hide resolved
**idx.index_options)
except (MongoGone, ConnectionFailure) as e:
if e.args[0] == 'not master':
Expand Down
18 changes: 9 additions & 9 deletions ming/metadata.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from bson import ObjectId
from datetime import datetime
from typing import Generic, TypeVar, Any, Optional, overload, List, Dict, Type, Union, Mapping, type_check_only
from pymongo.results import UpdateResult, DeleteResult

import bson
from ming.base import Cursor
Expand Down Expand Up @@ -178,7 +179,6 @@ class Field:
M = TypeVar('M')

MongoFilter = dict
ChangeResult = dict
SaveResult = Union[ObjectId, Any]
class _ClassManager(Generic[M]):
# proxies these from Session
Expand All @@ -190,28 +190,28 @@ class _ClassManager(Generic[M]):
def find_by(self, filter: MongoFilter, *args, validate: bool = True, **kwargs) -> Cursor[M]: ...
#@overload
#def find_by(self, filter: MongoFilter, *args, validate: Literal[False], **kwargs) -> Generator[M]: ...
def remove(self, spec_or_id: Union[MongoFilter, ObjectId] = None, **kwargs) -> ChangeResult: ...
def remove(self, spec_or_id: Union[MongoFilter, ObjectId] = None, **kwargs) -> DeleteResult: ...
def count(self) -> int: ...
def update_partial(self, filter: MongoFilter, fields: dict, **kwargs) -> ChangeResult: ...
def update_partial(self, filter: MongoFilter, fields: dict, **kwargs) -> UpdateResult: ...
def find_one_and_update(self, **kwargs) -> M: ...
def find_one_and_replace(self, **kwargs) -> M: ...
def find_one_and_delete(self, **kwargs) -> M: ...
"""
def group(self) -> int: ...
def ensure_indexes(self) -> int: ...
def index_information(self) -> int: ...
def drop_indexes(self) -> int: ...
def find_and_modify(self) -> int: ...
def aggregate(self) -> int: ...
def distinct(self) -> int: ...
def map_reduce(self) -> int: ...
def inline_map_reduce(self) -> int: ...
"""

class _InstanceManager:
# proxies these from Session
def save(self, *args: str, **kwargs) -> SaveResult: ...
def insert(self, **kwargs) -> SaveResult: ...
def upsert(self, spec_fields: List[str], **kwargs) -> ChangeResult: ...
def delete(self) -> ChangeResult: ...
def set(self, fields_values: Mapping[str, Any]) -> ChangeResult: ...
def upsert(self, spec_fields: List[str], **kwargs) -> UpdateResult: ...
def delete(self) -> DeleteResult: ...
def set(self, fields_values: Mapping[str, Any]) -> UpdateResult: ...
def increase_field(self, **kwargs) -> None: ...


Expand Down
Loading