Siyuan Miao
Siyuan Miao

Reputation: 754

PyMongo Strange Error "TypeError: 'Database' object is not callable."

I got a strange error.

Source: __init__.py

import os
import base64
import uuid

import tornado.web
import tornado.httpserver
import tornado.locale
import tornado.ioloop
import tornado.options

from tornado.options import define, options

from pymongo.connection import Connection
from pymongo.database import Database

from handlers import api
#from auth import AuthLoginHandler
#from auth import AuthLogoutHandler
#from auth import AuthFirstRunHandler
from handlers import home

## Options
define("listen_port",       default = 7456, type = "int", 
                help = "bind to port")

define("listen_address",    default = None, type = "string",
                help = "bind to address")

define("static_path",       default = os.path.join(os.path.dirname(__file__), "static"), type = "string",
                help = "directory to store static resource")

# http://www.v2ex.com/t/12646
define("cookie_secret",     default = base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes), type = "string",
                help = "cookie")

define("mongo_host",        default = "127.0.0.1", type = "string",
                help = "hostname or ip of mongo host")

define("mongo_port",        default = 27017, type = "int",
                help = "port of mongo host")

define("mongo_collection",  default = "meowth", type = "string",
                help = "collection name")

tornado.options.parse_command_line()

class Application(tornado.web.Application):
    def __init__(self):
        tornado.web.Application.__init__(self, [
            (r"/i", home.HomeHandler),
        #   (r"/auth/login", AuthLoginHandler),
        #   (r"/auth/logout", AuthLogoutHandler),
        #   (r"/auth/install", AuthFirstRunHandler),
        #   (r"/backstage", BackstageHomeHandler),
            (r"/api/cluster", api.APIHandler),
            (r"/api/user", api.APIHandler),
            (r"/api/connection", api.APIHandler),
            (r"/api/control", api.APIHandler),
            (r"/static/(.*)", tornado.web.StaticFileHandler, { "path" : options.static_path })
        ],** dict(
            xsrf_cookies = True,
            cookie_secret = options.cookie_secret
        ))

        # init database connection
        self.mongo = Database(
            Connection(
                options.mongo_host,
                options.mongo_port
            ),
            options.mongo_collection
        )
        #self.mongo = self.mongoConnection[options.mongo_collection]
        #self.mongo = self.mongoConnection.meowth

def main():
    if options.listen_address == None:
        tornado.httpserver.HTTPServer(Application()).listen(options.listen_port)
    else:
        tornado.httpserver.HTTPServer(Application()).listen(options.listen_port, address = options.listen_address)

    tornado.ioloop.IOLoop.instance().start()

if __name__ == "__main__":
    main()

base.py

# -*- coding: utf8 -*-
import tornado.web
import pymongo

class BaseHandler(tornado.web.RequestHandler):

    def __init__(self, application, request, **kwargs):
        tornado.web.RequestHandler.__init__(self, application, request, **kwargs)
        self.session_id = self.get_secure_cookie("meowth_session")
        self.session = {}

    @property
    def db(self):
        print self.application.mongo
        return self.application.mongo

    def init_session(self):
        if not self.session_id:
            self.session_id = self.db().meowth_sessions.save(
                {"data" : self.session}
            )
        else:
            self.session = self.db().meowth_sessions.find_one(
                {"_id" : self.session_id}
            )

    def flush_session(self):
        self.db().meowth_sessions.save(
                {"data" : self.session,
                 "_id"  : self.session_id
                }
            )

    def is_spider(self):
        # https://bitbucket.org/keakon/doodle/src/3ddf46ac59e7/zh-CN/common.py#cl-512
        user_agent = self.request.headers["User-Agent"]
        if 'bot' in user_agent or 'spider' in user_agent:
            return True
        return False

Error:

> [root@CloudK02 Meowth]# ./Meowth-Web Database(Connection('127.0.0.1',
> 27017), u'meowth') [E 120219 15:07:54 web:1031] Uncaught exception GET
> /i (122.94.31.186)
>     HTTPRequest(protocol='http', host='us1.loli.vg:7456', method='GET', uri='/i', version='HTTP/1.1', remote_ip='122.94.31.186',
> body='', headers={'Accept-Language': 'en-US,en;q=0.8',
> 'Accept-Encoding': 'gzip,deflate,sdch', 'Host': 'us1.loli.vg:7456',
> 'Accept':
> 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
> 'User-Agent': 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML,
> like Gecko) Chrome/17.0.963.56 Safari/535.11', 'Accept-Charset':
> 'ISO-8859-1,utf-8;q=0.7,*;q=0.3', 'Connection': 'keep-alive',
> 'Cookie': 'PHPSESSID=rm4ght6ivop9a1hf5oogcft3j4;
> session_id="MzZkODNiMWMyZjczOWZhNzcxYjU4YTNjNzVhZjA4Yzc=|1329674350|2562f7ed871c1ca3e24dcb5891d6e753cfacfa44";
> rock_format=json', 'Cache-Control': 'max-age=0'})
>     Traceback (most recent call last):
>       File "/usr/local/lib/python2.6/site-packages/tornado/web.py", line 988, in _execute
>         getattr(self, self.request.method.lower())(*args, **kwargs)
>       File "/home/aveline/Meowth/web/handlers/home.py", line 7, in get
>         self.init_session()
>       File "/home/aveline/Meowth/web/handlers/base.py", line 19, in init_session
>         self.session_id = self.db().meowth_sessions.save(
>       File "build/bdist.linux-x86_64/egg/pymongo/database.py", line 696, in __call__
>         "failing because no such method exists." % self.__name)
>     TypeError: 'Database' object is not callable. If you meant to call the 'meowth' method on a 'Connection' object it is failing because no
> such method exists.

It works well if I use self.mongo in class Application. But I got an error if I use it in class BaseHandler.

Why?

Upvotes: 3

Views: 17102

Answers (1)

Katriel
Katriel

Reputation: 123722

You've defined db as a property, meaning that you don't have to call it. But then you call it!

Either remove the @property or use self.db instead of self.db().


As always, Python's error messages are informative and you should look at them! In this case, you can see

TypeError: 'Database' object is not callable. If you meant to call the 'meowth' method on a 'Connection' object it is failing because no such method exists.

which means that you are calling (i.e. like a function) a database object somewhere. Where?

File "/home/aveline/Meowth/web/handlers/base.py", line 19, in init_session
    self.session_id = self.db().meowth_sessions.save(

See? self.db is a property, so gives you self.application.mongo. Then you call it, so the above line is equivalent to

self.session_id = self.application.mongo().meowth_sessions.save(

which is obviously wrong.

Upvotes: 7

Related Questions