Skip to content

Commit ee6b48a

Browse files
authored
Add github actions workflows (sezanzeb#267)
* Run linters and unit tests with github actions * Reformat with black, 22.1.0 (compiled: yes) * Remove native deps as should no longer be needed * Remove pylint from workflows * Remove unused Gtk dependency in test_daemon.py * Install subset of python deps with apt-get for ci
1 parent 162e7fc commit ee6b48a

File tree

13 files changed

+216
-24
lines changed

13 files changed

+216
-24
lines changed

.github/workflows/lint.yml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Lint
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
black:
7+
runs-on: ubuntu-latest
8+
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
9+
strategy:
10+
matrix:
11+
python-version: ["3.10"]
12+
steps:
13+
- uses: actions/checkout@v2
14+
- name: Set up Python ${{ matrix.python-version }}
15+
uses: actions/setup-python@v2
16+
with:
17+
python-version: ${{ matrix.python-version }}
18+
- name: Install dependencies
19+
run: |
20+
scripts/ci-install-deps.sh
21+
pip install black
22+
- name: Analysing the code with black --check --diff
23+
run: |
24+
black --check --diff ./inputremapper ./tests
25+

.github/workflows/reviewdog.yml

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
name: reviewdog
3+
# run reviewdog for PR only because "github-check" option is failing :(
4+
# https://github.com/reviewdog/reviewdog/issues/924
5+
on: [pull_request]
6+
7+
jobs:
8+
reviewdog_python:
9+
name: reviewdog - Python lint
10+
runs-on: ubuntu-latest
11+
strategy:
12+
matrix:
13+
python-version: ["3.10"]
14+
15+
steps:
16+
- uses: actions/checkout@v2
17+
18+
- name: Set up Python ${{ matrix.python-version }}
19+
uses: actions/setup-python@v2
20+
with:
21+
python-version: ${{ matrix.python-version }}
22+
- uses: reviewdog/action-setup@master
23+
with:
24+
reviewdog_version: latest
25+
- name: Install dependencies
26+
shell: bash
27+
run: |
28+
scripts/ci-install-deps.sh
29+
pip install flake8 pylint mypy black
30+
- name: Set env for PR
31+
if: github.event_name == 'pull_request'
32+
shell: bash
33+
run: echo "REWIEVDOG_REPORTER=github-pr-review" >> $GITHUB_ENV
34+
35+
- name: Set env for push
36+
if: github.event_name != 'pull_request'
37+
shell: bash
38+
run: echo "REWIEVDOG_REPORTER=github-check" >> $GITHUB_ENV
39+
40+
- name: Run reviewdog
41+
shell: bash
42+
env:
43+
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
44+
run: |
45+
reviewdog -list
46+
reviewdog -tee -runners=mypy,black -reporter=${{ env.REWIEVDOG_REPORTER }} -fail-on-error=false

.github/workflows/test.yml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Test
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
build:
7+
continue-on-error: true
8+
runs-on: ubuntu-latest
9+
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
10+
strategy:
11+
matrix:
12+
python-version: ["3.7", "3.10"] # min and max supported versions?
13+
steps:
14+
- uses: actions/checkout@v2
15+
- name: Set up Python ${{ matrix.python-version }}
16+
uses: actions/setup-python@v2
17+
with:
18+
python-version: ${{ matrix.python-version }}
19+
- name: Install dependencies
20+
run: |
21+
# Install deps as root since we will run tests as root
22+
sudo scripts/ci-install-deps.sh
23+
sudo pip install .
24+
- name: Run tests
25+
run: |
26+
# FIXME: Had some permissions issues, currently worked around by running tests as root
27+
mkdir test_tmp
28+
TMPDIR="$(realpath test_tmp)" sudo python tests/test.py --start-dir unit

.reviewdog.yml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
runner:
3+
mypy:
4+
name: mypy
5+
cmd: mypy --show-column-numbers inputremapper tests --ignore-missing-imports
6+
errorformat:
7+
- "%f:%l:%c: %m"
8+
9+
pylint:
10+
name: pylint
11+
cmd: pylint inputremapper tests --extension-pkg-whitelist=evdev
12+
errorformat:
13+
- "%f:%l:%c: %t%n: %m"
14+
15+
flake8:
16+
cmd: flake8 inputremapper tests
17+
format: flake8
18+
19+
black:
20+
cmd: black --diff --quiet --check ./inputremapper ./tests
21+
format: black

inputremapper/injection/consumers/joystick_to_mouse.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ async def run(self):
213213
non_linearity = preset.get("gamepad.joystick.non_linearity")
214214
x_scroll_speed = preset.get("gamepad.joystick.x_scroll_speed")
215215
y_scroll_speed = preset.get("gamepad.joystick.y_scroll_speed")
216-
max_speed = 2 ** 0.5 # for normalized abs event values
216+
max_speed = 2**0.5 # for normalized abs event values
217217

218218
if abs_range is not None:
219219
logger.info(

inputremapper/input_event.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
from inputremapper.exceptions import InputEventCreationError
2828

2929

30-
@dataclass(frozen=True) # Todo: add slots=True as soon as python 3.10 is in common distros
30+
@dataclass(
31+
frozen=True
32+
) # Todo: add slots=True as soon as python 3.10 is in common distros
3133
class InputEvent:
3234
"""
3335
the evnet used by inputremapper

scripts/ci-install-deps.sh

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env bash
2+
# Called from multiple CI pipelines in .github/workflows
3+
set -xeuo pipefail
4+
5+
# native deps
6+
# gettext required to generate translations, others are python deps
7+
sudo apt-get install -y gettext python3-evdev python3-pydbus python3-pydantic
8+
9+
# ensure pip and setuptools/wheel up to date so can install all pip modules
10+
python -m pip install --upgrade pip
11+
pip install wheel setuptools
12+
13+
# install test deps which aren't in setup.py
14+
pip install psutil

setup.py

+1-7
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,7 @@ def make_lang():
129129
("/usr/bin/", ["bin/key-mapper-service"]),
130130
("/usr/bin/", ["bin/key-mapper-control"]),
131131
],
132-
install_requires=[
133-
"setuptools",
134-
"evdev",
135-
"pydbus",
136-
"pygobject",
137-
"pydantic"
138-
],
132+
install_requires=["setuptools", "evdev", "pydbus", "pygobject", "pydantic"],
139133
cmdclass={
140134
"install": Install,
141135
},

shell.nix

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# shell.nix - used with nix-shell to get a development environment with necessary dependencies
2+
# Should be enough to run unit tests, integration tests and the service won't work
3+
# If you don't use nix, don't worry about/use this file
4+
let
5+
pkgs = import <nixpkgs> { };
6+
python = pkgs.python310;
7+
in
8+
pkgs.mkShell {
9+
nativeBuildInputs = [
10+
pkgs.pkg-config
11+
pkgs.wrapGAppsHook
12+
];
13+
buildInputs = [
14+
pkgs.gobject-introspection
15+
pkgs.gtk3
16+
pkgs.bashInteractive
17+
pkgs.gobject-introspection
18+
pkgs.xlibs.xmodmap
19+
pkgs.gtksourceview4
20+
(python.withPackages (
21+
python-packages: with python-packages; [
22+
pip
23+
wheel
24+
setuptools # for pkg_resources
25+
types-setuptools
26+
27+
evdev
28+
pydbus
29+
pygobject3
30+
pydantic
31+
32+
psutil # only used in tests
33+
]
34+
))
35+
];
36+
# https://nixos.wiki/wiki/Python#Emulating_virtualenv_with_nix-shell
37+
shellHook = ''
38+
# Tells pip to put packages into $PIP_PREFIX instead of the usual locations.
39+
# See https://pip.pypa.io/en/stable/user_guide/#environment-variables.
40+
export PIP_PREFIX=$(pwd)/venv
41+
export PYTHONPATH="$PIP_PREFIX/${python.sitePackages}:$PYTHONPATH"
42+
export PATH="$PIP_PREFIX/bin:$PATH"
43+
unset SOURCE_DATE_EPOCH
44+
45+
python setup.py egg_info
46+
pip install `grep -v '^\[' *.egg-info/requires.txt` || true
47+
'';
48+
}

tests/integration/test_gui.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -699,12 +699,18 @@ def get_state(_=None):
699699

700700
def test_editor_keycode_to_string(self):
701701
# not an integration test, but I have all the selection_label tests here already
702-
self.assertEqual(EventCombination((EV_KEY, evdev.ecodes.KEY_A, 1)).beautify(), "a")
702+
self.assertEqual(
703+
EventCombination((EV_KEY, evdev.ecodes.KEY_A, 1)).beautify(), "a"
704+
)
703705
self.assertEqual(
704706
EventCombination([EV_KEY, evdev.ecodes.KEY_A, 1]).beautify(), "a"
705707
)
706-
self.assertEqual(EventCombination((EV_ABS, evdev.ecodes.ABS_HAT0Y, -1)).beautify(), "DPad Up")
707-
self.assertEqual(EventCombination((EV_KEY, evdev.ecodes.BTN_A, 1)).beautify(), "Button A")
708+
self.assertEqual(
709+
EventCombination((EV_ABS, evdev.ecodes.ABS_HAT0Y, -1)).beautify(), "DPad Up"
710+
)
711+
self.assertEqual(
712+
EventCombination((EV_KEY, evdev.ecodes.BTN_A, 1)).beautify(), "Button A"
713+
)
708714
self.assertEqual(EventCombination((EV_KEY, 1234, 1)).beautify(), "1234")
709715
self.assertEqual(
710716
EventCombination([EV_ABS, evdev.ecodes.ABS_HAT0X, -1]).beautify(),
@@ -1736,7 +1742,7 @@ def test_gamepad_purpose_mouse_and_button(self):
17361742
gtk_iteration()
17371743
speed = active_preset.get("gamepad.joystick.pointer_speed")
17381744
active_preset.set("gamepad.joystick.non_linearity", 1)
1739-
self.assertEqual(speed, 2 ** 6)
1745+
self.assertEqual(speed, 2**6)
17401746

17411747
# don't consume the events in the reader, they are used to test
17421748
# the injection

tests/test.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121

2222
"""Sets up inputremapper for the tests and runs them."""
23+
import argparse
2324
import os
2425
import sys
2526
import tempfile
@@ -663,7 +664,15 @@ def spy(obj, name):
663664

664665

665666
def main():
666-
modules = sys.argv[1:]
667+
# https://docs.python.org/3/library/argparse.html
668+
parser = argparse.ArgumentParser(description=__doc__)
669+
# repeated argument 0 or more times with modules
670+
parser.add_argument("modules", type=str, nargs="*")
671+
# start-dir value if not using modules, allows eg python tests/test.py --start-dir unit
672+
parser.add_argument("--start-dir", type=str, default=".")
673+
parsed_args = parser.parse_args() # takes from sys.argv by default
674+
modules = parsed_args.modules
675+
667676
# discoverer is really convenient, but it can't find a specific test
668677
# in all of the available tests like unittest.main() does...,
669678
# so provide both options.
@@ -674,7 +683,9 @@ def main():
674683
testsuite = unittest.defaultTestLoader.loadTestsFromNames(modules)
675684
else:
676685
# run all tests by default
677-
testsuite = unittest.defaultTestLoader.discover(".", pattern="test_*.py")
686+
testsuite = unittest.defaultTestLoader.discover(
687+
parsed_args.start_dir, pattern="test_*.py"
688+
)
678689

679690
# add a newline to each "qux (foo.bar)..." output before each test,
680691
# because the first log will be on the same line otherwise

tests/unit/test_daemon.py

-7
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727

2828
import evdev
2929
from evdev.ecodes import EV_KEY, EV_ABS, KEY_B, KEY_A
30-
from gi.repository import Gtk
3130
from pydbus import SystemBus
3231

3332
from inputremapper.configs.system_mapping import system_mapping
@@ -51,12 +50,6 @@
5150
)
5251

5352

54-
def gtk_iteration():
55-
"""Iterate while events are pending."""
56-
while Gtk.events_pending():
57-
Gtk.main_iteration()
58-
59-
6053
check_output = subprocess.check_output
6154
os_system = os.system
6255
dbus_get = type(SystemBus()).get

tests/unit/test_input_event.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,14 @@ def test_properties(self):
9191
)
9292
self.assertEqual(e1.type_and_code, (evdev.ecodes.EV_KEY, evdev.ecodes.BTN_LEFT))
9393

94-
with self.assertRaises(FrozenInstanceError): # would be TypeError on a slotted class
94+
with self.assertRaises(
95+
FrozenInstanceError
96+
): # would be TypeError on a slotted class
9597
e1.event_tuple = (1, 2, 3)
9698

97-
with self.assertRaises(FrozenInstanceError): # would be TypeError on a slotted class
99+
with self.assertRaises(
100+
FrozenInstanceError
101+
): # would be TypeError on a slotted class
98102
e1.type_and_code = (1, 2)
99103

100104
with self.assertRaises(FrozenInstanceError):

0 commit comments

Comments
 (0)