4444 - name : Install dependencies
4545 run : |
4646 python -m pip install --upgrade pip
47- pip install -e ".[dev]"
47+ pip install -e ".[notebook,auth,mcp,acp,deepagent,openai,anthropic,magentic]"
48+ pip install ruff mypy pylint pytauri-wheel plotly pandas cryptography
4849
4950 - name : Run Ruff linter
5051 run : ruff check pywry/ tests/
@@ -65,19 +66,24 @@ jobs:
6566 contents : read
6667 strategy :
6768 fail-fast : false
69+ # ``deepagents`` (pulled in by ``.[dev]`` → ``features``) hard-
70+ # requires Python >=3.11 — 3.10 can't resolve the dev extra.
71+ # ``sqlcipher3`` is a source build against the SQLCipher C
72+ # library installed in the ``Build SQLCipher`` step below, so
73+ # any Python ABI works (no binary-wheel coverage gaps).
6874 matrix :
6975 include :
7076 - os : ubuntu-24.04
71- python-version : ' 3.10 '
77+ python-version : ' 3.11 '
7278 - os : ubuntu-24.04
7379 python-version : ' 3.14'
7480 - os : windows-2025
75- python-version : ' 3.10 '
81+ python-version : ' 3.11 '
7682 - os : windows-2025
7783 python-version : ' 3.14'
78- - os : macos-15
79- python-version : ' 3.10 '
80- - os : macos-15
84+ - os : macos-15-intel
85+ python-version : ' 3.11 '
86+ - os : macos-15-intel
8187 python-version : ' 3.14'
8288 - os : ubuntu-24.04-arm
8389 python-version : ' 3.11'
8894 - os : windows-11-arm
8995 python-version : ' 3.14'
9096 - os : macos-latest
91- python-version : ' 3.10 '
97+ python-version : ' 3.11 '
9298 - os : macos-latest
9399 python-version : ' 3.14'
94100
@@ -117,7 +123,77 @@ jobs:
117123 if : runner.os == 'Linux'
118124 run : |
119125 for i in 1 2 3; do sudo apt-get update && break || sleep 15; done
120- for i in 1 2 3; do sudo apt-get install -y --fix-missing xvfb dbus-x11 at-spi2-core libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 libxcb-shape0 libgl1 libegl1 libwebkit2gtk-4.1-dev libgtk-3-dev && break || { sleep 30; sudo apt-get update; }; done
126+ for i in 1 2 3; do sudo apt-get install -y --fix-missing xvfb dbus-x11 at-spi2-core libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 libxcb-shape0 libgl1 libegl1 libwebkit2gtk-4.1-dev libgtk-3-dev build-essential libssl-dev && break || { sleep 30; sudo apt-get update; }; done
127+
128+ - name : Build SQLCipher from source (Linux)
129+ if : runner.os == 'Linux'
130+ shell : bash
131+ run : |
132+ # Build from the upstream source (https://github.com/sqlcipher/sqlcipher)
133+ # so the ``sqlcipher3`` Python package's setup.py links
134+ # against a known-good library on every Python ABI —
135+ # binary wheels stop at Python 3.13. ``--disable-tcl``
136+ # skips the Tcl extension (not needed by the Python
137+ # binding, and modern Tcl bottles break its compile).
138+ git clone --depth=1 --branch=v4.6.1 https://github.com/sqlcipher/sqlcipher.git /tmp/sqlcipher
139+ cd /tmp/sqlcipher
140+ ./configure \
141+ --disable-tcl \
142+ --enable-tempstore=yes \
143+ CFLAGS="-DSQLITE_HAS_CODEC -DSQLCIPHER_CRYPTO_OPENSSL" \
144+ LDFLAGS="-lcrypto"
145+ make -j$(nproc) libsqlcipher.la || make -j$(nproc)
146+ sudo make install-libLTLIBRARIES install-includeHEADERS || sudo make install
147+ sudo ldconfig
148+
149+ - name : Build SQLCipher from source (macOS)
150+ if : runner.os == 'macOS'
151+ shell : bash
152+ run : |
153+ # Intentionally NOT installing ``tcl-tk`` from Homebrew:
154+ # the current bottle is Tcl 9.0, whose headers drop the
155+ # ``CONST`` macro and ``TCL_CHANNEL_VERSION_2``, so
156+ # SQLCipher's ``tclsqlite.c`` (still Tcl-8 API) fails to
157+ # compile. SQLCipher's configure auto-disables the Tcl
158+ # extension when no ``tclConfig.sh`` is on the usual
159+ # search paths — we only need the C library anyway; the
160+ # ``sqlcipher3`` Python binding doesn't touch Tcl.
161+ brew install openssl@3
162+ OPENSSL_PREFIX="$(brew --prefix openssl@3)"
163+ git clone --depth=1 --branch=v4.6.1 https://github.com/sqlcipher/sqlcipher.git /tmp/sqlcipher
164+ cd /tmp/sqlcipher
165+ ./configure \
166+ --disable-tcl \
167+ --enable-tempstore=yes \
168+ CFLAGS="-DSQLITE_HAS_CODEC -DSQLCIPHER_CRYPTO_OPENSSL -I$OPENSSL_PREFIX/include" \
169+ LDFLAGS="-L$OPENSSL_PREFIX/lib -lcrypto"
170+ # Build only the library target — the default ``make`` tries
171+ # to build the ``sqlcipher`` shell which links against Tcl.
172+ make -j$(sysctl -n hw.logicalcpu) libsqlcipher.la || make -j$(sysctl -n hw.logicalcpu)
173+ sudo make install-libLTLIBRARIES install-includeHEADERS || sudo make install
174+ echo "LDFLAGS=-L/usr/local/lib -L$OPENSSL_PREFIX/lib -lsqlcipher -lcrypto" >> $GITHUB_ENV
175+ echo "CPPFLAGS=-I/usr/local/include -I/usr/local/include/sqlcipher -I$OPENSSL_PREFIX/include" >> $GITHUB_ENV
176+
177+ - name : Install SQLCipher via vcpkg (Windows x64)
178+ if : runner.os == 'Windows' && runner.arch != 'ARM64'
179+ shell : pwsh
180+ run : |
181+ # vcpkg builds SQLCipher from source using the same upstream
182+ # repo (https://github.com/sqlcipher/sqlcipher), just
183+ # packaged as an MSVC-friendly port so we don't have to wire
184+ # nmake + OpenSSL manually. ``SQLCIPHER_PATH`` points
185+ # ``sqlcipher3``'s setup.py at the install root. Skipped on
186+ # arm64-windows: the transitive ``tcl`` port doesn't build
187+ # there even with ``--allow-unsupported``, and the
188+ # ``SqliteStateBackend`` handles the missing binding by
189+ # falling back to plain SQLite.
190+ $env:VCPKG_ROOT = "$env:VCPKG_INSTALLATION_ROOT"
191+ & "$env:VCPKG_ROOT\vcpkg" install "sqlcipher:x64-windows"
192+ $sqlcipherDir = "$env:VCPKG_ROOT\installed\x64-windows"
193+ echo "SQLCIPHER_PATH=$sqlcipherDir" >> $env:GITHUB_ENV
194+ echo "INCLUDE=$sqlcipherDir\include;$sqlcipherDir\include\sqlcipher;$env:INCLUDE" >> $env:GITHUB_ENV
195+ echo "LIB=$sqlcipherDir\lib;$env:LIB" >> $env:GITHUB_ENV
196+ echo "PATH=$sqlcipherDir\bin;$env:PATH" >> $env:GITHUB_ENV
121197
122198 - name : Cache vcpkg packages (Windows ARM)
123199 if : runner.os == 'Windows' && runner.arch == 'ARM64'
@@ -170,16 +246,45 @@ jobs:
170246 if : runner.os == 'Linux'
171247 run : docker version
172248
173- - name : Setup Docker (macOS Intel)
174- id : docker-macos
175- if : runner.os == 'macOS' && runner.arch == 'X64'
176- uses : docker/setup-docker-action@v4
177-
178- - name : Verify Docker (macOS Intel)
249+ - name : Configure Docker (macOS Intel)
179250 if : runner.os == 'macOS' && runner.arch == 'X64'
251+ shell : bash
180252 run : |
181- echo "DOCKER_HOST=$DOCKER_HOST"
182- docker version
253+ # ``docker/setup-docker-action@v4`` doesn't reliably bring up
254+ # a Docker daemon on ``macos-15-intel`` runners — testcontainers
255+ # then fails with ``FileNotFoundError: /var/run/docker.sock``
256+ # during the Redis fixture setup. Mirror the resilient
257+ # Docker-Desktop → Colima fallback used in publish-pywry.yml.
258+ set -euo pipefail
259+
260+ if docker info >/dev/null 2>&1; then
261+ echo "Docker daemon already available"
262+ else
263+ if [ -d "/Applications/Docker.app" ]; then
264+ echo "Starting Docker Desktop"
265+ open -a Docker
266+ for _ in {1..30}; do
267+ if docker info >/dev/null 2>&1; then
268+ break
269+ fi
270+ sleep 5
271+ done
272+ fi
273+ fi
274+
275+ if ! docker info >/dev/null 2>&1; then
276+ echo "Falling back to Colima"
277+ brew install docker colima
278+ colima start --runtime docker --arch x86_64 --cpu 2 --memory 4 --disk 20
279+ fi
280+
281+ if [ -S "$HOME/.colima/default/docker.sock" ]; then
282+ sudo mkdir -p /var/run
283+ sudo ln -sf "$HOME/.colima/default/docker.sock" /var/run/docker.sock
284+ fi
285+
286+ echo "DOCKER_HOST=unix:///var/run/docker.sock" >> "$GITHUB_ENV"
287+ docker info
183288
184289 - name : Run tests (Linux)
185290 if : runner.os == 'Linux'
0 commit comments