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.
Related
Given the following display function,
def display(some_object):
print(some_object.value)
is there a way to programmatically determine that the attributes of some_object must include value?
Modern IDEs (like PyCharm) yield a syntax error if I try to pass an int to the display function, so they are obviously doing this kind of analysis behind the scenes. I am aware how to get the function signature, this question is only about how to get the (duck) type information, i.e. which attributes are expected for each function argument.
EDIT: In my specific use case, I have access to the source code (non obfuscated), but I am not in control of adding the type hints as the functions are user defined.
Toy example
For the simple display function, the following inspection code would do,
class DuckTypeInspector:
def __init__(self):
self.attrs = []
def __getattr__(self, attr):
return self.attrs.append(attr)
dti = DuckTypeInspector()
display(dti)
print(dti.attrs)
which outputs
None # from the print in display
['value'] # from the last print statement, this is what i am after
However, as the DuckTypeInspector always returns None, this approach won't work in general. A simple add function for example,
def add(a, b):
return a + b
dti1 = DuckTypeInspector()
dti2 = DuckTypeInspector()
add(dti1, dti2)
would yield the following error,
TypeError: unsupported operand type(s) for +: 'DuckTypeInspector' and 'DuckTypeInspector'
The way to do this with static analysis is to declare the parameters as adhering to a protocol and then use mypy to validate that the actual parameters implement that protocol:
from typing import Protocol
class ValueProtocol(Protocol):
value: str
class ValueThing:
def __init__(self):
self.value = "foo"
def display(some_object: ValueProtocol):
print(some_object.value)
display(ValueThing()) # no errors, because ValueThing implements ValueProtocol
display("foo") # mypy error: Argument 1 to "display" has incompatible type "str"; expected "ValueProtocol"
Doing this at runtime with mock objects is impossible to do in a generic way, because you can't be certain that the function will go through every possible code path; you would need to write a unit test with carefully constructed mock objects for each function and make sure that you maintain 100% code coverage.
Using type annotations and static analysis is much easier, because mypy (or similar tools) can check each branch of the function to make sure that the code is compatible with the declared type of the parameter, without having to generate fake values and actually execute the function against them.
If you want to programmatically inspect the annotations from someone else's module, you can use the magic __annotations__ attribute:
>>> display.__annotations__
{'some_object': <class '__main__.ValueProtocol'>, 'return': None}
When the python help function is invoked with an argument of string type, it is interpreted by pydoc.Helper.help as a request for information on the topic, symbol, keyword or module identified by the value of the string. For other arguments, help on the object itself is provided, unless the object is an instance of a subclass of str. In this latter case, the pydoc.resolve function looks for a module with a name matching the value of the object and raises an exception if none is found.
To illustrate this, consider the example code:
class Extra(object):
def NewMethod(): return 'New'
Cls1 = type( 'FirstClass', (str,Extra), {'__doc__':'My new class','extra':'An extra attribute'})
inst1 = Cls1('METHODS')
help( 'METHODS' )
help( inst1 )
The first invocation of help produces information on the topic "METHODS", the 2nd produces an error message because the pydoc.resolve function is trying to find a module called "METHODS".
This means that it is difficult to provide effective documentation for user defined sub-classes of str. Would it not be possible for pydoc.resolve to use a test on the type of the object, as is done in pydoc.Helper.help, and allow instances of user defined sub-classes to be treated as other class instances?
This question follows from earlier discussion of a related question here.
The simple answer is that making user-defined subclasses of str is not the most common case—partly because the user-defined data but not the string data would be mutable. By the time you have to deal with such, it’s imagined that you know how to write help(type(x)), and using isinstance rather than type(…) is … is the correct default in general. (The other way, you’d have to use help(str(x)) if you wanted to use it, like any other string, to select a help topic, but that’s surely even rarer.)
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
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.
I am trying to teach myself object oriented programming in Python with the book "Python 3, Object Oriented Programming", by Dusty Phillips. On pages 54 and 55 he creates a class called Note and encourages the reader to repeat the example and import the module from the interpreter with the following commands. However, when I do, I type the n1 = command I get the message from the interpreter "TypeError: object() takes no parameters. Am I missing something in the implementation of this object, or did the book give a faulty example? Mind you the example and the lines typed into the interpreter are taken exactly from the book, at least I think I made no errors in copying the lines. This is different initialization syntax than C++, which makes me wonder if the author gave a bad example, but in the book example it looks as if he is trying to initialize with a call to the object directly and the object is supposed to recognize the text that gets passed to memo. Also I tried to run the example in python 2.7.9 and 3.4.2 to see if this was a version issue.
Interpreter lines
from notebook import Note
n1 = Note("hello first") # the code execution gets stopped here fur to the error
n2 = Note("hello again")
n1.id
n2.id
import datetime
# store the next available id for all new notes
last_id = 0
class Note:
'''Represent a note in the notebook. Match against a
string in searches and store tags for each note.'''
def _init_(self, memo, tags=''):
'''initialize a note with memo and optional
space-seperated tags. Automatically set the note's
creation date and a unique id.'''
self.memo = memo
self.tags = tags
self.creation_date = datetime.date()
global last_id
last_id += 1
self.id = last_id
def match(self, filter):
'''Determine if this note matches the filter
text. Return True if it matches, False otherwise.
Search is case sensitive and matches both text and
tags'''
return filter in self.memo or filter in self.tags
Maybe do what Christian said: Use __init__ instead of _init_. You need to have double underscores not single underscores. You can look at the Python Docs.
You are missing double underscores in the special __init__ method. You only have single underscores.
You might also consider having Note explicitly inherit from object, i.e. class Note(object).