[Checkins] SVN: m01.mongofake/ initial commit
Adam Groszer
cvs-admin at zope.org
Tue May 22 12:42:54 UTC 2012
Log message for revision 126427:
initial commit
Changed:
A m01.mongofake/branches/
A m01.mongofake/tags/
A m01.mongofake/trunk/
A m01.mongofake/trunk/AUTHORS.txt
A m01.mongofake/trunk/CHANGES.txt
A m01.mongofake/trunk/LICENSE.txt
A m01.mongofake/trunk/README.txt
A m01.mongofake/trunk/TODO.txt
A m01.mongofake/trunk/bootstrap.py
A m01.mongofake/trunk/buildout.cfg
A m01.mongofake/trunk/setup.py
A m01.mongofake/trunk/src/
A m01.mongofake/trunk/src/m01/
A m01.mongofake/trunk/src/m01/__init__.py
A m01.mongofake/trunk/src/m01/mongofake/
A m01.mongofake/trunk/src/m01/mongofake/__init__.py
-=-
Property changes on: m01.mongofake/trunk
___________________________________________________________________
Added: svn:ignore
+ .installed.cfg
bin
develop-eggs
parts
Added: m01.mongofake/trunk/AUTHORS.txt
===================================================================
--- m01.mongofake/trunk/AUTHORS.txt (rev 0)
+++ m01.mongofake/trunk/AUTHORS.txt 2012-05-22 12:42:51 UTC (rev 126427)
@@ -0,0 +1,6 @@
+Roger Ineichen
+Adam Groszer
+Albertas Agejevas
+Marius Gedminas
+Sascha Welter
+Stephan Richter
Property changes on: m01.mongofake/trunk/AUTHORS.txt
___________________________________________________________________
Added: svn:keywords
+ Date Author Id Revision
Added: svn:eol-style
+ native
Added: m01.mongofake/trunk/CHANGES.txt
===================================================================
--- m01.mongofake/trunk/CHANGES.txt (rev 0)
+++ m01.mongofake/trunk/CHANGES.txt 2012-05-22 12:42:51 UTC (rev 126427)
@@ -0,0 +1,9 @@
+=======
+CHANGES
+=======
+
+0.1.0 (unreleased)
+------------------
+
+- First independent release from m01.mongo.testing
+
Property changes on: m01.mongofake/trunk/CHANGES.txt
___________________________________________________________________
Added: svn:keywords
+ Date Author Id Revision
Added: svn:eol-style
+ native
Added: m01.mongofake/trunk/LICENSE.txt
===================================================================
--- m01.mongofake/trunk/LICENSE.txt (rev 0)
+++ m01.mongofake/trunk/LICENSE.txt 2012-05-22 12:42:51 UTC (rev 126427)
@@ -0,0 +1,44 @@
+Zope Public License (ZPL) Version 2.1
+
+A copyright notice accompanies this license document that identifies the
+copyright holders.
+
+This license has been certified as open source. It has also been designated as
+GPL compatible by the Free Software Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions in source code must retain the accompanying copyright
+notice, this list of conditions, and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying copyright
+notice, this list of conditions, and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to endorse or promote
+products derived from this software without prior written permission from the
+copyright holders.
+
+4. The right to distribute this software or to use it for any purpose does not
+give you the right to use Servicemarks (sm) or Trademarks (tm) of the
+copyright
+holders. Use of them is covered by separate agreement with the copyright
+holders.
+
+5. If any files are modified, you must cause the modified files to carry
+prominent notices stating that you changed the files and the date of any
+change.
+
+Disclaimer
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Property changes on: m01.mongofake/trunk/LICENSE.txt
___________________________________________________________________
Added: svn:keywords
+ Date Author Id Revision
Added: svn:eol-style
+ native
Added: m01.mongofake/trunk/README.txt
===================================================================
--- m01.mongofake/trunk/README.txt (rev 0)
+++ m01.mongofake/trunk/README.txt 2012-05-22 12:42:51 UTC (rev 126427)
@@ -0,0 +1,2 @@
+This package provides a FAKE mongoDB implementation.
+This is quite handy for testing.
Property changes on: m01.mongofake/trunk/README.txt
___________________________________________________________________
Added: svn:keywords
+ Date Author Id Revision
Added: svn:eol-style
+ native
Added: m01.mongofake/trunk/TODO.txt
===================================================================
--- m01.mongofake/trunk/TODO.txt (rev 0)
+++ m01.mongofake/trunk/TODO.txt 2012-05-22 12:42:51 UTC (rev 126427)
@@ -0,0 +1,5 @@
+====
+TODO
+====
+
+add some tests
\ No newline at end of file
Property changes on: m01.mongofake/trunk/TODO.txt
___________________________________________________________________
Added: svn:keywords
+ Date Author Id Revision
Added: svn:eol-style
+ native
Added: m01.mongofake/trunk/bootstrap.py
===================================================================
--- m01.mongofake/trunk/bootstrap.py (rev 0)
+++ m01.mongofake/trunk/bootstrap.py 2012-05-22 12:42:51 UTC (rev 126427)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id$
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+ cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+ os.P_WAIT, sys.executable, sys.executable,
+ '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)
Property changes on: m01.mongofake/trunk/bootstrap.py
___________________________________________________________________
Added: svn:keywords
+ Date Author Id Revision
Added: svn:eol-style
+ native
Added: m01.mongofake/trunk/buildout.cfg
===================================================================
--- m01.mongofake/trunk/buildout.cfg (rev 0)
+++ m01.mongofake/trunk/buildout.cfg 2012-05-22 12:42:51 UTC (rev 126427)
@@ -0,0 +1,27 @@
+[buildout]
+develop = .
+
+parts = test checker coverage coveragereport
+
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = m01.mongofake [test]
+
+
+[checker]
+recipe = lovely.recipe:importchecker
+path = src/m01.mongofake
+
+
+[coverage]
+recipe = zc.recipe.testrunner
+eggs = m01.mongofake [test]
+defaults = ['--all', '--coverage', '../../coverage']
+
+
+[coveragereport]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coveragereport
+arguments = ('parts/coverage', 'parts/coverage/report')
Property changes on: m01.mongofake/trunk/buildout.cfg
___________________________________________________________________
Added: svn:keywords
+ Date Author Id Revision
Added: svn:eol-style
+ native
Added: m01.mongofake/trunk/setup.py
===================================================================
--- m01.mongofake/trunk/setup.py (rev 0)
+++ m01.mongofake/trunk/setup.py 2012-05-22 12:42:51 UTC (rev 126427)
@@ -0,0 +1,57 @@
+##############################################################################
+#
+# Copyright (c) 2008 Projekt01 GmbH and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import os
+from setuptools import setup, find_packages
+
+
+def read(*rnames):
+ return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+setup(
+ name='m01.mongofake',
+ version='0.1.0.dev0',
+ author='Zope Foundation and Contributors',
+ author_email='zope-dev at zope.org',
+ description="Fake MongoDB implementation",
+ long_description=(
+ read('README.txt')
+ + '\n\n' +
+ read('CHANGES.txt')
+ ),
+ license="ZPL 2.1",
+ keywords="mongoDB mongo fake",
+ classifiers=[
+ 'Development Status :: 4 - Beta',
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: Zope Public License',
+ 'Programming Language :: Python',
+ 'Natural Language :: English',
+ 'Operating System :: OS Independent',
+ 'Topic :: Internet :: WWW/HTTP'],
+ url='http://pypi.python.org/pypi/m01.mongofake',
+ packages=find_packages('src'),
+ include_package_data=True,
+ package_dir={'': 'src'},
+ extras_require=dict(
+ test=[
+ 'zope.testing',
+ ]),
+ install_requires=[
+ 'setuptools',
+ 'pymongo',
+ ],
+ zip_safe=False,
+ )
Property changes on: m01.mongofake/trunk/setup.py
___________________________________________________________________
Added: svn:keywords
+ Date Author Id Revision
Added: svn:eol-style
+ native
Property changes on: m01.mongofake/trunk/src
___________________________________________________________________
Added: svn:ignore
+ m01.mongofake.egg-info
Added: m01.mongofake/trunk/src/m01/__init__.py
===================================================================
--- m01.mongofake/trunk/src/m01/__init__.py (rev 0)
+++ m01.mongofake/trunk/src/m01/__init__.py 2012-05-22 12:42:51 UTC (rev 126427)
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+ import pkg_resources
+ pkg_resources.declare_namespace(__name__)
+except ImportError:
+ import pkgutil
+ __path__ = pkgutil.extend_path(__path__, __name__)
Property changes on: m01.mongofake/trunk/src/m01/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Date Author Id Revision
Added: svn:eol-style
+ native
Added: m01.mongofake/trunk/src/m01/mongofake/__init__.py
===================================================================
--- m01.mongofake/trunk/src/m01/mongofake/__init__.py (rev 0)
+++ m01.mongofake/trunk/src/m01/mongofake/__init__.py 2012-05-22 12:42:51 UTC (rev 126427)
@@ -0,0 +1,542 @@
+##############################################################################
+#
+# Copyright (c) 2012 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+__docformat__ = "reStructuredText"
+
+import copy
+import re
+import types
+import pprint as pp
+
+from bson import objectid
+from bson import son
+from pymongo import cursor
+
+
+###############################################################################
+#
+# test helper methods
+#
+###############################################################################
+
+# SON to dict converter
+def dictify(data):
+ """Recursive replace SON instance with plain a dict"""
+ if isinstance(data, dict):
+ d = {}
+ for k, v in data.items():
+ d[k] = dictify(v)
+ elif isinstance(data, (tuple, list)):
+ d = []
+ for v in data:
+ d.append(dictify(v))
+ if isinstance(data, tuple):
+ d = tuple(d)
+ else:
+ d = data
+ return d
+
+
+def pprint(data):
+ """Can pprint a bson.son.SON instance like a dict"""
+ pp.pprint(dictify(data))
+
+
+class RENormalizer(object):
+ """Normalizer which can convert text based on regex patterns"""
+
+ def __init__(self, patterns):
+ self.patterns = patterns
+ self.transformers = map(self._cook, patterns)
+
+ def _cook(self, pattern):
+ if callable(pattern):
+ return pattern
+ regexp, replacement = pattern
+ return lambda text: regexp.sub(replacement, text)
+
+ def addPattern(self, pattern):
+ patterns = list(self.patterns)
+ patterns.append(pattern)
+ self.transformers = map(self._cook, patterns)
+ self.patterns = patterns
+
+ def __call__(self, data):
+ """Recursive normalize a SON instance, dict or text"""
+ if not isinstance(data, basestring):
+ data = pp.pformat(dictify(data))
+ for normalizer in self.transformers:
+ data = normalizer(dictify(data))
+ return data
+
+ def pprint(self, data):
+ """Pretty print data"""
+ if isinstance(data, cursor.Cursor):
+ for item in data:
+ print self(item)
+ else:
+ print self(data)
+
+
+# see testing.txt for a sample usage
+reNormalizer = RENormalizer([
+ (re.compile(u"(\d\d\d\d)-(\d\d)-(\d\d)[tT](\d\d):(\d\d):(\d\d)"),
+ r"NNNN-NN-NNTNN:NN:NN"),
+ (re.compile(u"(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)"),
+ r"NNNN-NN-NN NN:NN:NN"),
+ (re.compile("ObjectId\(\'[a-zA-Z0-9]+\'\)"), r"ObjectId('...')"),
+ (re.compile("Timestamp\([a-zA-Z0-9, ]+\)"), r"Timestamp('...')"),
+ (re.compile("datetime.datetime\([a-zA-Z0-9, ]+tzinfo=<bson.tz_util.FixedOffset[a-zA-Z0-9 ]+>\)"),
+ "datetime(..., tzinfo=<bson.tz_util.FixedOffset ...>)"),
+ (re.compile("datetime.datetime\([a-zA-Z0-9, ]+tzinfo=[a-zA-Z0-9>]+\)"),
+ "datetime(..., tzinfo= ...)"),
+ (re.compile("datetime\([a-z0-9, ]+\)"), "datetime(...)"),
+ (re.compile("object at 0x[a-zA-Z0-9]+"), "object at ..."),
+ ])
+
+
+###############################################################################
+#
+# fake MongoDB
+#
+###############################################################################
+
+class OrderedData(object):
+ """Ordered data."""
+
+ def __init__(self):
+ self.data = {}
+ self._order = []
+
+ def __len__(self):
+ return len(self.data)
+
+ def __contains__(self, key):
+ return key in self.data
+
+ def __getitem__(self, key):
+ return self.data[key]
+
+ def __setitem__(self, key, item):
+ if key not in self._order:
+ self._order.append(key)
+ self.data[key] = copy.deepcopy(item)
+
+ def __delitem__(self, key):
+ del self.data[key]
+ self._order.remove(key)
+
+ def get(self, key, default=None):
+ """Get item by key"""
+ return self.data.get(key, default)
+
+ def keys(self):
+ return self._order
+
+ def values(self):
+ for key in self._order:
+ return self.data[key]
+
+ def items(self):
+ for key in self._order:
+ yield (key, self.data[key])
+
+ def __iter__(self):
+ for key in self._order:
+ yield self.data[key]
+
+ def __repr__(self):
+ return repr(self.data.values())
+
+
+def sortByAttribute(name, order):
+ def sort(d1, d2):
+ v1 = d1.get(name, None)
+ v2 = d2.get(name, None)
+ try:
+ res = cmp(v1, v2)
+ except TypeError:
+ res = -1
+ if order:
+ return res
+ else:
+ return -res
+ return sort
+
+
+def cursor_comparator(keys):
+ def comparator(a, b):
+ for k, d in keys:
+ part = cmp(a.get(k), b.get(k))
+ if part:
+ return part * d
+ return 0
+ return comparator
+
+NOVALUEMARKER = object()
+
+
+def getPart(doc, k):
+ parts = k.split('.')
+
+ def getP(doc, part):
+ try:
+ # try an attribute
+ return getattr(doc, part)
+ except AttributeError:
+ try:
+ # try a dict
+ return doc[part]
+ except TypeError:
+ try:
+ # try a sequence
+ return doc[int(part)]
+ except:
+ pass
+ return NOVALUEMARKER
+
+ d = doc
+ for p in parts:
+ prevD = d
+ d = getP(d, p)
+ if d == NOVALUEMARKER:
+ #if it starts with '$' try again without $, like for $id
+ if p.startswith('$'):
+ d = getP(prevD, p[1:])
+ if d == NOVALUEMARKER:
+ return d
+ return d
+
+
+class FakeCursor(object):
+ """Fake mongoDB cursor."""
+
+ def __init__(self, collection, spec, fields, skip, limit, slave_okay,
+ timeout, tailable, snapshot=False, sort=None,
+ _sock=None, _must_use_master=False):
+ # filter and setup docs based on given spec
+ self.collection = collection
+ self._skip = skip
+ self._limit = limit
+ self.docs = self._query(collection, spec, sort)
+ self.total = len(self.docs)
+
+ def _query(self, collection, spec, sort=None):
+ docs = []
+ append = docs.append
+ for key, doc in collection.docs.items():
+ for k, v in spec.items():
+ if k in doc and isinstance(v, dict):
+ reject = False
+ for op, value in v.items():
+ if ((op == '$gt' and not doc[k] > value) or
+ (op == '$lt' and not doc[k] < value) or
+ (op == '$gte' and not doc[k] >= value) or
+ (op == '$lte' and not doc[k] <= value) or
+ (op == '$ne' and not doc[k] != value) or
+ (op == '$in' and not doc[k] in value) or
+ (op == '$exists' and not k in doc) or
+ (op == '$all' and not all([vv in doc[k]
+ for vv in value])) or
+ (op == '$nin' and not doc[k] not in value)
+ # TODO: $mod, $nor $or, $and, $size, $type, $regex
+ ):
+ reject = True
+ break
+ if reject:
+ break
+ else:
+ if '.' in k:
+ # support diving into attributes/documents
+ docVal = getPart(doc, k)
+ else:
+ # Mongo always ignores documents where a key of the
+ # spec is missing.
+ if k not in doc:
+ break
+ docVal = doc.get(k, NOVALUEMARKER)
+ # XXX: This is not generic and will not handle operator
+ # based specs.
+ if docVal != NOVALUEMARKER and v != docVal:
+ break
+ else:
+ append(copy.deepcopy(doc))
+
+ if sort:
+ docs = sorted(docs, cmp=cursor_comparator(sort))
+
+ return docs
+
+ def count(self, with_limit_and_skip=False):
+ if with_limit_and_skip:
+ return len(self.docs)
+ else:
+ return self.total
+
+ def skip(self, skip):
+ self._skip = skip
+ self.docs = self.docs[skip:]
+ return self
+
+ def limit(self, limit):
+ self._limit = limit
+ self.docs = self.docs[:limit]
+ return self
+
+ def sort(self, name, order):
+ sorter = sortByAttribute(name, order)
+ docs = list(self.docs)
+ docs.sort(sorter)
+ self.docs = docs
+ return self
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ if len(self.docs):
+ next = self.docs.pop(0)
+ else:
+ raise StopIteration
+ return next
+
+
+class FakeCollection(object):
+ """Fake mongoDB collection"""
+
+ def __init__(self, database, name):
+ self.database = database
+ self.name = name
+ self.full_name = '%s.%s' % (database, name)
+ self.docs = OrderedData()
+
+ def __getattr__(self, name):
+ """Get a sub-collection of this collection by name (e.g. gridfs)"""
+ return FakeCollection(self.database, u"%s.%s" % (self.name, name))
+
+ def clear(self):
+ for k in self.docs.keys():
+ del self.docs[k]
+
+ def count(self):
+ return len(self.docs)
+
+ def update(self, spec, document,
+ upsert=False, manipulate=False, safe=False, multi=False):
+ if not isinstance(spec, types.DictType):
+ raise TypeError("spec must be an instance of dict")
+ if not isinstance(document, types.DictType):
+ raise TypeError("document must be an instance of dict")
+ if not isinstance(upsert, types.BooleanType):
+ raise TypeError("upsert must be an instance of bool")
+
+ for key, doc in list(self.docs.items()):
+ for k, v in spec.items():
+ if k in doc and v == doc[k]:
+ setData = document.get('$set')
+ if setData is not None:
+ # do a partial update based on $set data
+ for pk, pv in setData.items():
+ doc[pk] = pv
+ else:
+ self.docs[key] = document
+ break
+
+ def save(self, to_save, manipulate=True, safe=False):
+ if not isinstance(to_save, types.DictType):
+ raise TypeError("cannot save object of type %s" % type(to_save))
+
+ if "_id" not in to_save:
+ return self.insert(to_save, manipulate, safe)
+ else:
+ self.update({"_id": to_save["_id"]}, to_save, True, manipulate, safe)
+ return to_save.get("_id", None)
+
+ def insert(self, doc_or_docs, manipulate=True, safe=False, check_keys=True,
+ continue_on_error=True):
+ docs = doc_or_docs
+ if isinstance(docs, types.DictType):
+ docs = [docs]
+ for doc in docs:
+ oid = doc.get('_id')
+ if oid is None:
+ oid = objectid.ObjectId()
+ doc[u'_id'] = oid
+ d = {}
+ for k, v in list(doc.items()):
+ # use unicode keys as mongodb does
+ d[unicode(k)] = v
+ self.docs[unicode(oid)] = d
+
+ ids = [doc.get("_id", None) for doc in docs]
+ return len(ids) == 1 and ids[0] or ids
+
+ def ensure_index(self, key_or_list, direction=None, unique=False, ttl=300):
+ # we do not need indexes
+ pass
+
+ def find_one(self, spec_or_object_id=None, fields=None, slave_okay=True,
+ _sock=None, _must_use_master=False):
+ spec = spec_or_object_id
+ if spec is None:
+ spec = son.SON()
+ if isinstance(spec, objectid.ObjectId):
+ spec = son.SON({"_id": spec})
+
+ for result in self.find(spec, limit=-1, fields=fields,
+ slave_okay=slave_okay, _sock=_sock,
+ _must_use_master=_must_use_master):
+ return result
+ return None
+
+ def find(self, spec=None, fields=None, skip=0, limit=0,
+ slave_okay=True, timeout=True, snapshot=False, tailable=False,
+ sort=None,
+ _sock=None, _must_use_master=False):
+ if spec is None:
+ spec = son.SON()
+
+ if not isinstance(spec, types.DictType):
+ raise TypeError("spec must be an instance of dict")
+ if not isinstance(fields, (
+ types.ListType, types.TupleType, types.NoneType)):
+ raise TypeError("fields must be an instance of list or tuple")
+ if not isinstance(skip, types.IntType):
+ raise TypeError("skip must be an instance of int")
+ if not isinstance(limit, types.IntType):
+ raise TypeError("limit must be an instance of int")
+ if not isinstance(slave_okay, types.BooleanType):
+ raise TypeError("slave_okay must be an instance of bool")
+ if not isinstance(timeout, types.BooleanType):
+ raise TypeError("timeout must be an instance of bool")
+ if not isinstance(snapshot, types.BooleanType):
+ raise TypeError("snapshot must be an instance of bool")
+ if not isinstance(tailable, types.BooleanType):
+ raise TypeError("tailable must be an instance of bool")
+
+ if fields is not None:
+ if not fields:
+ fields = ["_id"]
+ fields = self._fields_list_to_dict(fields)
+
+ return FakeCursor(self, spec, fields, skip, limit, slave_okay, timeout,
+ tailable, snapshot, sort=sort, _sock=_sock,
+ _must_use_master=_must_use_master)
+
+ def remove(self, spec_or_object_id, safe=False):
+ spec = spec_or_object_id
+ if isinstance(spec, objectid.ObjectId):
+ spec = {"_id": spec}
+
+ if not isinstance(spec, types.DictType):
+ raise TypeError("spec must be an instance of dict, not %s" %
+ type(spec))
+
+ for doc in self.find(spec, fields=()):
+ del self.docs[unicode(doc['_id'])]
+
+ # helper methods
+ def _fields_list_to_dict(self, fields):
+ as_dict = OrderedData()
+ for field in fields:
+ if not isinstance(field, types.StringTypes):
+ raise TypeError("fields must be a list of key names as "
+ "(string, unicode)")
+ as_dict[field] = 1
+ return as_dict
+
+
+class FakeDatabase(object):
+ """Fake mongoDB database."""
+
+ def __init__(self, connection, name):
+ self.connection = connection
+ self.name = name
+ self.cols = {}
+
+ def clear(self):
+ for k, col in self.cols.items():
+ col.clear()
+ del self.cols[k]
+
+ def collection_names(self):
+ return list(self.cols.keys())
+
+ def __getattr__(self, name):
+ col = self.cols.get(name)
+ if col is None:
+ col = FakeCollection(self, name)
+ self.cols[name] = col
+ return col
+
+ def __getitem__(self, name):
+ return self.__getattr__(name)
+
+ def create_collection(self, name, **kw):
+ return True
+
+
+class FakeMongoConnection(object):
+ """Fake MongoDB connection."""
+
+ def __init__(self):
+ self.dbs = {}
+
+ def __call__(self, host='localhost', port=27017, tz_aware=True):
+ return self
+
+ def drop_database(self, name):
+ db = self.dbs.get(name)
+ if db is not None:
+ db.clear()
+ del self.dbs[name]
+
+ def disconnect(self):
+ pass
+
+ def database_names(self):
+ return list(self.dbs.keys())
+
+ def __getattr__(self, name):
+ db = self.dbs.get(name)
+ if db is None:
+ db = FakeDatabase(self, name)
+ self.dbs[name] = db
+ return db
+
+ def __getitem__(self, name):
+ return self.__getattr__(name)
+
+# single shared connection instance
+fakeMongoConnection = FakeMongoConnection()
+
+
+class FakeMongoConnectionPool(object):
+ """Fake mongodb connection pool."""
+
+ #maybe this is better:
+ #def __init__(self, host='localhost', port=27017,
+ # connectionFactory=lambda host, port, tz=False: fakeMongoConnection,
+ # logLevel=20):
+ # self.connection = connectionFactory(host, port)
+
+ def __init__(self, host='localhost', port=27017,
+ connectionFactory=fakeMongoConnection, logLevel=20):
+ self.connection = fakeMongoConnection
+
+ def disconnect(self):
+ self.connection.disconnect()
+
+# single shared connection pool instance
+fakeMongoConnectionPool = FakeMongoConnectionPool()
+
Property changes on: m01.mongofake/trunk/src/m01/mongofake/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Date Author Id Revision
Added: svn:eol-style
+ native
More information about the checkins
mailing list