Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
b872fe3
replace monolithic setup.py with pyproject.toml + scripts
samizdatco Jul 9, 2026
19809d0
bump minimum python version to 3.9
samizdatco Jul 9, 2026
3256a87
publish wheels containing the native extension
samizdatco Jul 9, 2026
18f985c
reflect test results in exit code
samizdatco Jul 9, 2026
d486a29
test for presence of pyobjc+extension, not just paths
samizdatco Jul 9, 2026
cafc691
fix regex escape
samizdatco Jul 10, 2026
62e9ca2
fix objc.super use in ConsoleScript
samizdatco Jul 10, 2026
665bc57
fix `ordered()` crash on grobs and silent dotted-path failures
samizdatco Jul 10, 2026
3f69b4c
add python 3.14 support by bumping pyobjc to 11.1
samizdatco Jul 10, 2026
3639d49
ignore rsrc files resulting from in-place build
samizdatco Jul 10, 2026
dc2ac7f
generate MANIFEST.in only when needed for sdist
samizdatco Jul 10, 2026
cb696af
rename build.py to make.py (to prevent `-m build` shadowing)
samizdatco Jul 10, 2026
46052ee
opt into secure restorable state
samizdatco Jul 10, 2026
ddab30c
update embedded python to 3.14.6
samizdatco Jul 10, 2026
f8ca3c8
update python version compat
samizdatco Jul 10, 2026
7df6d3b
update 1.0.1 docs
samizdatco Jul 11, 2026
ef7093a
bump copyright year
samizdatco Jul 11, 2026
2f58879
fix typos
samizdatco Jul 11, 2026
e0e6d59
add missing 3.14 classifier
samizdatco Jul 11, 2026
00d7e22
use system fonts in typography tests
samizdatco Jul 11, 2026
6363a2a
fixed Text.flow() when invoked w/ callback
samizdatco Jul 11, 2026
30f574f
fix the test for blend-only effects
samizdatco Jul 11, 2026
e4b666a
fix MagicNumber's numeric-protocol implementation
samizdatco Jul 11, 2026
41556e2
fix rasterization of clipping masks based on vector images
samizdatco Jul 13, 2026
318b8d9
add clip() test cases that use canvas transforms
samizdatco Jul 13, 2026
e5b8d1b
replace deprecated WebView with WKWebView
samizdatco Jul 13, 2026
79b7051
update document contents after each edit
samizdatco Jul 13, 2026
bbff6e9
fix license format
samizdatco Jul 13, 2026
74fc923
rename `sync_edits` and `flash_menu` methods
samizdatco Jul 13, 2026
293f85a
add new default editor theme
samizdatco Jul 13, 2026
5280134
add `Assets.car` for macOS 26+ icon
samizdatco Jul 14, 2026
43e2599
Replace setup.py with direct call to tests
samizdatco Jul 14, 2026
cf15d6e
handle quadratic curves in `path_to_polygon`
samizdatco Jul 14, 2026
8315113
Add logo banner to readme
samizdatco Jul 14, 2026
0226c2b
Fix deprecation warning from pyobjc
samizdatco Jul 14, 2026
2e5635e
update module providing UTType*
samizdatco Jul 14, 2026
a119caf
set exit code on script errors when running `plotdevice` headless
samizdatco Jul 14, 2026
8338229
replace `xrange` with `range` in code samples
samizdatco Jul 14, 2026
1773ce0
update markdown docs
samizdatco Jul 14, 2026
ac940c6
fix crash when canvas is zoomed before script has rendered
samizdatco Jul 15, 2026
73471c5
upgrade vendored ace.js to 1.44.0
samizdatco Jul 13, 2026
40164de
local ace modification: filter autocompletions
samizdatco Jul 14, 2026
3846f3a
local ace modification: fix snippet formatting
samizdatco Jul 15, 2026
8ca98b3
rough draft: add command-click documentation lookups
samizdatco Jul 14, 2026
f68126d
Add links to the documentation for all known symbols
samizdatco Jul 14, 2026
81318c4
add usage samples
samizdatco Jul 14, 2026
41ca645
reformat
samizdatco Jul 14, 2026
4daf9a3
ensure only actual function tokens have clickable docs
samizdatco Jul 14, 2026
87f9178
Add tooltips with syntax reference for plotdevice symbols
samizdatco Jul 15, 2026
b22781b
remove command-click docs (but keep tooltip links)
samizdatco Jul 15, 2026
a94fec7
add context menu for opening docs
samizdatco Jul 15, 2026
97474d7
add () to token name in View Docs context menu
samizdatco Jul 15, 2026
e53ec91
clean up usage strings
samizdatco Jul 15, 2026
86cedbf
fix refreshdoc command mishandling an empty source string
samizdatco Jul 15, 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
18 changes: 13 additions & 5 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,22 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v3

- name: Run Tests
- name: Install build dependencies
run: pip3 install -U pip wheel twine build setuptools

- name: Install PlotDevice and run tests
run: |
pip3 install -U pip wheel twine
python3 setup.py test
pip3 install .
python3 -m tests

- name: Build Wheels
uses: pypa/cibuildwheel@v4
with:
output-dir: dist

- name: Build sdist
- name: Build Source Distribution
run: |
python3 setup.py sdist
python3 -m build --sdist

- name: Upload to PyPI
env:
Expand Down
28 changes: 20 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,17 @@ jobs:
# collect notarization credentials
xcrun notarytool store-credentials "AC_NOTARY" --apple-id "$AC_ID" --team-id "$AC_TEAM" --password "${{ secrets.AC_PASSWORD }}"

- name: Run Tests
- name: Install build dependencies
run: pip3 install -U pip wheel setuptools

- name: Install PlotDevice and run tests
run: |
python3 setup.py test
pip3 install .
python3 -m tests

- name: Build & Notarize App
run: |
python3 setup.py dist
python3 make.py dist

- name: Create Draft Release
uses: softprops/action-gh-release@v1
Expand All @@ -55,21 +59,30 @@ jobs:
files: |
dist/*.zip

sdist:
packages:
name: Post to test.pypi.org
runs-on: macos-latest

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Run Tests
- name: Install build dependencies
run: pip3 install -U pip wheel twine build setuptools

- name: Install PlotDevice and run tests
run: |
python3 setup.py test
pip3 install .
python3 -m tests

- name: Build Wheels
uses: pypa/cibuildwheel@v4
with:
output-dir: dist

- name: Build Source Distribution
run: |
python3 setup.py sdist
python3 -m build --sdist

- name: Upload to test.pypi.org
env:
Expand All @@ -78,6 +91,5 @@ jobs:
TWINE_REPOSITORY: https://test.pypi.org/legacy/
TWINE_NON_INTERACTIVE: 1
run: |
pip3 install twine
twine check dist/*
twine upload -r testpypi dist/*
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ jobs:
run: brew install python-setuptools

- name: Run tests
run: python3 setup.py test
run: python3 -m tests
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ build/
dist/
plotdevice.egg-info
app/Resources/viewer.nib
Manifest.in
plotdevice/rsrc
MANIFEST.in

# local development
deps/local
Expand Down
158 changes: 158 additions & 0 deletions BUILDING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# Building PlotDevice from Source

If you’re interested in unreleased code from the repository (or doing development work on the
library/app itself), there are a few different ways to build it.

## Requirements

- macOS 11+ and Xcode or the Xcode command line tools (`xcode-select --install`)
- A Python 3.9+ interpreter with wheel availability for `pyobjc-core==11.1`
(i.e. not a brand-new Python release that predates PyObjC’s own support for it)


## Setting up Python

By default, macOS 12.3 and later only include a `python3` interpreter if you install Xcode (or its command line tools).
There are a few other ways to get a usable Python setup worth considering if you're interested in using
PlotDevice from the command line. A key feature distinguishing the different options is whether they
install Python as a ‘framework’ or ‘stand-alone’:

> A **framework** Python installation allows PlotDevice to give you access to a GUI interface for
> running scripts via the `python3 -m plotdevice` command. **Stand-alone** Python is slightly more limited:
> it supports ‘headless’ use (via the command line tool’s [`--export`](#imageanimation-export) option) and
> can open a window displaying your canvas, but it will not show an icon in the Dock or give you access to
> commands in the menu bar.

### Xcode

The [Xcode command line tools](https://developer.apple.com/documentation/xcode/installing-the-command-line-tools/) provide a
**framework** build of the (now somewhat long in the tooth) 3.9 release of Python. If you're okay running such an old interpreter,
you can install the tools with the command:
```console
xcode-select --install
```

### Homebrew

The [Homebrew](https://docs.brew.sh/Homebrew-and-Python) package manager provides a **framework** build via its more up-to-date `python3` package. You can install it and run `plotdevice` with:
```console
brew install python3
```

### `pyenv`

The [pyenv](https://github.com/pyenv/pyenv) version manager lets you easily switch between multiple python versions on the same system.
You can install a new **stand-alone** interpreter by specifying the version number:
```console
pyenv install 3.14.6
```

If you want a **framework** install, you need to pass a custom option via environment variables:
```console
env PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install 3.14.6
```

### `uv`

A newer alternative is [`uv`](https://docs.astral.sh/uv/), which uses its own prebuilt interpreters (but currently does not provide
**framework** builds). If you're okay with the limitations of a **stand-alone** interpreter (see above), `uv` gives you a number of
ways to run PlotDevice.

Run a script without permanently installing `plotdevice`:
```console
uvx --from plotdevice plotdevice <script.pv>
```

Install `plotdevice` as a standalone CLI tool:
```console
uv tool install plotdevice
plotdevice <script.pv>
```

Add `plotdevice` as a dependency in a `uv`-managed project:
```console
uv python install 3.14
uv init myproject && cd myproject
uv add plotdevice
uv run plotdevice <script.pv>
```

## Local dev environment

`python3 make.py dev` sets up a self-contained virtualenv at `deps/local/<python-version>/`
and ensures PlotDevice’s dependencies (including its native-code extensions) are installed.
Once this environment has been set up you can use `python3 -m plotdevice <script.pv>` or
`app/plotdevice <script.pv>` to run scripts directly from the repo.

The dev environment is also useful for doing local builds of the app (since it has all the
necessary dependencies pre-installed), so be sure to ‘activate’ it via the correct invocation
for your shell before running one of the build commands:

```sh
source ./deps/local/<py-version>/bin/activate # bash, zsh, etc.
source ./deps/local/<py-version>/bin/activate.fish # fish
source ./deps/local/<py-version>/bin/activate.csh # tcsh
```

To stop using the dev environment and return to your global python interpreter run:
```sh
deactivate
```

## Application builds

The application can be built and debugged in Xcode with the `PlotDevice.xcodeproj` project.

The `make.py` script contains additional utilities for building **PlotDevice.app** (i.e., the full GUI application)
from the command line. If you have the full Xcode installed on your system, you can build the app
(including its own embedded copy of Python) with:
```sh
python3 make.py app
```

Alternatively (if you only have the Xcode command line tools installed) you can use `py2app`, which can
be especially useful for quick, local tests:
```sh
python3 make.py py2app
```

The resulting binary will appear in the `dist` subdirectory and can be moved to your
Applications folder or any other fixed directory. To install a symlink to the command
line tool, launch the app from its installed location and click the Install button in
the Preferences window.

## Module builds

PlotDevice can also be built as a Python module, allowing you to rely on an external editor
and launch scripts from the command line (or from a ‘shebang’ line at the top of your
script invoking the `plotdevice` tool).

The `plotdevice` Python module requires the compilation of native code in the `deps/extensions` directory
but can be installed like any other `pyproject.toml`-based package. From the repo root, type one of:
```sh
pip3 install . # for a regular install
pip3 install -e . # editable install, for dev work on plotdevice/*.py
```
You can run the test suite with:
```sh
python3 -m tests
```

Redistributable `sdists` and wheels can be built via:
```sh
python3 -m build --sdist
python3 -m build --wheel
```

## Utilities

The `make.py` script contains other subcommands that are primarily useful for packaging:
```sh
python3 make.py clean # remove build artifacts
python3 make.py distclean # also remove the embedded Python.framework and deps/local
python3 make.py icon # regenerate app/Resources/Assets.car from app/art/PlotDevice-app.icon
python3 make.py dist # build app (codesigned, notarized, and zipped) and update release.json
```

Note that `dist` requires a "Developer ID Application" signing identity and a `notarytool` keychain profile
named `AC_NOTARY`, and is intended for release builds only.
38 changes: 29 additions & 9 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
PlotDevice 1.1.0
----------------

##### Misc. Improvements
* Upgraded bundled Python to 3.14 in app
* Added precompiled wheels for module installs (supporting Python 3.9–3.14)
* No longer requires Xcode command line tools in order to install
* `plotdevice` command's exit code now reflects script errors
* Added support for running under `uv`
* Editor now uses a `WKWebView` (replacing the deprecated `WebView`)
* Added new default editor theme
* New app icon should avoid "squircle jail" on macOS 26+

##### Bugfixes
* `ordered()` now works correctly and no longer causes the `Advanced/Sorting.pv` example to crash
* `Text.flow()` will now invoke user-provided callbacks to determine layout of multi-column runs
* Command line tool now parses `{4}`-style padded number blocks in exported filenames correctly
* Silenced a console error by fixing `super()` use in command line tool
* Restorable state in the app now uses the newer 'secure' api

PlotDevice 1.0.0
-----------------

Expand All @@ -24,7 +44,7 @@ PlotDevice 1.0.0
* arguments defined using the command line tool's `--args` options are now passed to the script's `sys.argv`

##### Misc. Improvements
* the command line tool can be exited via ctrl-c in addtion to being Quit from the menu bar
* the command line tool can be exited via ctrl-c in addition to being Quit from the menu bar
* simplified unicode handling (and improved support for normalization of user-provided strings)
* building the module now only requires Xcode command line tools—not a full Xcode.app installation
* the `text()` command will always treat its first argument as content (even if it's not a string) unless a `str`, `xml`, or `src` keyword argument is provided
Expand Down Expand Up @@ -224,7 +244,7 @@ NodeBox 1.8.3

NodeBox 1.8.2
-------------
* Direct view is turned of because it broke vector output.
* Direct view is turned off because it broke vector output.
* AppleScripting is back.

NodeBox 1.8.1
Expand Down Expand Up @@ -267,8 +287,8 @@ NodeBox 1.0rc4
* Uses a scene graph internally for speeding things up. All objects now have an inheritFromContext that copies all state out of the context and into the objects.
* Added animation. Adding a speed method indicates that the script is an animation. Animation scripts have a setup() method that does initial setup, and a draw() method that is called for each frame. You can use the throttle to change parameters while the animation is running.
* Removed document properties and variables. NodeBox doesn't touch the code anymore.
* Added measurements for centimeters, milimeters and inches. Just use 5*cm for 5 centimeters.
* All drawing commands are now methods of the Context object. This makes sure that canvases don't interfere with eachother. NOTE: This will have some problems when drawing from libraries. Most notably, "from DrawingPrimitives import *" doesn't work anymore. However, libraries that do drawing can be imported with ximport("mylibrary") to automatically gain access to the _ctx global that has all drawing methods.
* Added measurements for centimeters, millimeters and inches. Just use 5*cm for 5 centimeters.
* All drawing commands are now methods of the Context object. This makes sure that canvases don't interfere with each other. NOTE: This will have some problems when drawing from libraries. Most notably, "from DrawingPrimitives import *" doesn't work anymore. However, libraries that do drawing can be imported with ximport("mylibrary") to automatically gain access to the _ctx global that has all drawing methods.
* BezierPaths are no longer lists internally. They can still be accessed as a sequence, but the returned PathElements are not bound to the path. To manipulate the PathElements, iterate over the sequence, do the changes and use the BezierPath constructor with a list of PathElements as argument.

NodeBox 1.0rc3
Expand Down Expand Up @@ -304,15 +324,15 @@ Version 1.0rc1
* The BezierPath object got a major overhaul: it now integrates nicely with the state model (using the transformedpath method) and is actually a list containing PathElement objects that contain a command, x and y coordinates and (optionally) control points.
* All 'w' and 'h' parameters were changed to 'width' and 'height' (image, strokewidth)
* All of the major state change commands return their state: font, fontsize, lineheight, align, colormode, fill, stroke, strokewidth, transform.
* Documentation is user-friendler and inside of the DrawBot application, so that it can be accessed through Apple's Help system.
* Documentation is user-friendlier and inside of the DrawBot application, so that it can be accessed through Apple's Help system.

Version 0.9b9
-------------
* ValueLadder now respects type of original value: if the original is an integer, the new value will be an integer as well.
* Fixed booleans in variables interface.
* Shift-dragging the value ladder now adds hundreths of a number instead of tenths.
* Shift-dragging the value ladder now adds hundredths of a number instead of tenths.
* Fixed an obscure bug when using CMYK color objects to set the fill (they used the infamous "DrawBot-black" because the converted from the RGB system instead of CMYK)
* Turned of line highlighting on error because of bugs in PyDETextView.
* Turned off line highlighting on error because of bugs in PyDETextView.

Version 0.9b8
-------------
Expand Down Expand Up @@ -345,7 +365,7 @@ Version 0.9b6
* text() command returns the text bounds. (In the same way as textmetrics() would do)
* size, width and height property for the Image object. You can use imagewidth() and imageheight() also.
* Fixed a bug where outlined text could not be stroked when the fill color was not set.
* The drawing region (DrawBotGraphicsView, a subclass of NSView) is acccessible using the graphicsView variable. This is only intented for hackers and will remain undocumented.
* The drawing region (DrawBotGraphicsView, a subclass of NSView) is accessible using the graphicsView variable. This is only intended for hackers and will remain undocumented.
* Added the 'New with code' command which invokes OttoBot.

Version 0.9b5
Expand Down Expand Up @@ -384,4 +404,4 @@ Version 0.9b1

Version 0.9a1
-------------
* Just's first public release of DrawBot.
* Just's first public release of DrawBot.
Loading
Loading