Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
QT_API=pyqt5
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ EXTERNAL/LOGGING
.idea
.cursorindexingignore*
templating/uv_deps_switcher/backups/*pyproject.toml.bak
.cursor/rules/derived-cursor-rules.mdc
216 changes: 216 additions & 0 deletions .specstory/history/2026-01-23_21-10Z-specifying-pyqt6-in-qtpy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
<!-- Generated by SpecStory, Markdown v2.1.0 -->

<!-- cursor Session aeb822f5-3cca-45ea-90bf-3f018b3e14fe (2026-01-23 21:10Z) -->

# Specifying PyQt6 in QtPy (2026-01-23 21:10Z)

_**User**_

how do I specify for qtpy that I want to use PyQt6 and not PySide6?

---

_**Agent (model default, mode Agent)**_

<think><details><summary>Thought Process</summary>

The user is asking how to configure qtpy to use PyQt6 instead of PySide6. This is a configuration question about the qtpy library, which is a compatibility layer that allows you to write code that works with either PyQt5, PyQt6, PySide2, or PySide6.

Let me search for how qtpy determines which binding to use. I recall that qtpy uses environment variables to select the backend. I should search the web or the codebase to give an accurate answer.

Actually, I know from experience that qtpy uses the environment variable `QT_API` to specify which Qt binding to use. The valid values are typically:
- `pyqt5`
- `pyqt6`
- `pyside2`
- `pyside6`

So to force PyQt6, you would set `QT_API=pyqt6` before importing qtpy.

Let me verify this with a quick web search to make sure I have the correct environment variable and value.
</details></think>

---





---

<tool-use data-tool-type="search" data-tool-name="web_search">
<details>
<summary>Tool use: **web_search** • Searched web `undefined` • **1** results</summary>

| Title | URL | Chunk |
|-------|-----|-------|
| Web search results for query: qtpy specify PyQt6 instead of PySide6 QT_API environment variable | | No results found |

</details>
</tool-use>

---

<think><details><summary>Thought Process</summary>

Let me try a more general search for qtpy backend selection.
</details></think>

---





---

<tool-use data-tool-type="search" data-tool-name="web_search">
<details>
<summary>Tool use: **web_search** • Searched web `undefined` • **1** results</summary>

| Title | URL | Chunk |
|-------|-----|-------|
| Web search results for query: qtpy QT_API environment variable choose backend | | Links:<br/>1. [spyder-ide/qtpy](https://github.com/spyder-ide/qtpy)<br/>2. [Environment variables — Matplotlib 3.10.8 documentation](https://matplotlib.org/stable/install/environment_variables_faq.html)<br/>3. [Search code, repositories, users, issues, pull requests...](https://github.com/jacobwilliams/qtpyguihelper)<br/>4. [QtPy 2.4.3](https://pypi.org/project/QtPy/)<br/>5. [Backends — Matplotlib 3.10.8 documentation](https://matplotlib.org/stable/users/explain/figure/backends.html)<br/><br/># QtPy QT_API Environment Variable<br/><br/>The `QT_API` environment variable is used to choose which Qt backend QtPy should use when multiple bindings are installed on your system.[1]<br/><br/>## Valid Values<br/><br/>The `QT_API` environment variable accepts the following values:[1]<br/><br/>- `pyqt5` (to use PyQt5)<br/>- `pyside2` (to use PySide2)<br/>- `pyqt6` (to use PyQt6)<br/>- `pyside6` (to use PySide6)<br/><br/>## Default Behavior<br/><br/>If several Qt bindings are found but `QT_API` is not set, PyQt5 is used by default.[1]<br/><br/>## How It Works<br/><br/>QtPy is an abstraction layer that allows you to write applications using a single API that works across PyQt5, PySide2, PyQt6, and PySide6.[1] By setting the `QT_API` environment variable before importing QtPy, you can specify which Qt binding should be loaded, enabling you to easily switch between different Qt bindings without changing your code. |

</details>
</tool-use>

---

<think><details><summary>Thought Process</summary>

Good, the web search confirmed it. Set `QT_API=pyqt6` to use PyQt6. Let me provide a clear answer to the user with the different ways they can set this.
</details></think>

---


Use the **`QT_API`** environment variable so qtpy loads PyQt6 instead of PySide6.

**Set it to:** `pyqt6`

### 1. In the environment (before running)

**Windows (PowerShell):**
```powershell
$env:QT_API = "pyqt6"
python your_script.py
```

**Windows (CMD):**
```cmd
set QT_API=pyqt6
python your_script.py
```

**Windows (persistent):** set `QT_API=pyqt6` in System Properties → Environment Variables.

### 2. In code (before any qtpy import)

Set it as early as possible, before importing qtpy or anything that uses it:

```python
import os
os.environ["QT_API"] = "pyqt6"

from qtpy import QtWidgets # will use PyQt6
```

### 3. In a `.env` file (if you use python-dotenv)

```text
QT_API=pyqt6
```

Load the env (e.g. `load_dotenv()`) before any qtpy import.

**Important:** `QT_API` must be set **before** the first qtpy (or Qt) import; changing it after import has no effect. Valid values: `pyqt5`, `pyqt6`, `pyside2`, `pyside6`.

---

_**User**_

@pypho_timeline/__init__.py:7-8 is this sufficient?

---

_**Agent (model default, mode Agent)**_

<think><details><summary>Thought Process</summary>

The user is asking if having `load_dotenv()` in their package's `__init__.py` (at lines 7-8) is sufficient for the `QT_API=pyqt6` setting to take effect when using qtpy.

For this to work:
1. The `.env` file would need to contain `QT_API=pyqt6`
2. The `load_dotenv()` call in `pypho_timeline/__init__.py` would need to run before any qtpy (or Qt) import anywhere in the application

The key question is: does anything import qtpy/Qt before `pypho_timeline` is imported? If the user does:
- `import pypho_timeline` first → then load_dotenv() runs, then later when something in pypho_timeline or the app imports qtpy, QT_API will already be set. ✓
- But if some other code path imports qtpy (or a library that imports qtpy) before pypho_timeline is ever imported, then load_dotenv() never runs first and QT_API won't be set. ✗

So it's "sufficient" only if `pypho_timeline` is always one of the first things imported in the application—typically meaning the app entry point (e.g. main.py) does `import pypho_timeline` or imports from it before any Qt/qtpy usage.

Let me check their __init__.py to see the full import order—does pypho_timeline itself import qtpy after load_dotenv()?
</details></think>

---


Checking the full import order in that file so we can give a precise answer.


---

<tool-use data-tool-type="read" data-tool-name="read_file_v2">
<details><summary>Tool use: **read_file_v2** • Read file: c:\Users\pho\repos\EmotivEpoc\ACTIVE_DEV\pyPhoTimeline\pypho_timeline\__init__.py</summary>

</details>
</tool-use>

---

<tool-use data-tool-type="read" data-tool-name="read_file_v2">
<details><summary>Tool use: **read_file_v2** • Read file: c:\Users\pho\repos\EmotivEpoc\ACTIVE_DEV\pyPhoTimeline\.env</summary>

</details>
</tool-use>

---

<think><details><summary>Thought Process</summary>

So:
1. `.env` has `QT_API=pyqt6` ✓
2. In `__init__.py`, `load_dotenv()` runs at lines 7-8, before any qtpy/Qt imports in this file.

But the critical question is: does anything in the imports that follow (lines 27+) eventually pull in qtpy or PyQt? Let me check - they import from pypho_timeline.core and pypho_timeline.docking. Those submodules might import qtpy. So the order is:
1. load_dotenv() runs → QT_API gets set from .env
2. Then a bunch of pypho_timeline submodules are imported

If any of those submodules import qtpy, then yes, it's sufficient because load_dotenv() has already run.

The only failure case would be if some other package or the user's script imports qtpy (or a library that uses qtpy) before ever importing pypho_timeline. For example:
- main.py does `from qtpy import QtWidgets` and then later `import pypho_timeline` → too late, qtpy already loaded.
- So it's sufficient as long as pypho_timeline is imported before any qtpy usage in the app.

I'll state that it's sufficient when pypho_timeline is imported first, and mention the edge case.
</details></think>

---


Yes, with one condition.

- Your `.env` has `QT_API=pyqt6`.
- In `pypho_timeline/__init__.py`, `load_dotenv()` runs at the top (lines 7–8), before any of the package’s own imports (e.g. from `core`, `docking`), so any qtpy/Qt imports that happen during `import pypho_timeline` will see `QT_API` already set.

So it’s sufficient as long as **`pypho_timeline` is imported before anything else imports qtpy or Qt**. For example, in `main.py` or your app entry point you should do:

```python
import pypho_timeline # or from pypho_timeline import ...
# ... then later use qtpy / run the app
```

If some other code path imports qtpy (or a library that imports qtpy) before `pypho_timeline` is ever imported, then `load_dotenv()` won’t have run yet and `QT_API` won’t be set in time. So: **yes, it’s sufficient when your app always imports `pypho_timeline` first.**

---

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!-- Generated by SpecStory, Markdown v2.1.0 -->

<!-- cursor Session b5c64e0a-ebe4-4968-8d32-46ecf6379c58 (2026-03-01 21:40Z) -->

# TypeError in LSLStreamReceiver connection (2026-03-01 21:40Z)

_**User**_

Exception has occurred: TypeError
connect() failed between LSLStreamReceiver.data_received[list, object, object] and _on_data_received()
File "C:\Users\pho\repos\EmotivEpoc\ACTIVE_DEV\pyPhoTimeline\pypho_timeline\rendering\datasources\specific\lsl.py", line 407, in __init__
receiver.data_received.connect(self._on_data_received)
File "C:\Users\pho\repos\EmotivEpoc\ACTIVE_DEV\pyPhoTimeline\live_lsl_timeline.py", line 440, in main
eeg_ds = LiveEEGTrackDatasource(
File "C:\Users\pho\repos\EmotivEpoc\ACTIVE_DEV\pyPhoTimeline\live_lsl_timeline.py", line 478, in <module>
sys.exit(main(use_synthetic=use_synthetic))
TypeError: connect() failed between LSLStreamReceiver.data_received[list, object, object] and _on_data_received()

---

Loading
Loading