Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a440496
feat: Add extensive type annotations, add classes for path handling, …
pappnu Aug 12, 2025
a2b308f
fix(Layer): return parent with correct type
pappnu Aug 13, 2025
2089887
fix(LayerSet): fix iterating LayerSet object directly
pappnu Aug 13, 2025
6d7429f
test(TestNewDocument): test getting layer parent and expand layer ite…
pappnu Aug 13, 2025
121328a
feat: add py.typed file to indicate that the package contains type an…
pappnu Aug 13, 2025
94d4344
fix(executeActionGet): correct input argument type
pappnu Aug 13, 2025
a8dedc4
fix(Application): executeAction can be called without an ActionDescri…
pappnu Aug 14, 2025
0b975b9
fix(Select): select takes an array of four coordinates
pappnu Aug 14, 2025
9d8de09
style: Format and sort imports
pappnu Aug 15, 2025
1a7b953
feat(Layer): Add default value to rotate anchor
pappnu Aug 15, 2025
e790d52
fix(Documents): Document width and height can be given as floats, tho…
pappnu Aug 16, 2025
9f8496e
fix(path_item.py): Import TYPE_CHECKING from typing instead of errone…
pappnu Aug 26, 2025
15309e3
refactor: Avoid unnecessary getattribute calls to the wrapper objects
pappnu Feb 15, 2026
22a673d
test(manual_test_new_document.py): Add tests for layer querying
pappnu Feb 15, 2026
f6c72c3
feat: Bump Python requirement to >=3.10, modernize pyproject.toml, up…
pappnu Feb 15, 2026
cee5fe1
docs(README.md): Instruct how to browse the COM API with Visual Studio
pappnu Feb 15, 2026
4430335
fix(Selection): Selection's select can take a sequence of more than f…
pappnu Feb 22, 2026
4acf07c
fix(FontSize): Don't use StrEnum as Python 3.10 doesn't have it
pappnu Feb 25, 2026
53965a6
fix(Notifiers): Access the Photoshop Application object correctly
pappnu Feb 25, 2026
4cd7f34
feat(Photoshop): Allow accessing the Photoshop Application object fro…
pappnu Feb 25, 2026
4fc7bcc
fix(import-test.yml): Fix and update test workflow
pappnu May 18, 2026
876d3f8
Merge remote-tracking branch 'origin/main' into type-annotation
pappnu May 18, 2026
e3dd8ae
build(pyproject.toml): Align and simplify Ruff and isort rules
pappnu May 19, 2026
3a61b25
build(.flake8): Ignore flake8 rule that clashes with Black formatting
pappnu May 19, 2026
7050109
style: Autoformat code
pappnu May 19, 2026
10236b0
test(manual_test_layer_comps.py): Generalize and expand layer comp tests
pappnu May 25, 2026
2af36e2
fix: adding and removing layer comps
pappnu May 25, 2026
0cfebf8
fix(Notifier): Use delete instead of remove to delete a notifier
pappnu May 25, 2026
d15128e
fix: Remove function calls that aren't present in the PS VBS API
pappnu May 25, 2026
40856e3
fix: function and property naming mistakes
pappnu May 26, 2026
dbd8401
ci: Replace Black, Isort and Flake8 with Ruff
pappnu Jun 13, 2026
7061201
style: Format and lint code
pappnu Jun 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 0 additions & 30 deletions .flake8

This file was deleted.

22 changes: 11 additions & 11 deletions .github/workflows/import-test.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
name: Import Test
on: [pull_request]
on:
pull_request:
workflow_dispatch:

jobs:
python-check:
runs-on: windows-2022
runs-on: windows-latest
strategy:
max-parallel: 3
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
fetch-depth: 0
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install -U pip poetry
poetry --version
poetry install -vvv || poetry install -vvv || poetry install -vvv
poetry run pytest
python -m pip install poetry
python -m poetry --version
python -m poetry install -vvv
python -m poetry run pytest
17 changes: 4 additions & 13 deletions .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ jobs:
strategy:
max-parallel: 3
matrix:
python-version: ["3.8", "3.9", "3.10"]
python-version: ["3.10"]

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -25,14 +25,5 @@ jobs:

- name: Run tests and linters
run: |
#!/bin/sh -e
git config --global user.email "action@github.com"
git config --global user.name "GitHub Action"
export PREFIX="poetry run python -m "
if [ -d 'venv' ] ; then
export PREFIX="venv/bin/"
fi

${PREFIX}black photoshop --check
${PREFIX}isort --check-only photoshop
${PREFIX}flake8 photoshop --max-line-length 120
poetry run ruff check photoshop
poetry run ruff format --check photoshop
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ result/
.coverage
/venv/
venv_python
.venv/

# Docs
docs_src/_build/
Expand Down
55 changes: 14 additions & 41 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
exclude: conf.py
repos:
- repo: https://github.com/ambv/black
rev: 22.12.0
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.17
hooks:
- id: ruff-check
args: [--fix]
- id: ruff-format
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: black
language_version: python3.10
- hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-docstring-first
Expand All @@ -14,43 +17,13 @@ repos:
- id: debug-statements
- id: name-tests-test
- id: requirements-txt-fixer
repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.4.0
- hooks:
- additional_dependencies:
- flake8-typing-imports==1.5.0
id: flake8
repo: https://github.com/pycqa/flake8
rev: 3.7.9
- hooks:
- id: autopep8
repo: https://github.com/pre-commit/mirrors-autopep8
rev: v1.4.4
- hooks:
- repo: https://github.com/pre-commit/pre-commit
rev: v4.6.0
hooks:
- id: validate_manifest
repo: https://github.com/pre-commit/pre-commit
rev: v1.21.0
- hooks:
- args:
- --py36-plus
id: pyupgrade
repo: https://github.com/asottile/pyupgrade
rev: v1.25.3
- hooks:
- args:
- --py3-plus
id: reorder-python-imports
repo: https://github.com/asottile/reorder_python_imports
rev: v1.9.0
- hooks:
- args:
- --py36-plus
id: add-trailing-comma
repo: https://github.com/asottile/add-trailing-comma
rev: v1.5.0
- hooks:
- repo: https://github.com/commitizen-tools/commitizen
rev: v4.16.3
hooks:
- id: commitizen
stages:
- commit-msg
repo: https://github.com/commitizen-tools/commitizen
rev: v2.17.8
7 changes: 0 additions & 7 deletions .pylintrc

This file was deleted.

2 changes: 0 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
language: python
python:
- "3.8"
- "3.9"
- "3.10"
before_script:
- pip install poetry
Expand Down
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ Useful links
- http://shining-lucy.com/wiki/page.php?id=appwiki:photoshop:ps_script
- http://web.archive.org/web/20140121053819/http://www.pcpix.com/Photoshop/char.html
- http://www.tonton-pixel.com/scripts/utility-scripts/get-equivalent-id-code/index.html
- https://github.com/Adobe-CEP/CEP-Resources/tree/master/Documentation/Product%20specific%20Documentation/Photoshop%20Scripting
- https://github.com/Adobe-CEP/Samples/tree/master/PhotoshopEvents
- https://evanmccall.wordpress.com/2015/03/09/how-to-develop-photoshop-tools-in-python

Expand Down Expand Up @@ -242,9 +243,7 @@ We maintain high code quality standards through automated tools and consistent s
- Quotes: Double quotes preferred

- **Quality Tools**:
- [Black](https://black.readthedocs.io/) - Code formatting
- [isort](https://pycqa.github.io/isort/) - Import organization
- [flake8](https://flake8.pycqa.org/) - Style enforcement
- [Ruff](https://docs.astral.sh/ruff/) - Linting, formatting, and import organization
- [pre-commit](https://pre-commit.com/) - Automated checks before commits

### 🔄 Git Workflow
Expand Down Expand Up @@ -279,7 +278,7 @@ We value thorough testing to ensure reliability:

### 📦 Development Environment

- **Python Versions**: We support Python 3.8+ (see `pyproject.toml` for specifics)
- **Python Versions**: We support Python 3.10+ (see `pyproject.toml` for specifics)
- **Dependency Management**: [Poetry](https://python-poetry.org/) for consistent environments
- **Virtual Environment**: Poetry automatically creates and manages virtual environments

Expand All @@ -295,3 +294,18 @@ We value thorough testing to ensure reliability:
8. **Merge**: Once approved, your PR will be merged

Thank you for contributing to the Photoshop Python API project! 🎉

### Development Notes

One way to view the COM API structure is to use Visual Studio.

1. Install Visual Studio with the .NET desktop development workload
2. Open Visual Studio
3. Choose View -> Object Browser
4. In the Object Browser from the Browse dropdown choose *Edit Custom Component Set...*
5. In the Edit Custom Component Set window's COM tab add Photoshop's Object and Type libraries
6. After pressing OK the libraries should show up in the Object Browser

If the libraries aren't visible in the COM tab make sure you have the .NET desktop development workload installed. Other things you may try are running Photoshop once as administrator and reinstalling Photoshop and/or your PC. The object library is defined usually in */your/path/to/Adobe Photoshop \<version\>/Required/Plug-ins/Extensions/ScriptingSupport.8li*

The [VBS reference 2020](https://github.com/Adobe-CEP/CEP-Resources/blob/master/Documentation/Product%20specific%20Documentation/Photoshop%20Scripting/photoshop-vbs-ref-2020.pdf) is also quite trustworthy, since Adobe isn't actively developing the COM API anymore.
2 changes: 1 addition & 1 deletion docs/gen_api_nav.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def main():
full_doc_path = full_doc_path.as_posix().replace("\\", "/")
with mkdocs_gen_files.open(full_doc_path, "w") as fd:
ident = ".".join(parts)
print(f"::: " + ident, file=fd)
print("::: " + ident, file=fd)

mkdocs_gen_files.set_edit_path(full_doc_path, path.as_posix().replace("\\", "/"))

Expand Down
4 changes: 3 additions & 1 deletion docs/gen_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

# Import built-in modules
import os

from pathlib import Path

# Import third-party modules
from jinja2 import Template
import mkdocs_gen_files
import stringcase

from jinja2 import Template


template = Template(
r"""
Expand Down
4 changes: 2 additions & 2 deletions examples/active_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
docRef.artLayers.add()

# Display current active layer name
ps.echo(docRef.activeLayer.name)
print(docRef.activeLayer.name)

# Create and rename a new layer
new_layer = docRef.artLayers.add()
ps.echo(new_layer.name)
print(new_layer.name)
new_layer.name = "test"
2 changes: 1 addition & 1 deletion examples/add_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
doc.info.provinceState = "Beijing"
doc.info.title = "My Demo"
print("Print all metadata of current active document.")
ps.echo(doc.info)
print(doc.info)
6 changes: 3 additions & 3 deletions examples/add_slate.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
"""

# Import built-in modules
from datetime import datetime
import os

from datetime import datetime
from tempfile import mkdtemp

# Import third-party modules
# Import local modules
import examples._psd_files as psd # Import from examples.

# Import local modules
from photoshop import Session


Expand Down
1 change: 1 addition & 0 deletions examples/add_start_application_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

# Import built-in modules
import os

from tempfile import mkdtemp

# Import local modules
Expand Down
3 changes: 1 addition & 2 deletions examples/apply_crystallize_filter_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@

"""

# Import third-party modules
# Import local modules
import examples._psd_files as psd # Import from examples.

# Import local modules
from photoshop import Session


Expand Down
4 changes: 2 additions & 2 deletions examples/change_color_of_background_and_foreground.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@
ps.app.backgroundColor = bg_color

# Print current colors
ps.echo(f"Foreground RGB: {ps.app.foregroundColor.rgb.red}, "
print(f"Foreground RGB: {ps.app.foregroundColor.rgb.red}, "
f"{ps.app.foregroundColor.rgb.green}, "
f"{ps.app.foregroundColor.rgb.blue}")

ps.echo(f"Background RGB: {ps.app.backgroundColor.rgb.red}, "
print(f"Background RGB: {ps.app.backgroundColor.rgb.red}, "
f"{ps.app.backgroundColor.rgb.green}, "
f"{ps.app.backgroundColor.rgb.blue}")
2 changes: 1 addition & 1 deletion examples/compare_colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@
color1.rgb.green == color2.rgb.green and
color1.rgb.blue == color2.rgb.blue)

ps.echo(f"Colors are {'same' if is_same else 'different'}")
print(f"Colors are {'same' if is_same else 'different'}")
6 changes: 3 additions & 3 deletions examples/convert_smartobject_to_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@

# Convert to smart object
layer.convertToSmartObject()
ps.echo("Layer converted to Smart Object")
print("Layer converted to Smart Object")

# Check if it's a smart object
if layer.kind == ps.LayerKind.SmartObjectLayer:
ps.echo("Layer is now a Smart Object")
print("Layer is now a Smart Object")

# Convert back to regular layer
layer.rasterize(ps.RasterizeType.EntireLayer)
ps.echo("Smart Object converted back to regular layer")
print("Smart Object converted back to regular layer")
1 change: 1 addition & 0 deletions examples/create_thumbnail.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

# Import built-in modules
import os

from tempfile import mkdtemp

# Import local modules
Expand Down
2 changes: 1 addition & 1 deletion examples/current_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@
current = ps.app.currentTool

# Print current tool name
ps.echo(f"Current tool: {current}")
print(f"Current tool: {current}")
9 changes: 5 additions & 4 deletions examples/delete_and_fill_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
import os

# Import third-party modules
from photoshop import Session
from photoshop.api import SolidColor
import photoshop.api as ps
from _psd_files import get_psd_files

# Import local modules
from _psd_files import get_psd_files
import photoshop.api as ps

from photoshop.api import SolidColor


def delete_and_fill_selection(doc, fill_type, mode=None, opacity=None, preserve_transparency=None):
"""Delete current selection and fill it with specified color.
Expand Down
2 changes: 1 addition & 1 deletion examples/eval_javascript.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@
# Execute JavaScript command
js_code = "app.documents.length"
result = ps.app.eval_javascript(js_code)
ps.echo(f"Number of open documents: {result}")
print(f"Number of open documents: {result}")
Loading