How to make my PyObjC application AppleScript-able - python

I want to create an application on OS X with Python, that is AppleScript-able.
First I used this tutorial to create an Application (it works!). Then I used this SO answer to add AppleScript support; I tried to translate the Objective-C stuff into Python. I added a plist-item to the options in setup.py:
OPTIONS = {
#...
'plist': {
'NSAppleScriptEnabled': True,
'OSAScriptingDefinition': 'SimpleXibDemo.sdef',
#...
}
}
I created SimpleXibDemo.sdef
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">
<dictionary title="SimpleXibDemo">
<suite name="SimpleXibDemo Suite" code="SXiD" description="SimpleXibDemo Scripts">
<command name="increase" code="increxib" description="Increase the value">
<cocoa class="SimpleXibDemoIncreaseCommand"/>
<parameter name="by" type="integer" optional="yes">
<cocoa key="by"/>
</parameter>
<result description="Returns the new value" type="integer"/>
</command>
</suite>
</dictionary>
and I added the class SimpleXibDemoIncreaseCommand:
class SimpleXibDemoIncreaseCommand(NSScriptCommand):
def performDefaultImplementation(self):
args = self.evaluatedArguments()
nr = args.valueForKey("by")
viewController.increment()
return nr + 1
The application itself works, but when I run this AppleScript:
tell application "SimpleXibDemo"
set myResult to increase by 3
end tell
I get this error:
error "SimpleXibDemo got an error: Can’t continue increase." number -1708
I can't find any info on error number -1708. And when I open the application with Script Editor -> Open Dictionary, nothing happens.
What is the problem here? I'm a bit stuck :-/

Related

Parse xsi:type in XML with ElementTree in Python

I'm trying to connect to a RESTful API and I'm hacing problems when building the XML request, for that I'm using Elementree library.
I have an example of the XML I have to send in the request. From that example a build a model and then write the different attributes by code. But the output XML is not exactly like the example I was given and I'm unable to connect to the API.
This is the example I have:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetLoc xmlns="http://abc/Getloc">
<request>
<Access>
<string xmlns="http://bcd/Arrays"></string>
</Access>
<Details xsi:type="Request">
<Postcode ></Postcode >
</Details>
<UserConsent>Yes</UserConsent>
</request>
</GetLoc>
</soap:Body>
</soap:Envelope>
This is my code:
tree = ET.parse('model.xml')
root = tree.getroot()
ns = {'loc':'http://abc/Getloc',\
'arr':http://bcd/Arrays',\
'soapenv':'http://schemas.xmlsoap.org/soap/envelope/', \
'xsi':"http://www.w3.org/2001/XMLSchema-instance", \
xsd': "http://www.w3.org/2001/XMLSchema"}
tree.find('.//arr:string', ns).text = 'THC'
tree.find('.//Postcode ', ns).text = '15478'
This is the output XML (SOAP):
<ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://abc/Getloc" xmlns:ns2="http://bcd/Arrays" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns0:Body>
<ns1:GetLoc >
<ns1:request>
<ns1:Access>
<ns2:string>THC</ns2:string>
</ns1:Access>
<ns1:Details xsi:type="Request">
<ns1:Postcode >15478</ns1:Postcode >
</ns1:Details>
<ns1:UserConsent>Yes</ns1:UserConsent>
</ns1:request>
</ns1:GetLoc >
</ns0:Body>
</ns0:Envelope>
With the example (first above) I have no problem when connecting to the API. However with the second one I get and error:
" status="Service Not Found. The request may have been sent to an invalid URL, or intended for an unsupported operation." xmlns:l7="http://www.layer7tech.com/ws/policy/fault"/>"
Both XML are sent to the same URL with the same headers and auth. I see both XML equivalent so I was expecting same behavior. I don't understand why it isn't working.
EDIT: The output XML needs to be like
<ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://abc/Getloc" xmlns:ns2="http://bcd/Arrays" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns0:Body>
<ns1:GetLoc >
<ns1:request>
<ns1:Access>
<ns2:string>THC</ns2:string>
</ns1:Access>
<ns1:Details xsi:type="ns1:Request">
<ns1:Postcode >15478</ns1:Postcode >
</ns1:Details>
<ns1:UserConsent>Yes</ns1:UserConsent>
</ns1:request>
</ns1:GetLoc >
</ns0:Body>
</ns0:Envelope>
But I don't know hoy to change the code to get: xsi:type="ns1:Request"
Finally I found the solution myself.
The solution is in here (an incredibly complete article), since I was already using ElementTree. You may find other solutions like using lxml library.
So, for ElementTree I just need to use my own parser instead of the standard ElementTree.parse('file.xml').
The xsi attribute name is handled by the parser, but the parser doesn’t know that the attribute happens to contain a qualified name as well, so it leaves it as is. To be able to handle such a format, you can use a custom parser that knows how to handle certain attributes and elements, or keep track of the prefix mapping for each element.
To do the latter, you can use the iterparse parser, and ask it to report “start-ns” and “end-ns” events. The following snippet adds an ns_map attribute to each element which contains the prefix/URI mapping that applies to that specific element:
def parse_map(file):
events = "start", "start-ns", "end-ns"
root = None
ns_map = []
for event, elem in ET.iterparse(file, events):
if event == "start-ns":
ns_map.append(elem)
elif event == "end-ns":
ns_map.pop()
elif event == "start":
if root is None:
root = elem
elem.ns_map = dict(ns_map)
return ET.ElementTree(root)

lxml: How do I search for fields without adding a xmlns (localhost) path to each search term?

I'm trying to locate fields in a SOAP xml file using lxml (3.6.0)
...
<soap:Body>
<Request xmlns="http://localhost/">
<Test>
<field1>hello</field1>
<field2>world</field2>
</Test>
</Request>
</soap:Body>
...
In this example I'm trying to find field1 and field2.
I need to add a path to the search term, to find the field:
print (myroot.find(".//{http://localhost/}field1").tag) # prints 'field1'
without it, I don't find anything
print (myroot.find("field1").tag) # finds 'None'
Is there any other way to search for the field tag (here field1) without giving path info?
Full example below:
from lxml import etree
example = """<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body><Request xmlns="http://localhost/">
<Test><field1>hello</field1><field2>world</field2></Test>
</Request></soap:Body></soap:Envelope>
"""
myroot = etree.fromstring(example)
# this works
print (myroot.find(".//{http://localhost/}field1").text)
print (myroot.find(".//{http://localhost/}field2").text)
# this fails
print (myroot.find(".//field1").text)
print (myroot.find("field1").text)
Comment: The input of the SOAP request is given, I can't change any of it in real live to make things easier.
There is a way to ignore namespace when selecting element using XPath, but that isn't a good practice. Namespace is there for a reason. Anyway, there is a cleaner way to reference element in namespace i.e by using namespace prefix that was mapped to the namespace uri, instead of using the actual namespace uri every time :
.....
>>> ns = {'d': 'http://localhost/'}
>>> print (myroot.find(".//d:field1", ns).text)
hello
>>> print (myroot.find(".//d:field2", ns).text)
world

Inquiry: Parse the following xml code with xml.etree?

Problem Statement:
Given the xml given below I want to write a simple script to produce (http)www.herp.com/ and (http)www.herp.com/derp. Conceivably for every application path I come across. That is, if I have more, such as: <application path = "wassup" applicationPool="derp />, I would want that too as (http)www.herp.com/wassup.
<sites>
<site name="(http)www.herp.com" id="1" serverAutoStart="true">
<application path="/" applicationPool="derp_administration">
<virtualDirectory path="/" physicalPath="D:\inetpub\herp_webs\derp" />
<virtualDirectory path="/Controls" physicalPath="D:\inetpub\usercontrolslibnew_ent" />
</application>
<application path="/derp" applicationPool="BOOGA">
<virtualDirectory path="/" physicalPath="D:\inetpub\herp_webs\derp" />
<virtualDirectory path="/Controls" physicalPath="D:\inetpub\usercontrolslibnew" />
</application>
</site>
</sites>
Attempted Solution:
I am using the following code:
import xml.etree.ElementTree as ET
tree = ET.parse("applicationHost.config")
root = tree.getroot()
sites = root.iter('site')
for site in sites:
print site.get('name')
However, this obviously will only give me:
(http) www.herp.com
I am unable to see in the attributes anything that will point me to the <application path = "i want this stuff" />
I tried using site.tag, site.text, site.attrib, and site.tail and none of this helps me see the application path to build my url. How can I parse this xml code to give me both name and path attribute?
So given the excellent suggestions from here. I tried the following code:
sites = root.iter('site')
for site in sites:
apps = site.findall('application')
print apps.tag, apps.attrib
I get the following error.
AttributeError: 'list' object has no attribute 'attrib'
Similar error is given for tags. Basically, if I used site.find('application') that will give me the first <application path ="/" applicationPool="whatever"/>, but I cannot find the rest below it. I'm sorry. Apparently this particular config I ran it on had website dependencies that I was unaware of. I'm new on the job.
Researched Sources:
RTFM: https://docs.python.org/2/library/xml.etree.elementtree.html
http://luisartola.com/software/2010/easy-xml-in-python/
google / here
Notes:
I have multiple *.config files and parsing using a script is the way to go. I am aware of some GUI tools that can do basic stuff, but not appropriate here.
You need to obtain the <application> Element before you can access its path attribute. Given site, you can do this using site.findall('application'):
import xml.etree.ElementTree as ET
tree = ET.parse("applicationHost.config")
root = tree.getroot()
sites = root.iter('site')
for site in sites:
apps = site.findall('application')
for app in apps:
print(''.join([site.get('name'), app.get('path')]))
prints
(http)www.herp.com/
(http)www.herp.com/derp

XBMC Text are not displaying

I'm working on my python script as I would like to change the language using xml when pressing on the enter button of the keyboard.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<strings>
<string id="32000">Hello UK</string>
</strings>
<control type="label">
<description>My hello label</description>
<posx>20</posx>
<posy>20</posy>
<width>180</width>
<height>248</height>
<align>middle</align>
<font>font12</font>
<textcolor>white</textcolor>
<visible>true</visible>
<label>$LOCALIZE[SCRIPT32000]</label>
</control>
Here is the python:
import xbmc
import xbmcgui
import xbmcaddon
#get actioncodes from keyboard.xml
ACTION_ENTER = 7
class MyClass(xbmcgui.WindowXML):
def onAction(self, action):
if action == ACTION_ENTER:
if image1_enabled:
my_hello_string = ADDON.getLocalizedString(32000)
I have got a problem with my python script, because when I press on the enter button, there are no text display on the screen. There are no error on the xbmc logs. I want to add the label to get the strings that I stored in xml to display the strings on the skins. Not sure if I have missing something?
If that is your complete code, it looks like you're not doing anything with the class. You might need to add to the end of your Python code something like:
if __name__ == '__main__':
w = MyClass("myclass.xml")
w.doModal()

How to validate XML with multiple namespaces in Python?

I'm trying to write some unit tests in Python 2.7 to validate against some extensions I've made to the OAI-PMH schema: http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd
The problem that I'm running into is business with multiple nested namespaces is caused by this specification in the above mentioned XSD:
<complexType name="metadataType">
<annotation>
<documentation>Metadata must be expressed in XML that complies
with another XML Schema (namespace=#other). Metadata must be
explicitly qualified in the response.</documentation>
</annotation>
<sequence>
<any namespace="##other" processContents="strict"/>
</sequence>
</complexType>
Here's a snippet of the code I'm using:
import lxml.etree, urllib2
query = "http://localhost:8080/OAI-PMH?verb=GetRecord&by_doc_ID=false&metadataPrefix=nsdl_dc&identifier=http://www.purplemath.com/modules/ratio.htm"
schema_file = file("../schemas/OAI/2.0/OAI-PMH.xsd", "r")
schema_doc = etree.parse(schema_file)
oaischema = etree.XMLSchema(schema_doc)
request = urllib2.Request(query, headers=xml_headers)
response = urllib2.urlopen(request)
body = response.read()
response_doc = etree.fromstring(body)
try:
oaischema.assertValid(response_doc)
except etree.DocumentInvalid as e:
line = 1;
for i in body.split("\n"):
print "{0}\t{1}".format(line, i)
line += 1
print(e.message)
I end up with the following error:
AssertionError: http://localhost:8080/OAI-PMH?verb=GetRecord&by_doc_ID=false&metadataPrefix=nsdl_dc&identifier=http://www.purplemath.com/modules/ratio.htm
Element '{http://www.openarchives.org/OAI/2.0/oai_dc/}oai_dc': No matching global element declaration available, but demanded by the strict wildcard., line 22
I understand the error, in that the schema is requiring that the child element of the metadata element be strictly validated, which the sample xml does.
Now I've written a validator in Java that works - however it would be helpful for this to be in Python, since the rest of the solution I'm building is Python based. To make my Java variant work, I had to make my DocumentFactory namespace aware, otherwise I got the same error. I've not found any working example in python that performs this validation correctly.
Does anyone have an idea how I can get an XML document with multiple nested namespaces as my sample doc validate with Python?
Here is the sample XML document that i'm trying to validate:
<?xml version="1.0" encoding="UTF-8"?>
<OAI-PMH xmlns="http://www.openarchives.org/OAI/2.0/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/
http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd">
<responseDate>2002-02-08T08:55:46Z</responseDate>
<request verb="GetRecord" identifier="oai:arXiv.org:cs/0112017"
metadataPrefix="oai_dc">http://arXiv.org/oai2</request>
<GetRecord>
<record>
<header>
<identifier>oai:arXiv.org:cs/0112017</identifier>
<datestamp>2001-12-14</datestamp>
<setSpec>cs</setSpec>
<setSpec>math</setSpec>
</header>
<metadata>
<oai_dc:dc
xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/
http://www.openarchives.org/OAI/2.0/oai_dc.xsd">
<dc:title>Using Structural Metadata to Localize Experience of
Digital Content</dc:title>
<dc:creator>Dushay, Naomi</dc:creator>
<dc:subject>Digital Libraries</dc:subject>
<dc:description>With the increasing technical sophistication of
both information consumers and providers, there is
increasing demand for more meaningful experiences of digital
information. We present a framework that separates digital
object experience, or rendering, from digital object storage
and manipulation, so the rendering can be tailored to
particular communities of users.
</dc:description>
<dc:description>Comment: 23 pages including 2 appendices,
8 figures</dc:description>
<dc:date>2001-12-14</dc:date>
</oai_dc:dc>
</metadata>
</record>
</GetRecord>
</OAI-PMH>
Found this in lxml's doc on validation:
>>> schema_root = etree.XML('''\
... <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
... <xsd:element name="a" type="xsd:integer"/>
... </xsd:schema>
... ''')
>>> schema = etree.XMLSchema(schema_root)
>>> parser = etree.XMLParser(schema = schema)
>>> root = etree.fromstring("<a>5</a>", parser)
So, perhaps, what you need is this? (See last two lines.):
schema_doc = etree.parse(schema_file)
oaischema = etree.XMLSchema(schema_doc)
request = urllib2.Request(query, headers=xml_headers)
response = urllib2.urlopen(request)
body = response.read()
parser = etree.XMLParser(schema = oaischema)
response_doc = etree.fromstring(body, parser)

Categories

Resources