How can I write my own decorator using xlwings decorators to create Excel UDFs - xlwings

I would like to write my own decorator to create UDFs in Excel using xlwings decorator. However, when I import my function, the function name imported is the decorator inner function name's.
A dummy example to clarify:
import pandas as pd
import numpy as np
import xlwings as xw
def to_excel(f): # my decorator
#xw.func
#xw.arg('xl_app', vba='Application')
def wrapped(xl_app, arg1 =None, arg2 =None):
# do some stuff
return len(f(arg1, arg2))
return wrapped
def foo(dim1, dim2):
dim1, dim2 =int(dim1), int(dim2)
return pd.DataFrame(np.ones((dim1, dim2)))
#to_excel
def xlFoo(*args, **kwargs): # Excel UDF
return foo(*args, **kwargs)
If I import it into Excel, it will auto generate the below VBA code:
'Autogenerated code by xlwings - changes will be lost with next import!
Function wrapped(Optional arg1, Optional arg2)
If TypeOf Application.Caller Is Range Then On Error GoTo failed
wrapped = Py.CallUDF("xl2", "wrapped", Array(Application, arg1, arg2), ThisWorkbook, Application.Caller)
Exit Function
failed:
wrapped = Err.Description
End Function
If I replace wrapped by xlFoo, it now works as expected:
Function xlFoo(Optional arg1, Optional arg2)
If TypeOf Application.Caller Is Range Then On Error GoTo failed
xlFoo = Py.CallUDF("xl2", "xlFoo", Array(Application, arg1, arg2), ThisWorkbook, Application.Caller)
Exit Function
failed:
xlFoo = Err.Description
End Function

Related

how to pass arguments between pythons scripts in MAYA?

I'm new in python and i'm trying to pass arguments between different scripts but they only update one way:
i'm calling the first script in maya with a shelf like this:
try:
myPM.close()
except:pass
import sys
sys.path.append("C:/Users/manue/Desktop/test")
import UiMayaTest as SBIRP
reload(SBIRP)
myPM = SBIRP.createUI()
this called script 'UiMayaTest.py' is a simple window with an intField entry and a button:
import sys
import maya.cmds as cmds
from functools import partial
def buttonPressed(episode, *args):
passValue(episode, *args)
print '============== buttonPressed ================'
print 'EpisodeName ', EpisodeName
Var = ''
import UiMayaTestFunction
Var = UiMayaTestFunction.FindVarFunc(EpisodeName,Var)
print 'Var : ',Var
def createUI():
myWindow = "SomeWindow"
if cmds.window(myWindow,ex=True):
cmds.deleteUI(myWindow)
cmds.window(myWindow)
cmds.columnLayout( adjustableColumn=True )
cmds.text( label='Episode: ', align='left' )
episode = cmds.intField( "Episode", minValue = 100, maxValue = 1000, value =100)
cmds.button(l="Open Last LIT scene", w=150, h=30, command=partial(buttonPressed,episode))
cmds.setParent("..")
cmds.showWindow()
def passValue(episode, *args):
global EpisodeName
EpisodeName = `cmds.intField( episode, query = True, value = True)`
and the script called by it is called 'UiMayaTestFunction.py' and just return a variable called Var:
def FindVarFunc(EpisodeName, Var):
print '============== FindVarFunc ================'
print 'EpisodeName:' , EpisodeName
Var = 'Hello world'
print 'Var: ',Var
return Var
the variable 'EpisodeName' from UiMayaTest to UiMayaTestFunction is well updated each time i press the button,
but if i change the variable 'Var' in UiMayaTestFunction , it doesn't update it, i've got always the same print or 'Var'...
Thanks by advance for any help...
Well.... it seems that the script does exactly do what it is supposed to do. What result for your Var variable do you expect?
Let's see.. if the button is pressed, the buttonPressed() function is called. There the variable 'Var' is initialized with an empty string ''. Then teh FindVarFunc() is called with the argument Var, what is still an empty string. In the FindVarFunc() the Variable 'Var' is printed and returnde, what is still.... well you guess it: an empty string. And finally the result of the function is assigned to the variable 'Var', and the result is... an empty string which is printed. It could help to assign 'Var' something else but an empty string to see if it works better.

Multiprocessing fails for ctypes shared library function inside class

I think my question was not very clear before..
I'm trying to create a class module that includes a function does a mutiprocessing of a ctpyes function.
I'm re-posting a working small code.
All I want to do is to remove the code below and call the function directly from my class. But it seems very hard since ctypes object is not picklable.. Is there a way to resolve this issue? Even a small hint will be appreciated!! Will I have to switch to using cython instead of ctypes? will that even help?
def myc(x):
return a.funct(x)
Below is the working code.
from ctypes import *
from ctypes.util import find_library
import multiprocess as mp
class ctest():
def __init__(self):
self.libapr = cdll.LoadLibrary(find_library('apr-1'))
self.libapr.apr_fnmatch.argtypes = [c_char_p, c_char_p, c_int]
self.libapr.apr_fnmatch.restype = c_int
def funct(self,x):
y=self.libapr.apr_fnmatch(x, 'name.ext', 0)
return y
def mymult(self,func,xlist):
pool=mp.Pool(20)
res=pool.map(func,xlist)
pool.close()
return res
if __name__ == "__main__":
a=ctest()
def myc(x):return a.funct(x)
print a.mymult(myc,['*.txt','*.ext'])
Below is what I want to do.
from ctypes import *
from ctypes.util import find_library
import multiprocess as mp
class ctest():
def __init__(self):
self.libapr = cdll.LoadLibrary(find_library('apr-1'))
self.libapr.apr_fnmatch.argtypes = [c_char_p, c_char_p, c_int]
self.libapr.apr_fnmatch.restype = c_int
def funct(self,x):
y=self.libapr.apr_fnmatch(x, 'name.ext', 0)
return y
def mymult(self,func,xlist):
pool=mp.Pool(20)
res=pool.map(func,xlist)
pool.close()
return res
if __name__ == "__main__":
a=ctest()
a.mymult(a.funct,['*.txt','*.ext'])

Mocking SOAPpy method call

I'm trying to mock a SOAPProxy call, setting a return value, but it is refusing to work:
#patch('SOAPpy.SOAPProxy')
def test_check_cedible_mock(self, mock_soappy):
mock_soappy.getToken.return_value = ':)'
#calling the function...
In the function, it is used like this:
from SOAPpy import SOAPProxy
_server = SOAPProxy(url, ns)
tree = etree.fromstring(signed_seed)
ss = etree.tostring(tree, pretty_print=True, encoding='iso-8859-1')
resp = etree.fromstring(_server.getToken(ss).encode('utf-8'))
But _server.getToken(ss) is returning a MagickMock object.
How can I make it to work? Thanks.

traits ui (enthought) and callback from C

I have the code:
import time
import numpy as np
from scipy.optimize import fmin_tnc
from enthought.traits.api import *
from enthought.traits.ui.api import *
class Minimizer(HasTraits):
iteration = Int(0)
run = Button
def callback(self, x):
self.iteration += 1
print self.iteration
time.sleep(0.5)
def func(self, x):
return (x**2).sum()
def fprime(self, x):
return 2*x
def minimize(self):
x0 = np.random.rand(50)
fmin_tnc(self.func, x0, fprime=self.fprime, messages=0, callback = self.callback)
def _run_fired(self):
self.minimize()
traits_view = View(Item('iteration'), UItem('run'))
m = Minimizer()
m.configure_traits()
After running the above and pressing Run button i expected the 'iteration' attribute will be updated in the GUI at each iteration, but this is not the case. I suspect that this is because this value is changed by callback from C. What should be done to update the user interface in these circumstances?
Regards,
Marek
The call to m.configure_traits() is blocking, which means execution of your script will not continue past that line until you close the window created by that call. In other words, m.minimize does not get called while the window is open.
I found the solution. Simply, 'minimize' method have to be non-blocking, so implementing minimization in separate thread, like this:
def minimize(self):
x0 = np.random.rand(50)
#fmin_tnc(self.func, x0, fprime=self.fprime, messages=0, callback = self.callback)
import thread
thread.start_new_thread(fmin_tnc, (self.func, x0), {'fprime':self.fprime, 'messages':0, 'callback':self.callback})
will result in updating the UI at real-time...
Thanks,
Marek

How to invoke a method from combo box event

I am trying to invoke a method from combo box selected change event
with lambda expression but I am stuck with following error
TypeError: () takes no arguments (1 given)
I think I have passed 1 argument as per the method definition, could somebody please help me where I am wrong
or any other combobox selected change event code will be great help!
please note my code
self.boxWidget[boxName].bind("<<ComboboxSelected>>", lambda:invoke_Setting_Group(self))
def invoke_My_method1(self):
print "expand another window"
I am trying to pass the first class object to the second python script file for variable value assigning easeness.I tried to use this combox event change code without lambda then I noticed that this method is getting called automatically so I used lambda to prevent this automatic method calling
Sorry I am not having the knowledge on lambda expression usage; here I used only to prevent the automatic method execution. Without lambda expression I noticed my combo box function starts automatically, I did not understand why it happens so?
I am using TKinter python 2.6
More Detailed Code of above:
#Main_GUI_Class.py
##----------------------
import sys
class App():
def __init__ (self,master,geometry=None,root=None):
try:
self.master=master
if not root:
self.root=Tkinter.Toplevel(master)
def initUI(self):
try:
self.master.title("GUI")
menubar = Menu(self.master)
self.root.config(menu=menubar)
fileMenu.add_command(label='Open')
submenu_ncss.add_command(label='Model Setting',command=lambda:Combo_Expand_Script.Call_Model_Setting(self))
##----------------------
def main():
r = Tkinter.Tk()
r.withdraw()
r.title("GUI Sample")
r.wm_iconbitmap(Pic1)
v = App(r)
r.mainloop()
if __name__ == "__main__":
main()
##Combo_Expand_Script.py
##-----------------------
import sys
import Tkinter
import Main_GUI_Class
def Call_Model_Setting(self):
try:
self.PopUpWin = Toplevel(bg='#54596d',height=500, width=365)
self.PopUpWin.title("POP UP SETTING")
#Combo Boxs in Pop Up
boxNameGroup="boxSetting"
boxPlaceY=0
for Y in range(4):
boxName=boxNameGroup+str(Y)
if Y == 0:
boxPlaceY=50
else:
boxPlaceY=boxPlaceY+40
self.box_value = StringVar()
self.boxWidget[boxName] = ttk.Combobox(self.PopUpWin, height=1, width=20)
if Y== 0:
self.boxWidget[boxName]['values'] = ('A', 'B')
self.boxWidget[boxName].current(1)
if Y== 1:
self.boxWidget[boxName]['values'] = ('X', 'Y')
self.boxWidget[boxName].bind("<<ComboboxSelected>>",lambda:invoke_Setting_Group(self))
self.boxWidget[boxName].place(x=180, y = boxPlaceY)
#Buttons in Pop Up
self.btnApply = tk.Button(self.PopUpWin,width=10, height=1,text="Apply",relief=FLAT,bg=btn_Bg_Color,command=lambda: treeDataTransfer(self,0))
self.btnApply.pack()
self.btnApply.place(x=75, y = 460)
self.btnCancel = tk.Button(self.PopUpWin,width=10, height=1,text="Cancel",relief=FLAT,command=lambda: deleteTreeNodes(self))
self.btnCancel.pack()
self.btnCancel.place(x=170, y = 460)
except IOError:
print "Error: data error"
def invoke_Setting_Group(self):#, event=None
try:
#self.boxName.current(0)
self.boxWidget["boxSetting3"].current(0)
self.PopUpWin['width']=1050
self.PopUpWin['height']=700
self.btnApply.place(x=500, y = 550)
self.btnCancel.place(x=600, y = 550)
self.txtWidget={}
lsttxtSetting = ['1', '2','3 ','4','5 ','6','7','8','9','10']
for t in range(10):
txtName=txtNameGroupTS+str(t)
if t == 0:
txtPlaceY=120
else:
txtPlaceY=txtPlaceY+30
self.txtWidget[txtName] = Text(self.groupSettingFrame,height=1, width=10,borderwidth = 2)
self.txtWidget[txtName].insert(INSERT, lsttxtSetting[t])
self.txtWidget[txtName].pack()
self.txtWidget[txtName].place(x=200, y = txtPlaceY)
except IOError:
print "Error: Group Settings Popup error"
def turbDataTransferBind(self):
for P in range(0,3):
boxName="boxSetting"+str(X)
dataSettingbox=self.lstTurb[X]+" "+self.boxWidget[boxName].get()
self.root_node_Setting = self.tree.insert( self.root_node_ChildSetting["ChildSettingNode"], 'end', text=dataSettingbox, open=True)
def treeDataTransfer(self,dlgTurbFlag):
self.treeDataTransferBind()
print "data tranfer sucess"
def deleteTreeNodes(self):
print "delete nodes"
command= and bind expect function name - without () and arguments - so in place of
If you use
.bind("<<ComboboxSelected>>", invoke_Setting_Group(self) )
then you use result from invoke_Setting_Group(self) as second argument in .bind(). This way you could dynamicly generate function used as argument in bind
TypeError: () takes no arguments (1 given)
This means you have function function() but python run it as function(arg1)
You run lambda:invoke_Setting_Group(self) but python expects lambda arg1:self.invoke_Setting_Group(self)
You could create function with extra argument
def invoke_My_method1(self, event):
print "expand another window"
print "event:", event, event.widget, event.x, event.y
And then you could use it
.bind("<<ComboboxSelected>>", lambda event:invoke_Setting_Group(self, event))
BTW: it looks strange - you have class App() but in second file you use only functions instead of some class too.