python: encapsulate data without a class? - python

I have a module in python that provides various functions for performing database queries.
It looks like this:
def do_some_query(conn):
## logic goes here
def do_something_else(conn):
## logic goes here
Where conn is a database connection object. Of course, this means a lot of passing around of the conn object.
I'd like to allow the user to just set the connection object once for their session and then call the functions.
OBVIOUSLY putting the whole thing in a class is a good answer, but I dont want to have to make the user initialise a class each time they want to use the functions.
I.E, I dont want the API to be like this:
from database_module import DatabaseClass
db = DatabaseClass()
db.connect(...)
db.do_some_query()
But like this:
import database_module as dm
dm.connect(...)
dm.do_some_query()
Is there a way to either 'hide' the class from a user, or provide encapsulation without the class?

You can have a connect function that puts the connection in a global variable, and the other functions will use it.
_conn = None
def connect():
global _conn
_conn = ...
def query():
_conn.execute("SELECT ...")

Related

in Django, can I use a class only to group functions?

I am creating an application using Django. The application has user registration and login functionality.
I have three functions related to user authentication as of now, login, registration, and email_check (which is called when the user types email address to see if it is available). I was trying to group these functions under a class for better organisation and easy accessibility.
So I wrote a class and function like so:
class user_auth:
def check_email(email):
with connection.cursor() as conn:
conn.execute('select count(*) from user_info where email = %s', [email])
row = conn.fetchall()
response = bool(row[0][0])
return(response)
However, when I do this, I get a pylint error saying Method should have "self" as the first argument.
If I save this and call it as user_auth.check_email('abc#xyz.com'), it works just fine. But if I add self as the first argument, it stops working.
Am I using classes in an incorrect way? If yes, what is a better way to create a group of functions like this which can be easily imported using a single statement in other files?
As in the comments said, you could use a module for it.
Otherwise if you want to group them inside a class you just need to use the staticmethod or classmethod decorator.
Example:
class user_auth:
#classmethod
def check_email(cls, email):
...
#staticmethod
def static_check_email(email):
...

Create a class for reading in files: creating an SQL api with distinct methods

This question is more about how one uses OOP to read in databases. SQLite and sqlite3 are simply examples to work with, and are not the main thrust of the question:
I am creating a software package which allows users to query SQLite index files which have already been generated. It's basically syntactic to make it super user-friendly to query SQLite files indexed in a certain way, for a very particular case This should be quite straightforward, but I am somewhat confused how to "automatically" read in the SQLite
Here's an example (with pseudo-code):
import sqlite3
Class EasySQL:
def __init__(self, filepath):
self.filepath = filepath
def connect(self, filepath): ## perhaps this should be above in init?
return sqlite3.connect(self.filepath)
def query_indexA(self):
## query index A on SQLite3 connection
I would prefer the connection to the SQLite database to be "automatic" upon instantiation of the class:
### instantiate class
my_table1 = EasySQL("path/to/file")
At the moment, users one need to call the function .connect() after instantiation.
my_table = EasySQL("path/to/file")
the_object_to_do_queries = my_table.connect()
## now users can actually use this
the_object_to_do_queries.query_indexA()
This seems like bad form, and unnecessarily complicated.
How does one write the the initialization method to immediately create the SQLite3 connection?
Hopefully this question is clear. I am happy to edit if not.
The main point here is that EasySQL should not return the connection (which makes it mostly useless) but use it internally by keeping a reference to it:
class EasySQL(object):
def __init__(self, filepath):
self._filepath = filepath
self._db = sqlite3.connect(self.filepath)
def close(self):
if self._db:
self._db.close()
self._db = None
def query_indexA(self):
# XXX example implementation
cursor = self._db.cursor()
cursor.execute("some query here")
return cursor.fetchall()

How do I make class variables/methods created and used only when needed?

I'm working on a model that uses player data. During development, only certain data is needed. My thought was to create a PlayerData class but my amateur mind doesn't understand/know how to do this properly.
I understand this code is basic, but it's just for example...
class PlayerData(object):
def __init__(self, player_id):
self.player_id = player_id
def past_games(self):
# only if requested, query DB for data
def vital_info(self):
# only if requested, query DB for data
def abilities(self):
# only if requested, query DB for data
pd = PlayerData(235)
If I call pd.vital_info for the first time, I only want to execute the query at that point. How do I structure this so the requested query is run while the other queries are not (unless needed later on)?
The following code should help you understand how functions of a class are called in Python.
class PlayerData:
def __init__(self,player_id):
print("Calling __init__. Yay!")
self.player_id = player_id
def past_games(self):
print("Calling past_games")
# only if requested, query DB for data
def vital_info(self):
print("Calling vital_info")
# only if requested, query DB for data
def abilities(self):
print("Calling Abilities")
# only if requested, query DB for data
>> p = PlayerData(1)
Calling __init__. Yay! #No other method was called so you see not print out
>>p.past_games()
Calling past_games
>>p.vital_info()
Calling Vital info
>>p.abilities()
Calling Abilities
As you see the class functions need to be explicitly called. There are only a handful of methods that are called when class is initializer. One them is __init__
You don't need to do anything at all. If your queries are in individual methods, then only the methods you actually call will be executed.

Writing a simple MongoDB module in python

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
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
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.

Python: inject new functions into an instance of class?

I tried to manipulate the __mro__ but it it read-only
The use case is as follow:
The Connection object created from pyodbc (a DBAPI) used to provide a property called 'autocommit'. Lately I have wrapped a SQLAlchemy db connection pool around the pyodbc for better resource management. The new db pool will return a _ConnectionFairy, a connection proxy class, which no longer exposes the autocommit property.
I would very much want to leave the thrid party code alone. So inheritance of _ConnectionFairy is not really an option (I might need to override the Pool class to change how it creates a connection proxy. For source code, please see here)
A rather not-so elegant solution is to change all occurance of
conn.autocommit = True
to
# original connection object is accessible via .connection
conn.connection.autocommit = True
So, I would like to know if it is possible at all to inject a set of getter, setter and property to an instance of _ConnectionFairy
You can "extend" almost any class using following syntax:
def new_func(self, param):
print param
class a:
pass
a.my_func = new_func
b = a()
b.my_func(10)
UPDATE
If you want to create some kind of wrappers for some methods you can use getattr and setattr to save original method and replace it with your implementation. I've done it in my project but in a bit different way:
Here is an example:
class A:
def __init__(self):
setattr(self, 'prepare_orig', getattr(self,'prepare'))
setattr(self, 'prepare', getattr(self,'prepare_wrapper'))
def prepare_wrapper(self,*args,**kwargs):
def prepare_thread(*args,**kwargs):
try:
self.prepare_orig(*args,**kwargs)
except:
print "Unexpected error:", sys.exc_info()[0]
t = threading.Thread(target=prepare_thread, args=args, kwargs=kwargs)
t.start()
def prepare(self):
pass
The idea of this code that other developer can just implement prepare method in derived classed and it will be executed in the background. It is not what you asked but I hope it will help you in some way.

Categories