From 405f8ddde00654eab03e81618d511c061f91e9f3 Mon Sep 17 00:00:00 2001 From: TsXor Date: Sun, 4 Sep 2022 23:57:57 +0800 Subject: [PATCH] fix(action_manager): patch to support py37 change patching to (try eval + except), and now run black -l 80 to avoid hound warning There will be lots of violations in hound's eye which I cannot find out locally because hound's linter is not up to date. I will have to do some shattered commits, and for these commits, I will name them hop (hound oriented programming). Signed-off-by: TsXor --- examples/apply_crystallize_filter_action.py | 5 +- examples/convert_smartobject_to_layer.py | 8 +- examples/emboss_action.py | 55 +++--- examples/import_image_as_layer.py | 14 +- examples/replace_images.py | 8 +- examples/session_smart_sharpen.py | 17 +- examples/smart_sharpen.py | 17 +- photoshop/api/_actionmanager_type_binder.py | 24 ++- photoshop/api/action_manager/__init__.py | 42 +++-- .../_main_types/_type_mapper.py | 109 ++++++------ .../_main_types/action_descriptor.py | 122 +++++++------ .../_main_types/action_descriptor_iterator.py | 31 ++-- .../action_manager/_main_types/action_list.py | 122 +++++++------ .../_main_types/action_list_iterator.py | 28 +-- .../_main_types/action_reference.py | 114 ++++++------ .../_main_types/action_reference_iterator.py | 37 ++-- .../desc_value_types/__init__.py | 3 +- .../desc_value_types/enumerated.py | 31 ++-- .../action_manager/desc_value_types/typeid.py | 27 +-- .../desc_value_types/unitdouble.py | 31 ++-- photoshop/api/action_manager/jprint.py | 116 ++++++------ .../action_manager/js_converter/__init__.py | 5 +- .../action_manager/js_converter/__main__.py | 22 ++- .../action_manager/js_converter/convert.py | 166 ++++++++++-------- .../js_converter/injection_js.py | 10 +- .../js_converter/node_execjs.py | 28 +-- .../action_manager/ref_form_types/__init__.py | 3 +- .../action_manager/ref_form_types/_marker.py | 32 ++-- .../ref_form_types/identifier.py | 7 +- .../action_manager/ref_form_types/index.py | 7 +- .../action_manager/ref_form_types/offset.py | 7 +- .../ref_form_types/referencekey.py | 112 ++++++------ photoshop/api/action_manager/utils.py | 71 ++++---- 33 files changed, 777 insertions(+), 654 deletions(-) diff --git a/examples/apply_crystallize_filter_action.py b/examples/apply_crystallize_filter_action.py index 7d4b38a8..5303a6e0 100644 --- a/examples/apply_crystallize_filter_action.py +++ b/examples/apply_crystallize_filter_action.py @@ -31,10 +31,7 @@ active_document.activeLayer = active_document.layerSets.item(len(nLayerSets)).artLayers.item(len(nArtLayers)) def applyCrystallize(cellSize): - filter_dict = { - '_classID':None, - 'ClSz':cellSize - } + filter_dict = {"_classID": None, "ClSz": cellSize} filter_desc = ps.ActionDescriptor.load(filter_dict) ps.app.executeAction(am.str2id("Crst"), filter_desc) diff --git a/examples/convert_smartobject_to_layer.py b/examples/convert_smartobject_to_layer.py index c5ebfc28..7d81f6ab 100644 --- a/examples/convert_smartobject_to_layer.py +++ b/examples/convert_smartobject_to_layer.py @@ -1,6 +1,6 @@ """Convert Smart object to artLayer.""" -# Import builtin modules +# Import built-in modules from textwrap import dedent # Import local modules @@ -10,10 +10,12 @@ # example 1 with Session() as ps: - js = dedent(""" + js = dedent( + """ var idplacedLayerConvertToLayers = stringIDToTypeID( "placedLayerConvertToLayers" ); executeAction( idplacedLayerConvertToLayers, undefined, DialogModes.NO ); - """) + """ + ) ps.app.doJavaScript(js) # example 2 diff --git a/examples/emboss_action.py b/examples/emboss_action.py index 5869bdf1..2dbc7626 100644 --- a/examples/emboss_action.py +++ b/examples/emboss_action.py @@ -2,54 +2,47 @@ from photoshop import Session import photoshop.api.action_manager as am + with Session() as ps: app = ps.app for index, x in enumerate(range(50)): # Execute an existing action from action palette. exec_dict = { - '_classID':None, - 'null':[ - '!ref', - am.ReferenceKey(desiredclass='action', value='Sepia Toning (layer)'), - am.ReferenceKey(desiredclass='actionSet', value='Default Actions') - ] + "_classID": None, + "null": [ + "!ref", + am.ReferenceKey(desiredclass="action", value="Sepia Toning (layer)"), + am.ReferenceKey(desiredclass="actionSet", value="Default Actions"), + ], } exec_desc = ps.ActionDescriptor.load(exec_dict) - app.executeAction(am.str2id('Ply '), exec_desc, ps.DialogModes.DisplayNoDialogs) + app.executeAction(am.str2id("Ply "), exec_desc, ps.DialogModes.DisplayNoDialogs) # Create solid color fill layer. filledlayer_dict = { - '_classID':None, - 'null':[ - '!ref', - am.ReferenceKey(desiredclass='contentLayer',value=None) - ], - 'using':{ - '_classID':'contentLayer', - 'type':{ - '_classID':'solidColorLayer', - 'color':{ - '_classID':'RGBColor', - 'red':index, - 'grain':index, - 'blue':index - } - } - } + "_classID": None, + "null": ["!ref", am.ReferenceKey(desiredclass="contentLayer", value=None)], + "using": { + "_classID": "contentLayer", + "type": { + "_classID": "solidColorLayer", + "color": {"_classID": "RGBColor", "red": index, "grain": index, "blue": index}, # noqa + }, + }, } filledlayer_desc = ps.ActionDescriptor.load(filledlayer_dict) - app.executeAction(am.str2id('Mk '), filledlayer_desc, ps.DialogModes.DisplayNoDialogs) + app.executeAction(am.str2id("Mk "), filledlayer_desc, ps.DialogModes.DisplayNoDialogs) # Select mask. selectmask_dict = { - '_classID':None, - 'null':[ - '!ref', - am.ReferenceKey(desiredclass='channel', value=am.Enumerated(type='channel',value='mask')) + "_classID": None, + "null": [ + "!ref", + am.ReferenceKey(desiredclass="channel", value=am.Enumerated(type="channel", value="mask")), ], - 'makeVisible':False + "makeVisible": False, } selectmask_desc = ps.ActionDescriptor.load(selectmask_dict) - app.executeAction(am.str2id('slct'), selectmask_desc, ps.DialogModes.DisplayNoDialogs) + app.executeAction(am.str2id("slct"), selectmask_desc, ps.DialogModes.DisplayNoDialogs) app.activeDocument.activeLayer.invert() diff --git a/examples/import_image_as_layer.py b/examples/import_image_as_layer.py index 49c39ceb..45468a73 100644 --- a/examples/import_image_as_layer.py +++ b/examples/import_image_as_layer.py @@ -1,14 +1,16 @@ """Import a image as a artLayer.""" +# Import built-in modules +import pathlib + # Import local modules from photoshop import Session -import pathlib +import photoshop.api.action_manager as am with Session(action="new_document") as ps: - import_dict = { - '_classID':None, - 'null':pathlib.Path("your/image/path") # replace it with your own path here - } + # replace it with your own path here + import_dict = {"_classID": None, "null": pathlib.Path("your/image/path")} import_desc = ps.ActionDescriptor.load(import_dict) - ps.app.executeAction(am.str2id("Plc "), import_desc) # `Plc` need one space in here. + ps.app.executeAction(am.str2id("Plc "), import_desc) + # length of charID should always be 4, if not, pad with spaces diff --git a/examples/replace_images.py b/examples/replace_images.py index 66cd28f6..cec73ad0 100644 --- a/examples/replace_images.py +++ b/examples/replace_images.py @@ -1,6 +1,6 @@ """Replace the image of the current active layer with a new image.""" -# Import builtin modules +# Import built-in modules import pathlib # Import third-party modules @@ -8,6 +8,7 @@ # Import local modules from photoshop import Session +import photoshop.api.action_manager as am PSD_FILE = psd.get_psd_files() @@ -17,10 +18,7 @@ active_layer = ps.active_document.activeLayer bounds = active_layer.bounds print(f"current layer {active_layer.name}: {bounds}") - input_dict = { - '_classID':None, - 'null':pathlib.Path(PSD_FILE["red_100x200.png"]) - } + input_dict = {"_classID": None, "null": pathlib.Path(PSD_FILE["red_100x200.png"])} input_desc = ps.ActionDescriptor.load(input_dict) ps.app.executeAction(am.str2id("placedLayerReplaceContents"), input_desc) diff --git a/examples/session_smart_sharpen.py b/examples/session_smart_sharpen.py index ff279953..9e89cef8 100644 --- a/examples/session_smart_sharpen.py +++ b/examples/session_smart_sharpen.py @@ -11,6 +11,7 @@ # Import local modules from photoshop import Session +import photoshop.api.action_manager as am PSD_FILE = psd.get_psd_files() @@ -20,14 +21,14 @@ def SmartSharpen(inAmount, inRadius, inNoise): ss_dict = { - '_classID':None, - 'presetKindType':am.Enumerated(type='presetKindType', value='presetKindCustom'), - 'amount':am.UnitDouble(unit='radius', double=inAmount), - 'radius':am.UnitDouble(unit='pixelsUnit', double=inRadius), - 'noiseReduction':am.UnitDouble(unit='percentUnit', double=inNoise), - 'blur':am.Enumerated(type='blurType', value='gaussianBlur') + "_classID": None, + "presetKindType": am.Enumerated(type="presetKindType", value="presetKindCustom"), # noqa + "amount": am.UnitDouble(unit="radius", double=inAmount), + "radius": am.UnitDouble(unit="pixelsUnit", double=inRadius), + "noiseReduction": am.UnitDouble(unit="percentUnit", double=inNoise), + "blur": am.Enumerated(type="blurType", value="gaussianBlur"), } ss_desc = ps.ActionDescriptor.load(ss_dict) - app.ExecuteAction(am.str2id('smartSharpen'), ss_desc) + ps.app.ExecuteAction(am.str2id("smartSharpen"), ss_desc) - SmartSharpen(300, 2.0, 20) \ No newline at end of file + SmartSharpen(300, 2.0, 20) diff --git a/examples/smart_sharpen.py b/examples/smart_sharpen.py index f850d05e..d92a158a 100644 --- a/examples/smart_sharpen.py +++ b/examples/smart_sharpen.py @@ -27,14 +27,15 @@ def SmartSharpen(inAmount, inRadius, inNoise): ss_dict = { - '_classID':None, - 'presetKindType':am.Enumerated(type='presetKindType', value='presetKindCustom'), - 'amount':am.UnitDouble(unit='radius', double=inAmount), - 'radius':am.UnitDouble(unit='pixelsUnit', double=inRadius), - 'noiseReduction':am.UnitDouble(unit='percentUnit', double=inNoise), - 'blur':am.Enumerated(type='blurType', value='gaussianBlur') + "_classID": None, + "presetKindType": am.Enumerated(type="presetKindType", value="presetKindCustom"), # noqa + "amount": am.UnitDouble(unit="radius", double=inAmount), + "radius": am.UnitDouble(unit="pixelsUnit", double=inRadius), + "noiseReduction": am.UnitDouble(unit="percentUnit", double=inNoise), + "blur": am.Enumerated(type="blurType", value="gaussianBlur"), } ss_desc = ps.ActionDescriptor.load(ss_dict) - app.ExecuteAction(am.str2id('smartSharpen'), ss_desc) + app.ExecuteAction(am.str2id("smartSharpen"), ss_desc) -SmartSharpen(300, 2.0, 20) \ No newline at end of file + +SmartSharpen(300, 2.0, 20) diff --git a/photoshop/api/_actionmanager_type_binder.py b/photoshop/api/_actionmanager_type_binder.py index 836d7aca..120cfc27 100644 --- a/photoshop/api/_actionmanager_type_binder.py +++ b/photoshop/api/_actionmanager_type_binder.py @@ -7,19 +7,25 @@ # Import local modules from photoshop.api.action_descriptor import ActionDescriptor as AD_proto -from photoshop.api.action_manager._main_types.action_descriptor import ActionDescriptor as AD_utils_proto from photoshop.api.action_list import ActionList as AL_proto -from photoshop.api.action_manager._main_types.action_list import ActionList as AL_utils_proto +from photoshop.api.action_manager._main_types.action_descriptor import ( + ActionDescriptor as AD_utils_proto, +) +from photoshop.api.action_manager._main_types.action_list import ( + ActionList as AL_utils_proto, +) +from photoshop.api.action_manager._main_types.action_reference import ( + ActionReference as AR_utils_proto, +) from photoshop.api.action_reference import ActionReference as AR_proto -from photoshop.api.action_manager._main_types.action_reference import ActionReference as AR_utils_proto from photoshop.api.enumerations import DescValueType from photoshop.api.enumerations import ReferenceFormType class ActionDescriptor(AD_proto, AD_utils_proto): @classmethod - def load(cls, adict: dict) -> 'ActionDescriptor': - '''Convert a python object to an ActionDescriptor''' + def load(cls, adict: dict) -> "ActionDescriptor": + """Convert a python object to an ActionDescriptor""" return super().load(adict, globals()) def __init__(self, parent=None, classID=None): @@ -45,8 +51,8 @@ def getReference(self, key: int) -> "ActionReference": class ActionList(AL_proto, AL_utils_proto): @classmethod - def load(cls, alist: list) -> 'ActionList': - '''Convert a python object to an ActionList''' + def load(cls, alist: list) -> "ActionList": + """Convert a python object to an ActionList""" return super().load(alist, globals()) def getType(self, index: int) -> DescValueType: @@ -68,8 +74,8 @@ def getReference(self, index: int) -> "ActionReference": class ActionReference(AR_proto, AR_utils_proto): @classmethod - def load(cls, adict: dict) -> 'ActionReference': - '''Convert a python object to an ActionReference''' + def load(cls, adict: dict) -> "ActionReference": + """Convert a python object to an ActionReference""" return super().load(adict) def getForm(self) -> ReferenceFormType: diff --git a/photoshop/api/action_manager/__init__.py b/photoshop/api/action_manager/__init__.py index 3af810db..b9ab3d35 100644 --- a/photoshop/api/action_manager/__init__.py +++ b/photoshop/api/action_manager/__init__.py @@ -1,20 +1,28 @@ -from .ref_form_types import * -from .desc_value_types import * -from .utils import * +from .desc_value_types import Enumerated +from .desc_value_types import TypeID +from .desc_value_types import UnitDouble +from .jprint import jformat +from .jprint import jprint from .js_converter import dump as dumpjs -from .jprint import * +from .ref_form_types import Identifier +from .ref_form_types import Index +from .ref_form_types import Offset +from .ref_form_types import ReferenceKey +from .utils import id2str +from .utils import str2id + __all__ = [ # noqa: F405 - 'str2id', - 'id2str', - 'Enumerated', - 'TypeID', - 'UnitDouble', - 'Identifier', - 'Index', - 'Offset', - 'ReferenceKey', - 'dumpjs', - 'jprint', - 'jformat', -] \ No newline at end of file + "str2id", + "id2str", + "Enumerated", + "TypeID", + "UnitDouble", + "Identifier", + "Index", + "Offset", + "ReferenceKey", + "dumpjs", + "jprint", + "jformat", +] diff --git a/photoshop/api/action_manager/_main_types/_type_mapper.py b/photoshop/api/action_manager/_main_types/_type_mapper.py index 2f689217..37016520 100644 --- a/photoshop/api/action_manager/_main_types/_type_mapper.py +++ b/photoshop/api/action_manager/_main_types/_type_mapper.py @@ -1,68 +1,73 @@ -'''Maybe the core of this submodule. +"""Maybe the core of this submodule. Handles almost all type mappings. (Some else are in ReferenceKey.) -This module is INTERNAL. You should not import functions from it.''' +This module is INTERNAL. You should not import functions from it.""" -from ..desc_value_types import * -from ..ref_form_types import * -from ..utils import * +from ..desc_value_types import Enumerated +from ..desc_value_types import TypeID +from ..desc_value_types import UnitDouble +from ..utils import id2str -__all__ = ['unpack', 'pack', 'parsetype'] + +__all__ = ["unpack", "pack", "parsetype"] pytype2str = { - bool:'Boolean', - int:'Integer', - float:'Double', - str:'String', - Enumerated:'Enumerated', - UnitDouble:'UnitDouble', - TypeID:'Class', - 'ActionDescriptor':'Object', - 'ActionList':'List', - 'ActionReference':'Reference', + bool: "Boolean", + int: "Integer", + float: "Double", + str: "String", + Enumerated: "Enumerated", + UnitDouble: "UnitDouble", + TypeID: "Class", + "ActionDescriptor": "Object", + "ActionList": "List", + "ActionReference": "Reference", } str2pytype = { - 'Enumerated':Enumerated, - 'UnitDouble':UnitDouble, - 'Class':TypeID, + "Enumerated": Enumerated, + "UnitDouble": UnitDouble, + "Class": TypeID, } + def unpack(val): - vtype = val.typename if hasattr(val, 'typename') else type(val) - typestr = pytype2str[vtype] - try: - args = val._unpacker() - except: - args = (val,) - return (typestr, args) + vtype = val.typename if hasattr(val, "typename") else type(val) + typestr = pytype2str[vtype] + try: + args = val._unpacker() + except BaseException: + args = (val,) + return (typestr, args) + def pack(obj, index): # "index" means id of key string or list index. - valtype = obj.getType(index) - typestr = str(valtype)[14:-4] - if typestr == 'Data': - # No plan to support RawType because it seldom runs successfully - # and is seldom used in regular scripting. - return None - if typestr in str2pytype: - pytype = str2pytype[typestr] - val = pytype._packer(obj, index) - elif typestr == 'Object': - val = obj.getObjectValue(index) - val.classID = id2str(obj.getObjectType(index)) - else: - get_func = getattr(obj, 'get'+typestr) - val = get_func(index) - return val + valtype = obj.getType(index) + typestr = str(valtype)[14:-4] + if typestr == "Data": + # No plan to support RawType because it seldom runs successfully + # and is seldom used in regular scripting. + return None + if typestr in str2pytype: + pytype = str2pytype[typestr] + val = pytype._packer(obj, index) + elif typestr == "Object": + val = obj.getObjectValue(index) + val.classID = id2str(obj.getObjectType(index)) + else: + get_func = getattr(obj, "get" + typestr) + val = get_func(index) + return val + def parsetype(obj): - if type(obj) == dict: - dtype = 'ActionDescriptor' - elif type(obj) == list: - first = obj[0] if obj else None - if first == '!ref': - dtype = 'ActionReference' + if type(obj) == dict: + dtype = "ActionDescriptor" + elif type(obj) == list: + first = obj[0] if obj else None + if first == "!ref": + dtype = "ActionReference" + else: + dtype = "ActionList" else: - dtype = 'ActionList' - else: - dtype = 'others' - return dtype \ No newline at end of file + dtype = "others" + return dtype diff --git a/photoshop/api/action_manager/_main_types/action_descriptor.py b/photoshop/api/action_manager/_main_types/action_descriptor.py index b4803a7b..1a16e715 100644 --- a/photoshop/api/action_manager/_main_types/action_descriptor.py +++ b/photoshop/api/action_manager/_main_types/action_descriptor.py @@ -1,68 +1,74 @@ -from ._type_mapper import * -from ..utils import * -from .action_descriptor_iterator import ActionDescriptor_Iterator +# Import built-in modules +from abc import ABC +from abc import abstractclassmethod from typing import Any -from abc import ABC, abstractclassmethod -class ActionDescriptor: - '''A vessel for my extra utils. - You should not use, and cannot initialize it - because it is an abstract class.''' +from ..utils import id2str +from ..utils import str2id +from ._type_mapper import pack +from ._type_mapper import parsetype +from ._type_mapper import unpack +from .action_descriptor_iterator import ActionDescriptor_Iterator + + +class ActionDescriptor(ABC): + """A vessel for my extra utils. + You should not use, and cannot initialize it + because it is an abstract class.""" + + @abstractclassmethod + def load(cls, adict: dict, namespace: dict): # pass globals() for namespace + clsid = adict["_classID"] if "_classID" in adict else None + new = cls(classID=clsid) + for k, v in adict.items(): + if k == "_classID": + continue + # py37 compat + try: + val = eval(r'v if (dtype := parsetype(v)) == "others" else namespace[dtype].load(v)') # noqa + except SyntaxError: + val = v if parsetype(v) == "others" else namespace[parsetype(v)].load(v) + new.uput(k, val) + return new - @abstractclassmethod - def load(cls, adict: dict, namespace: dict): # pass globals() for namespace - clsid = adict['_classID'] \ - if '_classID' in adict \ - else None - new = cls(classID=clsid) - for k,v in adict.items(): - if k == '_classID': - continue - v = v \ - if (dtype := parsetype(v)) == 'others' \ - else namespace[dtype].load(v) - new.uput(k,v) - return new + def uget(self, key: str) -> Any: + """Get a value of a key in an ActionDescriptor, no matter its type.""" + keyid = str2id(key) + val = pack(self, keyid) + return val - def uget(self, key: str) -> Any: - '''Get a value of a key in an ActionDescriptor, no matter its type.''' - keyid = str2id(key) - val = pack(self, keyid) - return val + def uput(self, key: str, val: Any): + """Put a value of a key into an ActionDescriptor, no matter its type.""" + keyid = str2id(key) + typestr, args = unpack(val) + put_func = getattr(self, "put" + typestr) + put_func(keyid, *args) - def uput(self, key: str, val: Any): - '''Put a value of a key into an ActionDescriptor, no matter its type.''' - keyid = str2id(key) - typestr, args = unpack(val) - put_func = getattr(self, 'put'+typestr) - put_func(keyid, *args) + def __len__(self): + return self.count - def __len__(self): - return self.count + def __iter__(self) -> ActionDescriptor_Iterator: + return ActionDescriptor_Iterator(self) - def __iter__(self) -> ActionDescriptor_Iterator: - return ActionDescriptor_Iterator(self) + def items(self) -> ((str, Any)): + keyids = (self.getKey(n) for n in range(len(self))) + return ((id2str(keyid), pack(self, keyid)) for keyid in keyids) - def __contains__(self, key): - keys = [key for key in self] - return key in keys + def __contains__(self, key): + keys = [key for key in self] + return key in keys - def dump(self) -> dict: - '''Convert an ActionDescriptor to a python object.''' - #This is a dict comprehension. - ddict = {'_classID':self.classID} - ddict.update({ - key:( - value.dump() \ - if hasattr(value := self.uget(key), 'dump') \ - else value - ) for key in self - }) - return ddict + def dump(self) -> dict: + """Convert an ActionDescriptor to a python object.""" + # This is a dict comprehension. + ddict = {"_classID": self.classID} + ext = {k: (v.dump() if hasattr(v, "dump") else v) for k, v in self.items()} + ddict.update(ext) + return ddict - def _unpacker(self) -> tuple: - value = self - if self.classID is None: - raise RuntimeError('Do not use old methods and new methods mixedly.') - clsid = str2id(self.classID) - return (clsid, value) \ No newline at end of file + def _unpacker(self) -> tuple: + value = self + if self.classID is None: + raise RuntimeError("Do not use old methods and new methods mixedly.") + clsid = str2id(self.classID) + return (clsid, value) diff --git a/photoshop/api/action_manager/_main_types/action_descriptor_iterator.py b/photoshop/api/action_manager/_main_types/action_descriptor_iterator.py index 9d5eee51..e2ee3303 100644 --- a/photoshop/api/action_manager/_main_types/action_descriptor_iterator.py +++ b/photoshop/api/action_manager/_main_types/action_descriptor_iterator.py @@ -1,20 +1,21 @@ -from ..utils import * +from ..utils import id2str + class ActionDescriptor_Iterator: - '''An iterator. You don't need to initialize it manually.''' + """An iterator. You don't need to initialize it manually.""" - def __init__(self, psobj: 'ActionDescriptor'): - self.curobj = psobj - self.n = -1 + def __init__(self, psobj): + self.curobj = psobj + self.n = -1 - def __next__(self) -> str: - self.n += 1 - try: - keyid = self.curobj.getKey(self.n) - except: - raise StopIteration - keystr = id2str(keyid) - return keystr + def __next__(self) -> str: + self.n += 1 + try: + keyid = self.curobj.getKey(self.n) + except BaseException: + raise StopIteration + keystr = id2str(keyid) + return keystr - def __repr__(self): - return ''%self.n \ No newline at end of file + def __repr__(self): + return "" % self.n diff --git a/photoshop/api/action_manager/_main_types/action_list.py b/photoshop/api/action_manager/_main_types/action_list.py index c5c85b43..fa56588d 100644 --- a/photoshop/api/action_manager/_main_types/action_list.py +++ b/photoshop/api/action_manager/_main_types/action_list.py @@ -1,60 +1,68 @@ -from ._type_mapper import * -from ..utils import * -from .action_list_iterator import ActionList_Iterator +# Import built-in modules +from abc import ABC +from abc import abstractclassmethod from typing import Any -from abc import ABC, abstractclassmethod + +from ._type_mapper import pack +from ._type_mapper import parsetype +from ._type_mapper import unpack +from .action_list_iterator import ActionList_Iterator + class ActionList(ABC): - '''A vessel for my extra utils. - You should not use, and cannot initialize it - because it is an abstract class.''' - - @abstractclassmethod - def load(cls, alist: list, namespace: dict): # pass globals() for namespace - new = cls() - for v in alist: - v = v \ - if (dtype := parsetype(v)) == 'others' \ - else namespace[dtype].load(v) - new.uput(v) - return new - - @property - def dtype(self) -> str: - if len(self) == 0: - return None - valtype = self.getType(0) - typestr = str(valtype)[14:-4] - return typestr - - def uget(self, index: int) -> Any: - '''Get an element in an ActionList, no matter its type.''' - val = pack(self, index) - return val - - def uput(self, val: Any): - '''Put an element into an ActionList, no matter its type.''' - typestr, args = unpack(val) - #ActionList type checking - assert True if (dtype := self.dtype) is None else dtype == typestr, \ - 'ActionList can only hold things of the same type' - put_func = getattr(self, 'put'+typestr) - put_func(*args) - - def __len__(self): - return self.count - - def __iter__(self) -> ActionList_Iterator: - return ActionList_Iterator(self) - - def dump(self) -> list: - '''Convert an ActionList to a python object.''' - #This is a list comprehension. - dlist = [ - ( - elem.dump() \ - if hasattr(elem, 'dump') \ - else elem - ) for elem in self - ] - return dlist \ No newline at end of file + """A vessel for my extra utils. + You should not use, and cannot initialize it + because it is an abstract class.""" + + @abstractclassmethod + def load(cls, alist: list, namespace: dict): # pass globals() for namespace + new = cls() + for v in alist: + # py37 compat + try: + val = eval(r'v if (dtype := parsetype(v)) == "others" else namespace[dtype].load(v)') # noqa + except SyntaxError: + val = v if parsetype(v) == "others" else namespace[parsetype(v)].load(v) + new.uput(val) + return new + + @property + def dtype(self) -> str: + if len(self) == 0: + return None + valtype = self.getType(0) + typestr = str(valtype)[14:-4] + return typestr + + def uget(self, index: int) -> Any: + """Get an element in an ActionList, no matter its type.""" + val = pack(self, index) + return val + + def uput(self, val: Any): + """Put an element into an ActionList, no matter its type.""" + typestr, args = unpack(val) + # ActionList type checking + # py37 compat + try: + assert eval( + r"True if (dtype := self.dtype) is None else dtype == typestr" + ), "ActionList can only hold things of the same type" + except SyntaxError: + assert ( + True if self.dtype is None else self.dtype == typestr + ), "ActionList can only hold things of the same type" + put_func = getattr(self, "put" + typestr) + put_func(*args) + + def __len__(self): + return self.count + + def __iter__(self) -> ActionList_Iterator: + return ActionList_Iterator(self) + + def dump(self) -> list: + """Convert an ActionList to a python object.""" + # This is a list comprehension. + dlist = [(elem.dump() if hasattr(elem, "dump") else elem) for elem in self] + return dlist diff --git a/photoshop/api/action_manager/_main_types/action_list_iterator.py b/photoshop/api/action_manager/_main_types/action_list_iterator.py index 68a62bf3..b269ea56 100644 --- a/photoshop/api/action_manager/_main_types/action_list_iterator.py +++ b/photoshop/api/action_manager/_main_types/action_list_iterator.py @@ -1,19 +1,21 @@ +# Import built-in modules from typing import Any + class ActionList_Iterator: - '''An iterator. You don't need to initialize it manually.''' + """An iterator. You don't need to initialize it manually.""" - def __init__(self, psobj: 'ActionList'): - self.curobj = psobj - self.n = -1 + def __init__(self, psobj): + self.curobj = psobj + self.n = -1 - def __next__(self) -> Any: - self.n += 1 - try: - elem = self.curobj.uget(self.n) - except: - raise StopIteration() - return elem + def __next__(self) -> Any: + self.n += 1 + try: + elem = self.curobj.uget(self.n) + except BaseException: + raise StopIteration() + return elem - def __repr__(self): - return ''%self.n \ No newline at end of file + def __repr__(self): + return "" % self.n diff --git a/photoshop/api/action_manager/_main_types/action_reference.py b/photoshop/api/action_manager/_main_types/action_reference.py index 0cadf6d0..d551ba1d 100644 --- a/photoshop/api/action_manager/_main_types/action_reference.py +++ b/photoshop/api/action_manager/_main_types/action_reference.py @@ -1,58 +1,62 @@ -from .action_reference_iterator import ActionReference_Iterator +# Import built-in modules +from abc import ABC +from abc import abstractclassmethod + from ..ref_form_types import ReferenceKey -from abc import ABC, abstractclassmethod +from .action_reference_iterator import ActionReference_Iterator + class ActionReference(ABC): - '''A vessel for my extra utils. - You should not use, and cannot initialize it - because it is an abstract class.''' - - @abstractclassmethod - def load(cls, alist: list): - new = cls() - # pack into a list if is a single key - alist = [alist] \ - if type(alist) == ReferenceKey \ - else alist - for rkey in alist: - if rkey == '!ref': - continue - new.uput(rkey) - return new - - def uget(self, index: int) -> ReferenceKey: - '''Get a key in an ActionReference as ReferenceKey, no matter its type.''' - target = self - for i in range(index+1): - try: - target = target.getContainer() - except: - raise IndexError('index out of range') - return ReferenceKey._packer(target) - - def uput(self, rkey: ReferenceKey): - '''Put a ReferenceKey into an ActionReference, no matter its type.''' - assert type(rkey) == ReferenceKey - ftype, dcls, v = rkey._unpacker() - put_func = getattr(self, 'put'+ftype) - args = (dcls,) if v is None else (dcls, *v) - put_func(*args) - - def dump(self) -> list: - '''Convert an ActionReference to a python object.''' - target = self - tlist = ['!ref'] - tlist.extend([elem for elem in self]) - return tlist - - def __len__(self): - rlen = 1; target = self - while True: - try: - target = target.getContainer(); rlen += 1 - except: - rlen -= 1; break - return rlen - - def __iter__(self) -> ActionReference_Iterator: - return ActionReference_Iterator(self) \ No newline at end of file + """A vessel for my extra utils. + You should not use, and cannot initialize it + because it is an abstract class.""" + + @abstractclassmethod + def load(cls, alist: list): + new = cls() + # pack into a list if is a single key + alist = [alist] if type(alist) == ReferenceKey else alist + for rkey in alist: + if rkey == "!ref": + continue + new.uput(rkey) + return new + + def uget(self, index: int) -> ReferenceKey: + """Get a key in an ActionReference as ReferenceKey, no matter its type.""" + target = self + for _i in range(index + 1): + try: + target = target.getContainer() + except BaseException: + raise IndexError("index out of range") + return ReferenceKey._packer(target) + + def uput(self, rkey: ReferenceKey): + """Put a ReferenceKey into an ActionReference, no matter its type.""" + assert type(rkey) == ReferenceKey + ftype, dcls, v = rkey._unpacker() + put_func = getattr(self, "put" + ftype) + args = (dcls,) if v is None else (dcls, *v) + put_func(*args) + + def dump(self) -> list: + """Convert an ActionReference to a python object.""" + tlist = ["!ref"] + tlist.extend([elem for elem in self]) + return tlist + + def __len__(self): + rlen = 1 + target = self + while True: + try: + target = target.getContainer() + rlen += 1 + except BaseException: + rlen -= 1 + break + return rlen + + def __iter__(self) -> ActionReference_Iterator: + return ActionReference_Iterator(self) diff --git a/photoshop/api/action_manager/_main_types/action_reference_iterator.py b/photoshop/api/action_manager/_main_types/action_reference_iterator.py index cb487a37..2f93ac29 100644 --- a/photoshop/api/action_manager/_main_types/action_reference_iterator.py +++ b/photoshop/api/action_manager/_main_types/action_reference_iterator.py @@ -1,24 +1,25 @@ from ..ref_form_types import ReferenceKey + class ActionReference_Iterator: - '''An iterator. You don't need to initialize it manually.''' + """An iterator. You don't need to initialize it manually.""" - def __init__(self, psobj: 'ActionReference'): - self.curobj = psobj - self.init = True - self.n = -1 + def __init__(self, psobj): + self.curobj = psobj + self.init = True + self.n = -1 - def __next__(self) -> ReferenceKey: - self.n += 1 - if self.init: - self.init = False - return ReferenceKey._packer(self.curobj) - self.curobj = self.curobj.getContainer() - try: - self.curobj.getContainer() - except: - raise StopIteration - return ReferenceKey._packer(self.curobj) + def __next__(self) -> ReferenceKey: + self.n += 1 + if self.init: + self.init = False + return ReferenceKey._packer(self.curobj) + self.curobj = self.curobj.getContainer() + try: + self.curobj.getContainer() + except BaseException: + raise StopIteration + return ReferenceKey._packer(self.curobj) - def __repr__(self): - return ''%self.n \ No newline at end of file + def __repr__(self): + return "" % self.n diff --git a/photoshop/api/action_manager/desc_value_types/__init__.py b/photoshop/api/action_manager/desc_value_types/__init__.py index e8342afa..6537c6f6 100644 --- a/photoshop/api/action_manager/desc_value_types/__init__.py +++ b/photoshop/api/action_manager/desc_value_types/__init__.py @@ -2,4 +2,5 @@ from .typeid import TypeID from .unitdouble import UnitDouble -__all__ = ['Enumerated', 'TypeID', 'UnitDouble'] \ No newline at end of file + +__all__ = ["Enumerated", "TypeID", "UnitDouble"] diff --git a/photoshop/api/action_manager/desc_value_types/enumerated.py b/photoshop/api/action_manager/desc_value_types/enumerated.py index 27acc6ec..97607b2e 100644 --- a/photoshop/api/action_manager/desc_value_types/enumerated.py +++ b/photoshop/api/action_manager/desc_value_types/enumerated.py @@ -1,16 +1,23 @@ -from ..utils import * +# Import built-in modules from collections import namedtuple -Enumerated_proto = namedtuple('Enumerated_proto', ['type', 'value']) +from ..utils import id2str +from ..utils import str2id + + +Enumerated_proto = namedtuple("Enumerated_proto", ["type", "value"]) + class Enumerated(Enumerated_proto): - '''You can initialize an Enumerated object with 2 arguments: type, value.''' - @classmethod - def _packer(cls, obj, index): - type = id2str(obj.getEnumerationType(index)) - value = id2str(obj.getEnumerationValue(index)) - return cls(type, value) - def _unpacker(self): - typeid = str2id(self.type) - valueid = str2id(self.value) - return (typeid, valueid) \ No newline at end of file + """You can initialize an Enumerated object with 2 arguments: type, value.""" + + @classmethod + def _packer(cls, obj, index): + type = id2str(obj.getEnumerationType(index)) + value = id2str(obj.getEnumerationValue(index)) + return cls(type, value) + + def _unpacker(self): + typeid = str2id(self.type) + valueid = str2id(self.value) + return (typeid, valueid) diff --git a/photoshop/api/action_manager/desc_value_types/typeid.py b/photoshop/api/action_manager/desc_value_types/typeid.py index c35fa42e..0fc10a19 100644 --- a/photoshop/api/action_manager/desc_value_types/typeid.py +++ b/photoshop/api/action_manager/desc_value_types/typeid.py @@ -1,14 +1,21 @@ -from ..utils import * +# Import built-in modules from collections import namedtuple -TypeID_proto = namedtuple('TypeID_proto', ['string']) +from ..utils import id2str +from ..utils import str2id + + +TypeID_proto = namedtuple("TypeID_proto", ["string"]) + class TypeID(TypeID_proto): - '''You can initialize a TypeID object with 1 argument: string.''' - @classmethod - def _packer(cls, obj, index): - typeid = id2str(obj.getClass(index)) - return cls(typeid) - def _unpacker(self): - nid = str2id(self.typeid) - return (nid,) \ No newline at end of file + """You can initialize a TypeID object with 1 argument: string.""" + + @classmethod + def _packer(cls, obj, index): + typeid = id2str(obj.getClass(index)) + return cls(typeid) + + def _unpacker(self): + nid = str2id(self.typeid) + return (nid,) diff --git a/photoshop/api/action_manager/desc_value_types/unitdouble.py b/photoshop/api/action_manager/desc_value_types/unitdouble.py index e25dbf63..0d0ee5a9 100644 --- a/photoshop/api/action_manager/desc_value_types/unitdouble.py +++ b/photoshop/api/action_manager/desc_value_types/unitdouble.py @@ -1,16 +1,23 @@ -from ..utils import * +# Import built-in modules from collections import namedtuple -UnitDouble_proto = namedtuple('UnitDouble_proto', ['unit', 'double']) +from ..utils import id2str +from ..utils import str2id + + +UnitDouble_proto = namedtuple("UnitDouble_proto", ["unit", "double"]) + class UnitDouble(UnitDouble_proto): - '''You can initialize a UnitDouble object with 2 arguments: unit, double.''' - @classmethod - def _packer(cls, obj, index): - unit = id2str(obj.getUnitDoubleType(index)) - double = obj.getUnitDoubleValue(index) - return cls(unit, double) - def _unpacker(self): - unitid = str2id(self.unit) - double = self.double - return (unitid, double) + """You can initialize a UnitDouble object with 2 arguments: unit, double.""" + + @classmethod + def _packer(cls, obj, index): + unit = id2str(obj.getUnitDoubleType(index)) + double = obj.getUnitDoubleValue(index) + return cls(unit, double) + + def _unpacker(self): + unitid = str2id(self.unit) + double = self.double + return (unitid, double) diff --git a/photoshop/api/action_manager/jprint.py b/photoshop/api/action_manager/jprint.py index 38c41530..fe1daf4f 100644 --- a/photoshop/api/action_manager/jprint.py +++ b/photoshop/api/action_manager/jprint.py @@ -1,61 +1,63 @@ -'''Format a repr() string like json. -This is just literal processing.''' +"""Format a repr() string like json. +This is just literal processing.""" + def jformat(astr, indent=4, prefix=None): - '''Formats a repr() string.''' - all_am_keywords = [ # noqa: F405 - 'str2id', - 'id2str', - 'Enumerated', - 'TypeID', - 'UnitDouble', - 'Identifier', - 'Index', - 'Offset', - 'ReferenceKey', - 'dumpjs', - 'jprint', - 'jformat', - ] - nstr = '' - indent_level = 0 - insmall = False - insquote = False - indquote = False - aftercomma = False - for i in range(len(astr)): - char = astr[i] - if aftercomma: - aftercomma = False - if char == ' ': - continue - if char == '(': - insmall = True - if char == ')': - insmall = False - if char == '"': - insquote = not insquote - if char == '\'': - indquote = not indquote - if insquote or indquote: - nstr += char - continue - if char in ',[]{}': - if char == ',' and not insmall: - char = char+'\n'+' '*(indent*indent_level) - aftercomma = True - if char in '[{': - indent_level += 1 - char = char+'\n'+' '*(indent*indent_level) - if char in ']}': - indent_level -= 1 - char = '\n'+' '*(indent*indent_level)+char - nstr += char - if not prefix is None: - for kwd in all_am_keywords: - nstr = nstr.replace(kwd, prefix+'.'+kwd) - return nstr + """Formats a repr() string.""" + all_am_keywords = [ # noqa: F405 + "str2id", + "id2str", + "Enumerated", + "TypeID", + "UnitDouble", + "Identifier", + "Index", + "Offset", + "ReferenceKey", + "dumpjs", + "jprint", + "jformat", + ] + nstr = "" + indent_level = 0 + insmall = False + insquote = False + indquote = False + aftercomma = False + for i in range(len(astr)): + char = astr[i] + if aftercomma: + aftercomma = False + if char == " ": + continue + if char == "(": + insmall = True + if char == ")": + insmall = False + if char == '"': + insquote = not insquote + if char == "'": + indquote = not indquote + if insquote or indquote: + nstr += char + continue + if char in ",[]{}": + if char == "," and not insmall: + char = char + "\n" + " " * (indent * indent_level) + aftercomma = True + if char in "[{": + indent_level += 1 + char = char + "\n" + " " * (indent * indent_level) + if char in "]}": + indent_level -= 1 + char = "\n" + " " * (indent * indent_level) + char + nstr += char + if prefix is not None: + for kwd in all_am_keywords: + nstr = nstr.replace(kwd, prefix + "." + kwd) + return nstr + def jprint(obj, indent=4): - '''Print formatted repr of an object.''' - print(jformat(repr(obj), indent=indent)) \ No newline at end of file + """Print formatted repr of an object.""" + print(jformat(repr(obj), indent=indent)) diff --git a/photoshop/api/action_manager/js_converter/__init__.py b/photoshop/api/action_manager/js_converter/__init__.py index 73ff17be..b12651f5 100644 --- a/photoshop/api/action_manager/js_converter/__init__.py +++ b/photoshop/api/action_manager/js_converter/__init__.py @@ -1 +1,4 @@ -from .convert import dump \ No newline at end of file +from .convert import dump + + +__all__ = ["dump"] diff --git a/photoshop/api/action_manager/js_converter/__main__.py b/photoshop/api/action_manager/js_converter/__main__.py index 34595e3e..d4e3709b 100644 --- a/photoshop/api/action_manager/js_converter/__main__.py +++ b/photoshop/api/action_manager/js_converter/__main__.py @@ -1,12 +1,16 @@ +# Import built-in modules import sys -from photoshop.api.action_manager.js_converter import dump + +# Import local modules from photoshop.api.action_manager import jprint +from photoshop.api.action_manager.js_converter import dump + -if __name__ == '__main__': - for obj in dump(sys.stdin.read()): - print('==========') - print('Executed an object:') - print('Operation:') - print(obj[0]) - print('Descriptor:') - jprint(obj[1], prefix='am') \ No newline at end of file +if __name__ == "__main__": + for obj in dump(sys.stdin.read()): + print("==========") + print("Executed an object:") + print("Operation:") + print(obj[0]) + print("Descriptor:") + jprint(obj[1], prefix="am") diff --git a/photoshop/api/action_manager/js_converter/convert.py b/photoshop/api/action_manager/js_converter/convert.py index 24652e41..9d1ccba5 100644 --- a/photoshop/api/action_manager/js_converter/convert.py +++ b/photoshop/api/action_manager/js_converter/convert.py @@ -1,96 +1,112 @@ -'''Defines functions to parse information got on the js side into loadable form. +"""Defines functions to parse information got on the js side into loadable form. Use with following: (You need to install Node.js to PATH!) import photoshop.api.action_manager as am -am.dumpjs(some_js_code)''' +am.dumpjs(some_js_code)""" -from .node_execjs import execjs -from .injection_js import injection -from ..utils import str2id, id2str, str2hash, hash2str -from ..desc_value_types import * -from ..ref_form_types import * +# Import built-in modules import json +from ..desc_value_types import Enumerated +from ..desc_value_types import TypeID +from ..desc_value_types import UnitDouble +from ..ref_form_types import Identifier +from ..ref_form_types import Index +from ..ref_form_types import Offset +from ..ref_form_types import ReferenceKey +from ..utils import id2str +from ..utils import str2hash +from .injection_js import injection +from .node_execjs import execjs + + def toid(string): - head = str(string)[:7] - if head == 'CharID_': - out = TypeID(id2str(str2hash(string[7:].ljust(4)))) - elif head == 'StrnID_': - out = TypeID(string[7:]) - else: - out = string - return out + head = str(string)[:7] + if head == "CharID_": + out = TypeID(id2str(str2hash(string[7:].ljust(4)))) + elif head == "StrnID_": + out = TypeID(string[7:]) + else: + out = string + return out + def unhead(string): - head = str(string)[:7] - if head == 'CharID_': - out = id2str(str2hash(string[7:].ljust(4))) - elif head == 'StrnID_': - out = string[7:] - else: - out = string - return out + head = str(string)[:7] + if head == "CharID_": + out = id2str(str2hash(string[7:].ljust(4))) + elif head == "StrnID_": + out = string[7:] + else: + out = string + return out + str2getpacker = { - 'UnitDouble':lambda x: UnitDouble(unhead(x['unit']), x['double']), - 'Enumerated':lambda x: Enumerated(unhead(x['enumtype']), unhead(x['enumval'])), - 'TypeID': lambda x: toid(x['string']), - 'ActionDescriptor':lambda x: parsedict(x), - 'ActionReference':lambda x: parseref(x), - 'ActionList':lambda x: parselist(x), - } + "UnitDouble": lambda x: UnitDouble(unhead(x["unit"]), x["double"]), + "Enumerated": lambda x: Enumerated(unhead(x["enumtype"]), unhead(x["enumval"])), + "TypeID": lambda x: toid(x["string"]), + "ActionDescriptor": lambda x: parsedict(x), + "ActionReference": lambda x: parseref(x), + "ActionList": lambda x: parselist(x), +} str2refgetpacker = { - 'default':lambda x: ReferenceKey(unhead(x['DesiredClass']), unhead(x['Value'])), - 'Enumerated':lambda x: ReferenceKey(unhead(x['DesiredClass']), Enumerated(unhead(x['Value']['enumtype']), unhead(x['Value']['enumval']))), - 'Identifier':lambda x: ReferenceKey(unhead(x['DesiredClass']), Identifier+int(x['Value'])), - 'Index':lambda x: ReferenceKey(unhead(x['DesiredClass']), Index+int(x['Value'])), - 'Offset':lambda x: ReferenceKey(unhead(x['DesiredClass']), Offset+int(x['Value'])), - 'Property':lambda x: ReferenceKey(unhead(x['DesiredClass']), toid(x['Value'])), - } + "default": lambda x: ReferenceKey(unhead(x["DesiredClass"]), unhead(x["Value"])), + "Enumerated": lambda x: ReferenceKey( + unhead(x["DesiredClass"]), + Enumerated(unhead(x["Value"]["enumtype"]), unhead(x["Value"]["enumval"])), # noqa + ), + "Identifier": lambda x: ReferenceKey(unhead(x["DesiredClass"]), Identifier + int(x["Value"])), + "Index": lambda x: ReferenceKey(unhead(x["DesiredClass"]), Index + int(x["Value"])), + "Offset": lambda x: ReferenceKey(unhead(x["DesiredClass"]), Offset + int(x["Value"])), + "Property": lambda x: ReferenceKey(unhead(x["DesiredClass"]), toid(x["Value"])), +} + def parsedict(tdict): - if not '_classID' in tdict: - tdict['_classID'] = None - else: - tdict['_classID'] = unhead(tdict['_classID']) - pdict = {unhead(k):( - str2getpacker[v['type']](v) \ - if type(v) == dict \ - else v - ) for k,v in tdict.items()} - del pdict['type'] - return pdict + if "_classID" not in tdict: + tdict["_classID"] = None + else: + tdict["_classID"] = unhead(tdict["_classID"]) + pdict = {unhead(k): (str2getpacker[v["type"]](v) if type(v) == dict else v) for k, v in tdict.items()} + del pdict["type"] + return pdict + def parselist(tdict): - d2l = [tdict[str(i)] for i in range(tdict['len'])] - plist = [( - str2getpacker[e['type']](e) \ - if type(e) == dict \ - else e - ) for e in d2l] - return plist + d2l = [tdict[str(i)] for i in range(tdict["len"])] + plist = [(str2getpacker[e["type"]](e) if type(e) == dict else e) for e in d2l] + return plist + def parseref(tdict): - d2l = [tdict[str(i)] for i in range(tdict['len'])] - plist = ['!ref'] - plist.extend( - [( - str2refgetpacker[val['type']](e) \ - if type(val := e['Value']) == dict \ - else str2refgetpacker['default'](e)\ - )for e in d2l] - ) - return plist + d2l = [tdict[str(i)] for i in range(tdict["len"])] + plist = ["!ref"] + # py37 compat + try: + exec( + """ext = [(str2refgetpacker[val["type"]](e) """ + + """if type(val := e["Value"]) == dict """ + + """else str2refgetpacker["default"](e)) for e in d2l]""" + ) + except SyntaxError: + ext = [ + (str2refgetpacker[e["Value"]["type"]](e) if type(e["Value"]) == dict else str2refgetpacker["default"](e)) + for e in d2l + ] + plist.extend(ext) + return plist + def json2obj(jsont): - obj_init = json.loads(jsont) - obj_desc = parsedict(obj_init['ActionDescriptor']) if 'ActionDescriptor' in obj_init else None - obj_operation = unhead(obj_init['Operation']) - obj_option = obj_init['Option'] - return (obj_operation,obj_desc,obj_option) + obj_init = json.loads(jsont) + obj_desc = parsedict(obj_init["ActionDescriptor"]) if "ActionDescriptor" in obj_init else None + obj_operation = unhead(obj_init["Operation"]) + obj_option = obj_init["Option"] + return (obj_operation, obj_desc, obj_option) + def dump(jst): - jsi = injection + '\n' + jst - jsont = execjs(jsi) - objs = [json2obj(j) for j in jsont.split('END OF JSON') if j != '\n'] - return objs - \ No newline at end of file + jsi = injection + "\n" + jst + jsont = execjs(jsi) + objs = [json2obj(j) for j in jsont.split("END OF JSON") if j != "\n"] + return objs diff --git a/photoshop/api/action_manager/js_converter/injection_js.py b/photoshop/api/action_manager/js_converter/injection_js.py index 08d91374..6d2c07a4 100644 --- a/photoshop/api/action_manager/js_converter/injection_js.py +++ b/photoshop/api/action_manager/js_converter/injection_js.py @@ -1,9 +1,11 @@ -'''Defines injection, a variable which contains js code. +# flake8: noqa + +"""Defines injection, a variable which contains js code. These js code implements Photoshop functions, and lures a piece of js code to output all its information on executing executeAction function. -You may turn on syntax highlighting for js here.''' +You may turn on syntax highlighting for js here.""" -injection = ''' +injection = """ class UnitDouble { constructor(unit,ndouble) { @@ -137,4 +139,4 @@ class ActionReference { console.log(execlogjson) console.log('END OF JSON') } -''' \ No newline at end of file +""" diff --git a/photoshop/api/action_manager/js_converter/node_execjs.py b/photoshop/api/action_manager/js_converter/node_execjs.py index 96352074..a8789a49 100644 --- a/photoshop/api/action_manager/js_converter/node_execjs.py +++ b/photoshop/api/action_manager/js_converter/node_execjs.py @@ -1,16 +1,22 @@ -'''Defines execjs, a function to run js in Node.js''' +"""Defines execjs, a function to run js in Node.js""" + +# Import built-in modules +import os +import re +import subprocess -import os,re,subprocess # Node.js check -nodestate = os.popen('node --version') -if not re.match('^v\d*\.\d*\.\d*',nodestate.read()): - raise RuntimeError('Please check if Node.js is installed to PATH!') +nodestate = os.popen("node --version") +if not re.match(r"^v\d*\.\d*\.\d*", nodestate.read()): + raise RuntimeError("Please check if Node.js is installed to PATH!") + def execjs(jst): - tmpjs = jst.replace('"""', '"') - run = subprocess.run('node', input=tmpjs, capture_output=True, text=True) - result = run.stdout; err = run.stderr - if err: - raise RuntimeError(err) - return result \ No newline at end of file + tmpjs = jst.replace('"""', '"') + run = subprocess.run("node", input=tmpjs, capture_output=True, text=True) + result = run.stdout + err = run.stderr + if err: + raise RuntimeError(err) + return result diff --git a/photoshop/api/action_manager/ref_form_types/__init__.py b/photoshop/api/action_manager/ref_form_types/__init__.py index b15de167..6ff5b91d 100644 --- a/photoshop/api/action_manager/ref_form_types/__init__.py +++ b/photoshop/api/action_manager/ref_form_types/__init__.py @@ -3,4 +3,5 @@ from .offset import Offset from .referencekey import ReferenceKey -__all__ = ['Identifier', 'Index', 'Offset', 'ReferenceKey'] \ No newline at end of file + +__all__ = ["Identifier", "Index", "Offset", "ReferenceKey"] diff --git a/photoshop/api/action_manager/ref_form_types/_marker.py b/photoshop/api/action_manager/ref_form_types/_marker.py index c095b5bf..5a0c20b2 100644 --- a/photoshop/api/action_manager/ref_form_types/_marker.py +++ b/photoshop/api/action_manager/ref_form_types/_marker.py @@ -1,16 +1,20 @@ -'''Defines class marker. It is the class of Identifier, Index, Offset. -It is INTERNAL. You should not import or initialize it.''' +"""Defines class marker. It is the class of Identifier, Index, Offset. +It is INTERNAL. You should not import or initialize it.""" + class marker: - def __init__(self, name, value=0): - self.name = name - self.value = value - def __add__(self, other): - return type(self)(self.name, self.value+other) - def __repr__(self): - return '%s+%d'%(self.name, self.value) - def __eq__(self, other): - try: - return self.name == other.name and self.value == other.value - except: - return False \ No newline at end of file + def __init__(self, name, value=0): + self.name = name + self.value = value + + def __add__(self, other): + return type(self)(self.name, self.value + other) + + def __repr__(self): + return "%s+%d" % (self.name, self.value) + + def __eq__(self, other): + try: + return self.name == other.name and self.value == other.value + except BaseException: + return False diff --git a/photoshop/api/action_manager/ref_form_types/identifier.py b/photoshop/api/action_manager/ref_form_types/identifier.py index 82906978..f716f935 100644 --- a/photoshop/api/action_manager/ref_form_types/identifier.py +++ b/photoshop/api/action_manager/ref_form_types/identifier.py @@ -1,7 +1,8 @@ -'''Defines a special object: Identifier. +"""Defines a special object: Identifier. You can give it a value by adding a number to it. -For example: id = Identifier+777''' +For example: id = Identifier+777""" from ._marker import marker -Identifier = marker('Identifier') \ No newline at end of file + +Identifier = marker("Identifier") diff --git a/photoshop/api/action_manager/ref_form_types/index.py b/photoshop/api/action_manager/ref_form_types/index.py index 9fbe6977..0a119ff3 100644 --- a/photoshop/api/action_manager/ref_form_types/index.py +++ b/photoshop/api/action_manager/ref_form_types/index.py @@ -1,7 +1,8 @@ -'''Defines a special object: Index. +"""Defines a special object: Index. You can give it a value by adding a number to it. -For example: index = Index+1''' +For example: index = Index+1""" from ._marker import marker -Index = marker('Index') \ No newline at end of file + +Index = marker("Index") diff --git a/photoshop/api/action_manager/ref_form_types/offset.py b/photoshop/api/action_manager/ref_form_types/offset.py index 76753162..8f11fef5 100644 --- a/photoshop/api/action_manager/ref_form_types/offset.py +++ b/photoshop/api/action_manager/ref_form_types/offset.py @@ -1,7 +1,8 @@ -'''Defines a special object: Offset. +"""Defines a special object: Offset. You can give it a value by adding a number to it. -For example: offset = Offset+12''' +For example: offset = Offset+12""" from ._marker import marker -Offset = marker('Offset') \ No newline at end of file + +Offset = marker("Offset") diff --git a/photoshop/api/action_manager/ref_form_types/referencekey.py b/photoshop/api/action_manager/ref_form_types/referencekey.py index f6fc7260..ade2d258 100644 --- a/photoshop/api/action_manager/ref_form_types/referencekey.py +++ b/photoshop/api/action_manager/ref_form_types/referencekey.py @@ -1,58 +1,72 @@ -'''Defines class ReferenceKey. It handles type mapping in ActionReference. -You can initialize it with 2 arguments: desiredclass, value.''' +"""Defines class ReferenceKey. It handles type mapping in ActionReference. +You can initialize it with 2 arguments: desiredclass, value.""" -from ..utils import * -from ..desc_value_types import TypeID, Enumerated +# Import built-in modules +from collections import namedtuple + +# Import local modules from photoshop.api.enumerations import ReferenceFormType -from .identifier import Identifier -from .index import Index -from .offset import Offset + +from ..desc_value_types import Enumerated +from ..desc_value_types import TypeID +from ..utils import id2str +from ..utils import str2id from ._marker import marker -from collections import namedtuple + +# Identifier, Index, Offset are used by getting them in globals(). +from .identifier import Identifier # noqa: F401 +from .index import Index # noqa: F401 +from .offset import Offset # noqa: F401 + psreftype2str = { - **{vtype.value:str(vtype)[27:-4] for vtype in ReferenceFormType}, - **{vtype:str(vtype)[27:-4] for vtype in ReferenceFormType}, + **{vtype.value: str(vtype)[27:-4] for vtype in ReferenceFormType}, + **{vtype: str(vtype)[27:-4] for vtype in ReferenceFormType}, } -ReferenceKey_proto = namedtuple('ReferenceKey', ['desiredclass', 'value']) +ReferenceKey_proto = namedtuple("ReferenceKey", ["desiredclass", "value"]) + class ReferenceKey(ReferenceKey_proto): - @classmethod - def _packer(cls, obj): - ftype = psreftype2str[obj.getForm()] - dcls = id2str(obj.getDesiredClass()) - try: - get_func = getattr(obj, 'get'+ftype) - except: - get_func = None - if ftype == 'Class': - v = None - elif ftype == 'Enumerated': - v = Enumerated(id2str(obj.getEnumeratedType()), id2str(obj.getEnumeratedValue())) - elif ftype == 'Property': - v = TypeID(id2str(obj.getProperty())) - elif ftype == 'Name': - v = get_func() - elif ftype in ('Identifier', 'Index', 'Offset'): - v = globals()[ftype]+get_func() - return cls(dcls, v) - def _unpacker(self): - dcls = str2id(self.desiredclass) - value = self.value - if value is None: - v = value - ftype = 'Class' - elif type(value) == TypeID: - v = value._unpacker() - ftype = 'Property' - elif type(value) == marker: - v = (value.value,) - ftype = value.name - elif type(value) == Enumerated: - v = value._unpacker() - ftype = 'Enumerated' - elif type(value) == str: - v = (value,) - ftype = 'Name' - return (ftype, dcls, v) \ No newline at end of file + @classmethod + def _packer(cls, obj): + ftype = psreftype2str[obj.getForm()] + dcls = id2str(obj.getDesiredClass()) + try: + get_func = getattr(obj, "get" + ftype) + except BaseException: + get_func = None + if ftype == "Class": + v = None + elif ftype == "Enumerated": + v = Enumerated( + id2str(obj.getEnumeratedType()), + id2str(obj.getEnumeratedValue()), + ) # noqa + elif ftype == "Property": + v = TypeID(id2str(obj.getProperty())) + elif ftype == "Name": + v = get_func() + elif ftype in ("Identifier", "Index", "Offset"): + v = globals()[ftype] + get_func() + return cls(dcls, v) + + def _unpacker(self): + dcls = str2id(self.desiredclass) + value = self.value + if value is None: + v = value + ftype = "Class" + elif type(value) == TypeID: + v = value._unpacker() + ftype = "Property" + elif type(value) == marker: + v = (value.value,) + ftype = value.name + elif type(value) == Enumerated: + v = value._unpacker() + ftype = "Enumerated" + elif type(value) == str: + v = (value,) + ftype = "Name" + return (ftype, dcls, v) diff --git a/photoshop/api/action_manager/utils.py b/photoshop/api/action_manager/utils.py index bf711984..dd4e8eee 100644 --- a/photoshop/api/action_manager/utils.py +++ b/photoshop/api/action_manager/utils.py @@ -1,45 +1,56 @@ -'''TypeID conversion utilities of this submodule.''' +"""TypeID conversion utilities of this submodule.""" +# Import local modules from photoshop.api._core import Photoshop -__all__ = ['str2id', 'id2str'] + +__all__ = ["str2id", "id2str"] + class app(Photoshop): - '''Partially reimplement the Application class in this file to avoid circular import.''' - typename = 'Application' - def str2id(self, string: str) -> int: - return self.app.stringIDToTypeID(string) - def id2str(self, number: int) -> str: - return self.app.typeIDToStringID(number) + """Partially reimplement the Application class in this file to avoid circular import.""" + + typename = "Application" + + def str2id(self, string: str) -> int: + return self.app.stringIDToTypeID(string) + + def id2str(self, number: int) -> str: + return self.app.typeIDToStringID(number) + converter = app() + def str2hash(x: str) -> int: - '''Convert charID to typeID.''' - assert len(x) == 4 - x = x.replace(' ', '\x20') - return int.from_bytes(bytes(x, encoding='utf-8'), byteorder='big') + """Convert charID to typeID.""" + assert len(x) == 4 + x = x.replace(" ", "\x20") + return int.from_bytes(bytes(x, encoding="utf-8"), byteorder="big") + def hash2str(x: int) -> str: - '''Convert typeID to charID.''' - assert len(hex(x)) == 10 - return x.to_bytes(length=4, byteorder='big').decode() + """Convert typeID to charID.""" + assert len(hex(x)) == 10 + return x.to_bytes(length=4, byteorder="big").decode() + def str2id(psstr: str) -> str: - '''Convert charID or stringID to typeID''' - assert type(psstr) == str - if len(psstr) == 4: - typeid = str2hash(psstr) - try: - restr = converter.id2str(psstr) - except: - restr = '' - if not restr: - typeid = converter.str2id(psstr) - else: - typeid = converter.str2id(psstr) - return typeid + """Convert charID or stringID to typeID""" + assert type(psstr) == str + if len(psstr) == 4: + typeid = str2hash(psstr) + try: + restr = converter.id2str(typeid) + except BaseException: + restr = "" + if not restr: + typeid = converter.str2id(psstr) + else: + typeid = converter.str2id(psstr) + return typeid + def id2str(typeid: int) -> str: - '''Convert typeID to stringID''' - return converter.id2str(typeid) \ No newline at end of file + """Convert typeID to stringID""" + return converter.id2str(typeid)