18

Is there any way to execute (and obtain the results of) AppleScript code from python without using the osascript command-line utility or appscript (which I don't really want to use (I think?) because it's no longer developed/supported/recommended)?

Rationale: in another question I've just posted, I describe a strange/undesired behaviour I'm experiencing with running some AppleScript via osascript. As I'm actually calling it from a python script, I wondered if there was a way to route around osascript altogether, since that seems to be where the problem lies - but appscript (the obvious choice?) looks risky now...

3
  • 1
    Why not the python osascript package? Was it not available at the time this question was asked? Commented Jan 23, 2017 at 23:09
  • 1
    Looks like that project got started in October 2015, so no, it wasn't available in 2013. But it looks good, yes - thanks! :-) Commented Jan 24, 2017 at 10:14
  • Because that's also just a wrapper around a subprocess call to the osascript utility. Commented Mar 6, 2019 at 16:16

3 Answers 3

25

You can use the PyObjC bridge:

>>> from Foundation import *
>>> s = NSAppleScript.alloc().initWithSource_("tell app \"Finder\" to activate")
>>> s.executeAndReturnError_(None)
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! Accepted this answer as it has the fewest dependencies, although py-applescript also looks good. :-)
Might want to fix the spelling of 'NSApplScript' to add the 'e' after 'Appl' - I pasted your code and it didn't work first time!
In case of ImportError: No module named Foundation, one may use sys.path.append("/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC") before the import statement.
24

PyPI is your friend...

http://pypi.python.org/pypi/py-applescript

Example:

import applescript

scpt = applescript.AppleScript('''
    on run {arg1, arg2}
        say arg1 & " " & arg2
    end run

    on foo()
        return "bar"
    end foo

    on Baz(x, y)
        return x * y
    end bar
''')

print(scpt.run('Hello', 'World')) #-> None
print(scpt.call('foo')) #-> "bar"
print(scpt.call('Baz', 3, 5)) #-> 15

4 Comments

Thanks - works great. Shall add PyPi to my list of stuff I should know about.
PyPI is indeed your friend. Ever so helpful, ever so often!
Thanks for the example, helps explain is so much faster than the package doc.
Note: py-applescript depends on PyObjC for its OSAscript functionality
2

If are looking to execute "Javascript for Automation" (applescript's successor) in your python code, here's how to do it:

script = None

def compileScript():
    from OSAKit import OSAScript, OSALanguage

    scriptPath = "path/to/file.jxa"
    scriptContents = open(scriptPath, mode="r").read()
    javascriptLanguage = OSALanguage.languageForName_("JavaScript")

    script = OSAScript.alloc().initWithSource_language_(scriptContents, javascriptLanguage)
    (success, err) = script.compileAndReturnError_(None)

    # should only occur if jxa is incorrectly written
    if not success:
        raise Exception("error compiling jxa script")

    return script

def execute():
    # use a global variable to cache the compiled script for performance
    global script
    if not script:
        script = compileScript()

    (result, err) = script.executeAndReturnError_(None)

    if err:
        # example error structure:
        # {
        #     NSLocalizedDescription = "Error: Error: Can't get object.";
        #     NSLocalizedFailureReason = "Error: Error: Can't get object.";
        #     OSAScriptErrorBriefMessageKey = "Error: Error: Can't get object.";
        #     OSAScriptErrorMessageKey = "Error: Error: Can't get object.";
        #     OSAScriptErrorNumberKey = "-1728";
        #     OSAScriptErrorRangeKey = "NSRange: {0, 0}";
        # }

        raise Exception("jxa error: {}".format(err["NSLocalizedDescription"]))
    
    # assumes your jxa script returns JSON
    return json.loads(result.stringValue())

2 Comments

JXA can't match AppleScript's functionality and was pretty much abandoned after its release, so I wouldn’t consider it a successor.
Interesting, didn't realize it was abandoned more than AppleScript. In what ways does it not match AppleScript's functionality? Curious to learn more.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.