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 :)
Related
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 try to use QRemoteObjects to share more than two objects but
i got "Dynamic metaobject is not assigned" warning while run client.py example, and i can't find out what happened, my example work fine, can anyone give me some advices?
server.py
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtRemoteObjects import *
from faker import Faker
fake = Faker()
class Name(QObject):
sig_name = pyqtSignal(str)
def __init__(self):
super().__init__()
self.name = ''
self.startTimer(1000)
def timerEvent(self, event):
self.name = fake.name()
self.sig_name.emit(self.name)
class Email(QObject):
sig_email = pyqtSignal(str)
def __init__(self):
super().__init__()
self.startTimer(1000)
def timerEvent(self, event):
self.sig_email.emit(fake.email())
class Server(QObject):
def __init__(self):
super().__init__()
self.name = Name()
self.email = Email()
host = QRemoteObjectHost(QUrl('local:server'), self)
r1 = host.enableRemoting(self.name, 'name')
r2 = host.enableRemoting(self.email, 'email')
print([r1, r2])
def print_name(self, x):
print(x)
app = QCoreApplication([])
s = Server()
app.exec()
client.py
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtRemoteObjects import *
class Client(QObject):
def __init__(self):
super().__init__()
node = QRemoteObjectNode(self)
node.connectToNode(QUrl("local:server"))
self.remote_name = node.acquireDynamic('name')
self.remote_email = node.acquireDynamic('email')
self.remote_name.initialized.connect(self.onInitName)
self.remote_email.initialized.connect(self.onInitEmail)
def onInitName(self):
self.remote_name.sig_name.connect(self.print_info)
def onInitEmail(self):
self.remote_email.sig_email.connect(self.print_info)
def print_info(self, x):
print('-->:', x)
app = QCoreApplication([])
c = Client()
app.exec()
After i run python server.py in terminal one and run python client.py in terminal two.
I got some warning as below in terminal two.
In C++ you can purchase the replica using 2 methods:
QRemoteObjectNode::acquire():
SimpleSwitchReplica *rep = repNode.acquire<SimpleSwitchReplica>("SimpleSwitch"));
QRemoteObjectNode::acquireDynamic():
QRemoteObjectDynamicReplica *rep = repNode.acquireDynamic("SimpleSwitch");
As the second method is observed, a QRemoteObjectDynamicReplica is used which is an object that is class created on-the-fly by copying the properties, signals and slots but does not contain all the information of the node class so it is not an exact copy so which has disadvantages as the docs points out:
There are generated replicas (replicas having the header files
produced by the Replica Compiler), and dynamic replicas, which are
generated on-the-fly. This is the class for the dynamic type of
replica.
When the connection to the Source object is made, the initialization
step passes the current property values (see Replica Initialization).
In a DynamicReplica, the property/signal/slot details are also sent,
allowing the replica object to be created on-the-fly. This can be
conventient in QML or scripting, but has two primary disadvantages.
First, the object is in effect "empty" until it is successfully
initialized by the Source. Second, in C++, calls must be made using
QMetaObject::invokeMethod(), as the moc generated lookup will not be
available.
(emphasis mine)
And in the case of PyQt, it only supports the second method, so you get that warning message indicating possible problems.
I have a bit of background in Java and used static variables and methods a lot. I am new to python and learning about using #classmethod as a static method.
Here is code,
import redis
class GetClients:
r = None
#classmethod
def connect_r(cls, host, port, db):
r = redis.StrictRedis(host=host, port=port, db=db)
#classmethod
def get_clients(cls, clients_key):
return r.smembers(clients_key)
My code first create a variable r and then inside a classmethod it assigns it to a redis connection, r = redis.StrictRedis(host=host, port=port, db=db)
In the next method get_clients, I am using the value of r to invoke a function on it., but I keep getting the following error
NameError: name 'r' is not defined
here is how i am using the class,
clients = GetClients()
clients.connect_r("localhost", 6379, 0)
allc = clients.get_clients("clients")
can someone please explain why I cannot access r in the 2nd method?
The problem is r in both class methods, you should replace r with cls.r.
like this:
import redis
class GetClients:
r = None
#classmethod
def connect_r(cls, host, port, db):
cls.r = redis.StrictRedis(host=host, port=port, db=db)
#classmethod
def get_clients(cls, clients_key):
return cls.r.smembers(clients_key)
But I think that your way of implementing these methods are a little bit wrong, you should not use class methods for this demands.
can someone please explain why I cannot access` in the 2nd method?
I should say that you can not even access r in connect_r too. that r is another variable with a different scop and if you want to see what will happen just change r to cls.r in get_clients, you will see that this method will returns None and it seems that connect_r method is not setting the actual r, for accessing those variables in class methods you should use cls.
also see the difference between cls and self here.
I have a class that I try to mock in tests. The class is located in server/cache.py and looks like:
class Storage(object):
def __init__(self, host, port):
# set up connection to a storage engine
def store_element(self, element, num_of_seconds):
# store something
def remove_element(self, element):
# remove something
This class is used in server/app.py similar to this one:
import cache
STORAGE = cache.Storage('host', 'port')
STORAGE.store_element(1, 5)
Now the problem arise when I try to mock it in the tests:
import unittest, mock
import server.app as application
class SomeTest(unittest.TestCase):
# part1
def setUp(self):
# part2
self.app = application.app.test_client()
This clearly does not work during the test, if I can't connect to a storage. So I have to mock it somehow by writing things in 'part1, part2'.
I tried to achieve it with
#mock.patch('server.app.cache') # part 1
mock.side_effect = ... # hoping to overwriting the init function to do nothing
But it still tries to connect to a real host. So how can I mock a full class here correctly? P.S. I reviewed many many questions which look similar to me, but in vain.
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.