kronosapiens
kronosapiens

Reputation: 1441

MongoAlchemy StringField unexpectedly replaced with QueryField?

I've been struggling with an odd bug while working with MongoAlchemy.

I have a name = db.StringField() on my Participant model. Most of the time it works fine, but for some reason, the field is occasionally overwritten by a QueryField. If I re-load my Participant class from the module, it works fine for a while, but then breaks again.

Here is a terminal session where this occurred:

In [99]: from webapp.models import *

In [100]: Participant.by_name('yaronTesting') # My own method, which filters by name
Out[100]: <Participant yaronTesting>

In [101]: Participant.query.all()
Out[101]: [<Participant name>, <Participant name>]

# What?

In [102]: Participant.query.all()[0]
Out[102]: <Participant name>

In [103]: Participant.query.all()[0].name
Out[103]: QueryField(name)

In [104]: from webapp.models import Participant

In [105]: Participant.query.all()
Out[105]: [<Participant yaronTesting>, <Participant tsviki>]

In [106]: Participant.query.all()[0].name
Out[106]: u'yaronTesting'

I'm new to MongoDB and quite nervous about putting this into production -- does anyone know what might be going on behind the scenes?

So in response to Jeff's comment, I've got another session where the issue happens outside of querying:

In [168]: tsviki_old
Out[168]: <Participant name>

In [169]: tsviki_old.mongo_id
Out[169]: ObjectId('53f4f27a6c4dae23aba41419')

In [170]: tsviki_new = Participant.by_name('tsviki')
Out[170]: <Participant tsviki>

In [171]: tsviki_new.mongo_id
Out[171]: ObjectId('53f4f27a6c4dae23aba41419')

In [172]: tsviki_old.mongo_id
Out[172]: ObjectId('53f4f27a6c4dae23aba41419')

In [173]: tsviki_old
Out[173]: <Participant name>

In [174]: tsviki_new
Out[174]: <Participant tsviki>

In [175]: tsviki_old.name
Out[175]: QueryField(name)

In [176]: tsviki_new.name
Out[176]: u'tsviki'

In [179]: tsviki_old.created
Out[179]: QueryField(created)

In [180]: tsviki_old.modified
Out[180]: QueryField(modified)

In [181]: tsviki_old.sessions
Out[181]: QueryField(sessions)

# It happened again! To tsviki_new!

In [182]: tsviki_new.created
Out[182]: QueryField(created)

In [183]: tsviki_new
Out[183]: <Participant name>

In [184]: tsviki_new.name
Out[184]: QueryField(name)

In [185]: tsviki_new.mongo_id
Out[185]: ObjectId('53f4f27a6c4dae23aba41419')

I don't recall doing anything else while I was working on this last session, except maybe saving a file at one point. There seems to be some time-related component -- it usually occurs if I leave the interpreter for a while and come back, but there's no particular behavior I can pinpoint as having caused this.

Also, FYI:

@classmethod
def by_name(cls, name):
    return Participant.query.filter({'name': name}).first()

And finally, here is the error when I add the name field to the __init__ function and try to instantiate some objects (the earlier version passed no arguments to init):

In [36]: Participant.query.all()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-36-310f11265a76> in <module>()
----> 1 Participant.query.all()

/Users/kronosapiens/Dropbox/Documents/Development/code/environments/pm/lib/python2.7/site-packages/mongoalchemy/query.pyc in all(self)
    177     def all(self):
    178         ''' Return all of the results of a query in a list'''
--> 179         return [obj for obj in iter(self)]
    180 
    181     def distinct(self, key):

/Users/kronosapiens/Dropbox/Documents/Development/code/environments/pm/lib/python2.7/site-packages/mongoalchemy/query.pyc in next(self)
    410 
    411     def next(self):
--> 412         return self._next_internal()
    413     __next__ = next
    414 

/Users/kronosapiens/Dropbox/Documents/Development/code/environments/pm/lib/python2.7/site-packages/mongoalchemy/query.pyc in _next_internal(self)
    421             if obj:
    422                 return obj
--> 423             value = self.session._unwrap(self.type, value, fields=self.fields)
    424             if not isinstance(value, dict):
    425                 self.session.cache_write(value)

/Users/kronosapiens/Dropbox/Documents/Development/code/environments/pm/lib/python2.7/site-packages/mongoalchemy/session.pyc in _unwrap(self, type, obj, **kwargs)
    333     def _unwrap(self, type, obj, **kwargs):
    334         obj = type.transform_incoming(obj, session=self)
--> 335         return type.unwrap(obj, session=self, **kwargs)
    336 
    337     @property

/Users/kronosapiens/Dropbox/Documents/Development/code/environments/pm/lib/python2.7/site-packages/mongoalchemy/document.pyc in unwrap(cls, obj, fields, session)
    494         if fields is not None:
    495             params['retrieved_fields'] = fields
--> 496         obj = cls(loading_from_db=True, **params)
    497         obj._mark_clean()
    498         obj._session = session

/Users/kronosapiens/Dropbox/Documents/Development/code/jobs/paragon/webapp/webapp/models.py in __init__(self, name, **kwargs)
    319 
    320     def __init__(self, name, **kwargs):
--> 321         super(Participant, self).__init__(
    322             name=name,
    323             **kwargs)

TypeError: super(type, obj): obj must be an instance or subtype of type

Upvotes: 2

Views: 207

Answers (1)

Jeff Jenkins
Jeff Jenkins

Reputation: 158

MongoAlchemy author here. I'm not super familiar with the flask integration since someone else wrote it, but what must be happening here is that all() is returning an instance of the class Participant rather than an instance created from the database data.

If you can give a complete runnable example I could give you more details, but that's all I can glean from your question as stated.

Upvotes: 0

Related Questions