Python 3 threadings.Thread callback error when targeting abstract method - multithreading

base_class.py
import threading
import websocket
from abc import ABCMeta, abstractmethod
class A:
__metaclass__ = ABCMeta
def __init__(self):
self.some_var = 0
#abstractmethod
def failed_method(self):
pass
def on_websocket_message(self, ws, msg):
var = self.failed_method()
print(var)
...
def open_websocket(self):
ws = websocket.WebSocketApp('http://some_url.com',
on_message=self.on_websocket_message, ...)
ws.run_forever()
def callback_method(self):
websocket_thread = threading.Thread(target=self.open_websocket, name='some_websocket_name')
another_var = self.failed_method()
print('Another variable\'s value is [{}]'.format(another_var))
child_class.py
from base_class import A
class B(A):
def failed_method(self):
return 3
other_class.py
import threading
from child_class import B
def main():
child_class_instance = B()
some_thread = threadings.Thread(target=child_class_instance.callback_method, name='some_name')
some_thread.start()
The result of main() is printed None, not 3, i.e., abstract class' method is called instead of child's one. (Assume all the modules are in the one place.)
Can anyone explain this behaviour? Or what is the thing I do not understand in inheritance in Python combined with threadings.Thread?
P.S. With the similar code I've met error from callback <bound method BaseClass... of < ...ChildClass...> > from websocket.WebSocketApp._callback().
P.P.S. Important to note that I use websocket-client, not websockets.

Related

How to pass class instance and all it does to another class in Python

I am writing a script with file structure as below:
main.py
field_integration.py
The field_integration.py:
import numpy as np
class Integration():
def __init__(self, param1, param2):
self.p1 = param1
self.p2 = param2
self.derive(self.p2)
def derive(self, param2):
self.pp1 = 2/self.p1
self.pp2 = param2/3
self.another_function_inside_the_class()
def another_function_inside_the_class(self):
print('OK')
The main.py:
from field_int import Integration
from fitting import Autofit
ppp1 = 1
ppp2 = 2
profile = Integration(ppp1, ppp2)
ppp5 = 3
fitt = Autofit(ppp5)
y_pre_fitted = fitt.pre_fitting(profile.p2, 0)
The fitting.py:
from field_int import Integration
class Autofit(Integration):
def __init__(self, param5):
self.p5 = param5
def pre_fitting(self, param2, param3):
Integration.derive(param2)
print(param3)
While fitting.py pre_fitting method works well when directly in main.py, here it throws the TypeError: line 8, in pre_fitting
Integration.derive(param2)
TypeError: derive() missing 1 required positional argument: 'param2'.
If I change the line to have Integration.derive(self, param2), it throws the AttributeError: 'Autofit' object has no attribute 'p1'
How then can I recreate the functionality of the code from the main.py inside another file? Should I move it to the same file as the class definition I instantiate? I am quite a noob concerning classes, I heard something about inheritance but I was only beating my head against the wall, because I don't understand how that would help me.
Since you are subclassing Integration, you can just call the function with self or super(). super() can be used when the subclass also overrides the superclass' method and we need to call the superclass method instead of the subclass. But in your case, you are not overriding so a simple self call should suffice, so -
from field_int import Integration
class Autofit(Integration):
def __init__(self, param5):
self.p5 = param5
def pre_fitting(self, param2, param3):
self.derive(param2)
print(param3)
On another note, it is usually a good idea to also Initialise the superclass using super() such as -
from field_int import Integration
class Autofit(Integration):
def __init__(self, param1, param2, param5):
super().__init__(param1, param2)
self.p5 = param5
def pre_fitting(self, param2, param3):
self.derive(param2)
print(param3)
Because now if you call the derive method without the super().__init__ the values for p1 and p2 required in the derive method will not be defined. So better to call __init__ on superclass before the method call.
Update
An alternate approach to what you want to achieve without using inheritance (if you are not extending the functionality of Integration class) -
fitting.py
from field_int import Integration
class Autofit():
def __init__(self, integration: Integration, param5):
self.p5 = param5
self.integration = integration
def pre_fitting(self, param2, param3):
self.integration.derive(param2)
print(param3)
main.py
from field_int import Integration
from fitting import Autofit
ppp1 = 1
ppp2 = 2
profile = Integration(ppp1, ppp2)
ppp5 = 3
fitt = Autofit(profile, ppp5)
y_pre_fitted = fitt.pre_fitting(profile.p2, 0)

having problems in importing from one file to another

For example :-Class B import some functions of Class A (Works fine). Problem arise when I tried to import some function of class B in class A.
file : a_class.py
from b_class import B
class A:
def fun(self):
print("fun")
def b(self):
print("Function is to test")
B().hello() #having issue
file : b_class.py
from a_class import A
class B:
def fun2(self):
print("more fun")
A().fun() # works fine
def hello(self):
print("want this function on class A")
if __name__ == '__main__':
a = B()
a.fun2()
bo = A()
bo.b()
Could someone please try to run this program and post the correct code in comment section because am working on one project and am having the same problem as I posted above.
I worked it out : you have to put the importstatement in a_class.py AFTER the class definition, like so:
file : a_class.py
class A:
def fun(self):
print("fun")
def b(self):
print("Function is to test")
B().hello() #having issue (not anymore)
from b_class import B
file : b_class.py
from a_class import A
class B:
def fun2(self):
print("more fun")
A().fun() # works fine
def hello(self):
print("want this function on class A")
if __name__ == '__main__':
a = B()
a.fun2()
bo = A()
bo.b()

PyQt5 + logging library

I want to redirect all the logging to QPlainTextEdit. I have been able to achieve that by following this thread. However, I have a bit of problem understand the actual code:
import logging
import sys
from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5 import QtWidgets
class Handler(QObject, logging.Handler):
new_record = pyqtSignal(object)
def __init__(self):
super().__init__()
super(logging.Handler).__init__()
def emit(self, record):
msg = self.format(record)
self.new_record.emit(msg)
class Formatter(logging.Formatter):
def formatException(self, ei):
result = super(Formatter, self).formatException(ei)
return result
def format(self, record):
s = super(Formatter, self).format(record)
if record.exc_text:
s = s.replace('\n', '')
return s
class MyTextBox(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
container = QtWidgets.QGroupBox()
layout = QtWidgets.QVBoxLayout()
self.text_box = QtWidgets.QPlainTextEdit()
self.text_box.setReadOnly(True)
layout.addWidget(self.text_box)
self.btn = QtWidgets.QPushButton("Click me")
layout.addWidget(self.btn)
container.setLayout(layout)
self.setCentralWidget(container)
handler = Handler()
logging.getLogger().addHandler(handler)
logging.getLogger().setLevel(logging.INFO)
handler.new_record.connect(self.text_box.appendPlainText)
self.btn.clicked.connect(self.heClickedMe)
def heClickedMe(self):
logging.debug('damn, a bug')
logging.info('something to remember')
logging.warning('that\'s not right')
logging.error('foobar')
app = QtWidgets.QApplication(sys.argv)
dlg = MyTextBox()
dlg.show()
sys.exit(app.exec_())
So I have trouble understanding the "emit" method in Handler class. For example, is "emit" a method of logging.Handler or QObject? When will "emit" be called?
is "emit" a method of logging.Handler or QObject?: To know the methods of the classes you have to use the docs and clearly emit is a method of logging.Handler.
When will "emit" be called?: This method is called internally when using the debug, info, warning and error methods.

Pytest object created by object assert_called_once_with

I known how I can test if an injected object was called with a specific argument. But in my case the injected object will create an object that object will create another object and I want to test if that last object was called with the right argument.
in the example below the question would be if c.dirve was called with 100 as argument:
class car:
def drive(self, distance):
print("so fast")
class car_shop:
def buy_car(self):
return car()
class shop_shop:
def buy_shop(self):
return car_shop()
class processor:
def __init__(self, sshop):
self.sshop = sshop
def run(self):
cshop = self.sshop.buy_shop()
c = cshop.buy_car()
c.drive(100)
def main():
sshop = shop_shop()
proc = processor(sshop)
proc.run()
if __name__ == "__main__":
main()
is there a way to test that?
Since this was requested here my approach for testing these objects:
import pytest
from unittest.mock import Mock
from object_returns_object_test_for_arguments import processor, shop_shop
#pytest.fixture
def mock_shop_shop():
return Mock(spec=shop_shop)
def test_processor_car_called_with_100(mock_shop_shop):
proc = processor(mock_shop_shop)
proc.run()
assert mock_shop_shop.car_shop.car.drive.assert_called_once_with(100)
assert mock_shop_shop.car_shop.car.drive.call_count == 1
If using just the code shown in the question, you only have to mock car.drive. This could be done for example this way:
from unittest import mock
from object_returns_object_test_for_arguments import processor, shop_shop
#mock.patch('object_returns_object_test_for_arguments.car.drive')
def test_processor_car_called_with_100(drive_mock):
proc = processor(shop_shop())
proc.run()
drive_mock.assert_called_once_with(100)
As I don't know your real code, you may have to mock more stuff.
As an aside: class names in Python are written upper-case, camelcase-style by default.

Why are my class functions executed when importing the class?

it's probably a very basic question but I was unable to find an answer that I could thoroughly understand.
In my main program main_program.py, I'm importing a class that itself imports another class:
in main_program.py:
from createTest import *
in createTest.py:
print("TEST")
from recordRecallQused import *
print("TEST")
now in recordRecallQused:
class recordRecallQused:
def __init__(self, path):
self.path = path
try:
with open(self.path, 'r',newline = '') as question_used:
question_used.closed
except IOError:
#if file doesnt exist
print("the file doesn't exist")
with open(self.path, 'w',newline = '') as question_used:
question_used.closed
def recallQused(self):
list_Qused = []
print("I'm being executed")
with open(self.path, 'r',newline = '') as question_used:
questionused = csv.reader(question_used)
for item in questionused:
if len(item)>0:
list_Qused.append(item[0])
question_used.closed
return list_Qused
What I obtain in the kernel:
>TEST
>I'm being executed
>TEST
so functions inside the class are executed even though they are not called, but I have read that it's "normal", "def" are no statements but "live" things.
Still, I have tried something much more simple:
in main_program_TEST.py
from class1 import *
a = class1()
in class1.py:
print("t")
from class2 import *
print("t")
class class1:
def __init__(self):
pass
def message(self):
print("prout")
in class2.py:
class class2:
def __init__(self):
pass
def message(self):
print("prout2")
When executing main_program_TEST.py the kernel displays
>t
>t
so this time the functions in class2.py have not been executed, otherwise the kernel would show instead:
>t
>prout2
>t
I really wonder why.
Stephen Rauch you are right, part of my code in recordRecallQused.py was calling the function.
"""#load all list
print("loading questions info")
# questions info: answers, category
list_AllQ = []
with open('questionsInfoTo130.csv', newline = '') as csvfile:
questionsInfo = csv.reader(csvfile)
# loop over the questions information rows
for (i,row) in enumerate(questionsInfo):
if(i!=0):
list_AllQ.append(row)
csvfile.close()
path = 'question_used.csv'"""
list_AllQ = [[0,1,2,1,"que"],[0,1,2,2,"que"],[0,1,2,3,"que"],[0,1,2,4,"que"],[0,1,2,55,"que"],[0,1,2,6,"que"],[0,1,2,7,"que"],[0,1,2,8,"que"],[0,1,2,9,"que"]]
a = recordRecallQused('question_used.csv')
list_Qused = a.recallQused()
list_avQ = a.createListavQ(list_Qused, list_AllQ)
list_Qtest = a.createListQtest(list_avQ)
a.recordQused(list_Qtest)

Resources