Skip to main content
Participant
January 17, 2022
Question

How to locate current_document property using Appscript in Python for Photoshop 2022

  • January 17, 2022
  • 2 replies
  • 839 views

I (foolishly) upgraded to Mac OSX Monterey, which in turn forced me to upgrade my Photoshop version to Photoshop 2022.

With Photoshop CC 2018 I used the following python code to get a specific layer by name:

 

from appscript import *

self.psApp = app('/Applications/Adobe Photoshop CC 2018/Adobe Photoshop CC 2018.app')

for layer_set in self.psApp.current_document.layer_sets():
    for group in layer_set.layers.get():
        if group.name() == "image_1":
            return group

 

Which worked great! Docs can be found here by the way.

But, when using the same code and replacing Adobe Photoshop CC 2018 with Adobe Photoshop 2022 I get an 'Unknown Property' error:

 

AttributeError: Unknown property, element or command: 'current_document'

 

And I can't get anything else to work anymore, the 'current_document' property seems to be gone or maybe renamed?

 

Any help would be greatly appreciated. The documentation for this is pretty much non-existent unfortunately.

Thanks in advance!

This topic has been closed for replies.

2 replies

kieranrgeary
Participant
June 24, 2023

Hey,

(Sorry about the necromancy)

 

Seems appscript can't pick up Photoshop's scripting definition anymore, and unfortunately appscript official development ended development many moons ago, so there's likely to be no fix for this.

 

One alternative is to use the PyObjC Python module to access Apple's ScriptingBridge for Objective-C. This is clunky, since you are effectively writing Objective-C code, but "translated" into Python, but it gets the job done and this is the solution I'm currently using.

 

Some sample code to get you started, here's how you could do what you wanted above:

from ScriptingBridge import SBApplication

class YourClass:
    def some_method(self):
        self.psApp = SBApplication.applicationWithBundleIdentifier_("com.adobe.Photoshop")
        for layer_set in self.psApp.currentDocument().layerSets():
            for group in layer_set.layers().get():
                if group.name() == "image_1":
                    return group

 

Photoshop Specific Limitations:

All the AppleScript commands are wrapped, but some may not be functional due to limitations of the "rules" of ScriptingBridge. For example, the "open" command is broken, since all possible arguments must be specified, and the "open options" argument requires a reference to a class that cannot be instantiated in ScriptingBridge. Luckily you can still use the "do javascript" function to open files, or the "open -a {photoshop} {file}" shell command.

 

(Py)Objective-C "Quirks":

Translation between Objective-C and Python makes your code super verbose. For example:

AppleScript:
do javascript [script] [arguments] [open options] [show debugger]

Python:
doJavascript_withArguments_showDebugger_(script, arguments, int.from_bytes(b'Nevr'))

Some (lots) of functions will need magic enum numbers from the Photoshop sdef file (like the b'Nevr' above). You can reference those by opening Script Editor, opening the Photoshop scripting dictionary, and then File -> Save As, open the file you just saved with a text editor, and you'll be able to see the values you need for each function.

 

I won't babble on more, but for Photoshop scripting this is seems like the most usable option now that appscript is dead.

 

Here's an old Apple doc explaining most things.

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/RubyPythonCocoa/Articles/UsingScriptingBridge.html

kieranrgeary
Participant
June 24, 2023

Ah just been looking around at the source for appscript and found this. Do not use ScriptingBridge lol. You can get appscript working with modern Photoshop versions by using the "terms" argument in the constructor:

from appscript import app

app(photoshop_path, terms="sdef")

 

Stephen Marsh
Community Expert
Community Expert
January 17, 2022

You obviously have a need to do this through Python, I can't help with that.

 

AppleScript can run JavaScript, so you maybe you could use JS:

 

var selectLayer1 = app.activeDocument.artLayers.getByName("Layer 1");
app.activeDocument.activeLayer = selectLayer1;

 

Or:

 

app.activeDocument.activeLayer = app.activeDocument.layers["Layer 1"];

 

 

As the AS wraps the JS in double quotes, any double quotes in the JS need to be escaped with a \ backslash:

 

tell application "Adobe Photoshop 2022"
	
	set js to "app.activeDocument.activeLayer = app.activeDocument.layers[\"Layer 1\"];"
	
	do javascript js
end tell

 

 

EDIT: Or you could change double quotes in the JS to use single open/close quotes so that there is no conflict with the double quotes used in the AS.

Participant
January 17, 2022

Hi Stephen,

Thank you so much for your answer! I didn't know I could pass javascript to Photoshop with Applescript like that!

I am actually already able to send Applescript via python, I'll post it here for anybody else who wants to know how to do that:

from subprocess import Popen, PIPE

def run_appscript(self, script):
	p = Popen(['osascript', '-'], stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True)
		stdout, stderr = p.communicate(script)

# example
def quit_photoshop(self):
      self.run_appscript('tell application "Adobe Photoshop 2022" to quit')

 

The only thing i'd miss is a way to communicate back from Photoshop to my Python/Applescript script. For example, if I want to get the name of a layer and use that later on in my script. Would you perhaps know a way to do so? 

Stephen Marsh
Community Expert
Community Expert
January 17, 2022

Sorry, I'm only a beginner in using JavaScript with Adobe apps and I don't know AppleScript or Python.