3

I have started writing a simple module for mongodb to use. I am new to python and I have been a problem with the code I wrote:

import pymongo


class mongoDB():

    conn = object

    def __init__(self):
        global conn
        self.conn = pymongo.Connection("localhost",27017)

    def CreateCollection(self,name =""):
        self.dbCollection  = conn.name
        return self.dbCollection

if __name__ == '__main__':
    database = mongoDB
    collection = database.CreateCollection("Hello")

Firstly I think there are probably few things wrong with my code if you can spot it and correct me. Also I am keep getting this erro:

collection = database.CreateCollection("Hello")
TypeError: unbound method CreateCollection() must be called with mongoDB      

instance as first argument (got str instance instead)

I want to be able to create the connection in the constructor of the class and then have a method for creating a collection and returning it, and also another method to insert delete and update the entities

5
  • 1
    As a suggestion, I would get all this worked out at the Python command line without introducing classes. Just having a look, your TypeError could be caused because your methods in the class are not prefixed with self. like this class GlobalData: def set_xfer_date(self, value): self.xfer_date = value self.date_str = str(value) self.xfer_date_base = self.date_str[0:10] + " " + "00:00:00" ... Commented Aug 6, 2012 at 16:58
  • 1
    I have tried the procedure in command line and now I want to create the module for it. I have tried it with "self" included as well but No luck. In my CreateCollection method I want to be able to pass a name when I am calling the function and replace the name in conn.name with the string I am passing in. Is that the correct way to go about it ? Commented Aug 6, 2012 at 17:31
  • 1
    I think you misunderstood some of the python basics. Neither global conn nor conn = object really make sense in your code. Commented Aug 6, 2012 at 17:31
  • 1
    right, I wanted to use the conn object created in init in my other function, So I read somewhere that I need to use global keyword for that. But then they first defined the variable in the class (outside any function) and in function they added the global keyword to the variable. Thats what I was trying to do, defining that conn as an object and then creating the connection inside init . for the other method I want to pass in names and create a collection corresponding to that name rather than calling it like database.[nameofcollection] Commented Aug 6, 2012 at 17:42
  • @esaelPsnoroMoN 'A big downvote for tinkering' - not the proper way to use a downvote. Bad code is not a bad question Commented Sep 18, 2012 at 11:36

2 Answers 2

19

So, syntax wise you have a number of problems. It looks like you're mixing a couple of tutorials in different ways. So, firstly I'll explain what is going on with your code and explain why you're seeing what you're seeing:

import pymongo

class mongoDB():  # you don't need ()'s here - only if you are inheriting classes
                  # you could inherit from object here, which is a good practice
                  # by doing class mongoDb(object):, otherwise you can just take
                  # them out

    conn = object # here, you're defining a class member - global for all instances
                  # generally, you don't instantiate an object pointer like this,
                  # you would set it to None instead.  It won't fail doing this,
                  # but it's not "right"

    def __init__(self):
        # the __init__ method is the constructor method - this will 
        # allow you to initialize a particular instance of your class, represented
        # by the self argument.  This method is called when you call the class, i.e.
        # inst = mongoDb()

        # in this case, the conn variable is not a global.  Globals are defined
        # at the root module level - so in this example, only pymongo is a global
        # conn is a class member, and would be accessed by doing mongoDB.conn
        global conn

        # with that being said, you're initializing a local variable here called conn
        # that is not being stored anywhere - when this method finishes, this variable
        # will be cleaned up from memory, what you are thinking you're doing here
        # should be written as mongoDB.conn = pymongo.Connection("localhost", 27017)
        conn = pymongo.Connection("localhost",27017)

    def CreateCollection(name =""):
        # there is one of two things you are trying to do here - 1, access a class 
        # level member called conn, or 2, access an instance member called conn

        # depending on what you are going for, there are a couple of different ways 
        # to address it.

        # all methods for a class, by default, are instance methods - and all of them
        # need to take self as the first argument.  An instance method of a class
        # will always be called with the instance first.  Your error is caused because
        # you should declare the method as:

        # def CreateCollection(self, name = ""):

        # The alternative, is to define this method as a static method of the class -
        # which does not take an instance but applies to all instances of the class
        # to do that, you would add a @staticmethod decorator before the method.

        # either way, you're attempting to access the global variable "conn" here,
        # which again does not exist

        # the second problem with this, is that you are trying to take your variable
        # argument (name) and use it as a property.  What python is doing here, is
        # looking for a member variable called name from the conn object.  What you
        # are really trying to do is create a collection on the connection with the
        # inputed name

        # the pymongo class provides access to your collections via this method as a
        # convenience around the method, create_collection.  In the case where you
        # are using a variable to create the collection, you would call this by doing

        # conn.create_collection(name)

        # but again, that assumes conn is what you think it is, which it isn't
        dbCollection  = conn.name
        return dbCollection

if __name__ == '__main__':
    # here you are just creating a pointer to your class, not instantiating it
    # you are looking for:

    # database = mongoDB()
    database = mongoDB

    # this is your error, because of the afore mentioned lack of 'self' argument
    collection = database.CreateCollection("Hello")

I'd say have a look through the Pep-8 (http://www.python.org/dev/peps/pep-0008/) coding style guides (very helpful) to learn about how to make your code "flow" pythonically.

Having gone through your code to explain what is going on - this is what you are ultimately trying to do:

import pymongo

class MongoDB: # Classes generally are camel-case, starting with uppercase
    def __init__(self, dbname):
        # the __init__ method is the class constructor, where you define
        # instance members.  We'll make conn an instance member rather
        # than a class level member
        self._conn = pymongo.Connection("localhost", 27017)
        self._db   = self._conn[dbname]

    # methods usually start with lowercase, and are either camel case (less desirable
    # by Python standards) or underscored (more desirable)
    # All instance methods require the 1st argument to be self (pointer to the
    # instance being affected)
    def createCollection(self, name=""):
        return self._db[name]

if __name__ == '__main__':
    # you want to initialize the class
    database   = MongoDB("Hello")
    collection = database.createCollection("MyTable")

Given that tho - what is the goal of writing this class wrapper? The same could be written as:

import pymongo
conn       = pymongo.Connection('localhost', 27017)
database   = conn["Hello"]
collection = database["MyTable"]

If you're trying to create a larger API wrapped around the pymongo database, then I'd recommend looking into some ORM modules that have already been built. There are some out there - not 100% sure which ones are available for MongoDB, but the one I use (I am biased, I wrote it) is called ORB, and can be found at http://docs.projexsoftware.com/api/orb

Sign up to request clarification or add additional context in comments.

7 Comments

Your code is exactly what I want to do and it looks right but when I run it i get the same error: unbound method createCollection() must be called with MongoDB instance as first argument (got str instance instead)
Are you using the first or second example? The first example is still broken...the second example SHOULD work...could you paste exactly what you have?
I am using the first example. The second one should work but the first example is what I am after.
actually this is the error i am getting with the first example : TypeError: 'Database' object is not callable. If you meant to call the 'create_collection' method on a 'Connection' object it is failing because no such method exists.
Ok, yea - you're right - I didn't really think through the full problem, just the syntax. I updated the code examples to reflect better what I mean. Hope it helps
|
1

This is not a specific answer to how to solve your problem, but instead an answer for how to step through what you want to do and work on simpler problems as they arise:

1) Forget about classes at first, and instead

2) Use the Python command line or a Python program like IDLE,

3) To establish your goals by writing calls to open the MongoDB database to accomplish your task or tasks. In other words, write the simplest code to accomplish your goals before worrying about classes.

4) Once you get that done, and feel good to move on, then write a test class using the documentation. My link is one of many you could find.

5) I think part, but not all, of your problem is your class is not set up correctly. My class -- not shown completely -- is as follows:

class GlobalData:
    def set_xfer_date(self, value):
        self.xfer_date = value
        self.date_str = str(value)
        self.xfer_date_base = self.date_str[0:10] + " " + "00:00:00"

        # Now build tomorrow.
        self.xfer_date_tomorrow = datetime.today() + timedelta(1)
        self.date_str_tomorrow = str(self.xfer_date_tomorrow) 
        self.xfer_date_tomorrow = \
          self.date_str_tomorrow[0:10] + " " + "00:00:00" 

        self.section_totals = {}
        self.billable_reads = {}

    def set_xfer_fnam_out(self, value):
        self.xfer_fnam_out = value

    def set_xfer_dir_in(self, value):
        self.xfer_dir_in = value
    .
    .
    .

    def get_billable_reads(self):
        return self.billable_reads

One of the problems I see is you are not referring to data using self. Good luck.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.