xtian
xtian

Reputation: 2947

How to pass args into a class to create instance of Python Singleton pattern wrapper for PyODBC?

Looking for examples of class patterns people use to wrap PyODBC, I found this example here at SO: single database connection throughout the python application.

I don't understand how the DBConnection class works in the original example. How is DBConnector being initialized if--

cls.connection = DBConnector().create_connection()

--doesn't pass the required init values to DBConnector()? When I try to add them I get TypeError: DBConnection() takes no arguments

import pyodbc    
class DBConnector(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, 'instance'):
            cls.instance = super(DBConnector, cls).__new__(cls)
        return cls.instance

    def __init__(self, ipaddress, port, dsn, remotedsn):
        self.ipaddress = ipaddress
        self.port = port
        self.dsn = dsn
        self.remotedsn = remotedsn
        self.dsnstr_default = 'OpenMode=F;OLE DB Services=-2;'
        self.dbconn = None

    # creates new connection
    def create_connection(self):
        return pyodbc.connect(self.dsnstr_default,
                                IPAddress = self.ipaddress,
                                Port = self.port,
                                DSN = self.dsn,
                                RemoteDSN = self.remotedsn,
                                autocommit=True)

    # For explicitly opening database connection
    def __enter__(self):
        self.dbconn = self.create_connection()
        return self.dbconn

    def __exit__(self):
        self.dbconn.close()

class DBConnection(object):
    connection = None

    @classmethod
    def get_connection(cls, new=False, *args, **kwargs): << ADDED THIS
        if new or not cls.connection:
            cls.connection = DBConnector(*args, **kwargs).create_connection()
                            /\/\/\/\/\/\/\/\/\/SEE NOTE 
        return cls.connection

    @classmethod
    def GetCompanyInfo(cls):
        """execute query on singleton db connection"""
        connection = cls.get_connection()
        try:
            connection.setencoding('utf-8')
            cursor = connection.cursor()
        except pyodbc.ProgrammingError:
            connection = cls.get_connection(new=True)
            cursor = connection.cursor()
        # Start Query
        cursor.execute("SELECT CompanyName, EIN, SSN FROM Company")
        for cname, ein, ssn in cursor.fetchall():
            result = (cname, ein, ssn)
        # End Query
        cursor.close()
        return result

Did some homework...

I can find several examples explaining the Singleton class pattern, so I've got the Connector class to work:

a = DBConnector('127.0.0.1', '4500', 'pyauto_local', None)
a.create_connection()
# <pyodbc.Connection at 0x5772110>
a = DBConnector('127.0.0.1', '4500', 'pyauto_local', None)
a.__enter__()
# <pyodbc.Connection at 0x605f278>
a.__exit__()

I did some testing...

I had a successful test manually inserting the connection parameters into the get_connection method:

cls.connection = DBConnector('127.0.0.1', '4500', 'pyauto_local', None).create_connection()
                             /\/\/\/\/\/\/ NOTED ABOVE
# Testing
cx = DBConnection()
cx.GetCompanyInfo()
# ('Zep', '12-3456789', None)

Now I'm curious

I could be done if I put the connection and queries all in the one class--Monster class.

OR I understand the Car > Blue Car OOP pattern better, and in another post here at SO is an example of extending the Singleton class. This makes more sense to me.

NOW I'm really curious how the original was supposed to work:

@classmethod
def get_connection(cls, new=False):
    """Creates return new Singleton database connection"""
    if new or not cls.connection:
        cls.connection = DBConnector().create_connection()
    return cls.connection

How to get the parameters into DBConnection class without INIT? The post is also tagged with Django, so they may have skipped an assumed Django context? Or Django gives it for free somehow?

Upvotes: 4

Views: 934

Answers (0)

Related Questions