Python exercises in Houdini ?

   20309   40   1
User Avatar
Member
250 posts
Joined: Feb. 2013
Offline
Hi everyone,

I'm learning Python, but the problem is that I do more theoretical (theory ?) than practice. So I don't progress.

Do you know where I can find little Python exercises in Houdini ?
Or can someone give me one ?

The problem is that so much thing are possible without scripting in Houdini that I don't even know what are the Python possibilities in Houdini…

Thanks !
https://vimeo.com/obreadytom [vimeo.com]
User Avatar
Member
678 posts
Joined: July 2005
Offline
I need shelf tool that will handle turning on/off Bypass flag on SOP nodes of specified type (example: “file”, “transform”, “cap”) in selected by me OBJ nodes of type “geo” (Geometry).

Basically, I run the tool, it asks me to select some OBJ (or more than one), when I accept selection window popups and gives me string field in which I can write node type that I want to turn on/off, and 3 buttons:
- ON
- OFF
- Cancel

You got one day for this task.

See you!


PS. You will get BONUS POINTS if you give me tool prepared as a separate *.shelf file, so I could just copy the file in my “toolbar” directory and load your shelf just like that without any code pasting myself. This will be the file in which you will store your future assignments from me or other users here.
User Avatar
Member
250 posts
Joined: Feb. 2013
Offline
Let's do it ! Thanks !
https://vimeo.com/obreadytom [vimeo.com]
User Avatar
Member
250 posts
Joined: Feb. 2013
Offline
I might be a bit late
https://vimeo.com/obreadytom [vimeo.com]
User Avatar
Member
678 posts
Joined: July 2005
Offline
Lewul
I might be a bit late

How many days? What is the reason? Your hamster got sick?

Come on. That's like 100-150 max lines of code, if I count comments too.

Everybody are counting on you!

EDIT: I will make this easier for you. You can ask for help on odforce or here, but make sure to link to this topic, so everybody knows exactly why are you need it.
User Avatar
Member
250 posts
Joined: Feb. 2013
Offline
Well I'm only a beginner

I know how to make a little ui, list what the user has written in the textfield, etc. But I don't know how to select sop nodes inside my objects, and how to select only the nodes that the user wrote. I really feel dumb. I don't blame Houdini, I know that it's my fault here.

I may need more tutorials on the subject, but even “Python and Houdini 11” from SideFX is not so simple.

But I don't need a lot for finishing the exercice. I know how to bypass, I have my list of words, my little ui (very simple of course), but how to select IN objects ? For example how to select xform and sphere only in geo1.
https://vimeo.com/obreadytom [vimeo.com]
User Avatar
Member
678 posts
Joined: July 2005
Offline
Lewul
But I don't know how to select sop nodes inside my objects, and how to select only the nodes that the user wrote.

http://lmgtfy.com/?q=houdini+%22findAllChildNodesOfType%22 [lmgtfy.com]
User Avatar
Member
250 posts
Joined: Feb. 2013
Offline
Haha thanks !
https://vimeo.com/obreadytom [vimeo.com]
User Avatar
Member
250 posts
Joined: Feb. 2013
Offline
I finished it ! I know, very late… But my goal is to learn, and really your exercise helped me a lot. And you were right to press me. I really want to thank you for it, even my teachers don't give me exercices (and I asked for one in Nuke, I'm still waiting for it). I know that it is not perfect, it seems to work okay, and there are some issues here and there.

import toolutils
import hou

def bypassUI():
# creation of the ui
textFieldUser = hou.ui.readInput('Bypass :', , title='Bypass', close_choice=2, initial_contents= ‘<Node(s) type>’)
# variable for the user's text
n = textFieldUser
str(n)
listText = n.split(' ')

# messages to print when press buttons
if textFieldUser == 0:
print ‘ON’
elif textFieldUser == 1:
print ‘OFF’
elif textFieldUser == 2:
print ‘CANCEL’


for n in selection:
for x in listText:
pathSel = n.path() # path of selected nodes
childNodes = toolutils.findAllChildNodesOfType(hou.node('%s'%pathSel), ‘%s’%x, dorecurse=True) # finding children of selection
if childNodes != : # if the name exist
lenChild = len(childNodes) # the lenght of the children contain the objects selected,
# an object may contain more than one type of the same node for example
for j in range(lenChild):
pathChild = childNodes.path() # the path of each child
toBypass = hou.node('%s'%pathChild)
if textFieldUser == 0: # if user press ON
toBypass.bypass(0)
elif textFieldUser == 1: # if user press OFF
toBypass.bypass(1)
else: # if the word(s) doesn't exist
print ‘Cannot find %s in %s’%(x, pathSel)


### Selection and UI

selection = hou.selectedNodes() # Objects selected

if selection == (): # if selection is empty
print ‘Select at least one object’
else:
print ‘Your selection :’ # launch bypassUI() function
for n in hou.selectedNodes():
print n.path()
bypassUI()


### Questions:

# - How can I print a warning message in the long dialog window at the bottom (don't know the name, sorry) ?
# - How can I keep the ui when pressing “ON” or “OFF” ?
# - Why is it not working when I'm in a node ?

I'm sorry I don't know to export the *.shelf…

I know that this one is maybe not finished, but can you give me an other one please ? I will have my classes next week but I really want it to be a priority.
https://vimeo.com/obreadytom [vimeo.com]
User Avatar
Member
678 posts
Joined: July 2005
Offline
1 - How can I print a warning message in the long dialog window at the bottom (don't know the name, sorry) ?
2 - How can I keep the ui when pressing “ON” or “OFF” ?
3 - Why is it not working when I'm in a node ?

1. Look for
hou.ui.setStatusMessage()
2. With readInput() you can't. This is really simple functionality. For anything more functional you have to code your UI in some external GUI library. Check those two links:
http://www.sidefx.com/docs/houdini13.0/hom/cookbook/wxPython/ [sidefx.com]
http://www.sidefx.com/docs/houdini13.0/hom/cookbook/pyqt/ [sidefx.com]
3. Use:

toolutils.sceneViewer().selectObjects()
for object selection, instead of
hou.selectNodes()
EDIT:
If you want to use it on SOP level, you have to check for it.
findAllChildNodesOfType() requires parent in which it searches for correct childs. SOP node doesn't have children (subnet have, but it's not a node like any other), so it fails. When findAllChildNodesOfType() fails, you could check if the parent node that we send to it is of type we are looking for and then execute the rest of the code.

I know that this one is maybe not finished, but can you give me an other one please ?

Nope, you have to learn write code, not leave it unfinished. Next time you will write the code to external files, so you will start building library of reusable functions that may be helpful in other tools that you may write in the future, so you have to know why split your code and when.

I'm sorry I don't know to export the *.shelf…

RMB on shelf tool and pick “Edit Tool”. There is a path “Save To” where you can specify the file to which it should be saved.

——————————————————————————————————–
Now your code.
——————————————————————————————————–
1. Don't use:
%
for string formating. It works in python 2.7, but in python 3.0 and up it's depracated. So if we switch to it in the future, you scripts will fail. Read this:
http://stackoverflow.com/questions/13945749/string-formatting-in-python-3 [stackoverflow.com]
2. For the same reason like in “1.”, don't use

print something

format. It will fail in Python 3.0. Use:

print (something)

3. Purpose of the function is to do one thing, and only one thing. In your code bypassUI() function is used for doing many things. It reads user input, finds the nodes and sets flags on them. Those are three things that you could split on couple functions that you could maybe reuse in the future.

I would split this like that:
1. SelectGeoNodes() - this function asks user to select geometry nodes, and if the user doesn't select anything, it prints error message. If user selected nodes, it should return them.
2. SpecifyNodeTypeAndState() - this is function that takes care of displaying popup window where user can write node types. All the filtering of the string that was passed should be made here (removing white spaces and splitting string to filter each node type.
This is also place where you can specify what should be returned if user pressed cancel button.
3. FindSpecifiedNodes(parent, nodetype) - this is function that finds specified nodes in each node that was returned by SelectGeoNodes(). This is also place where you should send some warning message if node wasn't found.
4. DisableOrEnableNodes(nodelist, state) - this should take care of setting bypass flag on each node that was returned by FindSpecifiedNodes(). It should also break execution if user pressed Cancel button in SpecifyNodeTypeAndState() so make sure you return correct data that you can use from all those functions.
5. DisableOrEnableNodes_Tool() - this should be your main function. This is place where you execute all previous functions and pass data returned by each to the next one. This is also place where you check if there was something returned at all, by each function, if there wasn't, terminate execution of the tool.
User Avatar
Member
250 posts
Joined: Feb. 2013
Offline
Thanks Mantragora, I will study it tomorrow. And I'll try to finish it also.

Just one question, is Houdini using Python 3 ? Nuke and Maya are using Python 2.7 I think, is it really important to learn 3 ? (I'm not saying that I don't want to learn it, it's just for information)
https://vimeo.com/obreadytom [vimeo.com]
User Avatar
Member
678 posts
Joined: July 2005
Offline
Python 3.0 is not that much different than Python 2.7. All the programs still use some version of Python 2.X, but why to write things in a manner that works only in Python 2.X while you could write them so they could work also in Python 3.0?


''.format()

and

print('')


works in 2.7 and 3.0 and up, so you don't learn Python 3.0, you just learn Python 2.7 in a correct, future proof, way
User Avatar
Member
250 posts
Joined: Feb. 2013
Offline
import toolutils
import hou

### Functions:

def SelectGeoNodes():

global geoSelected

hou.ui.setStatusMessage('Select one or more Geometry node', severity=hou.severityType.ImportantMessage)
if selection == (): # if selection is empty
hou.ui.setStatusMessage('Select at least one Geometry node', severity=hou.severityType.ImportantMessage)
print('Select at least one Geometry node')
geoSelected = 0

else:
print('Your selection :') # print the selection and go to the next function
for n in hou.selectedNodes():
print n.path()
geoSelected = 1


def SpecifyNodeTypeAndState():

global buttons
global listText
global textFieldUser

# creation of the ui
textFieldUser = hou.ui.readInput('Bypass :', , title='Bypass',
close_choice=2, initial_contents= ‘<Node(s) type>’)
# variable for the user's text
n = textFieldUser
str(n)
listText = n.split(' ')

# messages to print when press buttons
if textFieldUser == 0:
print('ON')
buttons = 1
elif textFieldUser == 1:
print('OFF')
buttons = 1
elif textFieldUser == 2:
print('CANCEL')
buttons = 0


def FindSpecifiedNodes(selection, listText):

global bypass
global childNodes
global lenChild

if listText == :
hou.ui.setStatusMessage('Textfield empty', severity=hou.severityType.ImportantMessage)
print('Textfield empty')
bypass = 0
else:
for n in selection:
for x in listText:
pathSel = n.path() # path of selected nodes
childNodes = toolutils.findAllChildNodesOfType(hou.node('{0}'.format(pathSel)), ‘{0}’.format(x),
dorecurse=True) # finding children of selection
if childNodes != : # if the name exist
lenChild = len(childNodes) # the lenght of the children contain the objects selected,
# an object may contain more than one type of the same node
# for example
else: # if the word(s) doesn't exist
hou.ui.setStatusMessage('Cannot find {0} in {1}'.format(x, pathSel))
print('Cannot find {0} in {1}'.format(x, pathSel))
bypass = 1


def DisableOrEnableNodes(childNodes, textFieldUser):

for j in range(lenChild):
pathChild = childNodes.path() # the path of each child
toBypass = hou.node('{0}'.format(pathChild))
if textFieldUser == 0: # if user press ON
toBypass.bypass(0)
elif textFieldUser == 1: # if user press OFF
toBypass.bypass(1)


def DisableOrEnableNodes_Tool():

SelectGeoNodes()
if geoSelected == 1: # if nothing is selected
SpecifyNodeTypeAndState()
if buttons == 1: # if buttons are ON or OFF
FindSpecifiedNodes(selection, listText)
if bypass == 1: # if the textfield is not empty, then the bypass function is launched
DisableOrEnableNodes(childNodes, textFieldUser)



### Selection and function starting:

selection = hou.selectedNodes() # Objects selected
DisableOrEnableNodes_Tool() # main function

### Questions:
# - In DisableOrEnableNodes_Tool() function, is it the good way to call the others functions?
# By putting some variables in others functions and calling them back in the main… ?
# - In this specific case I don't know why I have to put argument in some of my functions…
# - I may be wrong with all the “global” thing in my functions, I'm a bit confuse about it (I need to check more of it)


So I followed what you told me, about Python 3, functions, etc.

Attachments:
Bypass.shelf (4.4 KB)

https://vimeo.com/obreadytom [vimeo.com]
User Avatar
Member
678 posts
Joined: July 2005
Offline
Lewul
### Questions:
1 - In DisableOrEnableNodes_Tool() function, is it the good way to call the others functions?
2 - By putting some variables in others functions and calling them back in the main… ?
3 - In this specific case I don't know why I have to put argument in some of my functions…
4 - I may be wrong with all the “global” thing in my functions, I'm a bit confuse about it (I need to check more of it)

1. Yeah, its purpose is to execute all of them and check did they return data. All the other things (ui, filtering user input, bypassing nodes etc.) are handled by those functions that it calls. So it's still doing only one thing. Executes other functions.
2. , 3.
and
4. Read about “return” keyword in functions. Use it instead of “global” to pass data from one function to the other in DisableOrEnableNodes_Tool(). Check also how to return more than one value from functions, so you could, for example, return node types and number of the button that was pressed in SpecifyNodeTypeAndState(). Basically, every function beside DisableOrEnableNodes_Tool() should return some data. When you learn about return keyword, you will understand why you need to pass arguments to functions.

BTW. As a bonus, read about function commenting in python. Do not mistake this with code commenting.
Edited by - June 17, 2014 16:00:17
User Avatar
Member
250 posts
Joined: Feb. 2013
Offline
Thanks ! So I will learn this.

EDIT : I don't want to bother you, and maybe that my code is not finished here, but do you think that you will be able to give me another exercice ? I know that my level is very low, but I want to learn, and it's the only way to progress I think.
https://vimeo.com/obreadytom [vimeo.com]
User Avatar
Member
250 posts
Joined: Feb. 2013
Offline
Oh I'm seeing that my code isn't working correctly… :?
https://vimeo.com/obreadytom [vimeo.com]
User Avatar
Member
250 posts
Joined: Feb. 2013
Offline
Okay so I corrected it.

It's strange because if I add a list with the result of findAllChildNodesOfType() (which contains more than one object in general), it can't find the attribute path that is contain in the result (with a for loop in the list I mean, so checking for each child one by one). But if the result of findAllChildNodesOfType() is only one value, then it finds the path… So I wasn't able to store all the children node type in one list and use it later for findind each path.

So I had to kill my bypass function and add it in the function where I find do the findAllChildNodesOfType().

And it allow me to correct some mystakes.

Attachments:
Bypass.shelf (3.5 KB)

https://vimeo.com/obreadytom [vimeo.com]
User Avatar
Member
678 posts
Joined: July 2005
Offline
Why you are still using Global keyword?

Read this => http://www.tutorialspoint.com/python/python_functions.htm [tutorialspoint.com]

Do you see Global keyword anywhere in this link? I told you, use return keyword instead.
User Avatar
Member
250 posts
Joined: Feb. 2013
Offline
Yes sorry, I was somewhere else when I was correcting (= thinking about something else, I don't know if we can say it in english), I wanted to ask one of my teacher about return (he's in the same room actually, but he is busy).

Thanks for the link.
https://vimeo.com/obreadytom [vimeo.com]
User Avatar
Member
250 posts
Joined: Feb. 2013
Offline
I'm stuck, I don't know how to replace my “global”, I'm confused…

So I think that everything is working fine now (I hope), but I don't understand how to return my variables through other functions without the global. Do you have an example that can lead me to a solution ? I understand it in your links, but I'm confusing with the arguments in my script, the variables that should be global, etc. I also checked about multiple values in a return, but still I don't know how to apply it in this script.

I really don't want to take bad habits like with the “global”.

Attachments:
Bypass.shelf (4.5 KB)

https://vimeo.com/obreadytom [vimeo.com]
  • Quick Links