Skip to content

Commit

Permalink
Scheduler (#26)
Browse files Browse the repository at this point in the history
* Add support for using a scheduler

* Extend Qt example

* Update example to PySide6

* Fix linting

* cleanup repo and ci

* add poetry.lock

* see if this speeds things up

* split into modules and lint

* add module level docstrings

* Add method to register callback to request flush

* Remove unnecessary teardown as WeakSets icw GC is not needed

* Add index array to make use of bisect in queue while flushing

Also fix bug with self.has.remove

* Black

Co-authored-by: Berend Klein Haneveld <[email protected]>
  • Loading branch information
Korijn and Berend Klein Haneveld authored Sep 23, 2021
1 parent d80a058 commit cf637f8
Show file tree
Hide file tree
Showing 16 changed files with 1,770 additions and 486 deletions.
81 changes: 70 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ on:
push:
branches:
- master
tags:
- 'v*'
pull_request:
branches:
- master

jobs:
build:
name: ${{ matrix.name }}
test:
name: Lint and test on ${{ matrix.name }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- name: Linux py36
Expand All @@ -23,20 +26,76 @@ jobs:
pyversion: '3.8'
- name: Linux py39
pyversion: '3.9'

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.pyversion }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.pyversion }}
- name: Install poetry
run: |
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
echo "$HOME/.poetry/bin" >> $GITHUB_PATH
run: pip install "poetry>=1.1.8,<1.2"
- name: Install dependencies
run: |
poetry install
- name: Lint (black and flake8) and test
run: |
poetry run test
run: poetry install
- name: Lint
run: poetry run flake8
- name: Test
run: poetry run pytest --cov=observ --cov-report=term-missing

build:
name: Build and test wheel
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install poetry
run: pip install "poetry>=1.1.8,<1.2"
- name: Install dependencies
run: poetry install
- name: Build wheel
run: poetry build
- name: Twine check
run: poetry run twine check dist/*
- name: Upload wheel artifact
uses: actions/upload-artifact@v2
with:
path: dist
name: dist

publish:
name: Publish to Github and Pypi
runs-on: ubuntu-latest
needs: [test, build]
if: success() && startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v2
- name: Download wheel artifact
uses: actions/[email protected]
with:
name: dist
- name: Get version from git ref
id: get_version
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
- name: Create GH release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.get_version.outputs.VERSION }}
release_name: Release ${{ steps.get_version.outputs.VERSION }}
draft: false
prerelease: false
- name: Upload release assets
# Move back to official action after fix https://github.com/actions/upload-release-asset/issues/4
uses: AButler/[email protected]
with:
release-tag: ${{ steps.get_version.outputs.VERSION }}
files: 'dist/*.tar.gz;dist/*.whl'
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
user: __token__
password: ${{ secrets.PYPI_PASSWORD }}
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
poetry.lock
*.egg-info/
__pycache__
.vscode
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright © 2019-2020 observ authors
Copyright © 2019-2021 observ authors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
81 changes: 75 additions & 6 deletions examples/observe_qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,19 @@
and updates the label whenever a computed property
based on the state changes.
"""
from time import sleep

from observ import computed, observe, watch
from PyQt5.QtWidgets import QApplication, QLabel, QPushButton, QVBoxLayout, QWidget
from PySide6.QtCore import QObject, QThread, Signal
from PySide6.QtWidgets import (
QApplication,
QLabel,
QProgressBar,
QPushButton,
QVBoxLayout,
QWidget,
)

from observ import observe, scheduler, watch


class Display(QWidget):
Expand All @@ -19,23 +29,61 @@ def __init__(self, state, *args, **kwargs):
self.state = state

self.label = QLabel()
self.progress = QProgressBar()
self.progress.setMinimum(0)
self.progress.setMaximum(100)

layout = QVBoxLayout()
layout.addWidget(self.label)
layout.addWidget(self.progress)

self.setLayout(layout)

@computed
def label_text():
if state["clicked"] == 0:
return "Please click the button below"
return f"Clicked {state['clicked']} times!"

def progress_visible():
return state["progress"] > 0

self.watcher = watch(label_text, self.update_label, immediate=True)
self.progress_watch = watch(
lambda: state["progress"],
self.update_progress,
)
self.progress_visible = watch(
progress_visible, self.update_visibility, immediate=True
)

def update_progress(self, old_value, new_value):
# Trigger another watcher during scheduler flush
if new_value == 50:
self.state["clicked"] += 0.5
self.progress.setValue(new_value)

def update_label(self, old_value, new_value):
self.label.setText(new_value)

def update_visibility(self, old_value, new_value):
self.progress.setVisible(new_value)


class LongJob(QObject):
progress = Signal(int)
result = Signal(int)
finished = Signal()

def run(self):
self.progress.emit(0)
for i in range(100):
sleep(1 / 100.0)
self.progress.emit(i + 1)

self.progress.emit(0)
self.result.emit(1)
self.finished.emit()


class Controls(QWidget):
def __init__(self, state, *args, **kwargs):
Expand All @@ -56,18 +104,39 @@ def __init__(self, state, *args, **kwargs):
self.reset.clicked.connect(self.on_reset_clicked)

def on_button_clicked(self):
self.state["clicked"] += 1
self.thread = QThread()
self.worker = LongJob()
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.thread.finished.connect(self.thread.deleteLater)

self.thread.start()

def progress(x):
self.state["progress"] = x

def bump(x):
self.state["clicked"] += x * 0.5

self.button.setEnabled(False)
self.thread.finished.connect(lambda: self.button.setEnabled(True))
self.worker.result.connect(lambda x: bump(x))
self.worker.progress.connect(lambda x: progress(x))

def on_reset_clicked(self):
self.state["clicked"] = 0


if __name__ == "__main__":
# Define some state
state = observe({"clicked": 0})
state = observe({"clicked": 0, "progress": 0})

app = QApplication([])

scheduler.register_qt()

# Create layout and pass state to widgets
layout = QVBoxLayout()
layout.addWidget(Display(state))
Expand All @@ -78,4 +147,4 @@ def on_reset_clicked(self):
widget.show()
widget.setWindowTitle("Clicked?")

app.exec_()
app.exec()
Loading

0 comments on commit cf637f8

Please sign in to comment.