don't barf if we send a message with parameters to a method handler without one, made the dynamic action/plugin code easier to understand, dynamic route regexes check start/end to disambiguate substrings

This commit is contained in:
Tristan Rowley
2020-01-31 20:09:00 +00:00
parent 17c165af18
commit 880e3899f4
3 changed files with 63 additions and 55 deletions

View File

@@ -1,6 +1,7 @@
import subprocess import subprocess
import tracemalloc import tracemalloc
import data_centre.length_setter as length_setter import data_centre.length_setter as length_setter
from inspect import signature
import sys import sys
import shlex import shlex
import os import os
@@ -907,19 +908,19 @@ class Actions(object):
@property @property
def parserlist(self): def parserlist(self):
return { return {
( r"play_shader_([0-9])_([0-9])", self.shaders.play_that_shader ), ( r"^play_shader_([0-9])_([0-9])$", self.shaders.play_that_shader ),
( r"toggle_shader_layer_([0-2])", self.toggle_shader_layer ), ( r"^toggle_shader_layer_([0-2])$", self.toggle_shader_layer ),
( r"start_shader_layer_([0-2])", self.shaders.start_shader ), ( r"^start_shader_layer_([0-2])$", self.shaders.start_shader ),
( r"stop_shader_layer_([0-2])", self.shaders.stop_shader ), ( r"^stop_shader_layer_([0-2])$", self.shaders.stop_shader ),
( r"set_the_shader_param_([0-3])_layer_([0-2])_continuous", self.shaders.set_param_layer_to_amount ), ( r"^set_the_shader_param_([0-3])_layer_([0-2])_continuous$", self.shaders.set_param_layer_to_amount ),
( r"modulate_param_([0-3])_to_amount_continuous", self.shaders.modulate_param_to_amount ), ( r"^modulate_param_([0-3])_to_amount_continuous$", self.shaders.modulate_param_to_amount ),
( r"set_param_([0-3])_layer_([0-2])_modulation_level_continuous", self.shaders.set_param_layer_offset_modulation_level ), ( r"^set_param_([0-3])_layer_([0-2])_modulation_level_continuous$", self.shaders.set_param_layer_offset_modulation_level ),
( r"set_param_([0-3])_layer_offset_([0-2])_modulation_level_continuous", self.shaders.set_param_layer_offset_modulation_level ), ( r"^set_param_([0-3])_layer_offset_([0-2])_modulation_level_continuous$", self.shaders.set_param_layer_offset_modulation_level ),
( r"reset_selected_modulation", self.shaders.reset_selected_modulation ), ( r"^reset_selected_modulation$", self.shaders.reset_selected_modulation ),
( r"reset_modulation_([0-3])", self.shaders.reset_modulation ), ( r"^reset_modulation_([0-3])$", self.shaders.reset_modulation ),
( r"select_shader_modulation_slot_([0-3])", self.shaders.select_shader_modulation_slot ), ( r"^select_shader_modulation_slot_([0-3])$", self.shaders.select_shader_modulation_slot ),
( r"set_shader_speed_layer_offset_([0-2])_amount", self.shaders.set_speed_offset_to_amount ), ( r"^set_shader_speed_layer_offset_([0-2])_amount$", self.shaders.set_speed_offset_to_amount ),
( r"set_shader_speed_layer_([0-2])_amount", self.shaders.set_speed_layer_to_amount ), ( r"^set_shader_speed_layer_([0-2])_amount$", self.shaders.set_speed_layer_to_amount ),
} }
def detect_types(self, args): def detect_types(self, args):
@@ -942,34 +943,46 @@ class Actions(object):
return (found_method, args) return (found_method, args)
return None, None
def call_method_name(self, method_name, argument=None): def call_method_name(self, method_name, argument=None):
# if the target method doesnt exist, call the handler method = None
if not hasattr(self, method_name): arguments = None
self.call_parse_method_name(method_name, argument)
return
# first check if we have a native method to handle this for us
# todo: assess whether it would still be performant/desirable to be able to override core actions with plugins?
if hasattr(self, method_name):
method = getattr(self, method_name)
if argument is not None: if argument is not None:
getattr(self, method_name)(argument) arguments = [argument]
else:
getattr(self, method_name)()
# if not then check if its handled by one of our parserlist dynamic route methods
if method is None:
method, arguments = self.get_callback_for_method(method_name, argument)
def call_parse_method_name(self, method_name, argument): # if still nothing then test if a registered plugin handles this for us -- perhaps this ought to go first?
# first test if a registered plugin handles this for us if method is None:
from data_centre.plugin_collection import ActionsPlugin from data_centre.plugin_collection import ActionsPlugin
for plugin in self.data.plugins.get_plugins(ActionsPlugin): for plugin in self.data.plugins.get_plugins(ActionsPlugin):
if plugin.is_handled(method_name): if plugin.is_handled(method_name):
print ("Plugin %s is handling %s" % (plugin, method_name)) print ("Plugin %s is handling %s" % (plugin, method_name))
method, arguments = plugin.get_callback_for_method(method_name, argument) method, arguments = plugin.get_callback_for_method(method_name, argument)
method(*arguments) break # only deal with the first plugin
return
# if not then fall back to using internal method if method is None:
try:
method, arguments = self.get_callback_for_method(method_name, argument)
method(*arguments)
except:
print ("Failed to find a method for '%s'" % method_name) print ("Failed to find a method for '%s'" % method_name)
import traceback import traceback
traceback.print_exc() traceback.print_exc()
return
try:
#print ("for method_name %s, arguments is %s and len is %s" % (method_name, arguments, len(signature(method).parameters)))
if arguments is not None and len(signature(method).parameters)==len(arguments): # only pass arguments if count matches method sig
method(*arguments)
else:
method()
except:
print ("Exception calling action for '%s' with arguments ( %s ) " % ( method_name, arguments))
import traceback
traceback.print_exc()

View File

@@ -39,12 +39,12 @@ class SequencePlugin(Plugin):
@property @property
def parserlist(self): def parserlist(self):
return [ return [
( r"run_automation", self.run_automation ), ( r"^run_automation$", self.run_automation ),
( r"stop_automation", self.stop_automation ), ( r"^stop_automation$", self.stop_automation ),
( r"toggle_pause_automation", self.toggle_pause_automation ), ( r"^toggle_pause_automation$", self.toggle_pause_automation ),
( r"pause_automation", self.pause_automation ), ( r"^pause_automation$", self.pause_automation ),
( r"toggle_loop_automation", self.toggle_loop_automation ), ( r"^toggle_loop_automation$", self.toggle_loop_automation ),
( r"set_automation_speed", self.set_speed ), ( r"^set_automation_speed$", self.set_speed ),
] ]
def set_speed(self, speed): def set_speed(self, speed):
@@ -194,11 +194,6 @@ class ActionsPlugin(Plugin):
return (found_method, args) return (found_method, args)
#def call_parse_method_name(self, method_name, argument):
# method, arguments = self.actions.get_callback_for_method(method_name, argument)
# method(*arguments)
# adapted from https://github.com/gdiepen/python_plugin_example # adapted from https://github.com/gdiepen/python_plugin_example
class PluginCollection(object): class PluginCollection(object):
"""Upon creation, this class will read the plugins package for modules """Upon creation, this class will read the plugins package for modules

View File

@@ -10,13 +10,13 @@ class TestPlugin(ActionsPlugin,SequencePlugin):
@property @property
def parserlist(self): def parserlist(self):
return [ return [
( r"test_plugin", self.test_plugin ), ( r"^test_plugin$", self.test_plugin ),
( r"cycle_shaders", self.cycle_shaders ), ( r"^cycle_shaders$", self.cycle_shaders ),
( r"run_automation", self.run_automation ), ( r"^run_automation$", self.run_automation ),
( r"stop_automation", self.stop_automation ), ( r"^stop_automation$", self.stop_automation ),
( r"toggle_pause_automation", self.toggle_pause_automation ), ( r"^toggle_pause_automation$", self.toggle_pause_automation ),
( r"pause_automation", self.pause_automation ), ( r"^pause_automation$", self.pause_automation ),
( r"toggle_loop_automation", self.toggle_loop_automation ), ( r"^toggle_loop_automation$", self.toggle_loop_automation ),
] ]
def test_plugin(self): def test_plugin(self):
@@ -42,7 +42,7 @@ class TestPlugin(ActionsPlugin,SequencePlugin):
frequency = 50 frequency = 50
def run_sequence(self, position): def run_sequence(self, position):
self.pc.actions.call_method_name( self.pc.actions.call_method_name(
"set_the_shader_param_0_layer_0_continuous", position "set_the_shader_param_3_layer_0_continuous", position
) )
self.pc.actions.call_method_name( self.pc.actions.call_method_name(