{"id":22691703,"url":"https://github.com/swvanbuuren/pqthreads","last_synced_at":"2026-03-08T04:31:42.154Z","repository":{"id":226736868,"uuid":"769518470","full_name":"swvanbuuren/pqthreads","owner":"swvanbuuren","description":"Exposes class interfaces from the main GUI Thread in another QThread in Qt for Python","archived":false,"fork":false,"pushed_at":"2026-01-20T19:23:40.000Z","size":136,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-21T04:37:09.228Z","etag":null,"topics":["gui","pyside","qt","qt-for-python","qthread"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/swvanbuuren.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-03-09T10:01:48.000Z","updated_at":"2026-01-20T19:23:43.000Z","dependencies_parsed_at":"2024-03-09T11:24:58.699Z","dependency_job_id":"a5b59745-6fe6-4f21-9163-ad886009a539","html_url":"https://github.com/swvanbuuren/pqthreads","commit_stats":null,"previous_names":["swvanbuuren/pqthread-commms"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/swvanbuuren/pqthreads","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swvanbuuren%2Fpqthreads","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swvanbuuren%2Fpqthreads/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swvanbuuren%2Fpqthreads/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swvanbuuren%2Fpqthreads/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/swvanbuuren","download_url":"https://codeload.github.com/swvanbuuren/pqthreads/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swvanbuuren%2Fpqthreads/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30245219,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-08T00:58:18.660Z","status":"online","status_checked_at":"2026-03-08T02:00:06.215Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gui","pyside","qt","qt-for-python","qthread"],"created_at":"2024-12-10T01:12:00.626Z","updated_at":"2026-03-08T04:31:42.136Z","avatar_url":"https://github.com/swvanbuuren.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pqthreads\n\nPqthreads exposes class interfaces from the main GUI Thread in another\nQThread in [Qt for Python (PySide)](https://wiki.qt.io/Qt_for_Python). In doing so, it facilitates communication between the\nmain (GUI) thread and a dedicated `QThread`s as offered by [Qt for Python](https://wiki.qt.io/Qt_for_Python).\n\n## Installation\n\nPqthreads comes as a [package](https://pypi.org/project/pqthreads/) in the\n[Python Package Index (PyPi)](https://pypi.org/) and can be installed using pip:\n\n```console\npip install pqthreads\n```\n\n## Usage\n\nIn order to use pqhreads, you'll first need a GUI implementation (in [Qt for\nPython (PySide)](https://wiki.qt.io/Qt_for_Python)) whose interface you'd like\nto expose. Then you need to have a corresponding class that exposes (chosen)\nmethods and attributes in another thread.\n\n### GUI implementation\n\nThe GUI implementation would be a class that derives from\n[QWidget](https://doc.qt.io/qtforpython-5/PySide2/QtWidgets/QWidget.html), e.g.\n[QMainWindow](https://doc.qt.io/qtforpython-5/PySide2/QtWidgets/QMainWindow.html).\nA very basic example class called `FigureWindow` can be found in\n[window.py](https://github.com/swvanbuuren/pqthreads/blob/master/pqthreads/examples/window.py#L11).\n\n### Worker class\n\nIn a class that inherits from\n[containers.WorkerItem](https://github.com/swvanbuuren/pqthreads/blob/master/pqthreads/containers.py#L90)\nyou then choose which methods and attributes are exposed. An examples of this is\nthe class `FigureWorker` as found in\n[worker.py](https://github.com/swvanbuuren/pqthreads/blob/master/pqthreads/examples/worker.py#L14).\n\n### Putting it all together\n\nUsing the GUI implementation `FigureWindow` and worker class `FigureWorker` the\nutilities from\n[decorator.py](https://github.com/swvanbuuren/pqthreads/blob/master/pqthreads/decorator.py)\ncan be used to create a custom decorator:\n\n```python\nfrom pqthreads import decorator\n\nDecoratorCore = decorator.DecoratorCore\nDecoratorCore.add_agent('figure', window.FigureWindow, FigureWorker)\ndecorator_example = decorator.Decorator(DecoratorCore)\n``` \n\nAny decorated function will run in the worker thread, while all GUI elements run\nin the (main) GUI thread.\n\nTo simplify access to worker class interfaces, a helper function is useful. This\nalso illustrates how to create and access new GUI elements:\n\n```python\nfrom pqthreads import refs\n\ndef figure(*args, **kwargs):\n    \"\"\" Create, raise or modify FigureWorker objects \"\"\"\n    container = refs.worker.get('figure')\n    if not args:\n        return container.create(**kwargs)\n    figure_worker = args[0]\n    container.current = figure_worker\n    return figure_worker\n```\n\nThis can finally be used to to expose GUI implementation in an existing python\nprogram that will run in another worker thread.\n\n```python\nfrom pqthreads.examples import worker\n\n@decorator_example\ndef main():\n    fig = worker.figure(title='Initial title')\n    fig.change_title(title='Another title')\n    fig.close()\n```\n\n## Pittfalls\n\nAs illustrated in the previous section, worker class interfaces are accessed\nthrough the so-called `worker` references (as is provided in the module\n[`refs`](https://github.com/swvanbuuren/pqthreads/blob/master/pqthreads/refs.py)).\nAll interfaces are provided as weak references. As soon as the decorated\nfunction is exited, the weak references will invalidate and can't be used\nanymore. Therefore, it's recommended to decorate the function that encapsulates\nthe whole python program in question. This assures that different parts of your\nown program run in different threads.\n\nThe module [`refs`](https://github.com/swvanbuuren/pqthreads/blob/master/pqthreads/refs.py) also comes with an object called `gui`\nreferences that stores weak references to the GUI objects. These also will\ninvalidate when the decorated function is exited.\n\nFinally, one should not access the `worker` references from the (main) GUI\nthread and also not access `gui` references from the worker thread. This can\nlead to trace errors and all sorts of undefined behavior. **You have been\nwarned!**\n\n## Design\n\nPqthreads separates the GUI elements from all programming elements in\n`QThread`s. Since Qt demands that the main thread is used for GUI elements, all\nother programming functionalities are moved into a dedicated `QThread`. This\nshall be called the worker threads.\n\nThe following schematic depicts this design.\n\n![Pqthreads design](https://github.com/swvanbuuren/pqthreads/raw/master/doc/design.svg)\n\nCommunication between the GUI and worker threads is solely done using\nSignal/Slot connections. This is facilitated by the `GUIAgent`s and\n`WorkerAgent`s.\n\nThe interface of a GUI Object is exposed by means of a Worker Object in the\nWorker Thread.\n\nIt is possible expose the interface of multiple types of GUI Objects (in the\nshown schematic `FigureWindow` and `GraphWindow`), which requires multiple\n`Worker`- and `GUIAgent`s. These are held the `GUIAgency` and `WorkerAgency`\nrespectively.\n\nFor each type of GUI/Worker object pair, it's also possible to instantiate\nmultiple objects (of the same type). GUI and Worker objects are held in the\n`GUIItemContainer` and `WorkerItemContainer` respectively.\n\n## Pre-commit hooks\n\nThis repository comes with pre-commit hooks, which are stored in\n[`.hooks`](.hooks). To enable the hooks issue:\n\n```bash\ngit config --local core.hooksPath .hooks/\n```\n\n## License\n\nAn MIT style license applies for `pqthreads`, see the [LICENSE](LICENSE)\nfile for more details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswvanbuuren%2Fpqthreads","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fswvanbuuren%2Fpqthreads","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswvanbuuren%2Fpqthreads/lists"}