What is the best way to expose a variable from a module?
import otherDBInterface as odbi
def create(host):
global connection
global cursor
connection = odbi.connect(host)
cursor = connection.cursor()
...
I want to expose the cursor variable in the module so I can do something like mydb.cursor.execute("select * from foo;"). I thought using the global keyword would do this but no such luck. cursor is an object so I am not sure how I would declare it so that it would be exposed.
You can wrap your connection information in a class
class Database:
def __init__(self, **kwargs):
if kwargs.get("connection") is not None:
self.connection = kwargs["connection"]
elif kwargs.get("host") is not None:
self.connection = odbi.connect(host)
self.cursor = self.connection.cursor()
mydb = Database(host="localhost")
results = mydb.cursor.execute("select * from foo")
#or use it with a connection
mydb = Database(connection="localhost")
results = mydb.cursor.execute("select * from foo")
Any variable created on a module level is "exposed" by default.
Hence, a module like this will have three exposed variables:
configpath = '$HOME/.config'
class Configuration(object):
def __init__(self, configpath):
self.configfile = open(configpath, 'rb')
config = Configuration(configpath)
The variables are configpath, Configuration and config. All of these are importable from other modules. You can also access configs configfile as config.configfile.
You can also have configfile accessible globally this way:
configpath = '$HOME/.config'
configfile = None
class Configuration(object):
def __init__(self, configpath):
global configfile
configfile = open(configpath, 'rb')
config = Configuration(configpath)
But there are various tricky problems with this, as if you get a handle on configfile from another module and it then gets replaced from within Configuration your original handle will not change. Therefore this only works with mutable objects.
In the above example that means that using configfile as a global in this way will not be very useful. However, using config like that could work well.
Related
I have a few files in my code that speak to the database
This might look something like this:
def addUser():
# some code
def verifyUser():
# some code
def addStuffToDB():
# some code
In all of the above I need to use a variable - let's call it db - that holds a reference to the database (as opposed to redefining it in every function)
How would I do this? How can I have functions in one or more files that all make use of a variable (in this case db)
Thanks
If you have all this functions inside the same file, it is enough to just define variable db outside any function (this will make it global). Now all functions will be able to see db variable. But if you change db inside a function it will not change outside the function.
If you have this variable in another file you can simple import it like
from file_name import db
As #ddejohn said, you should wrap your functions in a class, so the variable self.db would have a class scope.
class DB():
def __init__(self) -> None:
self.db = "DB_connection or something..."
def addUser(self):
#Some code, acess db variable with self.db
def verifyUser(self):
#Some code, acess db variable with self.db
def addStuffToDB(self):
#Some code, acess db variable with self.db
MyDB = DB()
MyDB.addUser()
Thanks for asking the question.
You need to pass db as argument while calling the funcs like the following
db = "some referenec"
def addUser(database):
## now you can use db
# some code
def verifyUser(database):
# some code
## now you can use db
def addStuffToDB(database):
# some code
## now you can use db
## while calling each func pass db as argument like this
addUser(db)
verifyUser(db)
addStuffToDB(db)
add a db paramenter to yout funcs:
controller.py:
def addUser(db): # some code
obj.add(db)
def verifyUser(db): # some code
obj.verify(db)
def addStuffToDB(db): # some code
obj.add_stuff(db)
Then, you can use as follows:
view.py
import db
from controller import addUser
addUser(db)
I am currently working on a huge project, which constantly executes queries. My problem is, that my old code always created a new database connection and cursor, which decreased the speed immensivly. So I thought it's time to make a new database class, which looks like this at the moment:
class Database(object):
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = object.__new__(cls)
try:
connection = Database._instance.connection = mysql.connector.connect(host="127.0.0.1", user="root", password="", database="db_test")
cursor = Database._instance.cursor = connection.cursor()
except Exception as error:
print("Error: Connection not established {}".format(error))
else:
print("Connection established")
return cls._instance
def __init__(self):
self.connection = self._instance.connection
self.cursor = self._instance.cursor
# Do database stuff here
The queries will use the class like so:
def foo():
with Database() as cursor:
cursor.execute("STATEMENT")
I am not absolutly sure, if this creates the connection only once regardless of how often the class is created. Maybe someone knows how to initialize a connection only once and how to make use of it in the class afterwards or maybe knows if my solution is correct. I am thankful for any help!
Explanation
The keyword here is clearly class variables. Taking a look in the official documentation, we can see that class variables, other than instance variables, are shared by all class instances regardless of how many class instances exists.
Generally speaking, instance variables are for data unique to each instance and class variables are for attributes and methods shared by all instances of the class:
So let us asume you have multiple instances of the class. The class itself is defined like below.
class Dog:
kind = "canine" # class variable shared by all instances
def __init__(self, name):
self.name = name # instance variable unique to each instance
In order to better understand the differences between class variables and instance variables, I would like to include a small example here:
>>> d = Dog("Fido")
>>> e = Dog("Buddy")
>>> d.kind # shared by all dogs
"canine"
>>> e.kind # shared by all dogs
"canine"
>>> d.name # unique to d
"Fido"
>>> e.name # unique to e
"Buddy"
Solution
Now that we know that class variables are shared by all instances of the class, we can simply define the connection and cursor like shown below.
class Database(object):
connection = None
cursor = None
def __init__(self):
if Database.connection is None:
try:
Database.connection = mysql.connector.connect(host="127.0.0.1", user="root", password="", database="db_test")
Database.cursor = Database.connection.cursor()
except Exception as error:
print("Error: Connection not established {}".format(error))
else:
print("Connection established")
self.connection = Database.connection
self.cursor = Database.cursor
As a result, the connection to the database is created once at the beginning and can then be used by every further instance.
Kind of like this. It's a cheap way of using a global.
class Database(object):
connection = None
def __init__(self):
if not Database.connection:
Database.connection = mysql.connector.connect(host="127.0.0.1", user="root", password="", database="db_test")
def query(self,sql):
cursor = Database.connection.cursor()
cursor.execute(sql)
# Do database stuff here
This too does work and you are guaranteed to always have one instance of the database
def singleton(class_):
instances = {}
def get_instance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
return get_instance
#singleton
class SingletonDatabase:
def __init__(self) -> None:
print('Initializing singleton database connection... ', random.randint(1, 100))
The Reason you have to do all this is if you just create
a connection once and leave it at that you then
will end up trying to use a connection which is dropped
so you create a connection and attach it to your app
then whenever you get a new request check if the connection
still exists, with before request hook if not then recreate the
connection and proceeed.
on create_app
def create_app(self):
if not app.config.get('connection_created'):
app.database_connection = Database()
app.config['connection_created'] = True
on run app
#app.before_request
def check_database_connection(self):
if not app.config.get('connection_created') or not app.database_connection:
app.database_connection = Database()
app.config['connection_created'] = True
this will insure that your application always runs with an active connection
and that it gets created only once per app
if connection is dropped on any subsequent call then it gets recreated again...
I am facing weird error when I try to access self.cursor_dat' from class in different script. It says:ImportError: cannot import name query_selection_class`. The error also occur without trying to access the variable. There is just something wrong with the import command.
here is the file1.py where I create the variable:
class connection_settings_class(QtGui.QMainWindow,Ui_main_connection_settings_window):
def __init__(self):
self.create_connection_window()
self.host = 'localhost'
self.port = '3307'
self.user = 'root'
self.password = ''
self.database = 'rtr'
def connection(self):
""" connect to the database and create cursor that will be used to exetute MySQL queries """
try:
self.cnxn = pyodbc.connect(driver = '{MySQL ODBC 5.3 ANSI Driver}', # ANSI or Unicode
host = self.host,
port = self.port,
user = self.user,
password = self.password,
database = self.database)
except:
print('Connection FAIL')
**self.cursor_dat** = self.cnxn.cursor()
**self.cursor_dat**.execute("""SELECT * FROM test_db.attempt;""")
row = **self.cursor_dat**.fetchone()
if row:
print("Succesfully connected to the database.")
print row
self.status_label.setText("Connected")
else:
print("Connection FAIL")
self.status_label.setText("Disconnected")
def create_connection_window(self):
...rest of the code
...and here is file2
import file1 -> I also tried from file1 import connection_settings_class
class plausible_implausible_class(QtGui.QMainWindow,Ui_plausible_implausible_win):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setupUi(self)
self.show()
sc = MyStaticMplCanvas(self.centralwidget, width=500, height=400, dpi=100)
self.verticalLayout_3.addWidget(sc)
**a = file1.connection_settings_class.cursor_dat**
I might be making a really dumb mistake looking at your sample, but what I see is this:
self.cursor_dat= self.cnxn.cursor()
is defined in the connection_settings_class.connection() method. You never call connection(), so that property never gets created.
Also I noticed that you're calling the class statically, rather than creating an instance of the class but you've created no static properties, they're all created on __init__. You may want to create an instance of your class, which then defines the cursor_dat to be None initially.
If you want connection sharing you can set up a pool of connections and still create individual instances.
Ok, there is not problem with the path because all the scripts that #tdelaney mentioned were positive. The result of for cycle is '/Users/BauchMAC/PycharmProjects/py_GUI/Database_GUI' --> True. And the working directory which I got using os.getcwd() is same.
I also tried to create two new scripts and everything worked. So the problem is that I don't understand to "importing rules" in python because this is the source of the problem.
So there is obviously problem with crossing of imports. And the way to solve it is by passing the value as the parameter.
Below you can see how I wanted to do it and the reason for the error:
file1:
from try4 import ClassB
class ClassA():
def __init__(self):
self.cursor_dat = 1
self.query_selection_win = ClassB()
object1 = ClassA()
file 2:
from try3 import ClassA <-- source of the probles
class ClassB():
def __init__(self, cursor_dat):
print(ClassA.cursor_dat)
And here is how it should be (at least it works, I am not sure if it is the best way how to do it, I am still newbie)
file 1:
from try4 import ClassB
class ClassA():
def __init__(self):
self.cursor_dat = 1
self.query_selection_win = ClassB(self.cursor_dat)
object1 = ClassA()
file 2:
class ClassB():
def __init__(self, cursor_dat):
print(cursor_dat)
I hope it will be helpful to some newbie like me :)
I'm trying inherit psycopg2 like this:
import psycopg2
class myp(psycopg):
pass
ii = myp
ii.connect(database = "myDataBase", user = "myUser", password="myPassword")
Then it throws an error:
class myp(psycopg2._psycopg):
TypeError: Error when calling the metaclass bases
module.__init__() takes at most 2 arguments (3 given)
Is it possible to inherit from psycopg2 library?
EDIT:
I want to use different databases, so I just have to change the class MyDatabase. something like a wrapper.
example:
import psycopg2
class MyDatabase(psycopg2):
def connect(self):
#do some stuff
return psycopg2.connect(database = "myDataBase", user = "myUser", password="myPassword")
for mysqldb
import MySQLdb
class MyDatabase(MySQLdb)
def connect(self):
#do some stuff
return psycopg2.connect(database = "myDataBase", user = "myUser", password="myPassword")
and derived class
class MyDataBaseApp(MyDatabase):
def add(self, myObjectClass):
db = MyDatabase()
cn = None
try:
cn = db.connect()
cur = cn.cursor()
cur.execute ("INSERT ...",(myObjectClass.parameter1, myObjectClass.parameter2))
cn.commit()
except MyDatabase.DatabaseError, e:
print e
if cn:
cn.rollback()
finally:
if cn:
cn.close()
but according to the documentation I have to do it another way, suggestions?
Disclaimer: I'm not familiar with psycopg
Update
Seems the documentation recommends to subclass psycopg2.extensions.connection. Then, connect() is a factory function that can still be used to create new connections, but you have to provide your class as a factory, again according to the docs
Full code may have to look more like (untested):
import psycopg2
class myp(psycopg2.extensions.connection):
pass
ii = connect(connection_factory=myp,
database = "myDataBase", user = "myUser", password="myPassword")
Update 2
With the updated approach, you're trying to build new classes with different/divergent interfaces. Often, composition is better than inheritance, see wikipedia and this question.
Noobish question to be sure. I have tried to move some common code into a separate module and use the code as an imported function. The code makes a MySQL query through MySQLdb. When the function is part of the main script, it runs just fine. When I import the function from a separate module, the function fails because the cursor object is no longer defined. Is there a way to import functions without defining a separate cursor object for just the imported function?
Here is an coded example. This works:
import MySQLdb
#from mod2 import lookup_value
def get_db_connection(database_name):
db = MySQLdb.connect('localhost', 'user', 'pswrd', database_name)
cur = db.cursor()
return db, cur
def lookup_value(user_name):
query = "SELECT COUNT(*) FROM x_user_%s" % (user_name)
cur.execute("%s" % (query))
return cur.fetchone()
db_name = 'mg_test' # database name
user_name = 'test' # name of a specific table in the database
db, cur = get_db_connection(db_name)
value = lookup_value(user_name)
When I move the code for lookup_value to a second file, and import it ('from mod2 import lookup_value'), the code fails because the cursor object is undefined. The imported version of lookup_value only works if I create a cursor object for its use. This seems very inefficient. What is the best way to handle this problem?
That's because lookup_value searches for the cur within the file you import it in. You could put this all in a class.
class DB():
def __init__(self,database_name):
db = MySQLdb.connect('localhost', 'user', 'pswrd', database_name)
self.cur = db.cursor()
def lookup_value(self,user_name):
query = "SELECT COUNT(*) FROM x_user_%s"
self.cur.execute(query, (user_name,))
self.result = self.cur.fetchone()
return self.result
now you can do
....
db = DB(db_name)
value = db.lookup_value(user_name)
when you import the DB from mod2 import DB the last part should still work.
Also take note of how i execute the query in lookup_value this ensures the data is sanitized
You should pass a cursor variable to your functions if you want them to be independent.
In any case you should use in a function only local variables and variables passed as parameters.