-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from nocarryr/kivyui
Add Kivy UI
- Loading branch information
Showing
22 changed files
with
1,628 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,37 @@ | ||
dist: trusty | ||
sudo: false | ||
language: python | ||
python: "3.5" | ||
cache: | ||
directories: | ||
- "build/" | ||
addons: | ||
apt: | ||
packages: | ||
- libsdl2-dev | ||
- libsdl2-ttf-dev | ||
- libsdl2-image-dev | ||
- libsdl2-mixer-dev | ||
- libgstreamer1.0-dev | ||
- gstreamer1.0-alsa | ||
- gstreamer1.0-plugins-base | ||
- python-dev | ||
- libsmpeg-dev | ||
- libswscale-dev | ||
- libavformat-dev | ||
- libavcodec-dev | ||
- libjpeg-dev | ||
- libtiff4-dev | ||
- libX11-dev | ||
- libmtdev-dev | ||
- libgl1-mesa-dev | ||
- libgles2-mesa-dev | ||
- xvfb | ||
- pulseaudio | ||
install: | ||
- pip install -U pip setuptools wheel | ||
- pip install -r requirements-test.txt | ||
- ./tools/install-deps.sh | ||
- pip install -e . | ||
script: | ||
- py.test --cov-config .coveragerc --cov=vidhubcontrol | ||
- ./runtests.sh | ||
after_success: | ||
- coveralls |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,7 @@ | ||
pytest>=3.0.2 | ||
pytest-asyncio | ||
pytest-cov | ||
pytest-xdist | ||
git+https://github.com/The-Compiler/pytest-xvfb.git@master#egg=pytest-xvfb | ||
coveralls | ||
-r vidhubcontrol/kivyui/requirements.txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#!/bin/sh | ||
set -e | ||
|
||
py.test --cov-config .coveragerc --cov=vidhubcontrol | ||
mv .coverage .coverage-orig | ||
|
||
for f in tests/kv/test*.py | ||
do | ||
echo "Running $f" | ||
py.test --cov-append --cov-config .coveragerc --cov=vidhubcontrol "$f" | ||
coverage combine -a .coverage-orig | ||
mv .coverage .coverage-orig | ||
done | ||
coverage combine -a .coverage-orig | ||
coverage report |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,8 @@ | ||
[tool:pytest] | ||
testpaths = tests | ||
python_files = *.py | ||
norecursedirs = kv | ||
xvfb_width = 1280 | ||
xvfb_height = 720 | ||
xvfb_colordepth = 24 | ||
xvfb_args = +extension GLX |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
import os | ||
import asyncio | ||
import time | ||
import pytest | ||
|
||
KIVY_STALL_TIMEOUT = 90 | ||
|
||
@pytest.fixture | ||
def kivy_app(tmpdir, monkeypatch): | ||
vidhub_conf = tmpdir.join('vidhubcontrol.json') | ||
ui_conf = tmpdir.join('vidhubcontrol-ui.ini') | ||
|
||
monkeypatch.setenv('KIVY_UNITTEST', '1') | ||
monkeypatch.setattr('vidhubcontrol.runserver.Config.DEFAULT_FILENAME', str(vidhub_conf)) | ||
|
||
from kivy.clock import Clock | ||
from kivy.base import runTouchApp, stopTouchApp | ||
from vidhubcontrol.kivyui import main as kivy_main | ||
|
||
aio_loop = asyncio.get_event_loop() | ||
aio_loop.set_debug(True) | ||
|
||
class AppOverride(kivy_main.VidhubControlApp): | ||
def get_application_config(self): | ||
return str(ui_conf) | ||
|
||
def on_start(self, *args, **kwargs): | ||
super().on_start(*args, **kwargs) | ||
self._startup_ready.set() | ||
|
||
def run(self): | ||
kv_dir = os.path.dirname(os.path.abspath(kivy_main.__file__)) | ||
self.kv_file = os.path.join(kv_dir, 'vidhubcontrol.kv') | ||
self._startup_ready = asyncio.Event() | ||
if not self.built: | ||
self.load_config() | ||
self.load_kv(filename=self.kv_file) | ||
root = self.build() | ||
if root: | ||
self.root = root | ||
|
||
if self.root: | ||
from kivy.core.window import Window | ||
Window.add_widget(self.root) | ||
|
||
# Check if the window is already created | ||
from kivy.base import EventLoop | ||
window = EventLoop.window | ||
if window: | ||
self._app_window = window | ||
window.set_title(self.get_application_name()) | ||
icon = self.get_application_icon() | ||
if icon: | ||
window.set_icon(icon) | ||
self._install_settings_keys(window) | ||
else: | ||
Logger.critical("Application: No window is created." | ||
" Terminating application run.") | ||
return | ||
self._kv_loop = EventLoop | ||
self._kv_loop_running = True | ||
self._aio_running = True | ||
self.dispatch('on_start') | ||
runTouchApp(self.root, slave=True) | ||
self._aio_mainloop_future = asyncio.ensure_future(self._aio_mainloop()) | ||
|
||
def stop(self): | ||
self.dispatch('on_stop') | ||
|
||
stopTouchApp() | ||
|
||
# Clear the window children | ||
if self._app_window: | ||
for child in self._app_window.children: | ||
self._app_window.remove_widget(child) | ||
|
||
self._kv_loop_running = False | ||
|
||
async def wait_for_widget_init(self, root=None): | ||
if root is None: | ||
root = self.root | ||
def check_init(): | ||
for w in root.walk(): | ||
if w.parent is None: | ||
return False | ||
if 'app' in w.properties() and w.app is None: | ||
return False | ||
return True | ||
while not check_init(): | ||
await asyncio.sleep(0) | ||
|
||
async def start_async(self): | ||
self.run() | ||
await self._startup_ready.wait() | ||
await self.wait_for_widget_init() | ||
|
||
async def stop_async(self): | ||
if self._kv_loop_running: | ||
self.stop() | ||
await self._aio_mainloop_future | ||
while not self.async_server.thread_stop_event.is_set(): | ||
await asyncio.sleep(.1) | ||
|
||
async def _aio_mainloop(self): | ||
start_ts = aio_loop.time() | ||
while not self._kv_loop.quit: | ||
now = aio_loop.time() | ||
if now >= start_ts + KIVY_STALL_TIMEOUT: | ||
print('Exiting app. Runtime exceeded threshold') | ||
raise KeyboardInterrupt() | ||
self._kv_loop.idle() | ||
await asyncio.sleep(0) | ||
self._kv_loop.exit() | ||
|
||
app = AppOverride() | ||
return app | ||
|
||
@pytest.fixture | ||
def KvEventWaiter(): | ||
class KvEventWaiter_(object): | ||
def __init__(self): | ||
self.aio_event = asyncio.Event() | ||
def bind(self, obj, *events): | ||
kwargs = {e:self.kivy_callback for e in events} | ||
obj.bind(**kwargs) | ||
def unbind(self, obj, *events): | ||
kwargs = {e:self.kivy_callback for e in events} | ||
obj.unbind(**kwargs) | ||
async def wait(self): | ||
await self.aio_event.wait() | ||
self.aio_event.clear() | ||
async def bind_and_wait(self, obj, *events): | ||
self.aio_event.clear() | ||
self.bind(obj, *events) | ||
await self.wait() | ||
def kivy_callback(self, *args, **kwargs): | ||
self.aio_event.set() | ||
|
||
return KvEventWaiter_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import asyncio | ||
import pytest | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_vidhub_dropdown(kivy_app, KvEventWaiter): | ||
from vidhubcontrol.backends import DummyBackend | ||
|
||
kv_waiter = KvEventWaiter() | ||
kv_waiter.bind(kivy_app, 'on_start') | ||
kivy_app.run() | ||
await kv_waiter.wait() | ||
|
||
config = kivy_app.vidhub_config | ||
dropdown = kivy_app.root.header_widget.vidhub_dropdown | ||
assert len(dropdown.btns) == 0 | ||
|
||
kv_waiter.bind(dropdown, 'btns') | ||
vidhub1 = await DummyBackend.create_async(device_id='dummy1', device_name='Dummy 1') | ||
vidhub2 = await DummyBackend.create_async(device_id='dummy2', device_name='Dummy 2') | ||
config.add_vidhub(vidhub1) | ||
await kv_waiter.wait() | ||
config.add_vidhub(vidhub2) | ||
await kv_waiter.wait() | ||
kv_waiter.unbind(dropdown, 'btns') | ||
|
||
assert 'dummy1' in dropdown.btns | ||
assert 'dummy2' in dropdown.btns | ||
btn = dropdown.btns['dummy1'] | ||
assert btn.vidhub is vidhub1 | ||
assert btn.text == vidhub1.device_name == 'Dummy 1' | ||
|
||
kv_waiter.bind(kivy_app, 'selected_vidhub') | ||
btn.dispatch('on_release') | ||
await kv_waiter.wait() | ||
|
||
assert kivy_app.selected_vidhub is vidhub1 | ||
|
||
await kivy_app.wait_for_widget_init() | ||
|
||
btn = dropdown.btns['dummy2'] | ||
assert btn.vidhub is vidhub2 | ||
assert btn.text == vidhub2.device_name == 'Dummy 2' | ||
|
||
assert not kv_waiter.aio_event.is_set() | ||
btn.dispatch('on_release') | ||
await kv_waiter.wait() | ||
assert kivy_app.selected_vidhub is vidhub2 | ||
|
||
await kivy_app.stop_async() |
Oops, something went wrong.