216 lines
5.6 KiB
Python
216 lines
5.6 KiB
Python
import inspect
|
|
from typing import Callable
|
|
|
|
|
|
class RegisteredActionsAccessor:
|
|
def __init__(self, registered_actions, namespace):
|
|
self.registered_actions = registered_actions
|
|
self.namespace = namespace
|
|
|
|
def __getattr__(self, name):
|
|
for category in ("test", "module"):
|
|
cat_actions = self.registered_actions[category]
|
|
if self.namespace in cat_actions:
|
|
if name in cat_actions[self.namespace]:
|
|
return cat_actions[self.namespace][name]
|
|
|
|
raise AttributeError(f"Couldn't find action {self.namespace}.{name}")
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
# Provide a useful error message if people try something like
|
|
# actions.my_action() when they should do actions.user.my_action()
|
|
raise RuntimeError(f"actions.{self.namespace}() is not an available action")
|
|
|
|
|
|
class Actions:
|
|
"""
|
|
Implements something like talon.actions. You can use the register
|
|
function to add in an action definition from your test (e.g. a mock).
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.registered_actions = {
|
|
"module": {},
|
|
"test": {},
|
|
}
|
|
|
|
# Some built in actions
|
|
self.register_module_action("", "key", lambda x: None)
|
|
self.register_module_action("", "insert", lambda x: None)
|
|
self.register_module_action("", "sleep", lambda x: None)
|
|
self.register_module_action("edit", "selected_text", lambda: "test")
|
|
|
|
def reset_test_actions(self):
|
|
self.registered_actions["test"] = {}
|
|
|
|
def register_module_action(self, namespace: str, name: str, func: Callable):
|
|
"""
|
|
Registers an action to the module category. This should
|
|
only be called by importing files containing module definitions.
|
|
It won't be reset between test runs (or test files). Use
|
|
register_test_action and reset_test_actions to temporarily override
|
|
actions.
|
|
"""
|
|
|
|
self._register_action("module", namespace, name, func)
|
|
|
|
def register_test_action(self, namespace: str, name: str, func: Callable):
|
|
"""
|
|
Registers the given action, use like:
|
|
|
|
actions.register("user.my_action", lambda: None)
|
|
"""
|
|
|
|
self._register_action("test", namespace, name, func)
|
|
|
|
def _register_action(
|
|
self, category: str, namespace: str, name: str, func: Callable
|
|
):
|
|
if namespace not in self.registered_actions[category]:
|
|
self.registered_actions[category][namespace] = {}
|
|
|
|
self.registered_actions[category][namespace][name] = func
|
|
|
|
def __getattr__(self, name):
|
|
try:
|
|
# If name exists as a direct property of this class, then
|
|
# use that
|
|
return object.__getattribute__(self, name)
|
|
except AttributeError:
|
|
pass
|
|
|
|
try:
|
|
# Else if name is an action like actions.key
|
|
# that has no namespace then return that.
|
|
default_accessor = RegisteredActionsAccessor(self.registered_actions, "")
|
|
return getattr(default_accessor, name)
|
|
except AttributeError:
|
|
# Otherwise treat name as an action namespace
|
|
# (like actions.user).
|
|
return RegisteredActionsAccessor(self.registered_actions, name)
|
|
|
|
|
|
class Module:
|
|
"""
|
|
Implements something like the Module class built in to Talon
|
|
"""
|
|
|
|
def list(self, *args, **kwargs):
|
|
pass
|
|
|
|
def setting(self, *args, **kwargs):
|
|
pass
|
|
|
|
def capture(self, rule=None):
|
|
def __funcwrapper(func):
|
|
def __inner(*args, **kwargs):
|
|
return func(*args, **kwargs)
|
|
|
|
return __inner
|
|
|
|
return __funcwrapper
|
|
|
|
def tag(self, name, desc=None):
|
|
pass
|
|
|
|
def action_class(self, target_class):
|
|
# Register all the methods on the class with our actions implementation
|
|
for name, func in inspect.getmembers(target_class, inspect.isfunction):
|
|
actions.register_module_action("user", name, func)
|
|
|
|
return target_class
|
|
|
|
|
|
class Context:
|
|
"""
|
|
Implements something like the Context class built in to Talon
|
|
"""
|
|
|
|
lists = {}
|
|
|
|
def action_class(self, path=None):
|
|
def __funcwrapper(clazz):
|
|
return clazz
|
|
|
|
return __funcwrapper
|
|
|
|
def capture(self, name: str, rule: str = None):
|
|
def __funcwrapper(func):
|
|
def __inner(*args, **kwargs):
|
|
return func(*args, **kwargs)
|
|
|
|
return __inner
|
|
|
|
return __funcwrapper
|
|
|
|
|
|
class ImgUI:
|
|
"""
|
|
Stub out ImgUI so we don't get crashes
|
|
"""
|
|
|
|
GUI = None
|
|
|
|
def open(self):
|
|
def __funcwrapper(func):
|
|
def __inner(*args, **kwargs):
|
|
return func(*args, **kwargs)
|
|
|
|
return __inner
|
|
|
|
return __funcwrapper
|
|
|
|
|
|
class UI:
|
|
"""
|
|
Stub out UI so we don't get crashes
|
|
"""
|
|
|
|
def register(*args, **kwargs):
|
|
pass
|
|
|
|
|
|
class Settings:
|
|
"""
|
|
Implements something like talon.settings
|
|
"""
|
|
|
|
|
|
class Registry:
|
|
"""
|
|
Implements something like Talon's registry
|
|
"""
|
|
|
|
|
|
class Resource:
|
|
"""
|
|
Implements something like the talon resource system
|
|
"""
|
|
|
|
def open(self, path: str, mode: str = "r"):
|
|
return open(path, mode, encoding="utf-8")
|
|
|
|
def watch(self, path: str):
|
|
return lambda f: f
|
|
|
|
|
|
class App:
|
|
"""
|
|
Implements something like the talon app variable
|
|
"""
|
|
|
|
platform = "mac"
|
|
|
|
|
|
actions = Actions()
|
|
app = App
|
|
clip = None
|
|
imgui = ImgUI()
|
|
ui = UI()
|
|
settings = Settings()
|
|
resource = Resource()
|
|
registry = Registry()
|
|
|
|
# Indicate to test files that they should load since we're running in test mode
|
|
test_mode = True
|