Because of long codings, I put codings in this link:http://textuploader.com/5xofp
Here is the small codings:
from graphics import *
from math import *
def main():
win = GraphWin('Simple Calculator',400,600)
win.setBackground('slategray')
p1 = Point(10,70)
p2 = Point(390,10)
display_box = Rectangle(p1,p2)
display_box.draw(win)
text = Text(Point(190,30),"")
text.setStyle('italic')
text.setSize(15)
text.draw(win)
sqrt = Rectangle(Point(70,190),Point(120,140))
sqrt.draw(win)
sqrt1 = Text(Point(95,165),"√ ")
sqrt1.setStyle('italic')
sqrt1.setSize(36)
sqrt1.draw(win)
eq_sign = Rectangle(Point(170,510),Point(240,440))
eq_sign.draw(win)
eq = Text(Point(205,475),"=")
eq.setStyle('italic')
eq.setSize(36)
eq.draw(win)
num1 = Rectangle(Point(10,270),Point(80,200))
num1.draw(win)
num1_ = Text(Point(45,235),"1")
num1_.setStyle('italic')
num1_.setSize(36)
num1_.draw(win)
if 10<=mouse.x<=80 and 200<=mouse.y<=270:
text.setText(text.getText()+"1")
if 70<=mouse.x<=120 and 140<=mouse.y<=190:
text.setText(text.getText()+"sqrt(")
if 170<=mouse.x<=240 and 440<=mouse.y<=510:#=
try:
result = eval(text.getText())
except:
result = "ERROR"
text.setText(result)
main()
why when I enters sqrt(36), it gives error in the text? I have already made it as a string.
Is there any mistake in my codings?
sqrt = Rectangle(Point(70,190),Point(120,140))
sqrt.draw(win)
This overwrites the math module's sqrt function with a Rectangle object. Try changing the name of this variable to something else.
sqrt_button = Rectangle(Point(70,190),Point(120,140))
sqrt_button.draw(win)
Related
I've been having problems trying to estimate two variables while using fsolve. Below is the code
def f(variables):
#Ideal
n=0 #this is passed as an argument but given in this example for simplicity
P1 = 101325; T1 = 300
q = 'H2:2,O2:1,N2:{}'.format(molno[n])
mech = 'H2O2sandan.cti'
cj_speed,R2,plot_data = CJspeed(P1,T1,q,mech,fullOutput=True)
gas = PostShock_fr(cj_speed, P1, T1, q, mech)
Ta = gas.T; Ps = gas.P;
CVout1 = cvsolve(gas)
taua = CVout1['ind_time']
Tb = Ta*1.01
gas.TPX = Tb,Ps,q
CVout2 = cvsolve(gas)
taub = CVout2['ind_time']
#Constant Volume
k,Ea = variables
T_0_1= Tvn_mg_d[n]
T_vn_1 = Tvn_mg_d[n]
den = rhovn_mg_d[n]
t = np.linspace(0,0.0001,100000000)
qr = Q_mg[n]
perfect_var = T_vn_1,den,Ea,k,qr
sol_t= odeint(ode,T_0_1,t=t,args=(perfect_var,))
index = np.argmax(np.gradient(sol_t[:,0]))
tau_cv_1 = t[index]
T_0_2= Tvn_mg_d[n]*1.01
T_vn_2 = Tvn_mg_d[n]*1.01
den = rhovn_mg_d[n]
t = np.linspace(0,0.0001,100000000)
qr = Q_mg[n]
perfect_var = T_vn_2,den,Ea,k,qr
sol_t= odeint(ode,T_0_2,t=t,args=(perfect_var,))
index = np.argmax(np.gradient(sol_t[:,0]))
tau_cv_2 = t[index]
root1 = taua - t_cv_1
root2 = taub - t_cv_2
return[root1,root2]
import scipy.optimize as opt
k_guess = 95000
Ea_guess = 28*300
solution = opt.fsolve(f,(k_guess,Ea_guess))
print(solution)
I want to find values of k_guess and Ea_guess such that roo1 and roo2 are 0 (i.e. taua = t_cv_1 and taub = t_cv_2). However I don't know if I've used fsolve the right way as the values returned seem to be way off. Am I returning the right thing? I also get the below error:
lsoda-- warning..internal t (=r1) and h (=r2) are
such that in the machine, t + h = t on the next step
(h = step size). solver will continue anyway
What am I doing wrong here?
I'm trying to write a script to record player movement in Rocket League using the RLBot framework. I've got very minimal experience with code and I've been getting the error:
Traceback (most recent call last):
File "c:/Users/Julian/AppData/Local/RLBotGUIX/RLBotPackDeletable/RLBotPack-master/RLBotPack/CustomMutators/playerRecorder.py", line 27, in <module>
class playerRecorder(BaseScript):
File "c:/Users/Julian/AppData/Local/RLBotGUIX/RLBotPackDeletable/RLBotPack-master/RLBotPack/CustomMutators/playerRecorder.py", line 45, in playerRecorder
for car in packet.game_cars:
NameError: name 'packet' is not defined
Packet is defined within def run(self): but I'm still getting an error for it not being defined. Below is my full script from within VS Code. Any help is appreciated.
from typing import Optional
from rlbot.agents.base_agent import BaseAgent, GameTickPacket, SimpleControllerState
import os
import time
import math
from rlbot.agents.base_agent import BaseAgent, SimpleControllerState
from rlbot.utils.structures.game_data_struct import GameTickPacket
from rlbot.utils.game_state_util import GameState, BallState, CarState, Physics, Vector3 as vector3, Rotator
import random
from rlbot.agents.base_script import BaseScript
from rlbot.utils.game_state_util import GameState
DIRECTORY_LOCATION = "C:\Logs\Recorder\log"
randNum = random.randint(0,9999999999)
# Extending the BaseScript class is purely optional. It's just convenient / abstracts you away from
# some strange classes like GameInterface
class playerRecorder(BaseScript):
def __init__(self):
super().__init__("playerRecorder")
packet = self.get_game_tick_packet()
self.writeFile = open(DIRECTORY_LOCATION+"\\"+"HumanLog"+str(car.team)+"-"+str(randNum), "w")
def run(self):
while True:
packet = self.get_game_tick_packet()
get_output(packet)
sleep(1 / 3)
print("test")
for car in packet.game_cars:
if not car.is_bot:
team = car.team
index = car.index
break
def get_output(self, game_tick_packet):
#***************************************************************
packet = self.get_game_tick_packet()
goodTeam = str(car.team)
goodLoc = packet.game_cars[car.index].physics.location
goodLocX = str(goodLoc.x)
goodLocY = str(goodLoc.y)
goodLocZ = str(goodLoc.z)
goodRot = packet.game_cars[car.index].physics.rotation
goodRotP = str(goodRot.pitch)
goodRotY = str(goodRot.yaw)
goodRotR = str(goodRot.roll)
goodVel = packet.game_cars[car.index].physics.velocity
goodVelX = str(goodVel.x)
goodVelY = str(goodVel.y)
goodVelZ = str(goodVel.z)
goodAngVel = packet.game_cars[car.index].physics.angular_velocity
goodAngVelX = str(goodAngVel.x)
goodAngVelY = str(goodAngVel.y)
goodAngVelZ = str(goodAngVel.z)
hasWC = str(packet.game_cars[car.index].has_wheel_contact)
isSS = str(packet.game_cars[car.index].is_super_sonic)
jumped = str(packet.game_cars[car.index].jumped)
dJumped = str(packet.game_cars[car.index].double_jumped)
bst = str(packet.game_cars[car.index].boost)
ballLoc = packet.game_ball.physics.location
ballLocX = str(ballLoc.x)
ballLocY = str(ballLoc.y)
ballLocZ = str(ballLoc.z)
ballVel = packet.game_ball.physics.velocity
ballVelX = str(ballVel.x)
ballVelY = str(ballVel.y)
ballVelZ = str(ballVel.z)
self.writeFile.write(goodTeam+";"+
goodLocX+","+goodLocY+","+goodLocZ+";"+
goodRotP+","+goodRotY+","+goodRotR+";"+
goodVelX+","+goodVelY+","+goodVelZ+";"+
goodAngVelX+","+goodAngVelY+","+goodAngVelZ+";"+
hasWC+";"+isSS+";"+jumped+";"+dJumped+";"+bst+";"+
ballLocX+","+ballLocY+","+ballLocZ+";"+
ballVelX+","+ballVelY+","+ballVelZ)
self.writeFile.write("\n")
## WRITE OPPONENT
badIndex = -1
for i in range(len(packet.game_cars)):
if i != car.index:
badIndex = i
break
assert badIndex != car.index
assert badIndex != -1
badTeam = str(packet.game_cars[badIndex].team)
badLoc = packet.game_cars[badIndex].physics.location
badLocX = str(badLoc.x)
badLocY = str(badLoc.y)
badLocZ = str(badLoc.z)
badRot = packet.game_cars[badIndex].physics.rotation
badRotP = str(badRot.pitch)
badRotY = str(badRot.yaw)
badRotR = str(badRot.roll)
badVel = packet.game_cars[badIndex].physics.velocity
badVelX = str(badVel.x)
badVelY = str(badVel.y)
badVelZ = str(badVel.z)
badAngVel = packet.game_cars[badIndex].physics.angular_velocity
badAngVelX = str(badAngVel.x)
badAngVelY = str(badAngVel.y)
badAngVelZ = str(badAngVel.z)
badhasWC = str(packet.game_cars[badIndex].has_wheel_contact)
badisSS = str(packet.game_cars[badIndex].is_super_sonic)
badjumped = str(packet.game_cars[badIndex].jumped)
baddJumped = str(packet.game_cars[badIndex].double_jumped)
badbst = str(packet.game_cars[badIndex].boost)
self.writeFile.write(badTeam+";"+
badLocX+","+badLocY+","+badLocZ+";"+
badRotP+","+badRotY+","+badRotR+";"+
badVelX+","+badVelY+","+badVelZ+";"+
badAngVelX+","+badAngVelY+","+badAngVelZ+";"+
badhasWC+";"+badisSS+";"+badjumped+";"+baddJumped+";"+badbst)
self.writeFile.write("\n")
## WRITE ACTION
self.writeFile.write(str(action.throttle)+";"+str(action.steer)+";"+str(action.pitch)+";"+str(action.yaw)+";"+str(action.action.roll)+";"+str(action.jump)+";"+str(action.boost))
self.writeFile.write("\n")
##*****************************************************
return action
In the run(...) function you should type self.get_output(packet) instead of get_output(). You have to pass a packet as a parameter to a function and also you should write self before the name of a function because it's inside a class. I think you also misspelled the parameter of the get_output function because you've named it game_tick_packet and in the function you are using variable named just a packet.
I am running this code and oddly, nothing happens. There is no error nor does it freeze. It simply just runs the code without storing variables, nothing is printed out and it doesn't open the window that is supposed to show the plot. So it simply does nothing. It is very odd. This worked only a few minutes ago and I did not change anything about it previously. I did make sure that the variable explorer is displaying all the definitions in the script. I intentionally removed the plotting section at the end since it just made the code set longer and the same issue persists here without it.
Code:
#Import libraries
import numpy as np
from scipy.integrate import odeint
#from scipy.integrate import solve_ivp
from time import time
import matplotlib.pyplot as plt
from matplotlib.pyplot import grid
from mpl_toolkits.mplot3d import Axes3D
import numpy, scipy.io
from matplotlib.patches import Circle
'''
import sympy as sy
import random as rand
from scipy import interpolate
'''
'''
Initiate Timer
'''
TimeStart = time()
'''
#User defined inputs
'''
TStep = (17.8E-13)
TFinal = (17.8E-10)
R0 = 0.02
V0X = 1E7
ParticleCount = 1 #No. of particles to generate energies for energy generation
BInput = 0.64 #Magnitude of B field near pole of magnet in experiment
ScaleV0Z = 1
'''
#Defining constants based on user input and nature (Cleared of all errors!)
'''
#Defining Space and Particle Density based on Pressure PV = NkT
k = 1.38E-23 #Boltzman Constant
#Natural Constants
Q_e = -1.602E-19 #Charge of electron
M_e = 9.11E-31 #Mass of electron
JToEv = 6.24E+18 #Joules to eV conversion
EpNaut = 8.854187E-12
u0 = 1.256E-6
k = 1/(4*np.pi*EpNaut)
QeMe = Q_e/M_e
'''
Create zeros matrices to populate later (Cannot create TimeIndex array!)
'''
TimeSpan = np.linspace(0,TFinal,num=round((TFinal/TStep)))
TimeIndex = np.linspace(0,TimeSpan.size,num=TimeSpan.size)
ParticleTrajectoryMat = np.zeros([91,TimeSpan.size,6])
BFieldTracking = np.zeros([TimeSpan.size,3])
InputAngle = np.array([np.linspace(0,90,91)])
OutputAngle = np.zeros([InputAngle.size,1])
OutputRadial = np.zeros([InputAngle.size,1])
'''
Define B-Field
'''
def BField(x,y,z):
InputCoord = np.array([x,y,z])
VolMag = 3.218E-6 #Volume of magnet in experiment in m^3
BR = np.sqrt(InputCoord[0]**2 + InputCoord[1]**2 + InputCoord[2]**2)
MagMoment = np.array([0,0,(BInput*VolMag)/u0])
BDipole = (u0/(4*np.pi))*(((3*InputCoord*np.dot(MagMoment,InputCoord))/BR**5)-(MagMoment/BR**3))
#BVec = np.array([BDipole[0],BDipole[1],BDipole[2]])
#print(BDipole[0],BDipole[1],BDipole[2])
return (BDipole[0],BDipole[1],BDipole[2])
'''
Lorentz Force Differential Equations Definition
'''
def LorentzForce(PosVel,t,Constants):
X,Y,Z,VX,VY,VZ = PosVel
Bx,By,Bz,QeMe = Constants
BFInput = np.array([Bx,By,Bz])
VelInput = np.array([VX,VY,VZ])
Accel = QeMe * (np.cross(VelInput, BFInput))
LFEqs = np.concatenate((VelInput, Accel), axis = 0)
return LFEqs
'''
Cartesean to Spherical coordinates converter function. Returns: [Radius (m), Theta (rad), Phi (rad)]
'''
def Cart2Sphere(xIn,yIn,zIn):
P = np.sqrt(xIn**2 + yIn**2 + zIn**2)
if xIn == 0:
Theta = np.pi/2
else:
Theta = np.arctan(yIn/xIn)
Phi = np.arccos(zIn/np.sqrt(xIn**2 + yIn**2 + zIn**2))
SphereVector = np.array([P,Theta,Phi])
return SphereVector
'''
Main Loop
'''
for angletrack in range(0,InputAngle.size):
MirrorAngle = InputAngle[0,angletrack]
MirrorAngleRad = MirrorAngle*(np.pi/180)
V0Z = np.abs(V0X/np.sin(MirrorAngleRad))*np.sqrt(1-(np.sin(MirrorAngleRad))**2)
V0Z = V0Z*ScaleV0Z
#Define initial conditions
V0 = np.array([[V0X,0,V0Z]])
S0 = np.array([[0,R0,0]])
ParticleTrajectoryMat[0,:] = np.concatenate((S0,V0),axis=None)
for timeplace in range(0,TimeIndex.size-1):
ICs = np.concatenate((S0,V0),axis=None)
Bx,By,Bz = BField(S0[0,0],S0[0,1],S0[0,2])
BFieldTracking[timeplace,:] = np.array([Bx,By,Bz])
AllConstantInputs = [Bx,By,Bz,QeMe]
t = np.array([TimeSpan[timeplace],TimeSpan[timeplace+1]])
ODESolution = odeint(LorentzForce,ICs,t,args=(AllConstantInputs,))
ParticleTrajectoryMat[angletrack,timeplace+1,:] = ODESolution[1,:]
S0[0,0:3] = ODESolution[1,0:3]
V0[0,0:3] = ODESolution[1,3:6]
MatSize = np.array([ParticleTrajectoryMat.shape])
RowNum = MatSize[0,1]
SphereMat = np.zeros([RowNum,3])
SphereMatDeg = np.zeros([RowNum,3])
for cart2sphereplace in range(0,RowNum):
SphereMat[cart2sphereplace,:] = Cart2Sphere(ParticleTrajectoryMat[angletrack,cart2sphereplace,0],ParticleTrajectoryMat[angletrack,cart2sphereplace,1],ParticleTrajectoryMat[angletrack,cart2sphereplace,2])
for rad2deg in range(0,RowNum):
SphereMatDeg[rad2deg,:] = np.array([SphereMat[rad2deg,0],(180/np.pi)*SphereMat[rad2deg,1],(180/np.pi)*SphereMat[rad2deg,2]])
PhiDegVec = np.array([SphereMatDeg[:,2]])
RVec = np.array([SphereMatDeg[:,0]])
MinPhi = np.amin(PhiDegVec)
MinPhiLocationTuple = np.where(PhiDegVec == np.amin(PhiDegVec))
MinPhiLocation = int(MinPhiLocationTuple[1])
RAtMinPhi = RVec[0,MinPhiLocation]
OutputAngle[angletrack,0] = MinPhi
OutputRadial[angletrack,0] = RAtMinPhi
print('Mirror Angle Input (In deg): ',InputAngle[0,angletrack])
print('Mirror Angle Output (In deg): ',MinPhi)
print('R Value at minimum Phi (m): ',RAtMinPhi)
InputAngleTrans = np.matrix.transpose(InputAngle)
CompareMat = np.concatenate((InputAngleTrans,OutputAngle),axis=1)
I am creating a program which opens a world map in a window using Zelle's graphics.py. It has one function which draws dots on the map, and another function which undraws those dots after they are on the screen for 1 second (which are stored in a list after being drawn). I want these functions to work concurrently, but when the addDots() function is called in a thread it won't draw the dot in the window, it just stalls. Here is the module which I run:
import thread
import threading
import time
import random
import sys
sys.path.append('..')
from Display import map
import tester
import datetime
dots = list(())
def deleteDots():
while 1==1:
tF = datetime.datetime.now()
a = 0
for i in range(len(dots)):
tD = tF - dots[i-a][2]
tD = int(str(tD)[5:7])
if tD >= 1:
map.deletePoint(dots[i-a][0],dots[i-a][1])
dots.pop(i-a)
a = a+1
def addDots():
oldResponseCount = tester.getResponseCount()
oldResponseCount = int(str(oldResponseCount))
while 1==1:
print(oldResponseCount)
newResponseCount = tester.getResponseCount()
newResponseCount = int(str(newResponseCount))
print(newResponseCount)
if(newResponseCount != oldResponseCount):
difference = newResponseCount - oldResponseCount
for i in range(difference):
lat = random.randint(-90,90)
long = random.randint(-180,180)
map.drawPoint(lat,long)
tI = datetime.datetime.now()
dots.append([lat,long,tI])
oldResponseCount = newResponseCount
if __name__ == '__main__':
threading.Thread(target=addDots).start()
threading.Thread(target=deleteDots).start()
And here is the map module which draws the map on a graphics window and contains the functions to plot and delete a point:
from graphics import *
import math
import images
size = 0.6
Circles = list(())
win = GraphWin("My Window", 1920*size, 1080*size)
win.setBackground('blue')
images.test(size)
myImage = Image(Point(960*size,540*size), "../Display/temp.gif")
myImage.draw(win)
import time
def drawPoint(lat,long):
x = int(long*5.3+960)*size
y = int(lat*(-5.92)+540)*size
pt = Point(x,y)
cir = Circle(pt,5)
cir.setFill(color_rgb(255,0,0))
Circles.append([cir,x,y])
cir.draw(win)
def deletePoint(lat,long):
x = int(long*5.3+960)*size
y = int(lat*(-5.92)+540)*size
for c in Circles:
if c[1]==x and c[2]==y:
c[0].undraw()
How should I go about doing this?
There are a couple of issues that have to be addressed. First, any graphics.py commands that invoke tkinter (i.e. commands that cause something to be drawn/undrawn) must be issued by the primary (main) thread. So we need the secondary threads to communicate drawing requests to the primary thread.
Second, you have both your secondary threads modifying the Circles and dots lists -- you need to syncronize (lock) access to these lists so that only one thread at a time can modify or iterate them.
Below is my rework of your code as an example. I've eliminated map and tester routines as I'm just putting dots up on a window with one thread and deleting them after they are a second old from another thread:
from threading import Thread, Lock
from queue import Queue # use for thread-safe communications
from random import randint
import time
from graphics import *
def drawPoint(lat, long):
x = int(long * 5.3 + 960)
y = int(lat * -5.92 + 540)
point = Point(x, y)
circle = Circle(point, 5)
circle.setFill(color_rgb(255, 0, 0))
circles_lock.acquire()
circles.append(circle)
circles_lock.release()
actions.put((circle.draw, win))
def deletePoint(lat, long):
global circles
x = int(long * 5.3 + 960)
y = int(lat * -5.92 + 540)
keep_circles = []
circles_lock.acquire()
for circle in circles:
center = circle.getCenter()
if center.getX() == x and center.getY() == y:
actions.put((circle.undraw,))
else:
keep_circles.append(circle)
circles = keep_circles
circles_lock.release()
def deleteDots():
global dots
while True:
keep_dots = []
dots_lock.acquire()
now = time.time()
for dot in dots:
lat, long, then = dot
if now - then >= 1.0:
deletePoint(lat, long)
else:
keep_dots.append(dot)
dots = keep_dots
dots_lock.release()
time.sleep(0.5)
def addDots():
while True:
lat = randint(-90, 90)
long = randint(-180, 180)
drawPoint(lat, long)
dots_lock.acquire()
dots.append((lat, long, time.time()))
dots_lock.release()
time.sleep(0.25)
win = GraphWin("My Window", 1920, 1080)
circles = []
circles_lock = Lock()
dots = []
dots_lock = Lock()
actions = Queue()
Thread(target=addDots, daemon=True).start()
Thread(target=deleteDots, daemon=True).start()
while True:
if not actions.empty():
action, *arguments = actions.get()
action(*arguments)
time.sleep(0.125)
Here's the error:
File "/Users/KarenLee/Desktop/temp/worldmodel.py", line 76, in update_on_time
obj = VeinAction(entity, image_store)
NameError: global name 'VeinAction' is not defined
And here is my code (this is in the file "actions.py"):
import entities
import worldmodel
import pygame
import math
import random
import point
import image_store
BLOB_RATE_SCALE = 4
BLOB_ANIMATION_RATE_SCALE = 50
BLOB_ANIMATION_MIN = 1
BLOB_ANIMATION_MAX = 3
FREEZE_ANIMATION_RATE = 100
FREEZE_STEPS = 4
ORE_CORRUPT_MIN = 20000
ORE_CORRUPT_MAX = 30000
QUAKE_STEPS = 10
QUAKE_DURATION = 1100
QUAKE_ANIMATION_RATE = 100
VEIN_SPAWN_DELAY = 500
VEIN_RATE_MIN = 8000
VEIN_RATE_MAX = 17000
WYVERN_RATE_MIN = 200
WYVERN_RATE_MAX = 600
WYVERN_ANIMATION_RATE = 100
class VeinAction:
def __init__(self, entity, image_store):
self.entity = entity
self.image_store = image_store
def vein_action(self, world, action, ticks):
entity = self.entity
open_pt = find_open_around(world, entities.get_position(entity),
entities.get_resource_distance(entity))
if open_pt:
ore = create_ore(world,
"ore - " + entities.get_name(entity) + " - " + str(ticks),
open_pt, ticks, action.image_store)
worldmodel.add_entity(world, ore)
tiles = [open_pt]
else:
tiles = []
schedule_action(world, entity, VeinAction(entity, action.image_store),
ticks + entities.get_rate(entity))
return tiles
def vein_take_action(self, world, action, ticks):
entities.remove_pending_action(self.entity, action)
if isinstance(action, VeinAction):
return self.vein_action(world, action, ticks)
And this is in the file "worldmodel.py":
import entities
import pygame
import ordered_list
import actions
import occ_grid
import point
class WorldModel:
def __init__(self, num_rows, num_cols, background):
self.background = occ_grid.Grid(num_cols, num_rows, background)
self.num_rows = num_rows
self.num_cols = num_cols
self.occupancy = occ_grid.Grid(num_cols, num_rows, None)
self.entities = []
self.action_queue = ordered_list.OrderedList()
def update_on_time(world, ticks):
tiles = []
next = world.action_queue.head()
obj = VeinAction(entity, image_store)
while next and next.ord < ticks:
world.action_queue.pop()
tiles.extend(obj.vein_take_action(world, next.item, ticks))
tiles.extend(actions.take_action(world, next.item, ticks))
next = world.action_queue.head()
return tiles
The error message comes from the update_on_time function in "worldmodel.py". I thought that this was how you would call a method from a class in a different file in a function, but it doesn't work! What is the correct way to do this? Or, is it possible to do this? Thanks in advance.
You imported the module actions which contains the class VeinAction. However, Python does not know this. You need to tell Python where VeinAction is located by adding actions. before it:
obj = actions.VeinAction(entity, image_store)
That, or you could import VeinAction directly:
from actions import VeinAction
Either way, you need to make sure that Python can find the class VeinAction.