From 6c726cfcd4c78f686fdc2fb7c25dbc4836294d12 Mon Sep 17 00:00:00 2001 From: Martin Rys Date: Sat, 2 Nov 2024 02:09:56 +0100 Subject: [PATCH] Cleanup python 2-style explicit (object) definitions for classes with a sprinkle of linter and typing fixes on top --- generate_svg.py | 8 +- scc/actions.py | 17 ++- scc/config.py | 4 +- scc/controller.py | 4 +- scc/drivers/evdevdrv.py | 2 +- scc/drivers/hiddrv.py | 4 +- scc/drivers/sc_by_bt.py | 4 +- scc/drivers/usb.py | 6 +- scc/gui/ae/axis_action.py | 6 +- scc/gui/ae/gesture.py | 7 +- scc/gui/ae/gyro_action.py | 2 +- scc/gui/app.py | 2 +- scc/gui/binding_editor.py | 11 +- scc/gui/creg/data.py | 25 ++--- scc/gui/creg/grabs.py | 11 +- scc/gui/editor.py | 13 +-- scc/gui/importexport/import_sccprofile.py | 3 +- scc/gui/importexport/import_vdf.py | 4 +- scc/gui/key_grabber.py | 7 +- scc/gui/osd_mode.py | 10 +- scc/gui/svg_widget.py | 8 +- scc/gui/userdata_manager.py | 4 +- scc/lib/daemon.py | 2 +- scc/lib/hidparse.py | 4 +- scc/lib/hidraw.py | 2 +- scc/lib/jsonencoder.py | 2 +- scc/lib/xinput.py | 11 +- scc/mapper.py | 2 +- scc/menu_data.py | 16 +-- scc/osd/binding_display.py | 10 +- scc/osd/timermanager.py | 37 +++---- scc/parser.py | 4 +- scc/poller.py | 30 ++--- scc/profile.py | 23 ++-- scc/sccdaemon.py | 6 +- scc/scheduler.py | 32 +++--- scc/uinput.py | 4 +- scc/x11/autoswitcher.py | 8 +- scc/x11/scc-osd-daemon.py | 4 +- tests/test_boolean.py | 10 +- tests/test_compress.py | 38 +++---- tests/test_docs.py | 11 +- tests/test_glade.py | 11 +- tests/test_inputs.py | 2 +- tests/test_parser/test_actions.py | 95 ++++++++-------- tests/test_parser/test_macros.py | 45 ++++---- tests/test_parser/test_modifiers.py | 100 ++++++++--------- tests/test_parser/test_special_actions.py | 65 +++++------ tests/test_profile/test_actions.py | 121 +++++++++++---------- tests/test_profile/test_modeshift.py | 2 +- tests/test_profile/test_modifiers.py | 119 ++++++++++---------- tests/test_profile/test_special_actions.py | 65 +++++------ tests/test_setup.py | 2 +- tests/test_strings/test_keys.py | 10 +- tests/test_strings/test_modifiers.py | 21 ++-- tests/test_vdf.py | 29 ++--- 56 files changed, 542 insertions(+), 563 deletions(-) diff --git a/generate_svg.py b/generate_svg.py index c1abab7bb..9d9868184 100755 --- a/generate_svg.py +++ b/generate_svg.py @@ -28,7 +28,7 @@ def find_image(name): return None -class Line(object): +class Line: def __init__(self, icon, text): self.icons = [ icon ] @@ -49,7 +49,7 @@ def to_string(self): return "%-10s: %s" % (",".join([ x for x in self.icons if x ]), self.text) -class LineCollection(object): +class LineCollection: """ Allows calling add_icon on multiple lines at once """ def __init__(self, *lines): @@ -62,7 +62,7 @@ def add_icon(self, icon): return self -class Box(object): +class Box: PADDING = 5 SPACING = 2 MIN_WIDTH = 100 @@ -235,7 +235,7 @@ def place_marker(self, gen, root): -class Generator(object): +class Generator: PADDING = 10 def __init__(self): diff --git a/scc/actions.py b/scc/actions.py index c5a961313..cf8546f29 100644 --- a/scc/actions.py +++ b/scc/actions.py @@ -1,4 +1,4 @@ -"""SC Controller - Actions. +"""SC Controller - Actions Action describes what should be done when event from physical controller button, stick, pad or trigger is generated - typicaly what emulated button, stick or @@ -37,7 +37,7 @@ TRIGGERS = ( Axes["ABS_Z"], Axes["ABS_RZ"] ) -class Action(object): +class Action: """Action is what actually does something in SC-Controller. User can assotiate one or more Action to each available button, stick or pad in profile file.""" # Static dict of all available actions, filled later @@ -400,11 +400,8 @@ def trigger(self, mapper: Mapper, position, old_position): log.warning("Action %s can't handle trigger event", self.__class__.__name__) -class RangeOP(object): - """ - Allows to specify and store axis range and then use it in modeshift - instead of button. - """ +class RangeOP: + """Allows to specify and store axis range and then use it in modeshift instead of button.""" OPS = ("<", ">", "<=", ">=") def __init__(self, what, op, value): @@ -498,7 +495,7 @@ def __str__(self): return "%s %s %s" % (nameof(self.what), self.op, self.value) -class HapticEnabledAction(object): +class HapticEnabledAction: """ Action that can generate haptic feedback """ def __init__(self): self.haptic = None @@ -516,7 +513,7 @@ def get_haptic(self): return self.haptic -class OSDEnabledAction(object): +class OSDEnabledAction: """ Action that displays some sort of OSD when executed """ def __init__(self): self.osd_enabled = False @@ -531,7 +528,7 @@ def enable_osd(self, timeout): self.osd_enabled = True -class SpecialAction(object): +class SpecialAction: """ Action that needs to call special_actions_handler (aka sccdaemon instance) to actually do something. diff --git a/scc/config.py b/scc/config.py index e530fe3d0..1581fb7fa 100644 --- a/scc/config.py +++ b/scc/config.py @@ -1,4 +1,4 @@ -"""SC-Controller - Config. +"""SC Controller - Config Handles loading, storing and querying config file """ @@ -10,7 +10,7 @@ log = logging.getLogger("Config") -class Config(object): +class Config: DEFAULTS = { "autoswitch_osd": True, # True to show OSD message when profile is autoswitched "autoswitch": [], # Empty list of conditions diff --git a/scc/controller.py b/scc/controller.py index 0d26a09a5..ffec25853 100644 --- a/scc/controller.py +++ b/scc/controller.py @@ -14,7 +14,7 @@ next_id = 1 # Used with fallback controller id generator -class Controller(object): +class Controller: """Base class for all controller drivers. Implementations are in scc.drivers package. Derived class should implement every method from here. @@ -121,7 +121,7 @@ def disconnected(self) -> None: pass -class HapticData(object): +class HapticData: """ Simple container to hold haptic feedback settings """ def __init__(self, position, amplitude=512, frequency=4, period=1024, count=1): diff --git a/scc/drivers/evdevdrv.py b/scc/drivers/evdevdrv.py index 66de6c7a4..f45ef3eea 100644 --- a/scc/drivers/evdevdrv.py +++ b/scc/drivers/evdevdrv.py @@ -359,7 +359,7 @@ def parse_axis(axis): return AxisCalibrationData(scale, offset, center, clamp_min, clamp_max, deadzone) -class EvdevDriver(object): +class EvdevDriver: SCAN_INTERVAL = 5 def __init__(self): diff --git a/scc/drivers/hiddrv.py b/scc/drivers/hiddrv.py index 67fd27a20..f966fe56c 100644 --- a/scc/drivers/hiddrv.py +++ b/scc/drivers/hiddrv.py @@ -576,7 +576,7 @@ def set_gyro_enabled(self, enabled): pass -class HIDDrv(object): +class HIDDrv: def __init__(self, daemon: SCCDaemon): self.registered = set() @@ -650,7 +650,7 @@ def hiddrv_test(cls, args) -> int: except Exception: raise InvalidArguments() - class FakeDaemon(object): + class FakeDaemon: def __init__(self) -> None: self.poller = Poller() diff --git a/scc/drivers/sc_by_bt.py b/scc/drivers/sc_by_bt.py index 07715ea9e..6eff22505 100644 --- a/scc/drivers/sc_by_bt.py +++ b/scc/drivers/sc_by_bt.py @@ -1,4 +1,4 @@ -"""SC Controller - Steam Controller Driver. +"""SC Controller - Steam Controller Driver Driver for Steam Controller over bluetooth (evdev) @@ -312,7 +312,7 @@ def _input(self, *a): def hidraw_test(filename): - class FakeDaemon(object): + class FakeDaemon: def add_error(self, id, error): log.error(error) diff --git a/scc/drivers/usb.py b/scc/drivers/usb.py index 71cf1bc78..59aa4822e 100644 --- a/scc/drivers/usb.py +++ b/scc/drivers/usb.py @@ -24,7 +24,7 @@ log = logging.getLogger("USB") -class USBDevice(object): +class USBDevice: """Base class for all handled usb devices.""" def __init__(self, device: USBDevice, handle: USBDeviceHandle) -> None: @@ -130,7 +130,7 @@ def flush(self): def force_restart(self): """Restart device, close handle and try to re-grab it again. - Don't use unless absolutelly necessary. + Don't use unless absolutely necessary. """ tp = self.device.getVendorID(), self.device.getProductID() self.close() @@ -189,7 +189,7 @@ def close(self): pass -class USBDriver(object): +class USBDriver: def __init__(self): self.daemon = None self._known_ids = {} diff --git a/scc/gui/ae/axis_action.py b/scc/gui/ae/axis_action.py index 55b7b0a47..d35276417 100644 --- a/scc/gui/ae/axis_action.py +++ b/scc/gui/ae/axis_action.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -""" -SC-Controller - Action Editor - Axis Component +"""SC Controller - Action Editor - Axis Component Assigns emulated axis to trigger """ @@ -494,7 +492,7 @@ def on_cbAxisOutput_changed(self, *a): self.editor.set_action(action) -class FakeMapper(object): +class FakeMapper: """ Class that pretends to be mapper used when calling update_osd_area. It has two purposes: To provide get_xdisplay() method that does what it says diff --git a/scc/gui/ae/gesture.py b/scc/gui/ae/gesture.py index 1d6c8836e..dd5777d8d 100644 --- a/scc/gui/ae/gesture.py +++ b/scc/gui/ae/gesture.py @@ -1,7 +1,4 @@ -#!/usr/bin/env python3 -# coding=utf-8 -""" -SC-Controller - Action Editor - Gesture Component +"""SC Controller - Action Editor - Gesture Component Handles gesture recognition settings. """ @@ -205,7 +202,7 @@ def update(self): self.editor.set_action(a) -class GestureGrabber(object): +class GestureGrabber: def __init__(self, editor, builder): self.editor = editor self.builder = builder diff --git a/scc/gui/ae/gyro_action.py b/scc/gui/ae/gyro_action.py index fb817323a..2373b8aec 100644 --- a/scc/gui/ae/gyro_action.py +++ b/scc/gui/ae/gyro_action.py @@ -299,7 +299,7 @@ def send(self, *a) -> None: def is_gyro_enable(modemod) -> bool: - """ Returns True if ModeModifier instance is used to create "Gyro Enable Button" """ + """Return True if ModeModifier instance is used to create 'Gyro Enable Button'.""" if isinstance(modemod, ModeModifier): if len(modemod.mods) != 1: return False diff --git a/scc/gui/app.py b/scc/gui/app.py index 9f329d12c..45980f477 100644 --- a/scc/gui/app.py +++ b/scc/gui/app.py @@ -1699,7 +1699,7 @@ def convert_old_profiles(self): log.warning("Failed to convert %s: %s", name, e) -class UndoRedo(object): +class UndoRedo: """ Just dummy container """ def __init__(self, id, before, after): self.id = id diff --git a/scc/gui/binding_editor.py b/scc/gui/binding_editor.py index f74c06e7f..e49d9dfee 100644 --- a/scc/gui/binding_editor.py +++ b/scc/gui/binding_editor.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -""" -SC-Controller - BindingEditor +"""SC Controller - BindingEditor Base class for main application window and OSD Keyboard bindings editor. """ @@ -23,7 +21,7 @@ from scc.gui.ring_editor import RingEditor -class BindingEditor(object): +class BindingEditor: def __init__(self, app): self.button_widgets = {} @@ -31,10 +29,7 @@ def __init__(self, app): def create_binding_buttons(self, use_icons=True, enable_press=True): - """ - Creates ControllerWidget instances for available Gtk.Buttons defined - in glade file. - """ + """Create ControllerWidget instances for available Gtk.Buttons defined in glade file.""" for b in BUTTONS: w = self.builder.get_object("bt" + b.name) if w: diff --git a/scc/gui/creg/data.py b/scc/gui/creg/data.py index 3f3e4c759..9b68edb07 100644 --- a/scc/gui/creg/data.py +++ b/scc/gui/creg/data.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -""" -SC-Controller - Controller Registration data +"""SC Controller - Controller Registration data Dummy container classes """ @@ -11,9 +9,9 @@ log = logging.getLogger("CReg.data") -class AxisData(object): - """ - (Almost) dumb container. +class AxisData: + """(Almost) dumb container. + Stores position, center and limits for single axis. """ @@ -31,9 +29,7 @@ def __init__(self, name, xy, min=STICK_PAD_MAX, max=STICK_PAD_MIN): def reset(self): - """ - Resets min and max value so axis can (has to be) recalibrated again - """ + """Reset min and max value so axis can (has to be) recalibrated again""" self.min = STICK_PAD_MAX self.max = STICK_PAD_MIN @@ -43,9 +39,8 @@ def __repr__(self): def set_position(self, value): - """ - Returns (changed, x), value determining if axis limits were changed and - current position position. + """Return (changed, x), value determining if axis limits were changed and current position position. + translated to range of (STICK_PAD_MIN, STICK_PAD_MAX) """ changed = False @@ -67,9 +62,9 @@ def set_position(self, value): return changed, 0 -class DPadEmuData(object): - """ - Dumb container that stores dpad emulation data. +class DPadEmuData: + """Dumb container that stores dpad emulation data. + DPAd emulation is used, for example, on PS3 controller, where dpad does not inputs as 2 axes, but as 4 buttons. diff --git a/scc/gui/creg/grabs.py b/scc/gui/creg/grabs.py index 9e178a35f..6c024ffc5 100644 --- a/scc/gui/creg/grabs.py +++ b/scc/gui/creg/grabs.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -""" -SC-Controller - Controller Registration - Grabs +"""SC Controller - Controller Registration - Grabs Helper classes for grabbing buttons and axes from physical gamepads. @@ -16,11 +14,8 @@ log = logging.getLogger("CReg.grabs") -class InputGrabber(object): - """ - Base class for input grabbing. Waits for physical button being pressed - by default. - """ +class InputGrabber: + """Base class for input grabbing. Waits for physical button being pressed by default.""" def __init__(self, parent, what, text=_("Press a button...")): self.parent = parent diff --git a/scc/gui/editor.py b/scc/gui/editor.py index dade9fd8e..97e002467 100644 --- a/scc/gui/editor.py +++ b/scc/gui/editor.py @@ -1,4 +1,4 @@ -"""SC-Controller - Action Editor. +"""SC Controller - Action Editor Allows to edit button or trigger action. """ @@ -17,11 +17,11 @@ log = logging.getLogger("Editor") -class ComboSetter(object): +class ComboSetter: + + def set_cb(self, cb, key, keyindex=0) -> bool: + """Set combobox value. - def set_cb(self, cb, key, keyindex=0): - """ - Sets combobox value. Returns True on success or False if key is not found. """ model = cb.get_model() @@ -31,8 +31,7 @@ def set_cb(self, cb, key, keyindex=0): cb.set_active_iter(row.iter) self._recursing = False return True - else: - log.warning("Failed to set combobox value, key '%s' not found", key) + log.warning("Failed to set combobox value, key '%s' not found", key) self._recursing = False return False diff --git a/scc/gui/importexport/import_sccprofile.py b/scc/gui/importexport/import_sccprofile.py index e8004cc26..532c5756b 100644 --- a/scc/gui/importexport/import_sccprofile.py +++ b/scc/gui/importexport/import_sccprofile.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 from scc.tools import _ from gi.repository import Gtk, Gio, GLib, GObject @@ -13,7 +12,7 @@ import sys, os, json, tarfile, tempfile, logging log = logging.getLogger("IE.ImportSSCC") -class ImportSccprofile(object): +class ImportSccprofile: def on_btImportSccprofile_clicked(self, *a): # Create filters diff --git a/scc/gui/importexport/import_vdf.py b/scc/gui/importexport/import_vdf.py index d863ca69d..bac28bbe4 100644 --- a/scc/gui/importexport/import_vdf.py +++ b/scc/gui/importexport/import_vdf.py @@ -1,4 +1,4 @@ -"""SC-Controller - Global Settings. +"""SC Controller - Global Settings. Currently setups only one thing... """ @@ -18,7 +18,7 @@ log = logging.getLogger("IE.ImportVdf") -class ImportVdf(object): +class ImportVdf: PROFILE_LIST = "config/localconfig.vdf" STEAMPATH = "~/.steam/steam/" diff --git a/scc/gui/key_grabber.py b/scc/gui/key_grabber.py index 44d02daaa..fcbbff956 100644 --- a/scc/gui/key_grabber.py +++ b/scc/gui/key_grabber.py @@ -1,4 +1,4 @@ -"""SC-Controller - Action Editor. +"""SC Controller - Action Editor Allows to edit button or trigger action. """ @@ -29,7 +29,7 @@ def merge_modifiers(mods): # Just to speed shit up, KeyGrabber is singleton -class KeyGrabber(object): +class KeyGrabber: GLADE = "key_grabber.glade" _singleton = None @@ -73,8 +73,7 @@ def on_KeyGrab_destroy(self, *a): def on_keyGrab_key_press_event(self, trash, event): - """ - Handles keypress on "Grab Key" dialog. + """Handle keypress on "Grab Key" dialog. Remembers modifiers and displays text in middle of dialog. Dialog is dismissed (and key is accepted) by key_release handler bellow. diff --git a/scc/gui/osd_mode.py b/scc/gui/osd_mode.py index 163521907..a03fd3408 100644 --- a/scc/gui/osd_mode.py +++ b/scc/gui/osd_mode.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -""" -SC-Controller - OSD Mode Mapper +"""SC Controller - OSD Mode Mapper Very special case of mapper used when main application is launched in "odd mode". That means it's drawn in OSD layer, cannot be clicked and cannot react to @@ -44,7 +42,7 @@ def create_mouse(self, name): return OSDModeMouse(self) -class OSDModeKeyboard(object): +class OSDModeKeyboard: """ Emulates uinput keyboard emulator """ def __init__(self, mapper): @@ -78,7 +76,7 @@ def releaseEvent(self, keys=[]): Gtk.main_do_event(event) -class OSDModeMouse(object): +class OSDModeMouse: """ Emulates uinput keyboard emulator too """ def __init__(self, mapper): @@ -126,7 +124,7 @@ def keyEvent(self, key, val): Gtk.main_do_event(event) -class OSDModeMappings(object): +class OSDModeMappings: ICONS = { 'imgOsdmodeAct' : SCButtons.A, diff --git a/scc/gui/svg_widget.py b/scc/gui/svg_widget.py index 200b92f07..c2598e74a 100644 --- a/scc/gui/svg_widget.py +++ b/scc/gui/svg_widget.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -""" -SC-Controller - Background +"""SC Controller - Background Changes SVG on the fly and uptates that magnificent image on background with it. Also supports clicking on areas defined in SVG image. @@ -19,7 +17,7 @@ #ET = importlib.import_module('xml.etree.ElementTree') log = logging.getLogger("Background") -ET.register_namespace('', "http://www.w3.org/2000/svg") +ET.register_namespace("", "http://www.w3.org/2000/svg") class SVGWidget(Gtk.EventBox): @@ -262,7 +260,7 @@ def __str__(self): return "" % (self.x, self.y, self.w, self.h) -class SVGEditor(object): +class SVGEditor: """ Allows some basic edit operations by parsing SVG into dom tree and doing unholly mess on that. diff --git a/scc/gui/userdata_manager.py b/scc/gui/userdata_manager.py index 7cf3100a5..a4e859257 100644 --- a/scc/gui/userdata_manager.py +++ b/scc/gui/userdata_manager.py @@ -1,4 +1,4 @@ -"""SC-Controller - Profile Manager. +"""SC Controller - Profile Manager. Simple class that manages stuff related to creating, loading, listing (...) of user-editable data - that are profiles, menus and controller-icons. @@ -23,7 +23,7 @@ log = logging.getLogger("UDataManager") -class UserDataManager(object): +class UserDataManager: def __init__(self) -> None: profiles_path = get_profiles_path() diff --git a/scc/lib/daemon.py b/scc/lib/daemon.py index d51a91350..16ef1402f 100644 --- a/scc/lib/daemon.py +++ b/scc/lib/daemon.py @@ -11,7 +11,7 @@ import time -class Daemon(object): +class Daemon: """A generic daemon class. Usage: subclass the daemon class and override the run() method. diff --git a/scc/lib/hidparse.py b/scc/lib/hidparse.py index 73919f76f..2506489ce 100644 --- a/scc/lib/hidparse.py +++ b/scc/lib/hidparse.py @@ -74,7 +74,7 @@ class BusType(IntEnum): VIRTUAL = 0x06 -class ReservedItem(object): +class ReservedItem: _CACHE = {} def __init__(self, value): @@ -330,7 +330,7 @@ def get_report_descriptor(devfile, flat_list=False): return parse_report_descriptor(data, flat_list) -class Parser(object): +class Parser: def __init__(self, code, offset, count, size): self.code = code diff --git a/scc/lib/hidraw.py b/scc/lib/hidraw.py index 8f4d3b563..417258706 100644 --- a/scc/lib/hidraw.py +++ b/scc/lib/hidraw.py @@ -55,7 +55,7 @@ class DevInfo(NamedTuple): vendor: int product: int -class HIDRaw(object): +class HIDRaw: """Provide methods to access hidraw device's ioctls.""" def __init__(self, device): diff --git a/scc/lib/jsonencoder.py b/scc/lib/jsonencoder.py index 4260df9ab..ae4de7cb1 100644 --- a/scc/lib/jsonencoder.py +++ b/scc/lib/jsonencoder.py @@ -69,7 +69,7 @@ def replace(match): encode_basestring_ascii = ( c_encode_basestring_ascii or py_encode_basestring_ascii) -class JSONEncoder(object): +class JSONEncoder: """Extensible JSON encoder for Python data structures. Supports the following objects and types by default: diff --git a/scc/lib/xinput.py b/scc/lib/xinput.py index 2652dc227..1d029c2e6 100644 --- a/scc/lib/xinput.py +++ b/scc/lib/xinput.py @@ -18,15 +18,16 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ -import logging, re, subprocess +import logging +import re +import subprocess + log = logging.getLogger("XI") RE_DEVICE = re.compile(r"[ \t⎜]+↳ (.*)\tid=([0-9]+)[ \t]+\[([a-z ]+)") def get_devices(): - """ - Returns list of devices reported by xinput. - """ + """Return list of devices reported by xinput.""" rv = [] try: lst = (subprocess.Popen([ "xinput" ], stdout=subprocess.PIPE, stdin=None) @@ -48,7 +49,7 @@ def get_devices(): return rv -class XIDevice(object): +class XIDevice: def __init__(self, id, name, type): self._id = id self._name = name diff --git a/scc/mapper.py b/scc/mapper.py index a6b62bc78..ed0820c73 100644 --- a/scc/mapper.py +++ b/scc/mapper.py @@ -30,7 +30,7 @@ log = logging.getLogger("Mapper") -class Mapper(object): +class Mapper: DEBUG = False def __init__(self, profile, scheduler, keyboard=b"SCController Keyboard", diff --git a/scc/menu_data.py b/scc/menu_data.py index e408af979..c8d2130f8 100644 --- a/scc/menu_data.py +++ b/scc/menu_data.py @@ -1,15 +1,15 @@ -#!/usr/bin/env python3 -""" -SC-Controller - Menu Data +"""SC Controller - Menu Data Container for list of menu items + required parsers """ -from scc.tools import _, set_logging_level +import json +import os + from scc.actions import Action +from scc.tools import _, set_logging_level -import json, os -class MenuData(object): +class MenuData: """ Contains list of menu items. Indexable """ def __init__(self, *items): self.__items = list(items) @@ -189,7 +189,7 @@ def from_profile(filename, menuname, action_parser=None): return MenuData.from_json_data(data["menus"][menuname], action_parser) -class MenuItem(object): +class MenuItem: """ Really just dummy container """ def __init__(self, id, label, action=None, callback=None, icon=None): self.id = id @@ -260,7 +260,7 @@ def encode(self): return rv -class MenuGenerator(object): +class MenuGenerator: GENERATOR_NAME = None """ Generates list of MenuItems """ diff --git a/scc/osd/binding_display.py b/scc/osd/binding_display.py index 9300d963e..18f8bc68b 100644 --- a/scc/osd/binding_display.py +++ b/scc/osd/binding_display.py @@ -1,4 +1,4 @@ -"""SC-Controller - OSD Launcher. +"""SC Controller - OSD Launcher Display launcher with phone-like keyboard that user can use to select application (list is generated using xdg) and start it. @@ -178,7 +178,7 @@ def find_image(name): return None -class Line(object): +class Line: def __init__(self, icon, text): self.icons = [ icon ] @@ -199,7 +199,7 @@ def to_string(self): return "%-10s: %s" % (",".join([ x for x in self.icons if x ]), self.text) -class LineCollection(object): +class LineCollection: """ Allows calling add_icon on multiple lines at once """ def __init__(self, *lines): @@ -212,7 +212,7 @@ def add_icon(self, icon): return self -class Box(object): +class Box: PADDING = 5 SPACING = 2 MIN_WIDTH = 100 @@ -409,7 +409,7 @@ def place_marker(self, gen, root): ) -class Generator(object): +class Generator: PADDING = 10 def __init__(self, editor, profile): diff --git a/scc/osd/timermanager.py b/scc/osd/timermanager.py index 81c2999ed..8eccf5575 100644 --- a/scc/osd/timermanager.py +++ b/scc/osd/timermanager.py @@ -1,21 +1,16 @@ -#!/usr/bin/env python3 -""" -SC-Controller - Timer manager +"""SC Controller - Timer manager Simple abstract class for named, cancelable timers """ from gi.repository import GLib -class TimerManager(object): - def __init__(self): + +class TimerManager: + def __init__(self) -> None: self._timers = {} - def timer(self, name, delay, callback, *data, **kwdata): - """ - Runs callback after specified number of seconds. Uses - GLib.timeout_add_seconds with small wrapping to allow named - timers to be canceled by reset() call - """ + def timer(self, name, delay, callback, *data, **kwdata) -> None: + """Run callback after specified number of seconds. Uses GLib.timeout_add_seconds with small wrapping to allow named timers to be canceled by reset() call""" method = GLib.timeout_add_seconds if delay < 1 and delay > 0: method = GLib.timeout_add @@ -30,30 +25,26 @@ def timer(self, name, delay, callback, *data, **kwdata): # Create new one self._timers[name] = method(delay, self._callback, name, callback, *data, **kwdata) - def timer_active(self, name): - """ Returns True if named timer is active """ + def timer_active(self, name) -> bool: + """Return True if named timer is active""" return (name in self._timers) - def cancel_timer(self, name): - """ - Cancels named timer. Returns True on success, False if there is no such timer. - """ + def cancel_timer(self, name) -> bool: + """Cancel named timer. Returns True on success, False if there is no such timer.""" if name in self._timers: GLib.source_remove(self._timers[name]) del self._timers[name] return True return False - def cancel_all(self): - """ Cancels all active timers """ + def cancel_all(self) -> None: + """Cancel all active timers""" for x in self._timers: GLib.source_remove(self._timers[x]) self._timers = {} - def _callback(self, name, callback, *data, **kwdata): - """ - Removes name from list of active timers and calls real callback. - """ + def _callback(self, name, callback, *data, **kwdata) -> bool: + """Remove name from list of active timers and calls real callback.""" del self._timers[name] callback(*data, **kwdata) return False diff --git a/scc/parser.py b/scc/parser.py index 9df94b9b2..7eb6e530b 100644 --- a/scc/parser.py +++ b/scc/parser.py @@ -1,4 +1,4 @@ -"""SC Controller - ActionParser. +"""SC Controller - ActionParser Parses action(s) expressed as string or in dict loaded from json file into one or more Action instances. @@ -43,7 +43,7 @@ def build_action_constants() -> dict: return rv -class ActionParser(object): +class ActionParser: """Parse action expressed as string into Action instances. Usage: diff --git a/scc/poller.py b/scc/poller.py index 80b1fc3aa..1e6bb221b 100644 --- a/scc/poller.py +++ b/scc/poller.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -""" -SC-Controller - Poller +"""SC Controller - Poller Uses select to pool for file descriptors. Driver classes can use daemon.get_poller().register and .unregister to add file descriptors and @@ -8,48 +6,50 @@ Callback is called as callback(fd, event) where event is one of select.POLL* """ -import select, logging +import logging +import select + log = logging.getLogger("Poller") DO_NOTHING = lambda *a: False -class Poller(object): +class Poller: POLLIN = select.POLLIN POLLOUT = select.POLLOUT POLLPRI = select.POLLPRI - + def __init__(self): self._events = {} self._callbacks = {} self._pool_in = () self._pool_out = () self._pool_pri = () - - + + def register(self, fd, events, callback): if fd < 0: raise ValueError("Invalid file descriptor") self._events[fd] = events self._callbacks[fd] = callback self._generate_lists() - - + + def unregister(self, fd): if fd in self._events: del self._events[fd] if fd in self._callbacks: del self._callbacks[fd] self._generate_lists() - - + + def _generate_lists(self): self._pool_in = [ fd for fd, events in self._events.items() if events & Poller.POLLIN ] self._pool_out = [ fd for fd, events in self._events.items() if events & Poller.POLLOUT ] self._pool_pri = [ fd for fd, events in self._events.items() if events & Poller.POLLPRI ] - - + + def poll(self, timeout=0.01): inn, out, pri = select.select( self._pool_in, self._pool_out, self._pool_pri, timeout ) - + for fd in inn: self._callbacks.get(fd, DO_NOTHING)(fd, Poller.POLLIN) for fd in out: diff --git a/scc/profile.py b/scc/profile.py index a87d6b003..c38963325 100644 --- a/scc/profile.py +++ b/scc/profile.py @@ -1,23 +1,24 @@ -"""SC-Controller - Profile. +"""SC Controller - Profile Handles mapping profile stored in json file """ -from scc.constants import LEFT, RIGHT, CPAD, DPAD, WHOLE, STICK, RSTICK, GYRO -from scc.constants import SCButtons, HapticPos -from scc.special_actions import MenuAction -from scc.modifiers import HoldModifier +import json +import logging + +from scc.actions import NoAction +from scc.constants import CPAD, DPAD, GYRO, LEFT, RIGHT, RSTICK, STICK, WHOLE, HapticPos, SCButtons from scc.lib.jsonencoder import JSONEncoder -from scc.parser import TalkingActionParser from scc.menu_data import MenuData -from scc.actions import NoAction +from scc.modifiers import HoldModifier +from scc.parser import TalkingActionParser +from scc.special_actions import MenuAction -import json, logging log = logging.getLogger("profile") -class Profile(object): - VERSION = 1.4 # Current profile version. When loading profile file - # with version lower than this, auto-conversion may happen +class Profile: + # Current profile version. When loading profile file with version lower than this, auto-conversion may happen + VERSION = 1.4 LEFT = LEFT RIGHT = RIGHT diff --git a/scc/sccdaemon.py b/scc/sccdaemon.py index 217c40ad6..fc74d6094 100644 --- a/scc/sccdaemon.py +++ b/scc/sccdaemon.py @@ -1,4 +1,4 @@ -"""SC-Controller - Daemon class.""" +"""SC Controller - Daemon class.""" import stat from scc.lib import xwrappers as X @@ -1136,7 +1136,7 @@ def debug(self): self.sigterm() -class Client(object): +class Client: def __init__(self, connection, mapper, rfile, wfile): self.connection = connection self.rfile = rfile @@ -1419,7 +1419,7 @@ def whole(self, mapper, x, y, what): self.original_action.whole(mapper, x, y, what) -class Subprocess(object): +class Subprocess: """ Part of scc-daemon executed as another process, killed along with scc-daemon. Currently scc-osd-daemon and scc-windowswitch-daemon. diff --git a/scc/scheduler.py b/scc/scheduler.py index 6a464ce3f..d05afd3b6 100644 --- a/scc/scheduler.py +++ b/scc/scheduler.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -""" -SC-Controller - Scheduler +"""SC Controller - Scheduler Centralized scheduler that should be used everywhere. Runs in SCCDaemon's (single-threaded) mainloop. That means all callbacks are @@ -13,20 +11,20 @@ # TODO: Maybe create actual thread for this? Use poler? Scrap everything and rewrite it in GO? -class Scheduler(object): - +class Scheduler: + def __init__(self): self._scheduled = queue.PriorityQueue() self._next = None self._now = time.time() - - + + def schedule(self, delay, callback, *data): """ Schedules one-time task to be executed no sooner than after 'delay' of seconds. Delay may be float number. 'callback' is called as callback(*data). - + Returned Task instance can be used to cancel task once scheduled. """ task = Task(self._now + delay, callback, data) @@ -37,13 +35,13 @@ def schedule(self, delay, callback, *data): else: self._scheduled.put(task) return task - - + + def cancel_task(self, task): """ Returns True if task was sucessfully removed or False if task was already executed or not known at all. - + Note that this is slow as hell and completly thread-unsafe, so it _has_ to be called on main thread. """ @@ -62,8 +60,8 @@ def cancel_task(self, task): for t in tasks: self._scheduled.put(t) return found - - + + def run(self): self._now = time.time() while self._next and self._now >= self._next.time: @@ -72,14 +70,14 @@ def run(self): callback(*data) -class Task(object): - +class Task: + def __init__(self, time, callback, data): self.time = time self.callback = callback self.data = data - - + + def cancel(self): """ Marks task as canceled, without actually removing it from scheduler """ self.callback = lambda *a, **b: False diff --git a/scc/uinput.py b/scc/uinput.py index 13c87a3ee..2decbba06 100644 --- a/scc/uinput.py +++ b/scc/uinput.py @@ -213,7 +213,7 @@ def __init__(self): self.in_use = False -class UInput(object): +class UInput: """UInput class permits to create a uinput device. See Gamepad, Mouse, Keyboard for examples @@ -694,7 +694,7 @@ def releaseEvent(self, keys: list | None = None): self._pressed -= set(rem) -class Dummy(object): +class Dummy: """Fake uinput device that does nothing, but has all required methods.""" def __init__(self, *a, **b): diff --git a/scc/x11/autoswitcher.py b/scc/x11/autoswitcher.py index 3f708a54c..f6b0f5d4f 100644 --- a/scc/x11/autoswitcher.py +++ b/scc/x11/autoswitcher.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -""" -SC-Controller - Autoswitch Daemon +"""SC Controller - Autoswitch Daemon Observes active window and commands scc-daemon to change profiles as needed. """ @@ -19,7 +17,7 @@ import os, sys, re, time, socket, traceback, threading, logging log = logging.getLogger("AutoSwitcher") -class AutoSwitcher(object): +class AutoSwitcher: INTERVAL = 1 def __init__(self): @@ -198,7 +196,7 @@ def run(self): return 1 -class Condition(object): +class Condition: """ Represents AutoSwitcher condition loaded from configuration file. diff --git a/scc/x11/scc-osd-daemon.py b/scc/x11/scc-osd-daemon.py index f3e2afb02..939c8aad2 100755 --- a/scc/x11/scc-osd-daemon.py +++ b/scc/x11/scc-osd-daemon.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -"""SC-Controller - OSD Daemon. +"""SC Controller - OSD Daemon Controls stuff displayed as OSD. """ @@ -38,7 +38,7 @@ log = logging.getLogger("osd.daemon") -class OSDDaemon(object): +class OSDDaemon: def __init__(self): self.exit_code = -1 self.mainloop = GLib.MainLoop() diff --git a/tests/test_boolean.py b/tests/test_boolean.py index 2c41669bd..41aef40ac 100644 --- a/tests/test_boolean.py +++ b/tests/test_boolean.py @@ -1,7 +1,8 @@ from scc.actions import Action, NoAction -class TestBoolean(object): - + +class TestBoolean: + def test_noaction_is_false(self): """ Tests if None can be used as False boolean value. @@ -9,8 +10,8 @@ def test_noaction_is_false(self): assert not NoAction() if NoAction(): raise Exception("NoAction is True :(") - - + + def test_action_is_true(self): """ Tests if random action works as True boolean value. @@ -20,4 +21,3 @@ def test_action_is_true(self): if a: return raise Exception("Action is False :(") - diff --git a/tests/test_compress.py b/tests/test_compress.py index 672a9d721..441320fe6 100644 --- a/tests/test_compress.py +++ b/tests/test_compress.py @@ -1,10 +1,10 @@ -from scc.uinput import Keys, Axes, Rels -from scc.constants import SCButtons, HapticPos -from scc.modifiers import DoubleclickModifier from scc.actions import Action, AxisAction +from scc.constants import HapticPos, SCButtons from scc.macros import Macro -from scc.special_actions import MenuAction +from scc.modifiers import DoubleclickModifier from scc.parser import ActionParser +from scc.special_actions import MenuAction +from scc.uinput import Axes, Keys, Rels parser = ActionParser() @@ -112,7 +112,7 @@ "feedback": ["LEFT", 32640] }, "menu" : { - "action": "menu('Default.menu')", + "action": "menu('Default.menu')", "feedback": ["LEFT", 32640] }, "hold": { @@ -128,12 +128,12 @@ } } -class TestCompress(object): +class TestCompress: """ Tests Aciton.compress method. Basically, tests how various combinations of modifiers interacts together. """ - + def test_tests(self): # Test if there is key in CASES for every action that suppports # setting feedback or sensitivity. @@ -162,9 +162,9 @@ def test_tests(self): assert 'feedback' in CASES[cls.COMMAND], ( "%s supports feedback, but case for it has " "no 'feedback' key it" % ( - cls.COMMAND,)) - - + cls.COMMAND,)) + + def test_hold_doubleclick(self): """ Tests parsing of hold & doubleclick combination. @@ -174,7 +174,7 @@ def test_hold_doubleclick(self): 'hold' : { 'action' : "axis(ABS_X)" }, 'doubleclick' : { 'action' : "axis(ABS_Z)" } }).compress() - + assert isinstance(a, DoubleclickModifier) assert isinstance(a.normalaction, AxisAction) assert isinstance(a.action, AxisAction) @@ -182,8 +182,8 @@ def test_hold_doubleclick(self): assert a.normalaction.id == Axes.ABS_RX assert a.action.id == Axes.ABS_Z assert a.holdaction.id == Axes.ABS_X - - + + def test_sensitivity(self): """ Tests if all sensitivity setting are parsed and applied @@ -198,8 +198,8 @@ def test_sensitivity(self): or a.strip().get_speed() == CASES[case]['sensitivity'] ) - - + + def test_feedback(self): """ Tests if all feedback setting are parsed and applied @@ -210,8 +210,8 @@ def test_feedback(self): print("Testing 'feedback' on %s" % (case,)) a = parser.from_json_data(CASES[case]).compress() assert a.get_haptic().get_position().name == CASES[case]['feedback'][0] - - + + def test_multi(self): """ Tests if feedback and sensitivity setting are parsed and applied @@ -225,8 +225,8 @@ def test_multi(self): assert a.actions[0].get_haptic().get_position().name == "BOTH" for action in a.actions: assert action.get_speed()[0] == 2.0 - - + + def test_macro(self): """ Tests if feedback and sensitivity setting are parsed and applied diff --git a/tests/test_docs.py b/tests/test_docs.py index bf2b1e90b..83ab84fc9 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -1,15 +1,14 @@ from scc.actions import Action -import os -class TestDocs(object): +class TestDocs: """ Tests every glade file in glade/ directory (and subdirectories) for known problems that may cause GUI to crash in some environments. - + (one case on one environment so far) """ - + def test_every_action_has_docs(self): """ Tests if every known Action is documentated in docs/actions.md @@ -19,7 +18,7 @@ def test_every_action_has_docs(self): actions_md = f.read() with open("docs/profile-file.md") as f: profile_md = f.read() - + # Do stupid fulltext search, because currently it's simply fast enough for command in Action.ALL: if command in (None, 'None', 'exit'): @@ -27,7 +26,7 @@ def test_every_action_has_docs(self): continue anchor = '' % (command,) assert anchor in actions_md, "Action '%s' is not documented in actions.md" % (command,) - + for key in Action.PKEYS: anchor = '#### `%s`' % (key,) assert key in profile_md, "Key '%s' is not documented in profile-file.md" % (key,) diff --git a/tests/test_glade.py b/tests/test_glade.py index e49ae6b2f..71960939e 100644 --- a/tests/test_glade.py +++ b/tests/test_glade.py @@ -1,5 +1,6 @@ -import xml.etree.cElementTree as ET import os +import xml.etree.cElementTree as ET + def _get_files(): """ @@ -14,7 +15,7 @@ def recursive(path): recursive(filename) elif filename.endswith(".glade"): rv.append(filename) - + recursive("glade/") return rv @@ -33,14 +34,14 @@ def _check_ids(el, filename, parent_id): if subel.tag == "child": _check_ids(subel, filename, child.attrib['id']) -class TestGlade(object): +class TestGlade: """ Tests every glade file in glade/ directory (and subdirectories) for known problems that may cause GUI to crash in some environments. - + (one case on one environment so far) """ - + def test_every_widget_has_id(self): """ Tests if every defined widget has ID. diff --git a/tests/test_inputs.py b/tests/test_inputs.py index 69eefb205..cfc61597d 100644 --- a/tests/test_inputs.py +++ b/tests/test_inputs.py @@ -113,7 +113,7 @@ def clearRemainders(self): pass -class TestInputs(object): +class TestInputs: @input_test def test_button(self, mapper: Mapper): """Just a test for a test, this should work every time.""" diff --git a/tests/test_parser/test_actions.py b/tests/test_parser/test_actions.py index 92e2f0ffd..ea65f94bf 100644 --- a/tests/test_parser/test_actions.py +++ b/tests/test_parser/test_actions.py @@ -1,11 +1,14 @@ -from scc.uinput import Keys, Axes, Rels +import inspect + from scc.actions import * from scc.constants import HIPFIRE_SENSIBLE +from scc.uinput import Axes, Keys, Rels + from . import _parses_as_itself, parser -import inspect -class TestActions(object): - + +class TestActions: + def test_tests(self): """ Tests if this class has test for every Action defined in acitons.py. @@ -19,42 +22,42 @@ def test_tests(self): method_name = "test_%s" % (cls.COMMAND,) assert hasattr(self, method_name), \ "There is no test for %s" % (cls.COMMAND) - + def test_none(self): """ Tests if everything what should parse as NoAction parses as NoAction. """ assert not parser.restart("None").parse() assert not parser.restart("None()").parse() - - + + def test_axis(self): """ Tests if AxisAction can be converted to string and parsed back to same action. - """ + """ # With no optional parameters assert _parses_as_itself(AxisAction(Axes.ABS_X)) # With min and max set assert _parses_as_itself(AxisAction(Axes.ABS_X, -10, 10.0)) - - + + def test_raxis(self): """ Tests if RAxisAction can be converted to string and parsed back to same action. - """ + """ # With no optional parameters assert _parses_as_itself(RAxisAction(Axes.ABS_X)) # With min and max set assert _parses_as_itself(RAxisAction(Axes.ABS_X, -10, 10.0)) - - + + def test_hats(self): """ Tests if every Hat* actions can be converted to string and parsed back to same action. - """ + """ assert _parses_as_itself(HatUpAction(Axes.ABS_X)) assert _parses_as_itself(HatDownAction(Axes.ABS_X)) assert _parses_as_itself(HatLeftAction(Axes.ABS_X)) @@ -70,8 +73,8 @@ def test_mouse(self): assert _parses_as_itself(MouseAction(Rels.REL_WHEEL)) # Without axis (when used as trackbal) assert _parses_as_itself(MouseAction()) - - + + def test_mouseabs(self): """ Tests if MouseAbsAction can be converted to string and parsed back to @@ -81,40 +84,40 @@ def test_mouseabs(self): assert _parses_as_itself(MouseAbsAction(Rels.REL_X)) # Without axis (when used on pad directly) assert _parses_as_itself(MouseAbsAction()) - - + + def test_area(self): """ Tests if AreaAction can be converted to string and parsed back to same action. """ assert _parses_as_itself(AreaAction(10, 10, 50, 50)) - - + + def test_relarea(self): """ Tests if RelAreaAction can be converted to string and parsed back to same action. """ assert _parses_as_itself(RelAreaAction(10, 10, 50, 50)) - - + + def test_winarea(self): """ Tests if WinAreaAction can be converted to string and parsed back to same action. """ assert _parses_as_itself(WinAreaAction(10, 10, 50, 50)) - - + + def test_relwinarea(self): """ Tests if RelWinAreaAction can be converted to string and parsed back to same action. """ assert _parses_as_itself(RelWinAreaAction(10, 10, 50, 50)) - - + + def test_gyro(self): """ Tests if GyroAction can be converted to string and @@ -124,8 +127,8 @@ def test_gyro(self): assert _parses_as_itself(GyroAction(Axes.ABS_X)) assert _parses_as_itself(GyroAction(Axes.ABS_X, Axes.ABS_Y)) assert _parses_as_itself(GyroAction(Axes.ABS_X, Axes.ABS_Y, Axes.ABS_Z)) - - + + def test_gyroabs(self): """ Tests if GyroAbsAction can be converted to string and @@ -134,16 +137,16 @@ def test_gyroabs(self): assert _parses_as_itself(GyroAbsAction(Axes.ABS_X)) assert _parses_as_itself(GyroAbsAction(Axes.ABS_X, Axes.ABS_Y)) assert _parses_as_itself(GyroAbsAction(Axes.ABS_X, Axes.ABS_Y, Axes.ABS_Z)) - - + + def test_resetgyro(self): """ Tests if ResetGyroAction can be converted to string and parsed back to same action. """ assert _parses_as_itself(ResetGyroAction()) - - + + def test_tilt(self): """ Tests if TiltAction can be converted to string and @@ -156,16 +159,16 @@ def test_tilt(self): ButtonAction(Keys.KEY_D), ButtonAction(Keys.KEY_U), ButtonAction(Keys.KEY_L), ButtonAction(Keys.KEY_R) )) - - + + def test_trackball(self): """ Tests if TrackballAction can be converted to string and parsed back to same action. """ assert _parses_as_itself(TrackballAction()) - - + + def test_button(self): """ Tests if ButtonAction can be converted to string and parsed back to @@ -212,8 +215,8 @@ def test_dpad(self): ButtonAction(Keys.BTN_LEFT), ButtonAction(Keys.BTN_MIDDLE), )) - - + + def test_ring(self): """ Tests if DPadAction can be converted to string and @@ -231,8 +234,8 @@ def test_ring(self): AxisAction(Axes.ABS_Y) ) )) - - + + def test_dpad8(self): """ Tests if DPad8Action can be converted to string and @@ -260,8 +263,8 @@ def test_dpad8(self): ButtonAction(Keys.KEY_D), ButtonAction(Keys.BTN_MIDDLE), )) - - + + def test_XY(self): """ Tests if XYAciton can be converted to string and parsed back to @@ -271,8 +274,8 @@ def test_XY(self): AxisAction(Axes.ABS_X), AxisAction(Axes.ABS_Y) )) - - + + def test_relXY(self): """ Tests if relXYAciton can be converted to string and parsed back to @@ -282,8 +285,8 @@ def test_relXY(self): AxisAction(Axes.ABS_RX), AxisAction(Axes.ABS_RY) )) - - + + def test_trigger(self): """ Tests if TriggerAction can be converted to string and parsed back to diff --git a/tests/test_parser/test_macros.py b/tests/test_parser/test_macros.py index e0528d4a5..7553f5784 100644 --- a/tests/test_parser/test_macros.py +++ b/tests/test_parser/test_macros.py @@ -1,11 +1,14 @@ -from scc.uinput import Keys -from scc.actions import ButtonAction, AxisAction +import inspect + +from scc.actions import AxisAction, ButtonAction from scc.macros import * +from scc.uinput import Keys + from . import _parses_as_itself, parser -import inspect -class TestMacros(object): - + +class TestMacros: + def test_tests(self): """ Tests if this class has test for each known macro-related action defined. @@ -15,8 +18,8 @@ def test_tests(self): method_name = "test_%s" % (cls.COMMAND,) assert hasattr(self, method_name), \ "There is no test for %s" % (cls.COMMAND) - - + + def test_macro(self): """ Tests if Macro can be converted to string and parsed back to @@ -27,16 +30,16 @@ def test_macro(self): ButtonAction(Keys.BTN_RIGHT), ButtonAction(Keys.BTN_MIDDLE) )) - - + + def test_type(self): """ Tests if Type macro can be converted to string and parsed back to same action. """ assert _parses_as_itself(Type("ilovecandy")) - - + + def test_cycle(self): """ Tests if Cycle can be converted to string and parsed back to @@ -47,8 +50,8 @@ def test_cycle(self): ButtonAction(Keys.BTN_RIGHT), ButtonAction(Keys.BTN_MIDDLE) )) - - + + def test_repeat(self): """ Tests if Repeat can be converted to string and parsed back to @@ -60,32 +63,32 @@ def test_repeat(self): ButtonAction(Keys.BTN_RIGHT), ButtonAction(Keys.BTN_MIDDLE) ))) - - + + def test_sleep(self): """ Tests if SleepAction can be converted to string and parsed back to same action. """ assert _parses_as_itself(SleepAction(1.5)) - - + + def test_press(self): """ Tests if PressAction can be converted to string and parsed back to same action. """ assert _parses_as_itself(PressAction(Keys.BTN_LEFT)) - - + + def test_release(self): """ Tests if ReleaseAction can be converted to string and parsed back to same action. """ assert _parses_as_itself(ReleaseAction(Keys.BTN_LEFT)) - - + + def test_tap(self): """ Tests if TapAction can be converted to string diff --git a/tests/test_parser/test_modifiers.py b/tests/test_parser/test_modifiers.py index 05e5d40d9..4bc893060 100644 --- a/tests/test_parser/test_modifiers.py +++ b/tests/test_parser/test_modifiers.py @@ -1,12 +1,15 @@ -from scc.actions import Action, ButtonAction, AxisAction, MouseAction, GyroAction -from scc.constants import SCButtons, STICK, HapticPos -from scc.uinput import Keys, Axes, Rels -from scc.modifiers import * -from . import _parses_as_itself, _parse_compressed, parser import inspect -class TestModifiers(object): - +from scc.actions import Action, AxisAction, ButtonAction, GyroAction, MouseAction +from scc.constants import STICK, HapticPos, SCButtons +from scc.modifiers import * +from scc.uinput import Axes, Keys, Rels + +from . import _parse_compressed, _parses_as_itself, parser + + +class TestModifiers: + def test_tests(self): """ Tests if this class has test for each known modifier defined. @@ -16,8 +19,8 @@ def test_tests(self): method_name = "test_%s" % (cls.COMMAND,) assert hasattr(self, method_name), \ "There is no test for %s modifier" % (cls.COMMAND) - - + + def test_name(self): """ Tests if NameModifier is parsed @@ -25,64 +28,64 @@ def test_name(self): a = _parse_compressed("name('Not A Button', button(KEY_A))").compress() assert isinstance(a, ButtonAction) assert a.name == "Not A Button" - - + + def test_click(self): """ Tests if ClickModifier is parsed """ a = _parse_compressed("click(button(KEY_A))") assert isinstance(a, ClickModifier) - - + + def test_pressed(self): """ Tests if ReleasedModifier is parsed """ a = _parse_compressed("released(button(KEY_A))") assert isinstance(a, ReleasedModifier) - - + + def test_released(self): """ Tests if PressedModifier is parsed """ a = _parse_compressed("pressed(axis(KEY_A))") - assert isinstance(a, PressedModifier) - - + assert isinstance(a, PressedModifier) + + def test_touched(self): """ Tests if TouchedModifier is parsed """ a = _parse_compressed("touched(button(KEY_A))") assert isinstance(a, TouchedModifier) - - + + def test_untouched(self): """ Tests if UntouchedModifier is parsed """ a = _parse_compressed("untouched(button(KEY_A))") assert isinstance(a, UntouchedModifier) - - + + def test_circular(self): """ Tests if CircularModifier is parsed """ assert isinstance(_parse_compressed("circular(axis(ABS_X))"), CircularModifier) assert isinstance(_parse_compressed("circular(axis(REL_WHEEL))"), CircularModifier) - - + + def test_circularabs(self): """ Tests if CircularAbsModifier is parsed """ assert isinstance(_parse_compressed("circularabs(axis(ABS_X))"), CircularAbsModifier) assert isinstance(_parse_compressed("circularabs(axis(REL_WHEEL))"), CircularAbsModifier) - - + + def test_ball(self): """ Tests if BallModifier is parsed @@ -94,8 +97,8 @@ def test_ball(self): a = _parse_compressed("ball(mouse())") assert isinstance(a, BallModifier) assert isinstance(a.action, MouseAction) - - + + def test_smooth(self): """ Tests if SmoothModifier is parsed @@ -106,8 +109,8 @@ def test_smooth(self): assert a.action.id == Axes.ABS_X assert a.level == 5 assert a.multiplier == 0.3 - - + + def test_deadzone(self): """ Tests if DeadzoneModifier is parsed @@ -124,8 +127,8 @@ def test_deadzone(self): assert a.lower == 100 and a.upper == 2000 assert isinstance(a.action, AxisAction) assert a.action.id == Axes.ABS_X - - + + def test_mode(self): """ Tests if ModeModifier is parsed @@ -138,7 +141,7 @@ def test_mode(self): assert isinstance(a, ModeModifier) assert isinstance(a.mods[SCButtons.A], AxisAction) assert a.mods[SCButtons.A].id == Axes.ABS_X - + # With default a = _parse_compressed("""mode( A, axis(ABS_X), @@ -149,8 +152,8 @@ def test_mode(self): assert isinstance(a.mods[SCButtons.A], AxisAction) assert isinstance(a.default, ButtonAction) assert a.default.button == Keys.KEY_A - - + + def test_doubleclick(self): """ Tests if DoubleclickModifier is parsed @@ -170,8 +173,8 @@ def test_doubleclick(self): assert isinstance(a.normalaction, AxisAction) and a.normalaction.id == Axes.ABS_Y assert not a.holdaction assert a.timeout == 1.5 - - + + def test_hold(self): """ Tests if HoldModifier is parsed @@ -190,9 +193,9 @@ def test_hold(self): assert isinstance(a.holdaction, AxisAction) and a.holdaction.id == Axes.ABS_X assert isinstance(a.normalaction, AxisAction) and a.normalaction.id == Axes.ABS_Y assert not a.action - assert a.timeout == 1.5 - - + assert a.timeout == 1.5 + + def test_hold_doubleclick_combinations(self): """ Tests if combinations of DoubleclickModifier and HoldModifier @@ -214,8 +217,8 @@ def test_hold_doubleclick_combinations(self): assert isinstance(a.action, AxisAction) and a.action.id == Axes.ABS_Z assert isinstance(a.holdaction, AxisAction) and a.holdaction.id == Axes.ABS_RZ assert isinstance(a.normalaction, AxisAction) and a.normalaction.id == Axes.ABS_X - - + + def test_sens(self): """ Tests if SensitivityModifier can be converted to string and parsed @@ -225,19 +228,19 @@ def test_sens(self): assert _parse_compressed("sens(2, axis(ABS_X))").strip().get_speed() == (2.0,) assert _parse_compressed("sens(2, 3, mouse())").strip().get_speed() == (2.0, 3.0) assert _parse_compressed("sens(2, 3, 4, gyro(ABS_RZ, ABS_RX, ABS_Z))").strip().get_speed() == (2.0, 3.0, 4.0) - + # Basic modifiers, sensitivity should always end applied to mouse() action a = _parse_compressed("sens(2, 3, click(mouse()))") assert isinstance(a.action, MouseAction) and a.action.get_speed() == (2.0, 3.0) a = _parse_compressed("sens(2, 3, deadzone(2.0, mouse()))") assert isinstance(a.action, MouseAction) and a.action.get_speed() == (2.0, 3.0) - + # Special case, sensitivity should be applied to ball(), not mouse() a = _parse_compressed("sens(2, 3, ball(mouse()))") assert isinstance(a.action, MouseAction) and a.action.get_speed() == (1.0, 1.0) assert isinstance(a, BallModifier) and a.get_speed() == (2.0, 3.0) - - + + def test_feedback(self): """ Tests if FeedbackModifier can be converted to string and parsed @@ -251,8 +254,8 @@ def test_feedback(self): # Bellow was failing in past assert _parses_as_itself(FeedbackModifier(HapticPos.LEFT, MouseAction())) assert _parses_as_itself(FeedbackModifier(HapticPos.RIGHT, MouseAction())) - - + + def test_rotate(self): """ Tests if RotateInputModifier can be converted to string and parsed @@ -260,4 +263,3 @@ def test_rotate(self): """ a = _parse_compressed("rotate(61, mouse())") assert isinstance(a, RotateInputModifier) - diff --git a/tests/test_parser/test_special_actions.py b/tests/test_parser/test_special_actions.py index 4754d83cc..f9f3add6d 100644 --- a/tests/test_parser/test_special_actions.py +++ b/tests/test_parser/test_special_actions.py @@ -1,14 +1,16 @@ -from scc.uinput import Keys, Axes, Rels -from scc.constants import SCButtons, STICK +import inspect + +from scc.constants import STICK, SCButtons from scc.special_actions import * +from scc.uinput import Axes, Keys, Rels + from . import _parses_as_itself, parser -import inspect MENU_CLASSES = (MenuAction, HorizontalMenuAction, GridMenuAction, RadialMenuAction, QuickMenuAction) -class TestSpecialActions(object): - +class TestSpecialActions: + def test_tests(self): """ Tests if this class has test for each known SpecialAction defined. @@ -22,48 +24,48 @@ def test_tests(self): method_name = "test_%s" % (cls.COMMAND,) assert hasattr(self, method_name), \ "There is no test for %s" % (cls.COMMAND) - - + + def test_profile(self): """ Tests if ChangeProfileAction can be converted to string and parsed back to same action. """ assert _parses_as_itself(ChangeProfileAction("profile")) - - + + def test_shell(self): """ Tests if ShellAction can be converted to string and parsed back to same action. """ assert _parses_as_itself(ShellCommandAction("ls -la")) - - + + def test_turnoff(self): """ Tests if TurnOffAction can be converted to string and parsed back to same action. """ assert _parses_as_itself(TurnOffAction()) - - + + def test_restart(self): """ Tests if RestartDaemonAction can be converted to string and parsed back to same action. """ assert _parses_as_itself(RestartDaemonAction()) - - + + def test_led(self): """ Tests if LockedAction can be converted to string and parsed back to same action. """ assert _parses_as_itself(LedAction(66)) - - + + def test_osd(self): """ Tests if OSDAction can be converted to string and parsed back to @@ -73,8 +75,8 @@ def test_osd(self): assert _parses_as_itself(OSDAction("Hello")) # With subaction assert _parses_as_itself(OSDAction(TurnOffAction())) - - + + def test_clearosd(self): """ Tests if ClearOSDAction can be converted to string and parsed back to @@ -82,8 +84,8 @@ def test_clearosd(self): """ # With text assert _parses_as_itself(ClearOSDAction()) - - + + def test_menus(self): """ Tests if all Menu*Actions can be converted to string and parsed @@ -99,8 +101,8 @@ def test_menus(self): SCButtons.Y)) assert _parses_as_itself(cls('menu1', STICK, SCButtons.X, SCButtons.Y, True)) - - + + def test_dialog(self): """ Tests if all Menu*Actions can be converted to string and parsed @@ -114,24 +116,24 @@ def test_dialog(self): "Some Text", NameModifier('Option', OSDAction('display this')))) assert _parses_as_itself(DialogAction(SCButtons.X, SCButtons.Y, "Some Text", NameModifier('Option', OSDAction('display this')))) - - + + def test_position(self): """ Tests if PositionModifier can be converted to string and parsed back to same action. """ assert _parses_as_itself(PositionModifier(14, -34, MenuAction('menu1'))) - - + + def test_keyboard(self): """ Tests if KeyboardAction can be converted to string and parsed back to same action. """ assert _parses_as_itself(KeyboardAction()) - - + + def test_gestures(self): """ Tests if GesturesAction can be converted to string and parsed back to @@ -143,11 +145,10 @@ def test_gestures(self): 'LRLR', TurnOffAction() ) ) - - + + def test_cemuhook(self): """ Nothing to test here """ pass - diff --git a/tests/test_profile/test_actions.py b/tests/test_profile/test_actions.py index ff4e1b08f..5b0198f3a 100644 --- a/tests/test_profile/test_actions.py +++ b/tests/test_profile/test_actions.py @@ -1,17 +1,20 @@ -from scc.uinput import Keys, Axes, Rels +import inspect + from scc.actions import * from scc.modifiers import BallModifier +from scc.uinput import Axes, Keys, Rels + from . import parser -import inspect -class TestActions(object): - + +class TestActions: + # def test_tests(self): # Tests if this class has test for every Action defined in actions.py. # Removed: profile is not parsed this way anymore, so newly added actions # don't have to support what's tested. - - + + def test_none(self): """ Tests if empty json dict or dict without action is parsed NoAction. @@ -19,49 +22,49 @@ def test_none(self): assert isinstance(parser.from_json_data({}), NoAction) assert isinstance(parser.from_json_data({ 'action' : 'None' }), NoAction) assert isinstance(parser.from_json_data({ '___' : 'Invalid' }), NoAction) - - + + def test_axis(self): """ Tests if AxisAction is parsed correctly from json. """ assert isinstance(parser.from_json_data({ 'action' : 'axis(ABS_X)' }), AxisAction) assert parser.from_json_data({ 'action' : 'axis(ABS_X)' }).id == Axes.ABS_X - - + + def test_raxis(self): """ Tests if RAxisAction is parsed correctly from json. """ assert isinstance(parser.from_json_data({ 'action' : 'raxis(ABS_X)' }), RAxisAction) assert parser.from_json_data({ 'action' : 'raxis(ABS_X)' }).id == Axes.ABS_X - - + + def test_hats(self): """ Tests if every Hat* actions can be parsed correctly from json. - """ + """ assert isinstance(parser.from_json_data({ 'action' : 'hatup(ABS_X)' }), HatUpAction) assert isinstance(parser.from_json_data({ 'action' : 'hatdown(ABS_X)' }), HatDownAction) assert isinstance(parser.from_json_data({ 'action' : 'hatleft(ABS_X)' }), HatLeftAction) assert isinstance(parser.from_json_data({ 'action' : 'hatright(ABS_X)' }), HatRightAction) - + assert parser.from_json_data({ 'action' : 'hatup(ABS_X)' }).id == Axes.ABS_X assert parser.from_json_data({ 'action' : 'hatdown(ABS_X)' }).id == Axes.ABS_X assert parser.from_json_data({ 'action' : 'hatleft(ABS_X)' }).id == Axes.ABS_X assert parser.from_json_data({ 'action' : 'hatright(ABS_X)' }).id == Axes.ABS_X - + assert parser.from_json_data({ 'action' : 'hatup(ABS_X)' }).min == 0 assert parser.from_json_data({ 'action' : 'hatdown(ABS_X)' }).min == 0 assert parser.from_json_data({ 'action' : 'hatleft(ABS_X)' }).min == 0 assert parser.from_json_data({ 'action' : 'hatright(ABS_X)' }).min == 0 - + assert parser.from_json_data({ 'action' : 'hatup(ABS_X)' }).max == STICK_PAD_MIN + 1 assert parser.from_json_data({ 'action' : 'hatdown(ABS_X)' }).max == STICK_PAD_MAX - 1 assert parser.from_json_data({ 'action' : 'hatleft(ABS_X)' }).max == STICK_PAD_MIN + 1 assert parser.from_json_data({ 'action' : 'hatright(ABS_X)' }).max == STICK_PAD_MAX - 1 - - + + def test_mouse(self): """ Tests if MouseAction is parsed correctly from json. @@ -77,73 +80,73 @@ def test_mouseabs(self): """ assert parser.from_json_data({ 'action' : 'mouseabs(REL_X)' })._mouse_axis == Rels.REL_X assert parser.from_json_data({ 'action' : 'mouseabs()' })._mouse_axis is None - - + + def test_area(self): """ Tests if AreaAction are parsed correctly from json. """ assert isinstance(parser.from_json_data({ 'action' : 'area(10, 10, 50, 50)' }), AreaAction) assert parser.from_json_data({ 'action' : 'area(10, 10, 50, 50)' }).coords == (10, 10, 50, 50) - - + + def test_relarea(self): """ Tests if RelAreaAction are parsed correctly from json. """ assert isinstance(parser.from_json_data({ 'action' : 'relarea(10, 10, 50, 50)' }), RelAreaAction) assert parser.from_json_data({ 'action' : 'relarea(10, 10, 50, 50)' }).coords == (10, 10, 50, 50) - - + + def test_winarea(self): """ Tests if WinAreaAction are parsed correctly from json. """ assert isinstance(parser.from_json_data({ 'action' : 'winarea(10, 10, 50, 50)' }), WinAreaAction) assert parser.from_json_data({ 'action' : 'winarea(10, 10, 50, 50)' }).coords == (10, 10, 50, 50) - - + + def test_relwinarea(self): """ Tests if RelWinAreaAction are parsed correctly from json. """ assert isinstance(parser.from_json_data({ 'action' : 'relwinarea(10, 10, 50, 50)' }), RelWinAreaAction) assert parser.from_json_data({ 'action' : 'relwinarea(10, 10, 50, 50)' }).coords == (10, 10, 50, 50) - - + + def test_gyro(self): """ Tests if GyroAction is parsed correctly from json. """ assert isinstance(parser.from_json_data({ 'action' : 'gyro(ABS_X)' }), GyroAction) - + assert parser.from_json_data({ 'action' : 'gyro(ABS_X)' }).axes[0] == Axes.ABS_X assert parser.from_json_data({ 'action' : 'gyro(ABS_X)' }).axes[1] is None assert parser.from_json_data({ 'action' : 'gyro(ABS_X, ABS_Y)' }).axes[1] == Axes.ABS_Y assert parser.from_json_data({ 'action' : 'gyro(ABS_X, ABS_Y)' }).axes[2] is None assert parser.from_json_data({ 'action' : 'gyro(ABS_X, ABS_Y, ABS_Z)' }).axes[2] == Axes.ABS_Z - - + + def test_gyroabs(self): """ Tests if GyroAbsAction is parsed correctly from json. """ assert isinstance(parser.from_json_data({ 'action' : 'gyroabs(ABS_X)' }), GyroAbsAction) - + assert parser.from_json_data({ 'action' : 'gyroabs(ABS_X)' }).axes[0] == Axes.ABS_X assert parser.from_json_data({ 'action' : 'gyroabs(ABS_X)' }).axes[1] is None assert parser.from_json_data({ 'action' : 'gyroabs(ABS_X, ABS_Y)' }).axes[1] == Axes.ABS_Y assert parser.from_json_data({ 'action' : 'gyroabs(ABS_X, ABS_Y)' }).axes[2] is None assert parser.from_json_data({ 'action' : 'gyroabs(ABS_X, ABS_Y, ABS_Z)' }).axes[2] == Axes.ABS_Z - - + + def test_resetgyro(self): """ Tests if ResetGyroAction is parsed correctly from json. """ assert isinstance(parser.from_json_data({ 'action' : 'resetgyro()' }), ResetGyroAction) - - + + def test_tilt(self): """ Tests if TiltAction can be converted to string and @@ -153,13 +156,13 @@ def test_tilt(self): assert parser.from_json_data({ 'action' : 'tilt( button(KEY_D) )' }).actions[0].button == Keys.KEY_D - + # With all buttons assert parser.from_json_data({ 'action' : 'tilt( button(KEY_D), button(KEY_U), button(KEY_L), button(KEY_R))' }).actions[3].button == Keys.KEY_R - - + + def test_trackball(self): """ Tests if TrackballAction is parsed correctly from json. @@ -168,20 +171,20 @@ def test_trackball(self): a = parser.from_json_data({ 'action' : 'trackball' }) assert isinstance(a, BallModifier) assert isinstance(a.action, MouseAction) - - + + def test_button(self): """ Tests if ButtonAction is parsed correctly from json. """ assert isinstance(parser.from_json_data({ 'action' : 'button(KEY_X)' }), ButtonAction) - + assert parser.from_json_data({ 'action' : 'button(KEY_X)' }).button == Keys.KEY_X assert parser.from_json_data({ 'action' : 'button(KEY_X)' }).button2 is None assert parser.from_json_data({ 'action' : 'button(KEY_X, KEY_Z)' }).button == Keys.KEY_X assert parser.from_json_data({ 'action' : 'button(KEY_X, KEY_Z)' }).button2 == Keys.KEY_Z - - + + def test_multiaction(self): """ Tests if MultiAction is parsed correctly from json. @@ -192,8 +195,8 @@ def test_multiaction(self): assert a.actions[0].button == Keys.KEY_X assert isinstance(a.actions[1], ButtonAction) assert a.actions[1].button == Keys.KEY_Y - - + + def test_dpad(self): """ Tests if DPadAction is parsed correctly from json. @@ -209,12 +212,12 @@ def test_dpad(self): 'action' : 'button(KEY_D)' }] }) - + assert isinstance(a, DPadAction) for sub in a.actions: assert isinstance(sub, ButtonAction) - - + + def test_ring(self): """ Tests if DPadAction is parsed correctly from json. @@ -239,15 +242,15 @@ def test_ring(self): } } }) - + assert isinstance(a.outer, DPadAction) for sub in a.outer.actions: assert isinstance(sub, ButtonAction) assert isinstance(a.inner, XYAction) for sub in a.inner.actions: assert isinstance(sub, AxisAction) - - + + def test_dpad8(self): """ Tests if DPad8Action is parsed correctly from json. @@ -271,14 +274,14 @@ def test_dpad8(self): 'action' : 'button(KEY_H)' }] }) - + print(a) print(a.actions) assert isinstance(a, DPadAction) for sub in a.actions: assert isinstance(sub, ButtonAction) - - + + def test_XY(self): """ Tests if XYAction is parsed correctly from json. @@ -287,12 +290,12 @@ def test_XY(self): 'X' : { 'action' : 'axis(ABS_X)' }, 'Y' : { 'action' : 'axis(ABS_Y)' }, }) - + assert isinstance(a, XYAction) assert isinstance(a.x, AxisAction) assert isinstance(a.y, AxisAction) - - + + def test_trigger(self): """ Tests if TriggerAction is parsed correctly from json. @@ -301,7 +304,7 @@ def test_trigger(self): 'action' : 'button(KEY_X)', 'levels' : [ 10, 80 ] }) - + assert isinstance(a, TriggerAction) assert isinstance(a.action, ButtonAction) assert a.press_level == 10 diff --git a/tests/test_profile/test_modeshift.py b/tests/test_profile/test_modeshift.py index 77f42af2e..132020cf5 100644 --- a/tests/test_profile/test_modeshift.py +++ b/tests/test_profile/test_modeshift.py @@ -4,7 +4,7 @@ from . import parser -class TestModeshift(object): +class TestModeshift: """Test various combinations of modeshift and modifiers. Most are based on stuff that was failing in past. diff --git a/tests/test_profile/test_modifiers.py b/tests/test_profile/test_modifiers.py index 54bc3cbd2..8eed948f5 100644 --- a/tests/test_profile/test_modifiers.py +++ b/tests/test_profile/test_modifiers.py @@ -1,9 +1,12 @@ -from scc.uinput import Keys, Axes, Rels -from scc.actions import ButtonAction, AxisAction, GyroAction -from scc.constants import SCButtons, HapticPos +import inspect + +from scc.actions import AxisAction, ButtonAction, GyroAction +from scc.constants import HapticPos, SCButtons from scc.modifiers import * +from scc.uinput import Axes, Keys, Rels + from . import parser -import inspect + def _is_axis_with_value(a, value=Axes.ABS_X): """ @@ -15,8 +18,8 @@ def _is_axis_with_value(a, value=Axes.ABS_X): return True -class TestModifiers(object): - +class TestModifiers: + def test_tests(self): """ Tests if this class has test for each known modifier defined. @@ -26,8 +29,8 @@ def test_tests(self): method_name = "test_%s" % (cls.COMMAND,) assert hasattr(self, method_name), \ "There is no test for %s modifier" % (cls.COMMAND) - - + + def test_name(self): """ Tests if NameModifier is parsed correctly from json. @@ -36,13 +39,13 @@ def test_name(self): 'action' : "axis(ABS_X)", 'name' : 'hithere' }) - + # NameModifier is lost in parsing assert not isinstance(a, NameModifier) assert a.name == 'hithere' assert _is_axis_with_value(a) - - + + def test_click(self): """ Tests if ClickModifier is parsed correctly from json. @@ -51,11 +54,11 @@ def test_click(self): 'action' : "axis(ABS_X)", 'click' : True }) - + assert isinstance(a, ClickModifier) assert _is_axis_with_value(a.action) - - + + def test_pressed(self): """ Tests if PressedModifier is parsed correctly from json. @@ -63,8 +66,8 @@ def test_pressed(self): a = parser.from_json_data({ 'action' : "pressed(axis(ABS_X))" }) assert isinstance(a, PressedModifier) assert _is_axis_with_value(a.action) - - + + def test_released(self): """ Tests if ReleasedModifier is parsed correctly from json. @@ -72,24 +75,24 @@ def test_released(self): a = parser.from_json_data({ 'action' : "released(axis(ABS_X))" }) assert isinstance(a, ReleasedModifier) assert _is_axis_with_value(a.action) - - + + def test_touched(self): """ Tests if TouchedModifier is parsed correctly from json. """ a = parser.from_json_data({ 'action' : "touched(button(KEY_A))" }) assert isinstance(a, TouchedModifier) - - + + def test_untouched(self): """ Tests if UntouchedModifier is parsed correctly from json. """ a = parser.from_json_data({ 'action' : "untouched(button(KEY_A))" }) assert isinstance(a, UntouchedModifier) - - + + def test_circular(self): """ Tests if CircularModifier is parsed correctly from json. @@ -99,8 +102,8 @@ def test_circular(self): 'circular' : True }) assert isinstance(a, CircularModifier) - - + + def test_circularabs(self): """ Tests if CircularModifier is parsed correctly from json. @@ -110,8 +113,8 @@ def test_circularabs(self): 'circularabs' : True }) assert isinstance(a, CircularAbsModifier) - - + + def test_ball(self): """ Tests if BallModifier is parsed correctly from json. @@ -120,11 +123,11 @@ def test_ball(self): 'action' : "axis(ABS_X)", 'ball' : True }) - + assert isinstance(a, BallModifier) assert _is_axis_with_value(a.action) - - + + def test_smooth(self): """ Tests if SmoothModifier is parsed correctly from json. @@ -133,13 +136,13 @@ def test_smooth(self): 'action' : "axis(ABS_X)", 'smooth' : [ 5, 0.3 ] }) - + assert isinstance(a, SmoothModifier) assert a.level == 5 assert a.multiplier == 0.3 assert _is_axis_with_value(a.action) - - + + def test_deadzone(self): """ Tests if DeadzoneModifier is parsed correctly from json. @@ -149,22 +152,22 @@ def test_deadzone(self): 'action' : "axis(ABS_X)", 'deadzone' : { 'upper' : 300 } }) - + assert isinstance(a, DeadzoneModifier) assert a.upper == 300 assert _is_axis_with_value(a.action) - + # Two parameters a = parser.from_json_data({ 'action' : "axis(ABS_X)", 'deadzone' : { 'upper' : 300, 'lower' : 50 } }) - + assert isinstance(a, DeadzoneModifier) assert a.lower == 50 assert _is_axis_with_value(a.action) - - + + def test_sens(self): """ Tests if SensitivityModifier is parsed correctly from json. @@ -177,7 +180,7 @@ def test_sens(self): assert isinstance(a, SensitivityModifier) assert a.speeds == [ 2.0, 3.0, 4.0 ] assert _is_axis_with_value(a.action) - + # Hold and doubleclick a = parser.from_json_data({ 'hold' : { @@ -194,7 +197,7 @@ def test_sens(self): assert isinstance(a.holdaction, MouseAction) and a.holdaction.get_speed() == ( 3.0, 4.0 ) assert isinstance(a.action, GyroAction) and a.action.get_speed() == ( 7.0, 8.0, 9.0 ) assert isinstance(a.normalaction, AxisAction) and a.normalaction.get_speed() == ( 10.0, ) - + # Modeshift a = parser.from_json_data({ 'modes' : { @@ -218,8 +221,8 @@ def test_sens(self): assert isinstance(a.mods[SCButtons.B], AxisAction) and a.mods[SCButtons.B].get_speed() == ( 7.0, ) assert isinstance(a.mods[SCButtons.X], GyroAction) and a.mods[SCButtons.X].get_speed() == ( 8.0, 9.0, 10.0 ) assert isinstance(a.default, AxisAction) and a.default.get_speed() == ( 12.0, ) - - + + def test_feedback(self): """ Tests if FeedbackModifier is parsed correctly from json. @@ -229,25 +232,25 @@ def test_feedback(self): 'action' : "axis(ABS_X)", 'feedback' : [ "BOTH" ] }) - + assert isinstance(a, FeedbackModifier) assert a.haptic.get_position() == HapticPos.BOTH assert _is_axis_with_value(a.action) - + # All parameters a = parser.from_json_data({ 'action' : "axis(ABS_X)", 'feedback' : [ "RIGHT", 1024, 8, 2048 ] }) - + assert isinstance(a, FeedbackModifier) assert a.haptic.get_position() == HapticPos.RIGHT assert a.haptic.get_amplitude() == 1024 assert a.haptic.get_frequency() == 8 assert a.haptic.get_period() == 2048 assert _is_axis_with_value(a.action) - - + + def test_rotate(self): """ Tests if RotateInputModifier is parsed correctly from json. @@ -256,12 +259,12 @@ def test_rotate(self): 'action' : "axis(ABS_X)", 'rotate' : 33.14 }) - + assert isinstance(a, RotateInputModifier) assert a.angle == 33.14 assert _is_axis_with_value(a.action) - - + + def test_mode(self): """ Tests if ModeModifier is parsed correctly from json. @@ -274,12 +277,12 @@ def test_mode(self): 'LT' : { 'action' : "axis(ABS_Z)" }, } }) - + assert isinstance(a, ModeModifier) assert _is_axis_with_value(a.mods[SCButtons.A], Axes.ABS_X) assert _is_axis_with_value(a.mods[SCButtons.B], Axes.ABS_Y) assert _is_axis_with_value(a.mods[SCButtons.LT], Axes.ABS_Z) - + # With default a = parser.from_json_data({ 'action' : 'axis(ABS_RX)', @@ -288,13 +291,13 @@ def test_mode(self): 'RT' : { 'action' : "axis(ABS_Z)" }, } }) - + assert isinstance(a, ModeModifier) assert _is_axis_with_value(a.default, Axes.ABS_RX) assert _is_axis_with_value(a.mods[SCButtons.X], Axes.ABS_X) assert _is_axis_with_value(a.mods[SCButtons.RT], Axes.ABS_Z) - - + + def test_doubleclick(self): """ Tests if DoubleclickModifier is parsed correctly from json. @@ -305,13 +308,13 @@ def test_doubleclick(self): 'action' : "axis(ABS_X)" } }) - + assert isinstance(a, DoubleclickModifier) assert _is_axis_with_value(a.normalaction, Axes.ABS_RX) assert _is_axis_with_value(a.action, Axes.ABS_X) assert not a.holdaction - - + + def test_hold(self): """ Tests if HoldModifier is parsed correctly from json. @@ -322,7 +325,7 @@ def test_hold(self): 'action' : "axis(ABS_X)" } }) - + assert isinstance(a, HoldModifier) assert _is_axis_with_value(a.normalaction, Axes.ABS_RX) assert _is_axis_with_value(a.holdaction, Axes.ABS_X) diff --git a/tests/test_profile/test_special_actions.py b/tests/test_profile/test_special_actions.py index baaabd3d7..18ec93d8e 100644 --- a/tests/test_profile/test_special_actions.py +++ b/tests/test_profile/test_special_actions.py @@ -1,21 +1,23 @@ -from scc.uinput import Keys, Axes, Rels -from scc.constants import SCButtons, HapticPos -from scc.special_actions import * +import inspect + from scc.actions import ButtonAction +from scc.constants import HapticPos, SCButtons +from scc.special_actions import * +from scc.uinput import Axes, Keys, Rels + from . import parser -import inspect MENU_CLASSES = (MenuAction, HorizontalMenuAction, GridMenuAction, RadialMenuAction, QuickMenuAction) -class TestSpecialActions(object): - +class TestSpecialActions: + # def test_tests(self): # Tests if this class has test for each known SpecialAction defined. # Removed: profile is not parsed this way anymore, so newly added actions # don't have to support what's tested. - - + + def test_profile(self): """ Tests if ChangeProfileAction is parsed correctly from json. @@ -23,8 +25,8 @@ def test_profile(self): a = parser.from_json_data({ 'action' : "profile('xyz')" }) assert isinstance(a, ChangeProfileAction) assert a.profile == "xyz" - - + + def test_shell(self): """ Tests if ShellCommandAction is parsed correctly from json. @@ -32,24 +34,24 @@ def test_shell(self): a = parser.from_json_data({ 'action' : "shell('ls -la')" }) assert isinstance(a, ShellCommandAction) assert a.command == "ls -la" - - + + def test_turnoff(self): """ Tests if TurnOffAction is parsed correctly from json. """ a = parser.from_json_data({ 'action' : "turnoff" }) assert isinstance(a, TurnOffAction) - - + + def test_restart(self): """ Tests if RestartDaemonAction is parsed correctly from json. """ a = parser.from_json_data({ 'action' : "restart" }) assert isinstance(a, RestartDaemonAction) - - + + def test_led(self): """ Tests if LockedAction is parsed correctly from json. @@ -57,8 +59,8 @@ def test_led(self): a = parser.from_json_data({ 'action' : "led(66)" }) assert isinstance(a, LedAction) assert a.brightness == 66 - - + + def test_osd(self): """ Tests if OSDAction is parsed correctly from json. @@ -74,8 +76,8 @@ def test_osd(self): }) assert isinstance(a, OSDAction) assert isinstance(a.action, ButtonAction) - - + + def test_dialog(self): """ Tests if all Menu*Actions are parsed correctly from json. @@ -98,8 +100,8 @@ def test_dialog(self): assert len(a.options) == 2 assert a.options[0].describe(Action.AC_MENU) == "button" assert a.options[0].strip().text == "something" - - + + def test_menus(self): """ Tests if all Menu*Actions are parsed correctly from json. @@ -112,8 +114,8 @@ def test_menus(self): assert a.confirm_with == SCButtons.X assert a.cancel_with == SCButtons.Y assert a.show_with_release == True - - + + def test_position(self): """ Tests if PositionModifier is parsed correctly from json. @@ -122,12 +124,12 @@ def test_position(self): 'action' : "menu('some.menu', LEFT, X, Y, True)", 'position' : [ -10, 10 ] }).compress() - + assert isinstance(a, MenuAction) assert a.x == -10 assert a.y == 10 - - + + def test_keyboard(self): """ Tests if KeyboardAction is parsed correctly from json. @@ -135,8 +137,8 @@ def test_keyboard(self): # With text a = parser.from_json_data({ 'action' : "keyboard" }) assert isinstance(a, KeyboardAction) - - + + def test_gestures(self): """ Tests if GesturesAction is parsed correctly from json. @@ -161,11 +163,10 @@ def test_gestures(self): assert isinstance(a, OSDAction) assert isinstance(a.action, GesturesAction) assert isinstance(a.action.gestures['UD'], TurnOffAction) - - + + def test_cemuhook(self): """ Nothing to test here """ pass - diff --git a/tests/test_setup.py b/tests/test_setup.py index 7d421d89d..eaae01660 100644 --- a/tests/test_setup.py +++ b/tests/test_setup.py @@ -5,7 +5,7 @@ import scc -class TestSetup(object): +class TestSetup: """Test if SCC should be installable.""" def test_packages(self): diff --git a/tests/test_strings/test_keys.py b/tests/test_strings/test_keys.py index 3aac00a6a..757f87b58 100644 --- a/tests/test_strings/test_keys.py +++ b/tests/test_strings/test_keys.py @@ -3,8 +3,8 @@ from scc.uinput import Keys -class TestKeys(object): - def test_up_str(self): - assert isinstance(Keys.KEY_UP, IntEnum) - assert Keys.KEY_UP.name == "KEY_UP" - assert Keys.KEY_UP == 103 +class TestKeys: + def test_up_str(self): + assert isinstance(Keys.KEY_UP, IntEnum) + assert Keys.KEY_UP.name == "KEY_UP" + assert Keys.KEY_UP == 103 diff --git a/tests/test_strings/test_modifiers.py b/tests/test_strings/test_modifiers.py index 981bd9bc1..989ee1b3f 100644 --- a/tests/test_strings/test_modifiers.py +++ b/tests/test_strings/test_modifiers.py @@ -1,19 +1,20 @@ -from scc.actions import Action, ButtonAction, AxisAction, MouseAction -from scc.constants import SCButtons, STICK, HapticPos -from scc.uinput import Keys, Axes, Rels +import inspect + +from scc.actions import Action, AxisAction, ButtonAction, MouseAction +from scc.constants import STICK, HapticPos, SCButtons from scc.modifiers import * +from scc.uinput import Axes, Keys, Rels + from . import _parses_as, parser -import inspect -class TestModifiers(object): - + +class TestModifiers: + # TODO: Much more tests # TODO: test_tests - + def test_ball(self): - """ - Tests if BallModifier can be converted from string - """ + """Test if BallModifier can be converted from string""" # All options assert _parses_as( "ball(15, 40, 15, 0.1, 3265, 4, axis(ABS_X))", diff --git a/tests/test_vdf.py b/tests/test_vdf.py index 0581652b6..132234b89 100644 --- a/tests/test_vdf.py +++ b/tests/test_vdf.py @@ -1,13 +1,16 @@ -from scc.lib.vdf import parse_vdf -from scc.foreign.vdf import VDFProfile -from io import StringIO import os +from io import StringIO + import pytest import vdf -class TestVDF(object): +from scc.foreign.vdf import VDFProfile +from scc.lib.vdf import parse_vdf + + +class TestVDF: """ Tests VDF parser """ - + def test_parsing(self): """ Tests if VDF parser parses VDF """ sio = StringIO(""" @@ -24,8 +27,8 @@ def test_parsing(self): assert type(parsed["data"]) == vdf.vdict.VDFDict assert parsed["data"]["version"] == "3" assert parsed["data"]["more data"]["version"] == "7" - - + + def test_dict_without_key(self): """ Tests if VDF parser throws exception when there is dict with key missing @@ -41,8 +44,8 @@ def test_dict_without_key(self): """) with pytest.raises(SyntaxError) as excinfo: parsed = parse_vdf(sio) - - + + def test_unclosed_bracket(self): """ Tests if VDF parser throws exception when there is unclosed { @@ -57,8 +60,8 @@ def test_unclosed_bracket(self): """) with pytest.raises(SyntaxError) as excinfo: parsed = parse_vdf(sio) - - + + def test_too_many_brackets(self): """ Tests if VDF parser throws exception when there is } wihtout matching { @@ -75,8 +78,8 @@ def test_too_many_brackets(self): """) with pytest.raises(SyntaxError) as excinfo: parsed = parse_vdf(sio) - - + + def test_import(self): """ Tests if every *.vdf file in tests/vdfs can be imported.