XML Attribute modification not being saved - python

I have the following code:
def incrCount(root):
root.attrib['count'] = int(root.attrib['count']) + 1
# root.set('count', int(root.attrib['count']) + 1)
root = getXMLRoot('test.xml')
incrCount(root)
print root.attrib['count']
when I run it, the correct value is printed but that change is never visible in the file at the end of execution. I have tried both methods above to no success. Can anyone point out where I made the mistake?

As exemplified in the documentation (19.7.1.4. Modifying an XML File), you need to write back to file after all modification operations has been performed. Assuming that root references instance of ElementTree, you can use ElementTree.write() method for this purpose :
.....
root = getXMLRoot('test.xml')
incrCount(root)
print root.attrib['count']
root.write('test.xml')

Related

Maya Python Script Job Attribute Change

I am trying to get one boolean attribute (A) to change another(B). The one to be controlled (B) already has a script job running it and so I can't create a set driven key, direct connection, or expression to control it, so I'm trying another script job, since running the script function by itself achieves the desired result. I just can't figure out how to tie that script to run to the attribute change (B) that I want to drive it by (A).
This is placed in a script node set to the open gui trigger (to load when maya opens as I understand it). Here's a screenshot.
What am I missing here?
import maya.cmds as cmds
def togglePicker(pickerAttr):
cmds.setAttr(pickerAttr, not 0)
nameSpace = cmds.ls(sl=True)[0].rpartition(':')[0]
if len(nameSpace) > 0:
pickerAttr = nameSpace + ':Main.picker'
myPickerAttr = nameSpace + ':MoverMain_Cntrl.Picker'
else:
pickerAttr = 'Main.picker'
myPickerAttr = 'MoverMain_Cntrl.Picker'
cmds.scriptJob(attributeChange=[myPickerAttr,togglePicker])
Your script node is executed every time when maya loads a scene, not when it is started, at least that's what the docs say. So every time you load a scene, a new scriptJob is created.
Your script should show an error message since the togglePicker() function is called without an argument, but it requires an argument. Even if it works, it will not work.. what you do at the moment is the following:
As soon as you turn on the MoverMain_Cntrl.Picker attribute, the togglePicker() function is called and turns it on, even if you turn it off. The pickerAttrvariable is not used. So you should have a look at your program logic.
You can solve the agrument problem by using the partial function like this:
import maya.cmds as cmds
from functools import partial
def togglePicker(pickerAttr):
cmds.setAttr(pickerAttr, not 0)
nameSpace = cmds.ls(sl=True)[0].rpartition(':')[0]
if len(nameSpace) > 0:
pickerAttr = nameSpace + ':Main.picker'
myPickerAttr = nameSpace + ':MoverMain_Cntrl.Picker'
else:
pickerAttr = 'Main.picker'
myPickerAttr = 'MoverMain_Cntrl.Picker'
cmds.scriptJob(attributeChange=[myPickerAttr,partial(togglePicker, pickerAttr)])
I got it to work! (previously I had switched to the script node to MEL so I could test the mel command mentioned in the comments that did work, but I forgot to switch back to python when I realized the selection issue I also mentioned in the comments).
So here's what worked, where I know I'll have to manually change the namespace name in case the scene file name changes:
import maya.cmds as cmds
def togglePicker():
cmds.setAttr(pickerAttr, not 0)
if cmds.namespace(exists='ExtremeBallRig_v008'):
pickerAttr = 'ExtremeBallRig_v008:Main.picker'
myPickerAttr = 'ExtremeBallRig_v008:MoverMain_Cntrl.Picker'
else:
pickerAttr = 'Main.picker'
myPickerAttr = 'MoverMain_Cntrl.Picker'
cmds.scriptJob(attributeChange=[myPickerAttr,togglePicker])

Check if image is decorative in powerpoint using python-pptx

The company I work at requires a list of all inaccessible images/shapes in a .pptx document (don't have alt-text and aren't decorative). To automate the process, I'm writing a script that extracts all inaccessible images/shapes in a specified .pptx and compiles a list. So far, I've managed to make it print out the name, slide #, and image blob of images with no alt-text.
Unfortunately after extensively searching the docs, I came to find that the python-pptx package does not support functionality for checking whether an image/shape is decorative or not.
I haven't mapped XML elements to objects in the past and was wondering how I could go about making a function that reads the val attribute within the adec:decorative element in this .pptx file (see line 4).
<p:cNvPr id="3" name="Picture 2">
<a:extLst>
<a:ext uri="{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}"><a16:creationId xmlns:a16="http://schemas.microsoft.com/office/drawing/2014/main" id="{77922398-FA3E-426B-895D-97239096AD1F}" /></a:ext>
<a:ext uri="{C183D7F6-B498-43B3-948B-1728B52AA6E4}"><adec:decorative xmlns:adec="http://schemas.microsoft.com/office/drawing/2017/decorative" val="0" /></a:ext>
</a:extLst>
</p:cNvPr>
Since I've only recently started using this package, I'm not sure how to go about creating custom element classes within python-pptx. If anyone has any other workaround or suggestions please let me know, thank you!
Creating a custom element class would certainly work, but I would regard it as an extreme method (think bazooka for killing mosquitos) :).
I'd be inclined to think you could accomplish what you want with an XPath query on the closest ancestor you can get to with python-pptx.
Something like this would be in the right direction:
cNvPr = shape._element._nvXxPr.cNvPr
adec_decoratives = cNvPr.xpath(".//adec:decorative")
if adec_decoratives:
print("got one, probably need to look more closely at them")
One of the challenges is likely to be getting the adec namespace prefix registered because I don't think it is by default. So you probably need to execute this code before the XPath expression, possibly before loading the first document:
from pptx.oxml.ns import _nsmap
_nsmap["adec"] = "http://schemas.microsoft.com/office/drawing/2017/decorative"]
Also, if you research XPath a bit, I think you'll actually be able to query on <adec:decorative> elements that have val=0 or whatever specific attribute state satisfies what you're looking for.
But this is the direction I recommend. Maybe you can post your results once you've worked them out in case someone else faces the same problem later.
The problem was a lot simpler after all! All thanks too #scanny I was able to fix the issue and target the val=1 attribute in the adec:decorative element. The following function returns True if val=1 for that shape.
def isDecorative(shape):
cNvPr = shape._element._nvXxPr.cNvPr
adec_decoratives = cNvPr.xpath(".//adec:decorative[#val='1']")
if adec_decoratives:
return True
Here is the complete script for checking accessibility in a single specified .pptx so far (Prints out image name and slide # if image is not decorative and doesn't have alt-text):
from pptx import Presentation
from pptx.enum.shapes import MSO_SHAPE_TYPE
from pptx.enum.shapes import PP_PLACEHOLDER
from pptx.oxml.ns import _nsmap
_nsmap["adec"] = "http://schemas.microsoft.com/office/drawing/2017/decorative"
filePath = input("Specify PPT file path > ")
print()
def validShape(shape):
if shape.shape_type == MSO_SHAPE_TYPE.PICTURE:
return True
elif shape.shape_type == MSO_SHAPE_TYPE.PLACEHOLDER:
if shape.placeholder_format.type == PP_PLACEHOLDER.OBJECT:
return True
else:
return False
else:
return False
def isDecorative(shape):
cNvPr = shape._element._nvXxPr.cNvPr
adec_decoratives = cNvPr.xpath(".//adec:decorative[#val='1']")
if adec_decoratives:
return True
# Note: References custom #property added to shared.py and base.py
def hasAltText(shape):
if shape.alt_text:
return True
def checkAccessibility(prs):
for slide in prs.slides:
for shape in slide.shapes:
if validShape(shape) and not isDecorative(shape) and not hasAltText(shape):
yield shape
slideNumber = prs.slides.index(slide) + 1
print("Slide #: %d " % slideNumber + "\n");
for picture in checkAccessibility(Presentation(filePath)):
print(picture.name);

Last imported file overwrites statements from previous files. Better ways of specifying imported variables?

Hey stackoverflow community,
i’m new to this forum and to python developing in general and have a problem with Alexa/ Python overriding the similar named variable from different files.
In my language learning skill I want Alexa to specifically link a “start specific practice” intent from the user to a specific practice file and from this file to import an intro, keyword and answer to give back to the user.
My problem with the importing, is that Python takes the last imported file and overrides the statements of the previous files.
I know I could probably change the variable names according to the practices but then wouldn't I have have to create a lot of individual handler functions which link the user intent to a specific file/function and basically look and act all the same?
Is there a better way more efficient of doing the specifying of those variables when importing or inside the functions?
import files and variables
from übung_1 import intro_1, keywords_1, real_1
from übung_2 import intro_1, keywords_1, real_1
working with the variables
def get_practice_response(practice_number):
print("get_practice_response")
session_attributes = {}
card_title = "Übung"
number = randint(0, len(keywords_1))
print(intro_1 + keywords_1[number])
speech_output = intro_1 + keywords_1[number]
session_attributes["answer"] = real_1[number]
session_attributes["practice_number"] = practice_number
session_attributes["keyword"] = keywords_1[number]
reprompt_text = "test"
should_end_session = False
return build_response(session_attributes, build_speechlet_response(
card_title, speech_output, reprompt_text, should_end_session))
I expected giving out the content of the specifically asked file and not variable content from the most recent files.
Sadly I haven't found a solution for this specific problem and hope someone could help me pointing me in the right direction.
Thank you very much in advance.
Might be easiest to import the modules like so:
import übung_1
import übung_2
The refer to the contents as übung_1.intro_1, übung_2.intro_1, übung_1.keywords_1 and so on.
As you point out, these two lines
from übung_1 import intro_1, keywords_1, real_1
from übung_2 import intro_1, keywords_1, real_1
don't work the way you want because the second import overrides the first. This has to happen because you can't have two different variables in the same namespace called intro_1.
You can get around this by doing
import übung_1
import übung_2
and then in your code you explicitly state the namespace you want:
print(übung_1.intro_1 + übung_1.keywords_1[number])

Instantiating a class gives dubious results the 2nd time around while looping

Edit:
Firstly, thank you #martineau and #jonrsharpe for your prompt reply.
I was initially hesitant to write a verbose description, but I now realize that I am sacrificing clarity for brevity. (thanks #jonrsharpe for the link).
So here's my attempt to describe what I am upto as succinctly as possible:
I have implemented the Lempel-Ziv-Welch text file compression algorithm in form of a python package. Here's the link to the repository.
Basically, I have a compress class in the lzw.Compress module, which takes in as input the file name(and a bunch of other jargon parameters) and generates the compressed file which is then decompressed by the decompress class within the lzw.Decompress module generating the original file.
Now what I want to do is to compress and decompress a bunch of files of various sizes stored in a directory and save and visualize graphically the time taken for compression/decompression along with the compression ratio and other metrics. For this, I am iterating over the list of the file names and passing them as parameters to instantiate the compress class and begin compression by calling the encode() method on it as follows:
import os
os.chdir('/path/to/files/to/be/compressed/')
results = dict()
results['compress_time'] = []
results['other_metrics'] = []
file_path = '/path/to/files/to/be/compressed/'
comp_path = '/path/to/store/compressed/files/'
decomp_path = '/path/to/store/decompressed/file'
files = [_ for _ in os.listdir()]
for f in files:
from lzw.Compress import compress as comp
from lzw.Decompress import decompress as decomp
c = comp(file_path+f,comp_path) #passing the input file and the output path for storing compressed file.
c.encode()
#Then measure time required for comression using time.monotonic()
del c
del comp
d = decomp('/path/to/compressed/file',decomp_path) #Decompressing
d.decode()
#Then measure time required for decompression using
#time.monotonic()
#append metrics to lists in the results dict for this particular
#file
if decompressed_file_size != original_file_size:
print("error")
break
del d
del decomp
I have run this code independently for each file without the for loop and have achieved compression and decompression successfully. So there are no problems in the files I wish to compress.
What happens is that whenever I run this loop, the first file (the first iteration) runs successfully and the on the next iteration, after the entire process happens for the 2nd file, "error" is printed and the loop exits. I have tried reordering the list or even reversing it(maybe a particular file is having a problem), but to no avail.
For the second file/iteration, the decompressed file contents are dubious(not matching the original file). Typically, the decompressed file size is nearly double that of the original.
I strongly suspect that there is something to do with the variables of the class/package retaining their state somehow among different iterations of the loop. (To counter this I am deleting both the instance and the class at the end of the loop as shown in the above snippet, but no success.)
I have also tried to import the classes outside the loop, but no success.
P.S.: I am a python newbie and don't have much of an expertise, so forgive me for not being "pythonic" in my exposition and raising a rather naive issue.
Update:
Thanks to #martineau, one of the problem was regarding the importing of global variables from another submodule.
But there was another issue which crept in owing to my superficial knowledge about the 'del' operator in python3.
I have this trie data structure in my program which is basically just similar to a binary tree.
I had a self_destruct method to delete the tree as follows:
class trie():
def __init__(self):
self.next = {}
self.value = None
self.addr = None
def insert(self, word=str(),addr=int()):
node = self
for index,letter in enumerate(word):
if letter in node.next.keys():
node = node.next[letter]
else:
node.next[letter] = trie()
node = node.next[letter]
if index == len(word) - 1:
node.value = word
node.addr = addr
def self_destruct(self):
node = self
if node.next == {}:
return
for i in node.next.keys():
node.next[i].self_destruct()
del node
Turns out that this C-like recursive deletion of objects makes no sense in python as here simply its association in the namespace is removed while the real work is done by the garbage collector.
Still, its kinda weird why python is retaining the state/association of variables even on creating a new object(as shown in my loop snippet in the edit).
So 2 things solved the problem. Firstly, I removed the global variables and made them local to the module where I need them(so no need to import). Also, I deleted the self_destruct method of the trie and simple did: del root where root = trie() after use.
Thanks #martineau & #jonrsharpe.

attributes not appearing in xml2dict parse output even with xml_attribs = True

I am having a problem with python xmltodict. Following the near-consensus recommendation here, I tried xmltodict and liked it very much until I had to access attributes at the top level of my handler. I'm probably doing something wrong but it's not clear to me what. I have an xml document looking something like this
<api>
<cons id="79550" modified_dt="1526652449">
<firstname>Mackenzie</firstname>
...
</cons>
<cons id="79551" modified_dt="1526652549">
<firstname>Joe</firstname>
...
</cons>
<api>
I parse it with this:
xmltodict.parse(apiResult.body, item_depth=2, item_callback=handler, xml_attribs=True)
where apiResult.body contains the xml shown above. But, in spite of the xml_attribs=True, I see no #id or #modified_dt in the output after parsing in the handler, although all the elements in the original do appear.
The handler is coded as follows:
def handler(_, cons):
print (cons)
mc = MatchChecker(cons)
mc.check()
return True
What might I be doing wrong?
I've also tried xmljson and instantly don't like it as well as xmltodict, if only I had the way around this issue. Does anyone have a solution to this problem or a package that would handle this better?
xmltodict works just fine, but you are parsing the argument item_depth=2 which means your handler will only see the elements inside the <cons> elements rather than the <cons> element itself.
xml = """
<api>
<cons id="79550" modified_dt="1526652449">
<firstname>Mackenzie</firstname>
</cons>
</api>
"""
def handler(_,arg):
for i in arg.items():
print(i)
return True
xmltodict.parse(xml, item_depth=2, item_callback=handler, xml_attribs=True)
Prints ('firstname', 'Mackenzie') as expected.
Whereas:
xmltodict.parse(xml, item_depth=1, item_callback=handler, xml_attribs=True)
Prints ('cons', OrderedDict([('#id', '79550'), ('#modified_dt', '1526652449'), ('firstname', 'Mackenzie')])), again as expected.

Categories