Skip to content

Commit 076cfbc

Browse files
committed
update README and docs index
1 parent 1e7cbe8 commit 076cfbc

File tree

2 files changed

+86
-108
lines changed

2 files changed

+86
-108
lines changed

README.rst

+16-29
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,27 @@
22
nanomongo
33
=========
44

5-
**nanomongo** is a minimal MongoDB Object-Document Mapper for Python.
6-
It does not attempt to be a feature-complete ODM but if you like
7-
using ``pymongo`` api with python dictionaries and often find yourself
8-
writing validators and ``pymongo.Collection`` wrappers, nanomongo
9-
might suit your needs.
10-
11-
nanomongo has full test coverage.
12-
13-
**Quick Links**: `Source (github) <https://github.com/eguven/nanomongo>`_ - `Documentation (rtd) <https://nanomongo.readthedocs.org/>`_ - `Packages (PyPi) <https://pypi.python.org/pypi/nanomongo/>`_ - `Changelog <https://github.com/eguven/nanomongo/blob/master/CHANGELOG.md>`_
14-
155
.. image:: https://travis-ci.org/eguven/nanomongo.png
166
:target: https://travis-ci.org/eguven/nanomongo
177

18-
Features
19-
--------
8+
**nanomongo** is a minimal MongoDB Object-Document Mapper for Python. It does not attempt to be a feature-complete
9+
ODM but if you enjoy using PyMongo_ API with dictionaries and often find yourself writing validators and
10+
``pymongo.Collection`` wrappers, nanomongo might suit your needs.
2011

21-
- typed ``Field`` definitions with validators and a few common options such as ``required``, ``default``, ``auto_update``
22-
- ``IndexModel`` definitions within Document classes that are automatically created
23-
- optional ``dot_notation``
24-
- assignment and deletion (delta) tracking for ``'$set'`` and ``'$unset'``
25-
and atomic updates; you either insert or update
26-
- ``'$addToSet'`` on ``Document``
12+
**Quick Links**: `Source (github) <https://github.com/eguven/nanomongo>`_ - `Documentation (rtd) <https://nanomongo.readthedocs.org/>`_ - `Packages (PyPi) <https://pypi.python.org/pypi/nanomongo/>`_ - `Changelog <https://github.com/eguven/nanomongo/blob/master/CHANGELOG.md>`_
13+
14+
Quickstart
15+
-----------
2716

2817
::
2918

30-
# simple example
3119
import pymongo
3220
from nanomongo import Field, BaseDocument
3321

3422
client = pymongo.MongoClient()
3523

24+
# python3 notation, see documentation for python2 options
25+
# we can omit the keyword arguments here and later call MyDoc.register(client=client, db='dbname')
3626
class MyDoc(BaseDocument, dot_notation=True, client=client, db='dbname'):
3727
foo = Field(str)
3828
bar = Field(int, required=False)
@@ -42,20 +32,17 @@ Features
4232
pymongo.IndexModel([('bar', 1), ('foo', -1)], unique=True),
4333
]
4434

45-
doc = MyDoc(foo='L33t')
46-
doc.bar = 42
47-
doc.insert()
48-
49-
Doc.find_one({'foo': 'L33t'})
50-
51-
52-
nanomongo is Python23 compatible and I intend to support both pymongo & motor
53-
transparently under the hood.
35+
doc = MyDoc(foo='L33t') # creates document {'foo': 'L33t'}
36+
doc.insert() # inserts document {'_id': ObjectId('...'), 'foo': 'L33t'}
37+
doc.bar = 42 # records the change
38+
doc.save() # calls collection.update_one {'$set': {'bar': 42}}
5439

55-
Contributions and insight are welcome!
40+
MyDoc.find_one({'foo': 'L33t'})
41+
{'_id': ObjectId('...'), 'bar': 42, 'foo': 'L33t'}
5642

5743
:Author: Eren Güven (GitHub_, Twitter_)
5844
:License: `Apache License 2.0 <https://github.com/eguven/nanomongo/blob/master/LICENSE>`_
5945

46+
.. _PyMongo: https://api.mongodb.com/python/current
6047
.. _GitHub: https://github.com/eguven
6148
.. _Twitter: https://twitter.com/cyberfart

docs/index.rst

+70-79
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,11 @@
66
Welcome to nanomongo's documentation!
77
=====================================
88

9-
**nanomongo** is a minimal MongoDB Object-Document Mapper for Python.
10-
It does not attempt to be a feature-complete ODM but if you like
11-
using ``pymongo`` api with python dictionaries and often find yourself
12-
writing validators and ``pymongo.Collection`` wrappers, nanomongo
13-
might suit your needs.
9+
**nanomongo** is a minimal MongoDB Object-Document Mapper for Python. It does not attempt to be a feature-complete
10+
ODM but if you enjoy using `PyMongo <https://api.mongodb.com/python/current>`_ API with dictionaries and often find yourself writing validators and
11+
``pymongo.Collection`` wrappers, nanomongo might suit your needs.
1412

15-
nanomongo has full test coverage.
16-
17-
**Quick Links**: `Source (github) <https://github.com/eguven/nanomongo>`_ - `Documentation (rtd) <https://nanomongo.readthedocs.org/>`_ - `Packages (PyPi) <https://pypi.python.org/pypi/nanomongo/>`_
18-
19-
**Version 0.4**: Utility methods `dbref_field_getters`_, :meth:`~.document.BaseDocument.get_dbref`
20-
and Bugfix `Python23 text type compatibility <https://github.com/eguven/nanomongo/pull/14>`_
21-
22-
**Version 0.3**: nanomongo is now python2 compatible (with syntactic difference
23-
when defining your Document, see `Defining Your Document`_ below).
13+
**Quick Links**: `Source (github) <https://github.com/eguven/nanomongo>`_ - `Documentation (rtd) <https://nanomongo.readthedocs.org/>`_ - `Packages (PyPi) <https://pypi.python.org/pypi/nanomongo/>`_ - `Changelog <https://github.com/eguven/nanomongo/blob/master/CHANGELOG.md>`_
2414

2515
Installation
2616
------------
@@ -29,84 +19,74 @@ Installation
2919
3020
$ pip install nanomongo
3121
32-
Quick Tutorial
22+
Quickstart
3323
--------------
3424

35-
Defining Your Document
36-
^^^^^^^^^^^^^^^^^^^^^^
25+
Defining A Document And Registering
26+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3727

38-
::
28+
You can define a document as shown below::
3929

4030
import pymongo
41-
from nanomongo import Index, Field, BaseDocument
42-
43-
mclient = pymongo.MongoClient()
31+
from nanomongo import Field, BaseDocument
4432

45-
class Py23CompatibleDoc(BaseDocument):
46-
client = mclient
47-
db = 'dbname'
48-
dot_notation = True
49-
foo = Field(str)
50-
bar = Field(int, required=False)
5133

52-
# Python3 only
53-
class Py3Doc(BaseDocument, dot_notation=True, client=mclient, db='dbname'):
34+
class Py23Doc(BaseDocument):
35+
dot_notation = True # to allow attribute-like access to document keys
5436
foo = Field(str)
5537
bar = Field(int, required=False)
5638

5739
__indexes__ = [
58-
Index('foo'),
59-
Index([('bar', 1), ('foo', -1)], unique=True),
40+
pymongo.IndexModel('foo'),
41+
pymongo.IndexModel([('bar', 1), ('foo', -1)], unique=True),
6042
]
6143

62-
You don't have to declare ``client`` or ``db`` as shown above, you can
63-
:meth:`~.document.BaseDocument.register` (and I definitely prefer it on
64-
python2) your document later as such:
44+
# before use, the document needs to be registered. The following will connect
45+
# to the database and create indexes if necessary
46+
Py23Doc.register(client=pymongo.MongoClient(), db='mydbname', collection='Py23Doc')
6547

66-
::
48+
Python3 allows slightly cleaner definitions::
6749

68-
client = pymongo.MongoClient()
69-
MyDoc.register(client=client, db='dbname', collection='mydoc')
50+
# Python3 only
51+
class MyDoc(BaseDocument, dot_notation=True):
52+
foo = Field(str)
53+
bar = Field(int, required=False)
7054

71-
If you omit ``collection`` when defining/registering your document,
72-
``__name__.lower()`` will be used by default
55+
If you omit ``collection`` when defining/registering your document, ``__name__.lower()`` will
56+
be used by default.
7357

74-
Creating, Inserting, Saving
75-
^^^^^^^^^^^^^^^^^^^^^^^^^^^
58+
Creating, Inserting, Querying, Saving
59+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7660
::
7761

78-
doc = MyDoc(foo='42') # or MyDoc({'foo': '42'})
79-
doc.bar = 42 # attribute style access because dot_notation=True
80-
doc.insert()
81-
82-
:meth:`~.document.BaseDocument.insert()` is a wrapper around
83-
``pymongo.Collection().insert()`` and has the same return value (``_id``)
84-
unless you explicitly set ``w=0`` ::
85-
86-
doc.foo = 'new foo' # this change is recorded
87-
del doc.bar # this is recored as well
88-
doc.save() # save only does partial updates
89-
90-
:meth:`~.document.BaseDocument.save()` uses ``pymongo.Collection().update()``
91-
with the changed data. The above will run ::
62+
doc = MyDoc(foo='1337', bar=42) # creates document {'foo': '1337', 'bar': 42}
63+
doc.insert() # returns pymongo.results.InsertOneResult
64+
MyDoc.find_one({'foo': '1337'}) # returns document {'_id': ObjectId('...'), 'bar': 42, 'foo': '1337'}
9265

93-
update({'_id': doc['_id']}, {'$set': {'foo': 'new foo'}, '$unset': {'bar': 1}})
66+
doc.foo = '42' # records the change
67+
del doc.bar # records the change
68+
# save only does partial updates, this will call
69+
# collection.update_one({'_id': doc['_id']}, {'$set': {'foo': '42'}, '$unset': {'bar': 1}})
70+
doc.save() # returns pymongo.results.UpdateResult
9471

95-
Querying
96-
^^^^^^^^
97-
::
72+
MyDoc.find_one({'foo': '1337'}) # returns None
73+
MyDoc.find_one({'foo': '42'}) # returns document {'_id': ObjectId('...'), 'foo': '42'}
9874

99-
Doc.find({'bar': 42})
100-
Doc.find_one({'foo': 'new foo'})
75+
:meth:`~.document.BaseDocument.insert()` is a wrapper around
76+
``pymongo.Collection.insert_one()`` and :meth:`~.document.BaseDocument.save()` is
77+
a wrapper around ``pymongo.Collection.update_one()``. They pass along received
78+
keyword arguments and have the same return value.
10179

10280
:meth:`~.document.BaseDocument.find()` and :meth:`~.document.BaseDocument.find_one()`
103-
methods are essentially wrappers around respective methods of ``pymongo.Collection()``
104-
and they take the same arguments.
81+
methods are wrappers around respective methods of ``pymongo.Collection`` with same
82+
arguments and return values.
10583

10684
Extensive Example
10785
-----------------
10886

109-
See :doc:`example`
87+
.. toctree::
88+
example
89+
11090

11191
Advanced Features
11292
-----------------
@@ -122,14 +102,17 @@ on your document instance and record the change to be applied later when
122102

123103
::
124104

125-
# lets expand our MyDoc
126-
class NewDoc(MyDoc):
105+
import pymongo
106+
from nanomongo import Field, BaseDocument
107+
108+
class NewDoc(BaseDocument, dot_notation=True):
127109
list_field = Field(list)
128110
dict_field = Field(dict)
129111

130-
NewDoc.register(client=client, db='dbname')
131-
doc_id = NewDoc(list_field=[42], dict_field={'foo':[]}).insert()
112+
NewDoc.register(client=pymongo.MongoClient(), db='mydbname')
113+
doc_id = NewDoc(list_field=[42], dict_field={'foo':[]}).insert().inserted_id
132114
doc = NewDoc.find_one({'_id': doc_id})
115+
# {'_id': ObjectId('...'), 'dict_field': {'foo': []}, 'list_field': [42]}
133116

134117
doc.addToSet('list_field', 1337)
135118
doc.addToSet('dict_field.foo', 'like a boss')
@@ -141,12 +124,17 @@ Both of the above ``addToSet`` are applied to the ``NewDoc`` instance like Mongo
141124
- add new value to list field if it's missing (append)
142125
- complain if it is not a list field
143126

144-
When save is called, query becomes: ::
127+
When save is called, the following is called::
128+
129+
update_one(
130+
{'_id': doc['_id']},
131+
{'$addToSet': {'list_field': {'$each': [1337]}}, 'dict_field.foo': {'$each': ['like a boss']}}
132+
)
145133

146-
update({'$addToSet': {'list_field': {'$each': [1337]}},
147-
'dict_field.foo': {'$each': ['like a boss']}})
134+
Undefined fields or field type mismatch raises :class:`~.errors.ValidationError`::
148135

149-
Undefined fields or field type mismatch raises :class:`~.errors.ValidationError`.
136+
doc.addToSet('dict_field.foo', 'like a boss')
137+
ValidationError: Cannot apply $addToSet modifier to non-array: dict_field=<class 'dict'>
150138

151139
QuerySpec check
152140
^^^^^^^^^^^^^^^
@@ -162,13 +150,13 @@ an experimental feature at the moment and only does type checks as such:
162150

163151
or ``{'foo.bar': 1}`` will log warnings if
164152

165-
- ``foo`` field is not of type ``dict`` or ``list`` (dotted field type)
153+
- ``foo`` field is not of type ``dict`` or ``list``
166154

167155
dbref_field_getters
168-
-------------------
156+
^^^^^^^^^^^^^^^^^^^
169157

170158
Documents that define ``bson.DBRef`` fields automatically generate getter methods
171-
through :func:`nanomongo.document.ref_getter_maker` where the generated methods
159+
through :func:`~.document.ref_getter_maker` where the generated methods
172160
have names such as ``get_<field_name>_field``.
173161
::
174162

@@ -182,13 +170,16 @@ have names such as ``get_<field_name>_field``.
182170
user = Field(DBRef)
183171

184172
nanomongo tries to guess the ``document_class`` if it's not provided by looking at
185-
registered subclasses of :class:`~.document.BaseDocument`. If it matches two (for example
186-
when two document classes use the same collection), it will raise
173+
registered subclasses of :class:`~.document.BaseDocument`. If it matches more than one
174+
(for example when two document classes use the same collection), it will raise
187175
:class:`~.errors.UnsupportedOperation`.
188176

189177
pymongo & motor
190178
---------------
191179

180+
**0.5.0 update**: motor support is currently not in a working state, this section is
181+
kept for reference.
182+
192183
Throughout the documentation, ``pymongo`` is referenced but all features work the
193184
same when using `motor <https://github.com/mongodb/motor>`_ transparently if you
194185
register the document class with a ``motor.MotorClient``.
@@ -221,10 +212,10 @@ Contents
221212
.. toctree::
222213
:titlesonly:
223214

224-
field
225215
document
226-
util
227216
errors
217+
field
218+
util
228219

229220

230221
Indices and tables

0 commit comments

Comments
 (0)