Self variable not updated after running function in different class - python

I have a class (AngleInfo) in a file (Display.py) with a self variable (WheelAngle) which is not updated after running a function (GetAngle). This function is being called in a class in a second file (ManageInfo.py) with a trigger based on events. When I try to use the WheelAngle in a second class (AngleProcess) in Display.py, the value doesn't update from the initialization. When the function is triggered in the MessageHandler class, it has access to raw data being represented by m in the GetAngle declaration.
There is another class (SpeedInfo) in a different file (Radar.py) where the self variable (VehicleSpeed) is being updated after running its corresponding information retrieval function (GetSpeed) in the ManageInfo class.
The working case has a threading system, but after replicating it in the non-working case I found no improvement. I don't understand why the WheelAngle is not being updated inside the class and comparing with the working case hasn't brought me closer to the answer.
So basically after I run GetAngle I see WheelAngle has the correct value inside that function but when I call the self variable in the UpdatePlot function of the AngleProcess class in the Display.py file I get the initial value. I even tried to create a different function in the AngleInfo class to access WheelAngle and then call this function in the UpdatePlot function in the AngleProcess class, but the result is the same.
Keep in mind a working example is not possible since it requires live data being sent. Also, even though WheelAngle and VehSpeed don't seem to be used, the code that follows has been ommited for simplicity!
Any ideas? There is a sample of the code below. Thank you!
Display.py
class AngleInfo():
def __init__(self):
self.WheelAngle = 0
def GetAngle(self,m):
self.WheelAngle = float(m) # Angle is correct
class AngleProcess():
def __init__(self):
self.AngleInfoObj = AngleInfo()
def UpdatePlot(self,tupledata):
WheelAngle = self.AngleInfoObj.WheelAngle # Angle is set to initial
Radar.py
class SpeedInfo(threading.Thread):
def __init__(self,page):
threading.Thread.__init__(self)
self.daemon = True
self.start()
self.VehSpeed = 0
def run(self):
VehSpeed = self.VehSpeed # Speed is correct
def GetSpeed(self,m):
self.VehSpeed = float(m) # Speed is correct
ManageInfo.py
from AurixCAN import Receiver
from Radar import SpeedInfo
from Display import AngleInfo
class MessageHandler:
def __init__(self,page):
self.SpeedInfo = SpeedInfo(page)
self.AngleInfo = AngleInfo()
DataSet = Receiver(canIDsandCalls={0xE:[self.SpeedInfo.GetSpeed,self.AngleInfo.GetAngle]})

Related

How to verify when an unknown object created by the code under test was called as expected (pytest) (unittest)

I have some code that creates instances from a list of classes that is passed to it. This cannot change as the list of classes passed to it has been designed to be dynamic and chosen at runtime through configuration files). Initialising those classes must be done by the code under test as it depends on factors only the code under test knows how to control (i.e. it will set specific initialisation args). I've tested the code quite extensively through running it and manually trawling through reams of output. Obviously I'm at the point where I need to add some proper unittests as I've proven my concept to myself. The following example demonstrates what I am trying to test:
I would like to test the run method of the Foo class defined below:
# foo.py
class Foo:
def __init__(self, stuff):
self._stuff = stuff
def run():
for thing in self._stuff:
stuff = stuff()
stuff.run()
Where one (or more) files would contain the class definitions for stuff to run, for example:
# classes.py
class Abc:
def run(self):
print("Abc.run()", self)
class Ced:
def run(self):
print("Ced.run()", self)
class Def:
def run(self):
print("Def.run()", self)
And finally, an example of how it would tie together:
>>> from foo import Foo
>>> from classes import Abc, Ced, Def
>>> f = Foo([Abc, Ced, Def])
>>> f.run()
Abc.run() <__main__.Abc object at 0x7f7469f9f9a0>
Ced.run() <__main__.Abc object at 0x7f7469f9f9a1>
Def.run() <__main__.Abc object at 0x7f7469f9f9a2>
Where the list of stuff to run defines the object classes (NOT instances), as the instances only have a short lifespan; they're created by Foo.run() and die when (or rather, sometime soon after) the function completes. However, I'm finding it very tricky to come up with a clear method to test this code.
I want to prove that the run method of each of the classes in the list of stuff to run was called. However, from the test, I do not have visibility on the Abc instance which the run method creates, therefore, how can it be verified? I can't patch the import as the code under test does not explicitly import the class (after all, it doesn't care what class it is). For example:
# test.py
from foo import Foo
class FakeStuff:
def run(self):
self.run_called = True
def test_foo_runs_all_stuff():
under_test = Foo([FakeStuff])
under_test.run()
# How to verify that FakeStuff.run() was called?
assert <SOMETHING>.run_called, "FakeStuff.run() was not called"
It seems that you correctly realise that you can pass anything into Foo(), so you should be able to log something in FakeStuff.run():
class Foo:
def __init__(self, stuff):
self._stuff = stuff
def run(self):
for thing in self._stuff:
stuff = thing()
stuff.run()
class FakeStuff:
run_called = 0
def run(self):
FakeStuff.run_called += 1
def test_foo_runs_all_stuff():
under_test = Foo([FakeStuff, FakeStuff])
under_test.run()
# How to verify that FakeStuff.run() was called?
assert FakeStuff.run_called == 2, "FakeStuff.run() was not called"
Note that I have modified your original Foo to what I think you meant. Please correct me if I'm wrong.

How do I best store API data into a Python class instance variable?

I would like some advice on how to best design a class and it's instance variables. I initialize the class with self.name. However, the main purpose of this class it to retrieve data from an API passing self.name as a parameter, and then parsing the data accordingly. I have a class method called fetch_data(self.name) that makes the API request and returns ALL data. I want to store this data into a class instance variable, and then call other methods on that variable. For example, get_emotions(json), get_personality_traits(json), and get_handle(json), all take the same dictionary as a parameter, assign it to their own local variables, and then manipulate it accordingly.
I know I can make fetch_data(self.name) return data, and then call fetch_data(self.name) within the other methods, assign the return value to a local variable, and manipulate that. The problem is then I will need to call the API 5 times rather than 1, which I can't do for time and money reasons.
So, how do I make the result of fetch_data(self.name) global so that all methods within the class have access to the main data object? I know this is traditionally done in an instance variable, but in this scenario I can't initiliaze the data since I don't have it until after I call fetch_data().
Thank you in advance!
It seems like you just need to do something like this:
class Foo(object):
def __init__(self, name):
self.name = name
self.data = None
def fetch_data(self):
if self.data is None:
# Only call the API once
self.data = self.really_fetch_data()
return self.data
def get_emotions(self):
emotions = self.fetch_data().get("emotions")
...
Why don't you just try to solve this as you described?
For example, you can take this as a starting point:
import json
class APIBundle(object):
def __init__(self, name):
self.name = name
self.data = None
self.update()
def update():
response = json.loads(API_request(self.name))
# Do some parsing on response
self.data = response
def get_emotions():
# Work through current data state
# and filter as desired
result = []
for message in self.data['messages']:
if message.find(':)') != -1:
result.append((message, 'positive'))
if message.find(':(') != -1:
result.append((message, 'negative'))
return result
if __name__ == '__main__':
ab = APIBundle('my-secret-name')
print(self.get_emotions())
Try to do it with self.data=None , or make an instance variable and call whenever you need. writing algorithm will make this thing more complex try to solve issue with inbuilt functions or with algorithm program vulnerability will affect alot.

Using callbacks to run function using the current values in a class

I struggled to think of a good title so I'll just explain it here. I'm using Python in Maya, which has some event callback options, so you can do something like on save: run function. I have a user interface class, which I'd like it to update when certain events are triggered, which I can do, but I'm looking for a cleaner way of doing it.
Here is a basic example similar to what I have:
class test(object):
def __init__(self, x=0):
self.x = x
def run_this(self):
print self.x
def display(self):
print 'load user interface'
#Here's the main stuff that used to be just 'test().display()'
try:
callbacks = [callback1, callback2, ...]
except NameError:
pass
else:
for i in callbacks:
try:
OpenMaya.MEventMessage.removeCallback(i)
except RuntimeError:
pass
ui = test(5)
callback1 = OpenMaya.MEventMessage.addEventCallback('SomeEvent', ui.run_this)
callback2 = OpenMaya.MEventMessage.addEventCallback('SomeOtherEvent', ui.run_this)
callback3 = ......
ui.display()
The callback persists until Maya is restarted, but you can remove it using removeCallback if you pass it the value that is returned from addEventCallback. The way I have currently is just check if the variable is set before you set it, which is a lot more messy than the previous one line of test().display()
Would there be a way that I can neatly do it in the function? Something where it'd delete the old one if I ran the test class again or something similar?
There are two ways you might want to try this.
You can an have a persistent object which represents your callback manager, and allow it to hook and unhook itself.
import maya.api.OpenMaya as om
import maya.cmds as cmds
om.MEventMessage.getEventNames()
class CallbackHandler(object):
def __init__(self, cb, fn):
self.callback = cb
self.function = fn
self.id = None
def install(self):
if self.id:
print "callback is currently installed"
return False
self.id = om.MEventMessage.addEventCallback(self.callback, self.function)
return True
def uninstall(self):
if self.id:
om.MEventMessage.removeCallback(self.id)
self.id = None
return True
else:
print "callback not currently installed"
return False
def __del__(self):
self.uninstall()
def test_fn(arg):
print "callback fired 2", arg
cb = CallbackHandler('NameChanged', test_fn)
cb.install()
# callback is active
cb.uninstall()
# callback not active
cb.install()
# callback on again
del(cb) # or cb = None
# callback gone again
In this version you'd store the CallbackHandlers you create for as long as you want the callback to persist and then manually uninstall them or let them fall out of scope when you don't need them any more.
Another option would be to create your own object to represent the callbacks and then add or remove any functions you want it to trigger in your own code. This keeps the management entirely on your side instead of relying on the api, which could be good or bad depending on your needs. You'd have an Event() class which was callable (using __call__() and it would have a list of functions to fire then its' __call__() was invoked by Maya. There's an example of the kind of event handler object you'd want here

Method from another class does not work entirely when called

I have this code:
class Matplotlib_figure(QMainWindow):
minimumCoords = None
maximumCoords = None
initial_marker = None
final_marker = None
limite = None
def __init__(self):
#A lot of stuff to draw a matplotlib figure
def minimumLimit(self):
self.cMinL = self.figure_canvas.mpl_connect("button_press_event", self.select_minimumLimit)
self.limite = "minimum"
def select_minimumLimit(self, event):
if event.button == 1:
self.clearMarker() #This is another method that i call
Matplotlib_figure.minimumCoords = None
Matplotlib_figure.minimumCoords = event.xdata
if Matplotlib_figure.minimumCoords <= Matplotlib_figure.maximumCoords or Matplotlib_figure.maximumCoords == None:
marker = self.axes.axvline(event.xdata,0,1, linestyle='dashed',
linewidth = 2, color = "green" )
self.figure_canvas.draw_idle()
Matplotlib_figure.initial_marker = marker
class Data(QDialog):
minimum = None
maximum = None
def __init__(self, parent):
QDialog.__init__(self, None, QWindowsStayOnTopHint)
uic.loadUi("", self)
def show_lines(self):
SelectData.minimo = self.lineEdit.text()
SelectData.maximo = self.lineEdit_2.text()
Matplotlib_figure.minimumCoords = float(SelectData.minimo)
Matplotlib_figure.maximumCoords = float(SelectData.maximo)
#Here is where i want to call a method in the Matplotlib_figure class
view = Matplotlib_figure()
view.minimumLimit()
view.maximumLimit()
The problem comes in the Data class. When i want to call the minimumLimitmethod in the Matplotlib_figureclass (from show_lines in Data class), it does not trigger the figure_canvas.mpl_connectmethod, and select_minimumLimitmethod does not work.
What am i doing wrong? Hope you can help me.
I think the key issue comes from this note in the matplotlib event handling docs:
The canvas retains only weak references to the callbacks. Therefore if a callback is a method of a class instance, you need to retain a reference to that instance. Otherwise the instance will be garbage-collected and the callback will vanish.
So you have created a new view in the show_lines method, but this is a local variable. When the function returns, the variable goes out of scope and python will probably try to delete it. Normally if you save a reference to a method off, then the method retains the object it is a method for, and this would not happen, but because mpl_connect only takes a weak reference to the function it does not retain view, and therefore when the show_lines returns, the method is lost too, and so the callback will revert to doing nothing.
You can probably fix this by rewriting show_lines to save the view off, something like:
def show_lines(self):
SelectData.minimo = self.lineEdit.text()
SelectData.maximo = self.lineEdit_2.text()
Matplotlib_figure.minimumCoords = float(SelectData.minimo)
Matplotlib_figure.maximumCoords = float(SelectData.maximo)
#Here is where i want to call a method in the Matplotlib_figure class
self.view = Matplotlib_figure()
self.view.minimumLimit()
self.view.maximumLimit()
Now the Matplotlib_figure instance will be retained as long as the Data instance is.
[Previous answer based on error in question kept below]
I don't know the QT framework or the matplotlib APIs very well, but it looks to me that you've created an instance of ViewWidget, which is an entirely separate class (subclass of the QT QMainWindow class, if I recognise that, which is an entirely different python module) from Matplotlib_figure. Therefore I would expect when you call minimumLimit() that you'd get an AttributeError exception, and I wouldn't expect it to call your method. If you want that you'll have to create an instance of it and call that:
view = Matplotlib_figure()
view.minimumLimit()
view.maximumLimit()
Without more context of where your ViewWidget comes from it is hard to understand how you think this should work. It's also a bit odd that you are creating a matplotlib figure that is a subclass of the unrelated QMainWindow class. What are you trying to achieve with this? Could you provide some more context for the code?

How can I get this class to run in python?

class script(object):
def __init__(self, time_delay = 1.5):
self.time_delay = time_delay
self.lines = []
def run_script(self):
for line in self.lines:
print line
sleep(self.time_delay)
intro = script(1.5)
intro.lines = ["great", "boy"]
My guess would be that the sleep() function is from the time library. Just add
from time import *
at the beginning of the file. But, since the syntax above will import definitions as if they were declared in your file, you can use:
import time
...
time.sleep(self.time_delay)
But there is also another possibility. That sleep() has to be a function declared by you. If this is the case, you have to define it:
class script(object):
# ...
def sleep(delay):
# implementation
Note:
As #icktoofay commented, you are not using the run_script() method, so may want to add a call like:
intro.run_script()
There might be confusion on your part about "running" a class, since you don't "run" a class, but you can "run" a method of a class. Perhaps you just mean
intro.run_script()

Categories

Resources