How to get node parameter in Houdini with Python - python

I am very much new to Houdini and this might be something very obvious to ask but I have hit a brick wall. I would like to store a parameter, specifically the File Name of an alembic object so that I can validate the filename to see if it follows a namespace convention
The following is all I have
import hou
node = hou.node('obj/alembic1/alembic1')
after getting the node, how would I get the File Name property? Any guidance is greatly appreciated

There's two main ways:
1 As you you've started to do in your code, access the node then access the parm HOM method of Node:
parm = hou.node('obj/alembic1/alembic1').parm('fileName')
2 Use hou.parm directly:
parm = hou.parm('obj/alembic1/alembic1/fileName')
parm is an object representing a parameter, to get the value of the parameter you need to call it's eval method:
parmval = parm.eval()
So something like this is the usual case:
node = hou.node('obj/alembic1/alembic1')
parmVal = node.parm('fileName').eval()
Note that parm.eval() will work for most cases, but sometimes you might need more verbose methods such as parm.evalAsNode(). Check out the help here.
You can see the parm name to use in your code when you hover over the parameter name you want to access in the parameters window. Ie if you hover over "File Name" in the Alembic node it will show:
Parameter: fileName

Related

How to add objects to Sphinx's global index, or cross-reference by alias?

Each time I have to reference a method I rather not :func:`package.subpackage.module.method`, especially for frequently used methods. Is there a way to somehow "register" package.subpackage so that only module.method suffices? (Better yet, package.subpackage.module, so method suffices, assuming no conflicts).
A solution shouldn't involve adding directories to package or subpackage, but I'm fine adding whatever to docs/. Note that the problem here concerns a method defined outside of the docstring's module (otherwise .method works).
You could add a simple extension that will resolve the aliases you define. The below example is a short proof of concept for that:
# add this to conf.py
from sphinx.addnodes import pending_xref
from sphinx.ext.intersphinx import missing_reference
from docutils.nodes import Text
# alias ref is mapped to a pair (real ref, text to render)
reftarget_aliases = {
'foo.spam': ('foo.bar.baz.spam', 'spam'),
}
def resolve_intersphinx_aliases(app, env, node, contnode):
alias = node.get('reftarget', None)
if alias is not None and alias in reftarget_aliases:
real_ref, text_to_render = reftarget_aliases[alias]
# this will resolve the ref
node['reftarget'] = real_ref
# this will rewrite the rendered text:
# find the text node child
text_node = next(iter(contnode.traverse(lambda n: n.tagname == '#text')))
# remove the old text node, add new text node with custom text
text_node.parent.replace(text_node, Text(text_to_render, ''))
# delegate all the rest of dull work to intersphinx
return missing_reference(app, env, node, contnode)
def resolve_internal_aliases(app, doctree):
pending_xrefs = doctree.traverse(condition=pending_xref)
for node in pending_xrefs:
alias = node.get('reftarget', None)
if alias is not None and alias in reftarget_aliases:
real_ref, text_to_render = reftarget_aliases[alias]
# this will resolve the ref
node['reftarget'] = real_ref
# this will rewrite the rendered text:
# find the text node child
text_node = next(iter(node.traverse(lambda n: n.tagname == '#text')))
# remove the old text node, add new text node with custom text
text_node.parent.replace(text_node, Text(text_to_render, ''))
def setup(app):
app.connect('doctree-read', resolve_internal_aliases)
app.connect('missing-reference', resolve_intersphinx_aliases)
Now all refs :role:`foo.spam` will be replaced with :role:`spam <foo.bar.baz.spam>`, regardless of the exact role (class, func, mod, whatever). Sure, this is only a draft and untested, but you should get the idea. May be even a good starting point for a new Sphinx extension project :-)
From the moment you can see the class, function or method, in the index you can abreviate the writing of the name.
For example,
instead of writing the cross-reference with the fully qualified name:
:func:`~package.subpackage.module.method`
:meth:`~package.subpackage.module.method`
you can simply write:
:func:`.method`
:meth:`.method`
Notice the use of the dot . is necessary if you are cross-referencing something outside of your local scope. If, for example, you are referencing an attribute or method within the class where you write the cross-reference, then the following does work:
:meth:`method`
:attr:`method`
Notice also, that within the scope :meth: and :func: both work interchangeably. However, outside the scope you have to use the precise role, depending if you are referencing a method, or a function.
Be reminded you can have name collisions, since the same name can be used in different modules for different objects. In that case, you should use the fully qualified name to distinguish exactly which object you are referencing.
It's important to check the index to verify the object has already been inserted there (which is done automatically by the autodoc or domain directives in your .rst files). The normal index will display "object name (fully qualified name)", if it's in the index then it can be cross-referenced.
Edit: below's a workaround to show .method as class.method; info above applies.
`ClassName.`:meth:`.method`

TypeError: gettext() missing 1 required positional argument: 'self' - python

I'm new to python and I'm tring to make a class for a modul which checking curses in texts.
can someone help please?
import urllib
class Checktext:
def __init__(self, text):
self.text = text
def gettext(self):
file = open(self.text, "r")
filetext = open.read()
for word in filetext.split():
openurl = urllib.request.urlopen("http://www.wdylike.appspot.com/?q=" + word)
output = openurl.read()
truer = "true" in str(output)
print(truer)
s = Checktext(r"C:\Users\Tzach\.atom\Test\Training\readme.txt")
Checktext.gettext()
You declared s as a new Checktext object, so you need to call s.gettext() not an un-instantiated Checktext.gettext(), as that has no self to refer to
The urllib is a package. You have to import the module request that is located in the package:
import urllib.request
The open(filename) return a file object. You want to call the method of that object:
filetext = file.read()
And as G. Anderson wrote, you want to call s.gettext() instead of Checktext.gettext(). The self inside is actually equal to the s outside. If you want to be weird then you actually can use also:
Checktext.gettext(s)
Notice the s passed as your missing parameter. Here Python actually reveals how the Object Oriented things are implemented internally. In majority of OO languages, it is carefully hidden, but calling a method of an object is always internally translated as passing one more special argument that points to the instance of the class, that is the object. When defining a Python method, that special argument is explicitly named self (by convention; you can name it differently -- you can try as the lecture, but you should always keep that convention).
Thinking about it thoroughly, you can get the key idea of the hidden magic of an OO language syntax. The instance of the class (the object) is actually only a portion of memory that stores the data part, and that is passed to the functions that implement the methods. The Checktext.gettext is actually the function, the s is the object. The s.gettext() is actually only a different way to express exactly the same. AS s is the instance of the Checktext class, the fact is stored inside the s. Therefore, the s.gettext() creates the illusion that the rigth code will be called magically. It fits with the trained brain better than the function approach if the s is thought as a tangible something.

How to convert buildbot Property to string value

Problem:
I am trying to figure out how to convert a buildbot Property into a string value. I really don't have much experience with buildbot other than what I have read in the docs and someone elses code.
The issue is I have a Property that contains a path. I need to get the path as a string so that I can use some python functions such as 'split' and 'basename' to retrieve specific elements of the path.
What I Have Tried:
There is a property mapped like so
"artifact.output":"S3://dev/artifacts/out/package1.tar.gz"
When I call path.os.basename(util.Property("artifact.output")) it complains that Property has no 'rfind' method. I also tried using util.Interpolate but again, it has the same issue. Finally, I tried str(util.Property("artifact.output")) but it just outputs Property("artifact.output").
Question:
Is it possible to retrieve a buildbot Property as a string value?
note: I was only able to find one other post from someone back on 2014 asking the same thing but no answer.
A Property is not a string by itself, but it's a class that implements an IRenderable interface. This interface defines something, that can be "rendered" into a string when needed. To render a Property or any renderable (eg. the util.Interpolate object), you need a an IProperties provider.
The question is where to get such provider and how to render it. When implementing your own step, you can use the Build instance that you can access from self.build as such provider and use it to render the property.
class ExampleBuildStep(BuildStep):
def __init__(self, arg, **kwargs):
"""
Args:
arg - any string, Property or any renderable that will be rendered in run
"""
self.arg = arg
super().__init__(**kwargs)
#defer.inlineCallbacks
def run(self):
# the renderedcommand will be the string representation of the self.arg
renderedcommand = yield self.build.render(self.arg)
In the example above, the ExampleBuildStep takes an argument arg that will be rendered inside the run() function. Note that the arg does not have to be property, it can be a tring as well. You can now create use the build step with renderables:
step = ExampleBuildStep(util.Property("artifact.output"))
step = ExampleBuildStep(util.Interpolate('%(prop:artifact.output)s'))
step = ExampleBuildStep("string argument")
You can use Interpolate for that purpose:
util.Interpolate('string before ' + '%(prop:artifact.output)s' + ' string after')
If you have access to the BuildStep object, you can grab properties already formatted as a string via the getProperty() method.
If you wanted to grab the "workername" as a string and print it, you could call:
workerName = step.getProperties().getProperty('workername','wname')
print("workerName: %s" % workerName)
Note: workername is one of the Common Build Properties you should always expect to find, alongside the user-defined ones.
getProperty() is defined in properties.py:
def getProperty(self, name, default=None):
return self.properties.get(name, (default,))[0]
Remember to switch branches from 'master' to whatever your version of buildbot is.

Creating an object from a string, is it possible?

Is it possible to do the following
This works
usethismodule.LoginUsername="my value"
usethismodule.LoginPassword="another value"
But I don't know the second part of the object until the code is being run, I think what I want is this
listofthings=[]
listofthings.append('usethismodule.LoginUsername')
listofthings.append('usethismodule.LoginPassword')
for value in listofthings:
value="A value I set"
This would have the same outcome as the above. Does that make sense?
Indeed, setattr and a dictionary would do the trick.
dictofthings = {
'usethismodule.LoginUsername': 'my value',
'usethismodule.LoginPassword': 'my other value'
}
for k in dictofthings:
setattr(eval(k.split('.')[0]), k.split('.')[1], dictofthings[k])
Hope this helps!
You keep saying usethismodule.<something>. So let's pretend you're right.
Python maintains a dict of currently imported modules in sys.modules. You can look up a module, by name, and get an "object". (A module object, in fact.)
If you have an object in hand, you can either hard-code an access to one of its attributes, or use getattr or setattr on it.
import sys
module_name = "usethismodule" # I don't know where this come from.
utm = sys.modules[module_name]
utm.LoginUsername = "xyzzy"
utm.LoginPassword = "secret123"
# or
pw_attr_name = "passWord" # Maybe you read this from a config file?
setattr(utm, pw_attr_name, "secret123")

How to resolve a global variable in a module?

I have a script as follows
from mapper import Mapper
class A(object):
def foo(self):
print "world"
a = A()
a.foo()
Mapper['test']()
with Mapper defined in the file mapper.py:
Mapper = {'test': a.foo}
where I want to define a function call referencing an object not defined in mapper.py, but in the original code. However the code above gives the error
NameError: name 'a' is not defined
which makes kind of sense, as a is not defined in mapper.py itself. However, is it possible to change the code to let the code do the name resolution in the main code itself, or by the use of globals or something?
To solve this problem I could specify the implementation in mapper.py as a text and use eval in the main code, but I would like to avoid the usage of eval.
Additional information:
The full definition of the function has to be made in mapper.py
It is not known beforehand what the instance a is, or from what clas it is instantiated.
Barring security holes like eval, it's not possible to use a name a in mapper.py unless the name is either defined somewhere in mapper.py or imported from another module. There is no way to just let mapper.py automatically and silently access a value a from a different module.
In addition, if you're using it just in a dict as in your example, a.foo is going to be evaluated as soon as the dict is created. It's not going wait until you actually call the function; as soon as it evaluates a.foo to create the dict, it will fail because it doesn't know what a is.
You could get around this second problem by wrapping the element in a function (using a lambda for brevity):
Mapper = {'test': lambda: a.foo}
. . . but this still won't help unless you can somehow get a to be available inside mapper.py.
One possibility is to parameterize your Mapper by the "mystery" object and then pass that object in from outside:
# mapper.py
Mapper = {'test': lambda a: a.foo}
# other module
from mapper import Mapper
Mapper['test'](a)()
Or, similar to what mgilson suggested, you could "register" the object a with Mapper somehow. This lets you pass the object a only once to register it, and then you don't have to pass it for every call:
# mapper.py
Mapper = {'test': lambda a: Mapper['a'].foo}
# other module
from mapper import Mapper
Mapper['a'] = a
Mapper['test']()()
Note the two sets of parentheses at the end there: one set to evaluate the lambda and extract the function you want to call, and the second set to actually call that function. You could do a similar deal by, instead of using Mapper['a'] as the reference, using a module-level variable:
# mapper.py
Mapper = {'test': lambda: a.foo}
# other module
import mapper
Mapper = mapper.Mapper
mapper.a = a
Mapper['test']()()
Note that this requires you to do import mapper in order to set the module variable in that other module.
You could streamline this somewhat by using a custom class for Mapper instead of a regular dict, and having that class do some work in its __getitem__ to look in a "known location" (e.g., read some module variable) to use as a base for evaluating a. That would be a heavier-weight solution though.
The bottom line is that you simply cannot (again, without the use of eval or other such holes) write code in mapper.py that uses an undefined variable a, and then define a variable a in another module and have mapper.py automatically know about that. There has to be some line of code somewhere that "tells" mapper.py what value of a you want it to use.
I'm not sure I completely follow, but a could "register" it's method with Mapper from anywhere which has a reference to Mapper:
#mapping.py
Mapper = {}
and then:
#main.py
from mapping import Mapper
#snip
a = A()
Mapper['test'] = a.foo #put your instance method into the Mapper dict.
#snip
Mapper['test']()

Categories