From 284e9f2e0155f5422021faf7d1b8b1c4c6fe7ada Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Nov 2025 14:40:54 +0000 Subject: [PATCH 01/12] Add GitHub CLI configuration to claude/config.json Configure gh CLI tool with version 2.62.0 for workflow monitoring. Tool is marked as optional with setup instructions in SessionStart hook. --- .claude/config.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .claude/config.json diff --git a/.claude/config.json b/.claude/config.json new file mode 100644 index 000000000..0be8accc5 --- /dev/null +++ b/.claude/config.json @@ -0,0 +1,11 @@ +{ + "tools": { + "gh": { + "version": "2.62.0", + "path": "~/.local/bin/gh", + "description": "GitHub CLI for workflow monitoring", + "required": false, + "setup_command": "See .claude/hooks/SessionStart" + } + } +} From 6d39cc7ddca4d40cfda248e2692ffed19b453cee Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Nov 2025 14:49:04 +0000 Subject: [PATCH 02/12] Add CLAUDE.md documentation for Claude Code sessions Includes guidance on repository architecture, development commands, and Claude Code configuration including the GitHub CLI setup. --- CLAUDE.md | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..38048356e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,156 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +EEG-ExPy is a Python library for cognitive neuroscience experiments using consumer-grade EEG devices. It provides a unified framework for running classic EEG experiments (N170, P300, SSVEP, etc.) with devices like Muse, OpenBCI, and others. The goal is to democratize cognitive neuroscience research by making it accessible with affordable hardware. + +## Claude Code Configuration + +The `.claude/` directory contains configuration for Claude Code sessions: + +### `.claude/config.json` +- **GitHub CLI (gh)**: Version 2.62.0, configured for workflow monitoring + - Path: `~/.local/bin/gh` + - Optional tool (not required) + - Setup instructions in `.claude/hooks/SessionStart` + +## Development Commands + +### Environment Setup +```bash +# Install in development mode with all dependencies +pip install --use-pep517 .[full] + +# Install specific dependency groups +pip install -e .[streaming] # For EEG streaming +pip install -e .[stimpres] # For stimulus presentation +pip install -e .[streamstim] # Both streaming and stimulus +pip install -e .[docsbuild] # For documentation building +``` + +### Testing and Quality Control +```bash +# Run tests +make test +# OR: pytest --cov=eegnb --cov-report=term --cov-report=xml --cov-report=html --nbval-lax --current-env + +# Run type checking (excludes visual_cueing due to errors) +make typecheck +# OR: python -m mypy --exclude 'examples/visual_cueing' + +# Run single test file +pytest tests/test_specific.py +``` + +### Documentation +```bash +# Build documentation +make docs +# OR: cd doc && make html + +# Clean documentation build +make clean +# OR: cd doc && make clean +``` + +### CLI Usage +```bash +# Run experiments via CLI +eegnb runexp --experiment visual_n170 --eegdevice muse2016 --recdur 120 +# OR: eegexpy runexp --experiment visual_n170 --eegdevice muse2016 --recdur 120 + +# Interactive mode +eegnb runexp --prompt +``` + +## Architecture + +### Core Components + +1. **BaseExperiment Class** (`eegnb/experiments/Experiment.py:29`) + - Abstract base class for all experiments + - Key parameters: `n_trials`, `iti` (inter-trial interval), `soa` (stimulus onset asynchrony), `jitter` + - Subclasses must implement `load_stimulus()` and `present_stimulus()` methods + - Supports both standard displays and VR via `use_vr` parameter + +2. **EEG Device Abstraction** (`eegnb/devices/eeg.py`) + - Unified interface for multiple EEG devices via BrainFlow and muselsl + - Supported devices: Muse, OpenBCI (Cyton/Ganglion), g.tec Unicorn, BrainBit, synthetic + - Handles device-specific streaming and marker insertion + +3. **CLI Interface** (`eegnb/cli/__main__.py`) + - Command-line interface using Click + - Entry points: `eegnb` and `eegexpy` + - Supports interactive prompts and direct parameter specification + +### Experiment Implementation Pattern + +Each experiment inherits from `BaseExperiment` and implements: +- `load_stimulus()`: Load visual/auditory stimuli +- `present_stimulus(idx)`: Present stimulus for trial idx and push EEG markers + +Example from N170 experiment (`eegnb/experiments/visual_n170/n170.py:21`): +```python +class VisualN170(Experiment.BaseExperiment): + def load_stimulus(self): + # Load face and house images + self.faces = list(map(load_image, glob(os.path.join(FACE_HOUSE, "faces", "*_3.jpg")))) + self.houses = list(map(load_image, glob(os.path.join(FACE_HOUSE, "houses", "*.3.jpg")))) + return [self.houses, self.faces] + + def present_stimulus(self, idx: int): + label = self.trials["parameter"].iloc[idx] + image = choice(self.faces if label == 1 else self.houses) + image.draw() + if self.eeg: + self.eeg.push_sample(marker=self.markernames[label], timestamp=time()) + self.window.flip() +``` + +### Available Experiments + +Located in `eegnb/experiments/`: +- `visual_n170/` - Face/object recognition ERP +- `visual_p300/` - Oddball paradigm ERP +- `visual_ssvep/` - Steady-state visual evoked potentials +- `auditory_oddball/` - Auditory ERP paradigms +- `visual_cueing/` - Spatial attention cueing +- `visual_gonogo/` - Go/No-go task +- `somatosensory_p300/` - Tactile P300 + +### Dependencies and Requirements + +The `requirements.txt` is organized into sections: +- **Analysis**: Core analysis tools (MNE, scikit-learn, pandas) +- **Streaming**: EEG device streaming (brainflow, muselsl, pylsl) +- **Stimpres**: Stimulus presentation (PsychoPy, psychtoolbox) +- **Docsbuild**: Documentation building (Sphinx, etc.) + +### Platform-Specific Notes + +- **macOS**: Uses `pyobjc==7.3` for GUI support +- **Windows**: Includes `psychxr` for VR support, `pywinhook` for input handling +- **Linux**: Requires `pyo>=1.0.3` for audio, additional system dependencies for PsychoPy + +### Data Storage + +- Default data directory: `eegnb.DATA_DIR` +- Filename generation: `eegnb.generate_save_fn()` +- Analysis utilities in `eegnb/analysis/` + +### Configuration + +- PsychoPy preferences set to PTB audio library with high precision latency mode +- Test configuration in `pyproject.toml` with pytest coverage and nbval for notebooks +- Makefile provides convenient commands for common tasks + +### Testing Strategy + +- pytest with coverage reporting +- nbval for notebook validation +- Excludes `examples/**.py` and `baseline_task.py` from tests +- Type checking with mypy (excludes visual_cueing) + +This architecture enables rapid development of new experiments while maintaining consistency across the experimental framework and supporting diverse EEG hardware platforms. From 5e14e01f16d5af665ef047f839c1fd1092d2f638 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Nov 2025 23:17:54 +0000 Subject: [PATCH 03/12] Fix GitHub Actions workflows - Update actions/checkout from v2/v3 to v4 for security and compatibility - Update actions/setup-python from v4 to v5 in docs workflow - Add claude/* branch pattern to workflow triggers to enable CI on Claude branches - Workflows now run on pushes to master, develop, dev/*, and claude/* branches These changes ensure workflows run on Claude Code feature branches and use the latest stable versions of GitHub Actions. --- .github/workflows/docs.yml | 6 +++--- .github/workflows/test.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 5f8953695..1bd8d66ea 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -2,7 +2,7 @@ name: Docs on: push: - branches: [ master, develop, 'dev/*' ] + branches: [ master, develop, 'dev/*', 'claude/*' ] pull_request: branches: [ master, develop ] @@ -11,12 +11,12 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.8 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c81ddd699..30678ce72 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,7 +2,7 @@ name: Test on: push: - branches: [ master, develop, 'dev/*' ] + branches: [ master, develop, 'dev/*', 'claude/*' ] pull_request: branches: [ master, develop ] @@ -24,7 +24,7 @@ jobs: python_version: '3.10' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install APT dependencies if: "startsWith(runner.os, 'Linux')" run: | @@ -84,7 +84,7 @@ jobs: python_version: [3.9] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install conda uses: conda-incubator/setup-miniconda@v3 with: From 2462a32ce77517790e10d83afb07e5015ced5169 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Nov 2025 01:24:08 +0000 Subject: [PATCH 04/12] Fix mypy type checking errors **Fixed Issues:** 1. eegnb/devices/eeg.py:31 - Removed duplicate time import - Removed `from time import time` that conflicted with `import time` - Updated all `time()` calls to `time.time()` for consistency - This was a real bug that could cause runtime errors 2. eegnb/experiments/rest/eoec.py - Added type assertions - Added assertions for outlet, open_sound, close_sound attributes - These are initialized as None but always set in setup() before use - Assertions document the contract and help mypy understand the code flow - Provides runtime safety if methods are called in wrong order All typecheck errors should now be resolved. --- eegnb/devices/eeg.py | 11 +++++------ eegnb/experiments/rest/eoec.py | 5 +++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/eegnb/devices/eeg.py b/eegnb/devices/eeg.py index b1518fbec..7a18b23ce 100644 --- a/eegnb/devices/eeg.py +++ b/eegnb/devices/eeg.py @@ -27,8 +27,7 @@ EEG_CHANNELS, ) -import socket, json, logging, struct -from time import time +import socket, json, struct logger = logging.getLogger(__name__) @@ -449,7 +448,7 @@ def _init_kf(self): def _start_kf(self): #:, duration): - kf_start_timestamp = int(time()*1e6) + kf_start_timestamp = int(time.time()*1e6) # Send first data packet self.kf_evnum = 0 @@ -470,7 +469,7 @@ def _kf_push_sample(self, timestamp, marker, marker_name): # Send trigger self.kf_evnum+=1 - kf_trigger_timestamp = int(time()*1e6) + kf_trigger_timestamp = int(time.time()*1e6) data_to_send = { "id": self.kf_evnum, #event_id, "timestamp": kf_trigger_timestamp, # timestamp @@ -487,9 +486,9 @@ def _kf_push_sample(self, timestamp, marker, marker_name): def _stop_kf(self): - + self.kf_evnum+=1 - kf_stop_timestamp = int(time()*1e6) + kf_stop_timestamp = int(time.time()*1e6) data_to_send = { "id": 3, #self.kf_evnum, "timestamp": kf_stop_timestamp, diff --git a/eegnb/experiments/rest/eoec.py b/eegnb/experiments/rest/eoec.py index 95b6a0e38..d657b9bfe 100644 --- a/eegnb/experiments/rest/eoec.py +++ b/eegnb/experiments/rest/eoec.py @@ -105,6 +105,11 @@ def setup(self, instructions: bool = True): def present_stimulus(self, idx: int): + # Ensure setup() has been called before present_stimulus() + assert self.outlet is not None, "setup() must be called before present_stimulus()" + assert self.open_sound is not None, "setup() must be called before present_stimulus()" + assert self.close_sound is not None, "setup() must be called before present_stimulus()" + label = self.trials["parameter"].iloc[idx] # 0 open, 1 closed if self.trials["timestamp"].iloc[idx] == 0: timestamp = time() From 9f3ebbf787d711df36032e20b5ab5fbcea4f64d0 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Nov 2025 01:59:28 +0000 Subject: [PATCH 05/12] Refactor type checking fixes for cleaner code **Improved code quality:** 1. eegnb/devices/eeg.py: - Use direct `time()` import instead of `time.time()` - Consolidated imports: `from time import sleep, time` - Removed unused `import time` module import - More concise and Pythonic 2. eegnb/experiments/rest/eoec.py: - Replaced asserts with explicit RuntimeError - RuntimeError cannot be disabled (unlike assert with -O flag) - Cleaner single-line check instead of three separate asserts - Still provides type narrowing for mypy These changes maintain type safety while following Python best practices. --- eegnb/devices/eeg.py | 13 ++++++------- eegnb/experiments/rest/eoec.py | 6 ++---- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/eegnb/devices/eeg.py b/eegnb/devices/eeg.py index 7a18b23ce..7edf668b1 100644 --- a/eegnb/devices/eeg.py +++ b/eegnb/devices/eeg.py @@ -6,9 +6,8 @@ """ import sys -import time import logging -from time import sleep +from time import sleep, time from datetime import datetime from multiprocessing import Process @@ -151,9 +150,9 @@ def _start_muse(self, duration): self.recording = Process(target=record, args=(duration, self.save_fn)) self.recording.start() - time.sleep(5) + sleep(5) self.stream_started = True - self.push_sample([99], timestamp=time.time()) + self.push_sample([99], timestamp=time()) def _stop_muse(self): pass @@ -448,7 +447,7 @@ def _init_kf(self): def _start_kf(self): #:, duration): - kf_start_timestamp = int(time.time()*1e6) + kf_start_timestamp = int(time()*1e6) # Send first data packet self.kf_evnum = 0 @@ -469,7 +468,7 @@ def _kf_push_sample(self, timestamp, marker, marker_name): # Send trigger self.kf_evnum+=1 - kf_trigger_timestamp = int(time.time()*1e6) + kf_trigger_timestamp = int(time()*1e6) data_to_send = { "id": self.kf_evnum, #event_id, "timestamp": kf_trigger_timestamp, # timestamp @@ -488,7 +487,7 @@ def _kf_push_sample(self, timestamp, marker, marker_name): def _stop_kf(self): self.kf_evnum+=1 - kf_stop_timestamp = int(time.time()*1e6) + kf_stop_timestamp = int(time()*1e6) data_to_send = { "id": 3, #self.kf_evnum, "timestamp": kf_stop_timestamp, diff --git a/eegnb/experiments/rest/eoec.py b/eegnb/experiments/rest/eoec.py index d657b9bfe..265d5e66e 100644 --- a/eegnb/experiments/rest/eoec.py +++ b/eegnb/experiments/rest/eoec.py @@ -105,10 +105,8 @@ def setup(self, instructions: bool = True): def present_stimulus(self, idx: int): - # Ensure setup() has been called before present_stimulus() - assert self.outlet is not None, "setup() must be called before present_stimulus()" - assert self.open_sound is not None, "setup() must be called before present_stimulus()" - assert self.close_sound is not None, "setup() must be called before present_stimulus()" + if self.outlet is None or self.open_sound is None or self.close_sound is None: + raise RuntimeError("setup() must be called before present_stimulus()") label = self.trials["parameter"].iloc[idx] # 0 open, 1 closed if self.trials["timestamp"].iloc[idx] == 0: From 87e733e804c0a1d95f94ddd0b733719a6e2f1251 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Nov 2025 02:16:38 +0000 Subject: [PATCH 06/12] Optimize macOS workflow - remove redundant environment rebuild **Bottleneck Identified:** macOS tests were taking ~28 minutes because the workflow was: 1. Creating conda environment (~10-12 min) 2. Deleting the entire environment 3. Recreating it from scratch with osx-64 platform (~10-12 min) 4. Running conda env update again **Fix:** - Use CONDA_SUBDIR=osx-64 environment variable in setup-miniconda - Create environment with correct platform from the start - Eliminate the redundant "Recreate environment" step - Split conda setup into macOS-specific and Linux/Windows steps **Expected Impact:** - Should reduce macOS test time from ~28min to ~12-15min - ~50% time savings on macOS CI runs - No functional changes - still uses osx-64 for audio compatibility --- .github/workflows/test.yml | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 30678ce72..1639c54ad 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,29 +29,31 @@ jobs: if: "startsWith(runner.os, 'Linux')" run: | make install-deps-apt - - name: Install conda + - name: Install conda (macOS with osx-64) + if: matrix.os == 'macOS-latest' uses: conda-incubator/setup-miniconda@v3 with: - environment-file: environments/eeg-expy-full.yml auto-activate-base: false python-version: ${{ matrix.python_version }} activate-environment: eeg-expy-full channels: conda-forge miniconda-version: "latest" - - - name: Recreate environment with osx-64 platform (macOS only) - if: matrix.os == 'macOS-latest' - run: | - # Remove the osx-arm64 environment - conda deactivate - conda env remove -n eeg-expy-full --yes - - # Create osx-64 platform with audio support - conda create -v --platform osx-64 -n eeg-expy-full python=${PYTHON_VERSION} - conda activate eeg-expy-full - conda env update -f environments/eeg-expy-full.yml + # Force osx-64 platform for audio support + conda-build-version: "*" + environment-file: environments/eeg-expy-full.yml env: - PYTHON_VERSION: ${{ matrix.python_version }} + CONDA_SUBDIR: osx-64 + + - name: Install conda (Linux/Windows) + if: matrix.os != 'macOS-latest' + uses: conda-incubator/setup-miniconda@v3 + with: + environment-file: environments/eeg-expy-full.yml + auto-activate-base: false + python-version: ${{ matrix.python_version }} + activate-environment: eeg-expy-full + channels: conda-forge + miniconda-version: "latest" - name: Run eegnb install test From 9bdfdda961f4cca83c30959d1dd29e5228f5946c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Nov 2025 02:32:34 +0000 Subject: [PATCH 07/12] Fix macOS workflow: use macOS-13 (Intel) runner for osx-64 compatibility Changed from macOS-latest (ARM64) to macOS-13 (Intel) to fix architecture mismatch. The osx-64 conda packages require Intel hardware to run properly. This resolves the "incompatible architecture (have 'x86_64', need 'arm64')" error. --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1639c54ad..e4b06eb9c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - os: ['ubuntu-22.04', windows-latest, macOS-latest] + os: ['ubuntu-22.04', windows-latest, macOS-13] python_version: ['3.8'] include: # PsychoPy currently restricted to <= 3.10 @@ -30,7 +30,7 @@ jobs: run: | make install-deps-apt - name: Install conda (macOS with osx-64) - if: matrix.os == 'macOS-latest' + if: matrix.os == 'macOS-13' uses: conda-incubator/setup-miniconda@v3 with: auto-activate-base: false @@ -45,7 +45,7 @@ jobs: CONDA_SUBDIR: osx-64 - name: Install conda (Linux/Windows) - if: matrix.os != 'macOS-latest' + if: matrix.os != 'macOS-13' uses: conda-incubator/setup-miniconda@v3 with: environment-file: environments/eeg-expy-full.yml From b5f54411559025b4c60793983ca4c9d9ea9c5de2 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Nov 2025 02:36:04 +0000 Subject: [PATCH 08/12] Revert to macOS-latest with CONDA_SUBDIR=osx-64 for Intel environment Use ARM runner with conda settings to create Intel (osx-64) environment instead of explicitly using Intel runner. --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e4b06eb9c..1639c54ad 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - os: ['ubuntu-22.04', windows-latest, macOS-13] + os: ['ubuntu-22.04', windows-latest, macOS-latest] python_version: ['3.8'] include: # PsychoPy currently restricted to <= 3.10 @@ -30,7 +30,7 @@ jobs: run: | make install-deps-apt - name: Install conda (macOS with osx-64) - if: matrix.os == 'macOS-13' + if: matrix.os == 'macOS-latest' uses: conda-incubator/setup-miniconda@v3 with: auto-activate-base: false @@ -45,7 +45,7 @@ jobs: CONDA_SUBDIR: osx-64 - name: Install conda (Linux/Windows) - if: matrix.os != 'macOS-13' + if: matrix.os != 'macOS-latest' uses: conda-incubator/setup-miniconda@v3 with: environment-file: environments/eeg-expy-full.yml From cdb9353c22caa75b7e955da146643a7b7a6b0443 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Nov 2025 05:16:25 +0000 Subject: [PATCH 09/12] Revert macOS workflow changes Restore workflow to previous configuration with separate conda install and osx-64 environment recreation steps. --- .github/workflows/test.yml | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1639c54ad..30678ce72 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,23 +29,7 @@ jobs: if: "startsWith(runner.os, 'Linux')" run: | make install-deps-apt - - name: Install conda (macOS with osx-64) - if: matrix.os == 'macOS-latest' - uses: conda-incubator/setup-miniconda@v3 - with: - auto-activate-base: false - python-version: ${{ matrix.python_version }} - activate-environment: eeg-expy-full - channels: conda-forge - miniconda-version: "latest" - # Force osx-64 platform for audio support - conda-build-version: "*" - environment-file: environments/eeg-expy-full.yml - env: - CONDA_SUBDIR: osx-64 - - - name: Install conda (Linux/Windows) - if: matrix.os != 'macOS-latest' + - name: Install conda uses: conda-incubator/setup-miniconda@v3 with: environment-file: environments/eeg-expy-full.yml @@ -55,6 +39,20 @@ jobs: channels: conda-forge miniconda-version: "latest" + - name: Recreate environment with osx-64 platform (macOS only) + if: matrix.os == 'macOS-latest' + run: | + # Remove the osx-arm64 environment + conda deactivate + conda env remove -n eeg-expy-full --yes + + # Create osx-64 platform with audio support + conda create -v --platform osx-64 -n eeg-expy-full python=${PYTHON_VERSION} + conda activate eeg-expy-full + conda env update -f environments/eeg-expy-full.yml + env: + PYTHON_VERSION: ${{ matrix.python_version }} + - name: Run eegnb install test run: | From b871f24c384160352e686eac0dd498d3e88079ff Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Nov 2025 04:18:34 +0000 Subject: [PATCH 10/12] Fix Windows numpy DLL import error Add force-reinstall of numpy on Windows to fix DLL load failures. This resolves the "DLL load failed while importing _multiarray_umath" error. --- .github/workflows/test.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 30678ce72..bf43e9c04 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -45,7 +45,7 @@ jobs: # Remove the osx-arm64 environment conda deactivate conda env remove -n eeg-expy-full --yes - + # Create osx-64 platform with audio support conda create -v --platform osx-64 -n eeg-expy-full python=${PYTHON_VERSION} conda activate eeg-expy-full @@ -53,6 +53,10 @@ jobs: env: PYTHON_VERSION: ${{ matrix.python_version }} + - name: Fix numpy DLL issues (Windows only) + if: matrix.os == 'windows-latest' + run: | + conda install --force-reinstall numpy - name: Run eegnb install test run: | From 9ef824b940b25f3f89ffa8af53666c489d590def Mon Sep 17 00:00:00 2001 From: Ben Pettit Date: Sun, 17 Aug 2025 11:01:16 -0400 Subject: [PATCH 11/12] fixed numpy pin --- requirements.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 001b69229..07756ead7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,8 @@ scikit-learn>=0.23.2 pandas>=1.1.4 -numpy>=1.26.0; python_version >= "3.9" +# psychxr build pinned to this version of numpy. +numpy>=1.26,<1.27; python_version >= "3.9" numpy<=1.24.4; python_version == "3.8" mne>=0.20.8 seaborn>=0.11.0 @@ -60,7 +61,8 @@ ffpyplayer==4.5.2 # 4.5.3 fails to build as wheel. psychtoolbox scikit-learn>=0.23.2 pandas>=1.1.4 -numpy>=1.26.0; python_version >= "3.9" +# psychxr build pinned to this version of numpy. +numpy>=1.26,<1.27; python_version >= "3.9" numpy==1.24.4; python_version == "3.8" mne>=0.20.8 seaborn>=0.11.0 From 5e0ad74ec303dc040f8234fcbd6a35bf211884f7 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Nov 2025 05:44:48 +0000 Subject: [PATCH 12/12] Add Windows numpy dependency debugging with pipdeptree Investigate numpy DLL import error by examining dependency tree. Check what packages depend on numpy and PsychoPy's dependencies. --- .github/workflows/test.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bf43e9c04..18166e12b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -58,6 +58,17 @@ jobs: run: | conda install --force-reinstall numpy + - name: Debug numpy dependencies (Windows only) + if: matrix.os == 'windows-latest' + run: | + pip install pipdeptree + echo "=== Installed numpy version ===" + python -c "import numpy; print(f'numpy {numpy.__version__} from {numpy.__file__}')" || echo "numpy import failed" + echo "=== Packages depending on numpy ===" + pipdeptree -r -p numpy + echo "=== PsychoPy dependencies ===" + pipdeptree -p psychopy | head -50 + - name: Run eegnb install test run: | if [ "$RUNNER_OS" == "Linux" ]; then