Compare variable to multiple strings python3 - python

Looking to see if this is the most pythonic way to compare a string variable passed in as an argument in python3. My testing shows that this works, however I was confused to why or would not work and and will. This is just a demo, the tag variable is set from the command line. When I test with centos6, centos7, centos8 I hit the else and it works as expected. Is this the best way to do this? Or is this wrong?
tag = 'centos6'
if tag != 'centos6' and tag != 'centos7' \
and tag != 'centos8':
print('[--os %s] must be [--os centos6] or '
'[--os centos7] or [--os centos8]' % tag)
print('fail')
else:
print('good')

Because the or makes the if True if the tag is not equal to one of the centos values, it doesn't matter if it's just one or all of them, and makes the if True only if it's different to all values. Now this is simpler to write:
options = ['centos6', 'centos7', 'centos8']
tag = 'centos6'
if tag not in options:
...

Related

How to get the tag to be recognized correctly?

I want to make a code that does something only if the tag of an object matches the characters of interest. What I did was write this:
if str(canvas.gettags(object))=='thistag':
do_this_thing(object)
else:
pass
When I run the code, it seem that the tag never matches. So I print the tag in the condition else and I get this:
('thistag',).
How should I write the tag so that it can be recognized?
gettags returns a tuple, so you need to compare it to a tuple or check that your tag is part of the tuple.
if (canvas.gettags(object) == ('thistag',)):
...
... or ...
if 'thistag' in canvas.gettags(object):
...

How to detect an empty paragraph in python-docx

Given a document containing a paragraph
d = docx.Document()
p = d.add_paragraph()
I expected the following technique to work every time:
if len(p._element) == 0:
# p is empty
OR
if len(p._p) == 0:
# p is empty
(Side question, what's the difference there? It seems that p._p is p._element in every case I've seen in the wild.)
If I add a style to my paragraph, the check no longer works:
>>> p2 = d.add_paragraph(style="Normal")
>>> print(len(p2._element))
1
Explicitly setting text=None doesn't help either, not that I would expect it to.
So how to I check if a paragraph is empty of content (specifically text and images, although more generic is better)?
Update
I messed around a little and found that setting the style apparently adds a single pPr element:
>>> p2._element.getchildren()
[<CT_PPr '<w:pPr>' at 0x7fc9a2b64548>]
The element itself it empty:
>>> len(p2._element.getchildren()[0])
0
But more importantly, it is not a run.
So my test now looks like this:
def isempty(par):
return sum(len(run) for run in par._element.xpath('w:r')) == 0
I don't know enough about the underlying system to have any idea if this is a reasonable solution or not, and what the caveats are.
More Update
Seems like I need to be able to handle a few different cases here:
def isempty(par):
p = par._p
runs = p.xpath('./w:r[./*[not(self::w:rPr)]]')
others = p.xpath('./*[not(self::w:pPr) and not(self::w:r)] and '
'not(contains(local-name(), "bookmark"))')
return len(runs) + len(others) == 0
This skips all w:pPr elements and runs with nothing but w:rPr elements. Any other element, except bookmarks, whether in the paragraph directly or in a run, will make the result non-empty.
The <w:p> element can have any of a large number of children, as you can see from the XML Schema excerpt here: http://python-docx.readthedocs.io/en/latest/dev/analysis/schema/ct_p.html (see the CT_P and EG_PContent definitions).
In particular, it often has a w:pPr child, which is where the style setting goes.
So your test isn't very reliable against false positives (if being empty is considered positive).
I'd be inclined to use paragraph.text == '', which parses through the runs.
A run can be empty (of text), so the mere presence of a run is not proof enough. The actual text is held in a a:t (text) element, which can also be empty. So the .text approach avoids all those low-level complications for you and has the benefit of being part of the API so much, much less likely to change in a future release.

How can I instruct python 'filter' to ignore punctuation?

I'm attempting to write a small patch for a piece of python that checks a supplied string against a list of objects and returns the matching one if the object title field matches the supplied string.
The code does this using the filter function and passes a simple test to use to find the matches.
I want to alter the filter test to now ignore punctuation marks.
I started with this original code:
res = (self._db_list(session).movies.filter(func.lower(MovieListMovie.title) == name.lower())
.filter(MovieListMovie.year == year).first())
if res:
log.debug('found movie %s', res)
return res
Essentially, it is using supplied 'name' and 'year' strings and seeing if any of the 'movie' objects in the 'movies' list have a title and year attribute that matches. If so, it returns it.
And have tried modifying it to be:
nameWithoutPunctuation = name.translate(None,string.punctuation)
res = (self._db_list(session).movies.filter(func.lower(MovieListMovie.title).translate(None, string.punctuation) == nameWithoutPunctuation.lower())
.filter(MovieListMovie.year == year).first())
if res:
log.debug('found movie %s', res)
return res
But I'm getting an error that translate only accepts one variable, suggesting that I'm using it incorrectly.
Is this the right way to tell 'filter' that I want to ignore punctuation? I'd rather not try and pull apart the 'movie' object or start fiddling with the lower level functions as they serve other functions too.

Boolean not working like it should?

imgfound=False
imgexists=0
img_ext=['.jpg','.jpeg','.png','.gif']
while True:
httpfind=html.find('http',imgexists)
if httpfind==-1:
break
imgexists=httpfind
imgexist=html.find('"',imgexists)
imgurl=html[imgexists:imgexist]
imgexists+=len(imgurl)
for extscan in img_ext:
if not imgurl.find(extscan)==-1:
imgfound=True
break
#print imgfound
if imgfound==False:
continue
print imgurl
I want to find links to images in a html document. But something is not working like it should. Like it prints all links regardless of whether they have a img_ext substring in them. I printed the value in imgfound, and for all the links it is True. Where have I gone wrong?
The expression
not imgurl.find(extscan) == -1
will evaluate to False for every integer, because of operators precedence.
How can you fix it?
Change it to
imgurl.find(extscan) != -1
Or, change it to
not(imgurl.find(extscan) == -1)
Christian's answer is correct, but it's worth noting that this is not good Python style. The preferred form is:
if extscan not in imgurl
Your version looks like a Java-ism.

Renaming fails for duplicated objects

I am making a renaming script, but I am getting in a bit of trouble with my
Seach and Replace function.
Actually, the function works as long as there are no duplication of the same
object in the hierarchy. For example, as depicted in the attachment, locator1
and locator2 are created from scratch, whereas locator3 is a duplication from
locator2
If I were to display them in their short name, it is as follows:
locator1
locator2
locator2|locator3
So as mentioned, when I tried to replace the word 'locator' to 'Point', the
renaming works for locator 1 and 2, but when it comes to locator3, I got the
error RuntimeError: No object matches name
As such, I was wondering if there is a better way for me to recode, cause in
cases like in Modelling, where artists duplicates the object over and over again
or using of instances..
I know that this fails is due to the short name in itself but is it possible to bypass it?
def searchReplace(self):
wordSearch = str(self.searchTxt.text())
wordReplace = str(self.replaceTxt.text())
objCnt = cmds.ls(sl=True, sn=True)
if len(objCnt) == 0:
self.searchTxt.clear()
self.replaceTxt.clear()
cmds.warning('Nothing is selected')
else:
for wordString in sorted(objCnt):
if wordSearch in wordString:
newWordString = wordString.replace(wordSearch, wordReplace)
cmds.rename(wordString, newWordString)
self.searchTxt.clear()
self.replaceTxt.clear()
print '%s' %wordString + " has changed to : " + "%s" %newWordString
This is a tricky problem, but the solution is actually really simple!
When you sort objCnt, you're doing it lexicographically:
for wordString in sorted(objCnt):
This means that locator2 comes before locator2|locator3. On its own that should be fine, but...
When locator2 is renamed, the path to locator3 has also changed, so accessing it fails.
The trick is to reverse the sort so longer objects come first. That way the children always get renamed before their parents
for wordString in sorted(objCnt, reverse=True):
For this to work, you also need to make sure your ls gives you long names, be adding the long=True argument

Categories

Resources