Python - Calling to a function within a method from another class - python

I'm using Python inside of Autodesk Maya but this should apply anywhere.
I have a class called bRigUI and it inherits from another class called wingUtils inside of the file wingUtilities.py
I can get to the self.gPrefix / etc. names by using inheritance. But I don't know how to get to the functions inside of the function that's inside of the class such as def cName(txt):
Here is the wingUtilities script:
import maya.cmds as cmds
class wingUtils():
def __init__(self):
pass
def wingUtil(self, *args):
self.gPrefix = cmds.textField(self.prefixField, q = True, text = True)
self.lPrefix = cmds.textField(self.leftPrefixField, q = True, text = True)
self.rPrefix = cmds.textField(self.rightPrefixField, q = True, text = True)
def cName(txt):
n = self.gPrefix + (txt)
def lName(txt):
n = self.gPrefix + self.lPrefix + (txt)
def rName(txt):
n = self.gPrefix + self.rPrefix + (txt)
w = wingUtils()
And here is a VERY dumbed down UI script that is trying to call it (and is also the class with the inheritance) - this script wont work, it's just a shell to show you what I'm doing without all the clutter.
import maya.cmds as cmds
import jtWingRigAutomation.wingUtilities as wingUtilities
reload(wingUtilities)
class bRigUI(wingUtilities.wingUtils):
def __init__(self):
bRigUI = 'bRigUI'
if cmds.window(bRigUI, exists = True):
cmds.deleteUI(bRigUI)
bRigUI = cmds.window('bRigUI', title = 'JT Wing Rig Automation')
form = cmds.formLayout()
tabs = cmds.tabLayout(innerMarginWidth = 5, innerMarginHeight = 5)
cmds.formLayout(form, e = True, attachForm=((tabs, 'top', 0), (tabs, 'left', 0), (tabs, 'bottom', 0), (tabs, 'right', 0)))
tab2 = cmds.rowColumnLayout('Wing Setup', parent = tabs)
cmds.text(self.naming(), parent = tab2)
cmds.showWindow(bRigUI)
cmds.window(bRigUI, e = True, w = 250, h = 500)
b = bRigUI()
What do I enter in the UI script to call to the function cName within the method within the wingUtils class?

You can't. cName is a local variable which only exists within the function context of wingUtils.wingUtil, and is only accessible via code within that function.

The only way would be to move the inner functions to the outer scope. Do you have a good reason for them to be function-internal? If so, there's no way to do what you want. Otherwise you may consider rewriting that class. Currently the three functions cName(), lName() and rName() do absolutely nothing, because no code can call them from outside, and they're not being called inside. In this case it's as easy as unindenting them, and adding self:
class wingUtils():
def __init__(self):
pass
def wingUtil(self, *args):
self.gPrefix = cmds.textField(self.prefixField, q = True, text = True)
self.lPrefix = cmds.textField(self.leftPrefixField, q = True, text = True)
self.rPrefix = cmds.textField(self.rightPrefixField, q = True, text = True)
def cName(self, txt):
n = self.gPrefix + (txt)
def lName(self, txt):
n = self.gPrefix + self.lPrefix + (txt)
def rName(self, txt):
n = self.gPrefix + self.rPrefix + (txt)

Related

Python class scope lost in nested recursion function

When I attempted to write a recursive nested function within a python class, every time the recursive function completed and returned back to the first function my class property reverted back to the original state.
def main():
input = [
[1,3,1],
[1,5,1],
[4,2,1]
]
sln = Solution()
sln.findPath(input)
print("Output: " + str(sln.minPathSum))
print(*sln.minPath, sep = "->")
class Solution():
minPath = []
minPathSum = None
grid = []
def findPath(self, grid):
self.minPath = []
self.minPathSum = None
self.grid = grid
self.recurse(0,0,[])
def recurse(self, xCoord, yCoord, currentPath):
if(len(self.grid) <= yCoord):
return
if(len(self.grid[yCoord]) <= xCoord):
return
currentValue = self.grid[yCoord][xCoord]
currentPath.append(currentValue)
if(len(self.grid) - 1 == yCoord and len(self.grid[yCoord]) - 1 == xCoord):
currentPathSum = sum(currentPath)
if(self.minPathSum == None or currentPathSum < self.minPathSum):
self.minPathSum = currentPathSum
self.minPath = currentPath
else:
#right
self.recurse(xCoord + 1, yCoord, currentPath)
#down
self.recurse(xCoord, yCoord + 1, currentPath)
currentPath.pop()
return
if __name__ == "__main__":
main()
Running this results in:
Output: 7
Debugging the code within VSCode does indicate that self.minPath is getting set within the recurse function; however, it appears to be losing scope to the original class instance.
In addition I attempted to recreate the same nested situation with separate code and ended up with the following.
def main():
tst = ScopeTest()
tst.run()
print(*tst.tstArray)
print(tst.tstNumber)
class ScopeTest():
tstArray = []
tstNumber = 0
def run(self):
self.otherFunc()
def otherFunc(self):
self.tstArray = [1,2,3,4,5]
self.tstNumber = 7
if __name__ == "__main__":
main()
The above did return the expected outcome which leads me to think this has something to do with the recursion.
Just a heads up, I'm fairly new to python so I may be making a rookie mistake, but I can't seem to figure out why this is happening.
Your recurse() method is generating a currentPath parameter and when this is deemed to be correct you execute: self.minPath = currentPath. Unfortunately, you just reference the same object as currentPath which is later mutated.
Your line should be: self.minPath = currentPath[:]
You then see some contents in self.minPath
Mandatory link to Ned Batchelder
Also you can remove these lines:
minPath = []
minPathSum = None
grid = []
from just below class Solution():

How to re-execute a file

I am trying to re-execute a file's code within the program
main.py
# Within the main.py
exec(open('PDM/Path2.py').read())
PDM/Path2.py
# Within the file being read
import tkinter as tkin
class path2_wind:
def __init__(self):
self.path2 = tkin.Tk()
self.path2.geometry('400x430')
self.path2.title('PDM/Path_2')
self.sight = tkin.PhotoImage(file='PDM/Path_2.Sight.png')
self.back = tkin.Label(self.path2,image=self.sight)
self.back.pack(side='top')
self.frame = tkin.Frame(self.path2)
self.hello = tkin.Label(self.frame,text='Welcome User (Name Here)')
self.back = tkin.Button(self.frame,text='Back',command = self.path2.destroy)
self.frame.pack(side='top')
self.hello.pack(side='left')
self.back.pack(side='left')
tkin.mainloop()
open = path2_wind()
The error displayed is TypeError: 'path2_wind' object is not callable.
It is because you have override the standard function open() by the line:
open = path2_wind()
So when the following code is being executed again:
exec(open('PDM/Path2.py').read())
it raises the exception since open is not the standard function now.
Use other name instead of open, for example:
win = path2_wind()
As #TheLizzard stated in the comment, it is better to use import instead of exec():
main.py
from PDM.Path2 import path2_wind
win = path2_wind()
...
PDM/Path2.py
import tkinter as tkin
class path2_wind:
def __init__(self):
self.path2 = tkin.Tk()
self.path2.geometry('400x430')
self.path2.title('PDM/Path_2')
#self.sight = tkin.PhotoImage(file='PDM/Path_2.Sight.png')
self.sight = tkin.PhotoImage(file='images/nier-a2.png')
self.back = tkin.Label(self.path2,image=self.sight)
self.back.pack(side='top')
self.frame = tkin.Frame(self.path2)
self.hello = tkin.Label(self.frame,text='Welcome User (Name Here)')
self.back = tkin.Button(self.frame,text='Back',command = self.path2.destroy)
self.frame.pack(side='top')
self.hello.pack(side='left')
self.back.pack(side='left')
tkin.mainloop()
if __name__ == '__main__':
win = path2_wind()

Python class recording attributes without specifying self ?

I have a question regarding a Python class I use in Blender. Basically, I wonder how the class works because some attributes are recorded without me specifically writing self.value = something. Here's the code:
class DialogOperator(bpy.types.Operator):
bl_idname = "object.dialog_operator"
bl_label = "Save/Load animation"
saving = bpy.props.BoolProperty(name="Save ? Else load.")
path_to_anim = bpy.props.StringProperty(name="Path to folder")
anim_name = bpy.props.StringProperty(name="Animation name:")
# path_to_anim += "/home/mehdi/Blender/Scripts/"
def execute(self, context):
# print('This is execute with: Saving: {} Name:{}'.format(self.saving, self.path_to_anim))
if self.saving:
self.launch_save()
message = 'Animation {} saved at {}'.format(self.anim_name, self.path_to_anim)
else:
self.launch_load()
message = 'Animation {} loaded'.format(self.anim_name)
self.report({'INFO'}, message)
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
return wm.invoke_props_dialog(self)
def launch_load(self):
full_path = self.path_to_anim + self.anim_name
target_armature = Humanoid(bpy.data.objects['Armature'])
load_all(full_path, target_armature, 'LastLoaded')
def launch_save(self):
full_path = self.path_to_anim + self.anim_name
source_armature = Humanoid(bpy.data.objects['Armature'])
curves = source_armature.get_curves()
save_all(curves, source_armature,full_path)
Now, how come saving, path_to_anim and anim_name are considered as attributes (I'm able to call them in execute() and launch()) even though I did not write self.saving = saving
Thanks !
This is because saving,path_to_anim and anim_name are class attributes. They are defined for the class and not for a particular instance. They are shared among the instances. Here is a link for further explanation class-instance-attributes-python

How to pass parameters into __init__ function

I am starting my journey in python. I want to create a program that will convert my xlsx file into an sql file and then load data into a data base.
I want to create class that will have two parameters:
ex - will open xlsx workbook
sh - will open sheet from ex with correct index
This is initial version (for now I am just printing rows):
class XToSql():
def __init__(self, ex = xlrd.open_workbook('ex1.xlsx'), sh = ex.sheet_by_index(0)):
self.ex = ex
self.sh = sh
def modify(self):
for i in str((self.sh.nrows-1)):
a = 1
print(self.sh.row_values(a))
a += 1
a1 = XToSql()
a1.modify()
In the __init__ function, this line is marked with red color: sh = ex.sheet_by_index(0) -> and this error appears after Run:
def __init__(self, ex = xlrd.open_workbook('ex1.xlsx'), sh = ex.sheet_by_index(0)):
NameError: name 'ex' is not defined
Any ideas what I am doing wrong?
In __init__'s parameter list, ex has not been evaluated yet so sh = ex.sheet_by_index(0)) is throwing the NameError. This happens when the class object is being created.
You can do a couple of things. One reason to write a class is so you can reuse it, so maybe the class should only except the filepath as an argument.
class XToSql():
def __init__(self, ex_file):
self.ex = xlrd.open_workbook(ex_file)
self.sh = self.ex.sheet_by_index(0)
def modify(self):
for i in str(self.sh.nrows - 1):
a = 1
print(self.sh.row_values(a))
a += 1
Maybe you should be able to specify the sheet to process
class XToSql():
def __init__(self, ex_file, sheet=0):
self.ex = xlrd.open_workbook(ex_file)
self.sh = self.ex.sheet_by_index(sheet))
def modify(self):
for i in str(self.sh.nrows - 1):
a = 1
print(self.sh.row_values(a))
a += 1
And use it like this
a = XToSql(ex_file='ex1.xlsx', sheet=0)
ex is not available until inside the body of the __init__ method. You cannot access an argument of the method outside the body of the method.
You would need to do something like the following:
class XToSql:
def __init__(self, ex, sh=None):
self.ex = ex
if sh is None:
sh = ex.sheet_by_index(0)
self.sh = sh
And then call it like this:
a1 = XToSql(xlrd.open_workbook('ex1.xlsx'))

Button binding in Kivy Python

I am wondering how to get my code to work. I have a class wich creates a popup window with buttons. Each button should be bound to subclass. But it doesnt work. What´s wrong with my code?
class chooser:
def __init__(self):
None
def show(self,title,options=["NOTHING"],size=(.5,.5)):
self.bts = {}
self.response = False
self.content = FloatLayout()
self.content.pos_hint = {"y":0,"x":0}
# create buttons
pos_cntr = 0
for opt in options:
self.bts[pos_cntr] = Button(text=opt)
self.bts[pos_cntr].size_hint = 1,float(1)/float(len(options))
self.bts[pos_cntr].pos_hint = {"x":0,"y":pos_cntr}
self.bts[pos_cntr].bind(on_press=self.canceldia)
self.content.add_widget(self.bts[pos_cntr])
print "bound"
pos_cntr += float(1)/float(len(options))
self.pop = Popup(title=title,content=self.content,auto_dismiss=False)
self.pop.size_hint = size
self.pop.open()
def canceldia(self,instance):
print "closing"
self.response = instance.text
self.pop.dismiss()
def getresponse(self):
return self.response
I have imported all needed modules.
I execute it so:
c = chooser()
c.show("hello","world",["welcome","close","nothing","example"])
I have create a root widget. The popup works fine and all is created nice but the buttons are not bound. Please help me!
In your loop, you always reference self.bts[pos_cntr], so you override it in every iteration. How about this?
for idx, opt in enumerate(options):
self.bts[idx] = Button(text=opt)
self.bts[idx].size_hint = 1,float(1)/float(len(options))
self.bts[idx].pos_hint = {"x":0,"y":pos_cntr}
self.bts[idx].bind(on_press=self.canceldia)
self.content.add_widget(self.bts[idx])

Categories