def test_factory_re_register(function_factory: FunctionFactoryBase): from ceed.function.plugin import ConstFunc, LinearFunc with pytest.raises(Exception): function_factory.register(ConstFunc) with pytest.raises(Exception): function_factory.register(LinearFunc)
def test_copy_funcs(function_factory: FunctionFactoryBase): from ceed.function import FuncGroup, CeedFuncRef f1 = function_factory.get('ConstFunc')(function_factory=function_factory, a=.5, name='f1', duration=1.2) f2 = function_factory.get('LinearFunc')(function_factory=function_factory, m=.5, b=.2, name='f2', duration=1.2) f3 = function_factory.get('ExponentialFunc')( function_factory=function_factory, A=.5, B=.2, tau1=1.3, tau2=1.5, name='f3', duration=1.2) f4 = function_factory.get('CosFunc')(function_factory=function_factory, f=.5, A=3.4, th0=7.5, b=12.2, name='f4', duration=1.2) g = FuncGroup(function_factory=function_factory, name='g') function_factory.add_func(f1) function_factory.add_func(f2) function_factory.add_func(f3) function_factory.add_func(f4) g.add_func(function_factory.get_func_ref(func=f1)) g.add_func(function_factory.get_func_ref(func=f2)) g.add_func(function_factory.get_func_ref(func=f3)) g.add_func(function_factory.get_func_ref(func=f4)) for func in (f1, f2, f3, f4): func_copy = copy.deepcopy(func) assert func is not func_copy assert isinstance(func_copy, func.__class__) for name in func.get_gui_props(): if name == 'name': continue assert getattr(func, name) == getattr(func_copy, name) func_copy = copy.deepcopy(g) assert len(func_copy.funcs) == 4 for new_f, original_f in zip(func_copy.funcs, g.funcs): assert new_f is not original_f assert isinstance(new_f, CeedFuncRef) assert isinstance(original_f, CeedFuncRef) assert new_f.func is original_f.func
def test_func_ref(function_factory: FunctionFactoryBase): const_cls = function_factory.get('ConstFunc') f = const_cls(function_factory=function_factory, duration=4, a=.7, name='f') f2 = const_cls(function_factory=function_factory, duration=5, a=.9, name='f') function_factory.add_func(f) ref1 = function_factory.get_func_ref(name='f') ref2 = function_factory.get_func_ref(func=f2) assert ref1.func is f assert ref2.func is f2 assert f.has_ref assert f2.has_ref assert f in function_factory._ref_funcs assert f2 in function_factory._ref_funcs function_factory.return_func_ref(ref1) assert ref2.func is f2 assert not f.has_ref assert f2.has_ref assert f not in function_factory._ref_funcs assert f2 in function_factory._ref_funcs function_factory.return_func_ref(ref2) assert not f.has_ref assert not f2.has_ref assert f not in function_factory._ref_funcs assert f2 not in function_factory._ref_funcs
def test_return_not_added_func_ref(function_factory: FunctionFactoryBase): from ceed.function import CeedFuncRef const_cls = function_factory.get('ConstFunc') f = const_cls(function_factory=function_factory, duration=4, a=.7, name='f') ref = CeedFuncRef(function_factory=function_factory, func=f) with pytest.raises(ValueError): function_factory.return_func_ref(ref)
def test_factory_func_remove(function_factory: FunctionFactoryBase): assert not function_factory.funcs_user initial_funcs_n = len(function_factory.funcs_inst) const_cls = function_factory.get('ConstFunc') f = const_cls(function_factory=function_factory, duration=4, a=.7, name='f') function_factory.add_func(f) f2 = const_cls(function_factory=function_factory, duration=4, a=.7, name='f2') function_factory.add_func(f2) assert len(function_factory.funcs_inst) == initial_funcs_n + 2 function_factory.test_changes_count = 0 assert function_factory.remove_func(f2) assert function_factory.test_changes_count assert f in function_factory.funcs_user assert f2 not in function_factory.funcs_user assert len(function_factory.funcs_user) == 1 assert f.name == 'f' assert f2.name == 'f2' assert function_factory.funcs_inst['f'] is f assert 'f2' not in function_factory.funcs_inst assert len(function_factory.funcs_inst) == initial_funcs_n + 1 function_factory.test_changes_count = 0 f2.name = 'f' assert not function_factory.test_changes_count assert f.name == 'f' assert f2.name == 'f' function_factory.test_changes_count = 0 assert function_factory.remove_func(f) assert function_factory.test_changes_count assert f not in function_factory.funcs_user assert f2 not in function_factory.funcs_user assert not function_factory.funcs_user assert f.name == 'f' assert f2.name == 'f' assert 'f' not in function_factory.funcs_inst assert 'f2' not in function_factory.funcs_inst assert len(function_factory.funcs_inst) == initial_funcs_n
def test_auto_register(function_factory: FunctionFactoryBase): from ceed.function.plugin import ConstFunc, LinearFunc, CosFunc, \ ExponentialFunc assert not function_factory.funcs_user assert function_factory.get('ConstFunc') is ConstFunc assert function_factory.get('LinearFunc') is LinearFunc assert function_factory.get('CosFunc') is CosFunc assert function_factory.get('ExponentialFunc') is ExponentialFunc assert isinstance(function_factory.funcs_inst['Const'], ConstFunc) assert isinstance(function_factory.funcs_inst['Linear'], LinearFunc) assert isinstance(function_factory.funcs_inst['Cos'], CosFunc) assert isinstance(function_factory.funcs_inst['Exp'], ExponentialFunc)
def __init__(self, open_player_thread=True, **kwargs): self.drag_controller = CeedDragNDrop() self.function_factory = FunctionFactoryBase() register_all_functions(self.function_factory) self.stage_factory = StageFactoryBase( function_factory=self.function_factory, shape_factory=None) self.player = CeedPlayer(open_player_thread=open_player_thread) self.view_controller = ControllerSideViewControllerBase() self.ceed_data = CeedDataWriterBase() self.data_serializer = DataSerializerBase() super(CeedApp, self).__init__(**kwargs) self.load_app_settings_from_file() self.apply_app_settings()
def test_recover_funcs(function_factory: FunctionFactoryBase): f1 = function_factory.get('ConstFunc')(function_factory=function_factory, a=.5, name='f1') f2 = function_factory.get('LinearFunc')(function_factory=function_factory, m=.5, b=.2, name='f2') f3 = function_factory.get('ExponentialFunc')( function_factory=function_factory, A=.5, B=.2, tau1=1.3, tau2=1.5, name='f3') f4 = function_factory.get('CosFunc')(function_factory=function_factory, f=.5, A=3.4, th0=7.5, b=12.2, name='f4') function_factory.add_func(f1) function_factory.add_func(f2) function_factory.add_func(f3) function_factory.add_func(f4) funcs = function_factory.save_functions() assert len(funcs) == 4 recovered_funcs, name_mapping = function_factory.recover_funcs(funcs) assert len(recovered_funcs) == 4 assert len(name_mapping) == 4 for f_name in ('f1', 'f2', 'f3', 'f4'): assert f_name in name_mapping assert name_mapping[f_name] != f_name assert f_name in function_factory.funcs_inst assert name_mapping[f_name] in function_factory.funcs_inst for name in function_factory.funcs_inst[f_name].get_gui_props(): original_f = function_factory.funcs_inst[f_name] new_f = function_factory.funcs_inst[name_mapping[f_name]] if name == 'name': assert original_f.name != new_f.name assert new_f.name.startswith(original_f.name) continue assert getattr(original_f, name) == getattr(new_f, name)
def function_factory() -> FunctionFactoryBase: from ceed.function import FunctionFactoryBase, register_all_functions function_factory = FunctionFactoryBase() register_all_functions(function_factory) add_prop_watch(function_factory, 'on_changed', 'test_changes_count') yield function_factory
def test_can_other_func_be_added_ref(function_factory: FunctionFactoryBase): factory = function_factory const_cls = factory.get('ConstFunc') g1 = FuncGroup(function_factory=factory) g2 = FuncGroup(function_factory=factory) ref_g2 = function_factory.get_func_ref(func=g2) g1.add_func(ref_g2) f = const_cls(function_factory=factory, a=.9, duration=2) g2.add_func(f) f2 = const_cls(function_factory=factory, a=.25, duration=2) g1.add_func(f2) g3 = FuncGroup(function_factory=factory) g1.add_func(g3) f4 = const_cls(function_factory=factory, a=.8, duration=2) g3.add_func(f4) assert g1.can_other_func_be_added(g2) assert g1.can_other_func_be_added(ref_g2) assert g1.can_other_func_be_added(g3) assert not g1.can_other_func_be_added(g1) assert not g2.can_other_func_be_added(g1) assert g2.can_other_func_be_added(g3) assert not g2.can_other_func_be_added(g2) assert not g2.can_other_func_be_added(ref_g2) assert not g3.can_other_func_be_added(g1) assert g3.can_other_func_be_added(g2) assert g3.can_other_func_be_added(ref_g2) assert not g3.can_other_func_be_added(g3)
def test_call_funcs_ref(function_factory: FunctionFactoryBase): factory = function_factory const_cls = factory.get('ConstFunc') g1 = FuncGroup(function_factory=factory) g2 = FuncGroup(function_factory=factory) ref_g2 = function_factory.get_func_ref(func=g2) g1.add_func(ref_g2) f = const_cls(function_factory=factory, a=.9, duration=2) g2.add_func(f) f2 = const_cls(function_factory=factory, a=.25, duration=2) g1.add_func(f2) with pytest.raises(TypeError): g1.init_func(0) with pytest.raises(TypeError): ref_g2.init_func(0) with pytest.raises(TypeError): ref_g2(0) with pytest.raises(TypeError): g1(0)
def test_timebase_group(function_factory: FunctionFactoryBase): g = FuncGroup(function_factory=function_factory) assert g.get_timebase() == 1 const_cls = function_factory.get('ConstFunc') f = const_cls(function_factory=function_factory) assert f.get_timebase() == 1 g.add_func(f) assert f.get_timebase() == 1 g.timebase_numerator = 1 g.timebase_denominator = 4 assert g.get_timebase() == 1 / 4 assert f.get_timebase() == 1 / 4 f.timebase_numerator = 1 f.timebase_denominator = 8 assert g.get_timebase() == 1 / 4 assert f.get_timebase() == 1 / 8 f.timebase_numerator = 0 assert g.get_timebase() == 1 / 4 assert f.get_timebase() == 1 / 4 f.timebase_numerator = 1 assert g.get_timebase() == 1 / 4 assert f.get_timebase() == 1 / 8 g.timebase_numerator = 0 assert g.get_timebase() == 1 assert f.get_timebase() == 1 / 8
def test_make_function(function_factory: FunctionFactoryBase): f1 = function_factory.get('ConstFunc')(function_factory=function_factory, a=.5, name='f1') f2 = function_factory.get('LinearFunc')(function_factory=function_factory, m=.5, b=.2, name='f2') f3 = function_factory.get('ExponentialFunc')( function_factory=function_factory, A=.5, B=.2, tau1=1.3, tau2=1.5, name='f3') f4 = function_factory.get('CosFunc')(function_factory=function_factory, f=.5, A=3.4, th0=7.5, b=12.2, name='f4') funcs = f1, f2, f3, f4 states = [f.get_state() for f in funcs] new_funcs = [function_factory.make_func(state) for state in states] assert len(new_funcs) == len(funcs) for new_func, f in zip(new_funcs, funcs): for name in f.get_gui_props(): if name == 'name': assert f.name != new_func.name continue assert getattr(f, name) == getattr(new_func, name) # close should make them identical in all ways new_funcs = [ function_factory.make_func(state, clone=True) for state in states ] assert len(new_funcs) == len(funcs) for new_func, f in zip(new_funcs, funcs): for name in f.get_gui_props(): assert getattr(f, name) == getattr(new_func, name) # provide instances new_funcs = [ function_factory.make_func(state, instance=function_factory.get(state['cls'])( function_factory=function_factory), clone=True) for state in states ] assert len(new_funcs) == len(funcs) for new_func, f in zip(new_funcs, funcs): for name in f.get_gui_props(): assert getattr(f, name) == getattr(new_func, name)
def test_expand_ref_funcs(function_factory: FunctionFactoryBase): from ceed.function import FuncGroup, CeedFuncRef factory = function_factory const_cls = factory.get('ConstFunc') g1 = FuncGroup(function_factory=factory) g2 = FuncGroup(function_factory=factory) ref_g2 = function_factory.get_func_ref(func=g2) g1.add_func(ref_g2) f = const_cls(function_factory=factory, a=.9, duration=2) g2.add_func(f) f1 = const_cls(function_factory=factory, a=.1, duration=2) g2.add_func(f1) f2 = const_cls(function_factory=factory, a=.25, duration=2) g1.add_func(f2) f3 = const_cls(function_factory=factory, a=.75, duration=2) ref_f3 = function_factory.get_func_ref(func=f3) g1.add_func(ref_f3) g3 = FuncGroup(function_factory=factory) g1.add_func(g3) f4 = const_cls(function_factory=factory, a=.8, duration=2) ref_f4 = function_factory.get_func_ref(func=f4) g3.add_func(ref_f4) f5 = const_cls(function_factory=factory, a=.2, duration=2) g3.add_func(f5) assert list(g1.get_funcs(step_into_ref=False)) == \ [g1, ref_g2, f2, ref_f3, g3, ref_f4, f5] assert list(g1.get_funcs(step_into_ref=True)) == \ [g1, g2, f, f1, f2, f3, g3, f4, f5] g1_copy = g1.copy_expand_ref() # the copy shouldn't have any refs assert len(list(g1_copy.get_funcs(step_into_ref=False))) == \ len(list(g1.get_funcs(step_into_ref=True))) for original_f, new_f in zip(g1.get_funcs(step_into_ref=True), g1_copy.get_funcs(step_into_ref=False)): for name in original_f.get_gui_props(): if name == 'name': continue assert getattr(original_f, name) == getattr(new_f, name)
def test_timebase_func(function_factory: FunctionFactoryBase): const_cls = function_factory.get('ConstFunc') f = const_cls(function_factory=function_factory) assert f.get_timebase() == 1 f = const_cls(function_factory=function_factory, timebase_numerator=1, timebase_denominator=2) assert f.get_timebase() == 0.5
def test_t_offset(function_factory: FunctionFactoryBase): f1 = function_factory.get('ConstFunc')(function_factory=function_factory, a=.5, name='f1', t_offset=3.5, duration=1.2) f2 = function_factory.get('LinearFunc')(function_factory=function_factory, m=.5, b=.2, name='f2', t_offset=3.5, duration=1.2) f3 = function_factory.get('ExponentialFunc')( function_factory=function_factory, A=.5, B=.2, tau1=1.3, tau2=1.5, name='f3', t_offset=3.5, duration=1.2) f4 = function_factory.get('CosFunc')(function_factory=function_factory, f=.5, A=3.4, th0=7.5, b=12.2, name='f4', t_offset=3.5, duration=1.2) for f in (f1, f2, f3, f4): f.init_func(2.3) t = 1 + 3.5 assert math.isclose(f1(3.3), .5) assert math.isclose(f2(3.3), t * .5 + .2) assert math.isclose(f3(3.3), .5 * math.exp(-t / 1.3) + .2 * math.exp(-t / 1.5)) assert math.isclose( f4(3.3), 3.4 * math.cos(2 * math.pi * .5 * t + 7.5 * math.pi / 180.) + 12.2)
def __init__(self, **kwargs): self.view_controller = ViewSideViewControllerBase() self.ceed_data = CeedDataWriterBase() self.data_serializer = DataSerializerBase() self.function_factory = FunctionFactoryBase() register_all_functions(self.function_factory) self.shape_factory = CeedPaintCanvasBehavior() self.stage_factory = StageFactoryBase( function_factory=self.function_factory, shape_factory=self.shape_factory) super(CeedViewApp, self).__init__(**kwargs)
def load_experiment(self, experiment): self._block = block = self._nix_file.blocks[ CeedDataWriterBase.get_experiment_block_name(experiment)] section = self._nix_file.sections['experiment{}_metadata'.format( experiment)] self.loaded_experiment = experiment self.experiment_stage_name = section['stage'] self.experiment_notes = section['notes'] if 'notes' in section else '' self.experiment_start_time = float( section['save_time']) if 'save_time' in section else 0 config = section.sections['app_config'] config_data = {} for prop in config.props: config_data[prop.name] = yaml_loads(read_nix_prop(prop)) view = self.view_controller = ViewControllerBase() ser = self.data_serializer = DataSerializerBase() func = self.function_factory = FunctionFactoryBase() register_all_functions(func) shape = self.shape_factory = CeedPaintCanvasBehavior() stage = self.stage_factory = StageFactoryBase(function_factory=func, shape_factory=shape) for name, obj in { 'view': view, 'serializer': ser, 'function': func }.items(): if name in config_data['app_settings']: apply_config(obj, config_data['app_settings'][name]) self.populate_config(config_data, shape, func, stage) self.experiment_cam_image = self.read_image_from_block(self._block) data = self.shapes_intensity = {} for item in block.data_arrays: if not item.name.startswith('shape_'): continue data[item.name[6:]] = item self.led_state = block.data_arrays['led_state'] if ('ceed_mcs_alignment' in self._nix_file.blocks and 'experiment_{}'.format(experiment) in self._nix_file.blocks['ceed_mcs_alignment'].data_arrays): self.electrode_intensity_alignment = self._nix_file.blocks[ 'ceed_mcs_alignment'].data_arrays['experiment_{}'.format( experiment)] else: self.electrode_intensity_alignment = None
def test_factory_func_unique_names(function_factory: FunctionFactoryBase): assert not function_factory.funcs_user function_factory.test_changes_count = 0 const_cls = function_factory.get('ConstFunc') f = const_cls(function_factory=function_factory, duration=4, a=.7, name='f') function_factory.add_func(f) f2 = const_cls(function_factory=function_factory, duration=4, a=.7, name='f') function_factory.add_func(f2) def assert_not_f(): assert function_factory.test_changes_count assert f in function_factory.funcs_user assert f2 in function_factory.funcs_user assert len(function_factory.funcs_user) == 2 f2_name = f2.name assert f.name == 'f' assert f2_name != 'f' assert f2_name assert function_factory.funcs_inst['f'] is f assert function_factory.funcs_inst[f2_name] is f2 assert_not_f() function_factory.test_changes_count = 0 f2.name = 'f2' assert function_factory.test_changes_count assert f in function_factory.funcs_user assert f2 in function_factory.funcs_user assert len(function_factory.funcs_user) == 2 assert f.name == 'f' assert f2.name == 'f2' assert function_factory.funcs_inst['f'] is f assert function_factory.funcs_inst['f2'] is f2 function_factory.test_changes_count = 0 f2.name = 'f' assert_not_f()
def __init__(self, **kwargs): drag = self.drag_controller = CeedDragNDrop() drag.knsname = 'dragger' self.function_factory = FunctionFactoryBase() register_all_functions(self.function_factory) self.stage_factory = StageFactoryBase( function_factory=self.function_factory, shape_factory=None) self.player = CeedPlayer() self.view_controller = ControllerSideViewControllerBase() self.ceed_data = CeedDataWriterBase() self.data_serializer = DataSerializerBase() self.remote_viewer = RemoteViewerListenerBase() self.remote_player = CeedRemotePlayer() super(CeedApp, self).__init__(**kwargs) self.load_app_settings_from_file() self.apply_app_settings()
def test_clear_funcs(function_factory: FunctionFactoryBase): assert not function_factory.funcs_user initial_funcs_n = len(function_factory.funcs_inst) const_cls = function_factory.get('ConstFunc') f = const_cls(function_factory=function_factory, duration=4, a=.7, name='f') function_factory.add_func(f) f2 = const_cls(function_factory=function_factory, duration=4, a=.7, name='f2') function_factory.add_func(f2) assert len(function_factory.funcs_inst) == initial_funcs_n + 2 function_factory.test_changes_count = 0 function_factory.clear_added_funcs() assert len(function_factory.funcs_inst) == initial_funcs_n assert not function_factory.funcs_user
def test_group_remove_func(function_factory: FunctionFactoryBase): factory = function_factory const_cls = factory.get('ConstFunc') g1 = FuncGroup(function_factory=factory) g2 = FuncGroup(function_factory=factory) ref_g2 = function_factory.get_func_ref(func=g2) g1.add_func(ref_g2) f = const_cls(function_factory=factory, a=.9, duration=2) g2.add_func(f) f1 = const_cls(function_factory=factory, a=.9, duration=2) g2.add_func(f1) f2 = const_cls(function_factory=factory, a=.25, duration=2) g1.add_func(f2) assert list(g1.get_funcs(step_into_ref=False)) == [g1, ref_g2, f2] assert g1.duration == 6 assert g1.duration_min == 6 assert g1.duration_min_total == 6 g1.remove_func(f2) assert list(g1.get_funcs(step_into_ref=False)) == [g1, ref_g2] assert g1.duration == 4 assert g1.duration_min == 4 assert g1.duration_min_total == 4 g2.remove_func(f) assert list(g1.get_funcs(step_into_ref=False)) == [g1, ref_g2] assert g1.duration == 2 assert g1.duration_min == 2 assert g1.duration_min_total == 2 g1.remove_func(ref_g2) assert list(g1.get_funcs(step_into_ref=False)) == [ g1, ] assert g1.duration == 0 assert g1.duration_min == 0 assert g1.duration_min_total == 0
def load_application_data(self): self.app_logs = self.app_notes = '' if 'app_logs' in self._nix_file.sections: self.app_logs = self._nix_file.sections['app_logs']['log_data'] self.app_notes = self._nix_file.sections['app_logs']['notes'] config = self._nix_file.sections['app_config'] config_data = {} for prop in config.props: config_data[prop.name] = yaml_loads(read_nix_prop(prop)) self.ceed_version = config_data.get('ceed_version', '') view = ViewControllerBase() ser = DataSerializerBase() func = FunctionFactoryBase() register_all_functions(func) shape = CeedPaintCanvasBehavior() stage = StageFactoryBase(function_factory=func, shape_factory=shape) for name, obj in { 'view': view, 'serializer': ser, 'function': func }.items(): if name in config_data['app_settings']: apply_config(obj, config_data['app_settings'][name]) self.populate_config(config_data, shape, func, stage) self.app_config = { 'view_controller': view, 'data_serializer': ser, 'function_factory': func, 'shape_factory': shape, 'stage_factory': stage, }
def test_register_user_func(function_factory: FunctionFactoryBase): assert not function_factory.funcs_user const_cls = function_factory.get('ConstFunc') f = const_cls(function_factory=function_factory, duration=4, a=.7, name='f') f2 = const_cls(function_factory=function_factory, duration=5, a=.9, name='f2') function_factory.test_changes_count = 0 function_factory.add_func(f) assert function_factory.test_changes_count assert f in function_factory.funcs_user assert function_factory.funcs_inst['f'] is f function_factory.test_changes_count = 0 function_factory.add_func(f2) assert function_factory.test_changes_count assert f2 in function_factory.funcs_user assert function_factory.funcs_inst['f2'] is f2
class CeedApp(CPLComApp): '''The app which runs the GUI. ''' function_factory = None player = None view_controller = None ceed_data = None data_serializer = None remote_viewer = None stage_factory = None shape_factory = None remote_player = None agreed_discard = False drag_controller = None ''' ''' @classmethod def get_config_classes(cls): d = super(CeedApp, cls).get_config_classes() d['function'] = FunctionFactoryBase d['view'] = ControllerSideViewControllerBase d['data'] = CeedDataWriterBase d['serializer'] = DataSerializerBase d['player'] = CeedPlayer d['point_gray_cam'] = CeedPTGrayPlayer d['video_file_playback'] = CeedFFmpegPlayer d['remote_viewer'] = RemoteViewerListenerBase app = cls.get_running_app() if app is not None: d['function'] = app.function_factory d['view'] = app.view_controller d['data'] = app.ceed_data d['serializer'] = app.data_serializer p = d['player'] = app.player d['point_gray_cam'] = p.pt_player d['video_file_playback'] = p.ff_player d['remote_viewer'] = app.remote_viewer return d def __init__(self, **kwargs): drag = self.drag_controller = CeedDragNDrop() drag.knsname = 'dragger' self.function_factory = FunctionFactoryBase() register_all_functions(self.function_factory) self.stage_factory = StageFactoryBase( function_factory=self.function_factory, shape_factory=None) self.player = CeedPlayer() self.view_controller = ControllerSideViewControllerBase() self.ceed_data = CeedDataWriterBase() self.data_serializer = DataSerializerBase() self.remote_viewer = RemoteViewerListenerBase() self.remote_player = CeedRemotePlayer() super(CeedApp, self).__init__(**kwargs) self.load_app_settings_from_file() self.apply_app_settings() def build(self): base = dirname(__file__) # Builder.load_file(join(base, 'graphics', 'graphics.kv')) Builder.load_file(join(base, 'ceed_style.kv')) Builder.load_file(join(base, 'player', 'player_style.kv')) Builder.load_file(join(base, 'shape', 'shape_style.kv')) Builder.load_file(join(base, 'function', 'func_style.kv')) Builder.load_file(join(base, 'stage', 'stage_style.kv')) Builder.load_file(join(base, 'view', 'view_style.kv')) Builder.load_file(join(base, 'storage', 'storage_style.kv')) self.yesno_prompt = Factory.CeedYesNoPrompt() root = Factory.get('MainView')() return super(CeedApp, self).build(root) def on_start(self): self.stage_factory.shape_factory = self.shape_factory = knspace.painter remove_shapes_upon_deletion( self.stage_factory, self.shape_factory, knspace.stages.remove_shape_from_stage) knspace.painter.shapes_canvas = knspace.painter.canvas knspace.painter.shape_widgets_list = knspace.shapes def clear_all(): knspace.funcs.clear_all() knspace.stages.clear_all() self.ceed_data.stage_display_callback = knspace.stages.show_stage self.ceed_data.func_display_callback = knspace.funcs.show_function self.ceed_data.clear_all_callback = clear_all HighightButtonBehavior.init_class() self.ceed_data.create_file('') self.stage_factory.fbind('on_changed', self.changed_callback) self.function_factory.fbind('on_changed', self.changed_callback) for func in self.function_factory.funcs_inst_default.values(): func.fbind('on_changed', self.changed_callback) knspace.painter.fbind('on_changed', self.changed_callback) self.view_controller.fbind('on_changed', self.changed_callback) self.set_tittle() self.ceed_data.fbind('filename', self.set_tittle) self.ceed_data.fbind('config_changed', self.set_tittle) self.ceed_data.fbind('has_unsaved', self.set_tittle) self.ceed_data.fbind('read_only_file', self.set_tittle) try: self.view_controller.set_led_mode(self.view_controller.LED_mode_idle) except ImportError: pass def set_tittle(self, *largs): ''' Sets the title of the window using the currently running tab. This is called at 1Hz. ''' star = '' if self.ceed_data.has_unsaved or self.ceed_data.config_changed: star = '*' read_only = '' if self.ceed_data.read_only_file: read_only = ' - Read Only' if self.ceed_data.filename: filename = ' - {}'.format(self.ceed_data.filename) else: filename = ' - Unnamed File' Window.set_title('Ceed v{}, CPL lab{}{}{}'.format( ceed.__version__, star, filename, read_only)) def changed_callback(self, *largs, **kwargs): self.ceed_data.config_changed = True def check_close(self): if CeedPlayer.is_player_active(): self._close_message = 'Cannot close while player is active.' return False if self.view_controller.stage_active or self.ceed_data.data_thread: self._close_message = 'Cannot close during an experiment.' return False self.view_controller.stop_process() self.view_controller.finish_stop_process() if not self.ceed_data.ui_close(app_close=True): self._close_message = '' return False return True def handle_exception(self, *largs, **kwargs): val = super(CeedApp, self).handle_exception(*largs, **kwargs) self.view_controller.request_stage_end() return val
class CeedApp(BaseKivyApp): """The app which runs the main Ceed GUI. """ _config_props_ = ('last_directory', 'external_function_plugin_package', 'external_stage_plugin_package') _config_children_ = { 'function': 'function_factory', 'view': 'view_controller', 'data': 'ceed_data', 'serializer': 'data_serializer', 'player': 'player', } last_directory = StringProperty('~') """The last directory opened in the GUI. """ external_function_plugin_package: str = '' """The name of an external function plugin package that contains additional functions to be displayed in the GUI to the user. See :mod:`~ceed.function.plugin` for details. """ external_stage_plugin_package: str = '' """The name of an external stage plugin package that contains additional stages to be displayed in the GUI to the user. See :mod:`~ceed.stage.plugin` for details. """ kv_loaded = False """For tests, we don't want to load kv multiple times so we only load kv if it wasn't loaded before. """ yesno_prompt = ObjectProperty(None, allownone=True) '''Stores a instance of :class:`YesNoPrompt` that is automatically created by this app class. That class is described in ``base_kivy_app/graphics.kv`` and shows a prompt with yes/no options and callback. ''' function_factory: FunctionFactoryBase = None """The :class:`~ceed.function.FunctionFactoryBase` that contains all the functions shown in the GUI. """ player: CeedPlayer = None """The :class:`ceed.player.CeedPlayer` used to play the video camera and record the images to disk. """ view_controller: ControllerSideViewControllerBase = None """The :class:`~ceed.view.controller.ControllerSideViewControllerBase` used to run the experiment and display the stages. """ ceed_data: CeedDataWriterBase = None """The :class:`~ceed.storage.controller.CeedDataWriterBase` used to load and save the data to disk. """ data_serializer: DataSerializerBase = None """The :class:`~ceed.storage.controller.DataSerializerBase` used to generate the corner pixel values for Ceed-MCS temporal synchronization. """ stage_factory: StageFactoryBase = None """The :class:`~ceed.stage.StageFactoryBase` that contains all the stages shown in the GUI. """ shape_factory: CeedPainter = ObjectProperty(None, rebind=True) """The :class:`~ceed.shape.shape_widgets.CeedPainter` used to draw shapes and contains all the shapes shown in the GUI. """ agreed_discard = False drag_controller: CeedDragNDrop = ObjectProperty(None, rebind=True) """The :class:`~ceed.graphics.CeedDragNDrop` used for dragging and dropping widgets on in the GUI. """ stages_container: StageList = ObjectProperty(None, rebind=True) """The :class:`~ceed.stage.stage_widgets.StageList` widget that contains all the root stages' widgets in the GUI. """ funcs_container: FuncList = ObjectProperty(None, rebind=True) """The :class:`~ceed.function.func_widgets.FuncList` widget that contains all the root functions' widgets in the GUI. """ shapes_container: ShapeList = ObjectProperty(None, rebind=True) """The :class:`~ceed.shape.shape_widgets.ShapeList` widget that contains all the shapes' widgets in the GUI. """ shape_groups_container = ObjectProperty( None, rebind=True) # type: ShapeGroupList """The :class:`~ceed.shape.shape_widgets.ShapeGroupList` widget that contains all the shape groups' widgets in the GUI. """ pinned_graph = None """PinnedGraph widget into which the experiment preview graph may be pinned. When pinned, it's displayed not as a popup, but as a flat widget. """ mea_align_widget: MEAArrayAlign = ObjectProperty(None, rebind=True) """The :class:`~ceed.view.view_widgets.MEAArrayAlign` widget used to align the MEA grid to the camera. """ central_display: BufferImage = ObjectProperty(None, rebind=True) """The :class:`~base_kivy_app.graphics.BufferImage` widget into which the camera widget is drawn. """ _processing_error = False def __init__(self, open_player_thread=True, **kwargs): self.drag_controller = CeedDragNDrop() self.function_factory = FunctionFactoryBase() register_all_functions(self.function_factory) self.stage_factory = StageFactoryBase( function_factory=self.function_factory, shape_factory=None) register_all_stages(self.stage_factory) self.player = CeedPlayer(open_player_thread=open_player_thread) self.view_controller = ControllerSideViewControllerBase() self.ceed_data = CeedDataWriterBase() self.data_serializer = DataSerializerBase() super(CeedApp, self).__init__(**kwargs) self.load_app_settings_from_file() self.apply_app_settings() def load_app_kv(self): """Loads the app's kv files, if not yet loaded. """ if CeedApp.kv_loaded: return CeedApp.kv_loaded = True base = dirname(__file__) # Builder.load_file(join(base, 'graphics', 'graphics.kv')) Builder.load_file(join(base, 'ceed_style.kv')) Builder.load_file(join(base, 'player', 'player_style.kv')) Builder.load_file(join(base, 'shape', 'shape_style.kv')) Builder.load_file(join(base, 'function', 'func_style.kv')) Builder.load_file(join(base, 'stage', 'stage_style.kv')) Builder.load_file(join(base, 'view', 'view_style.kv')) Builder.load_file(join(base, 'storage', 'storage_style.kv')) def build(self): self.load_app_kv() self.yesno_prompt = Factory.FlatYesNoPrompt() self.player.create_widgets() root = Factory.get('MainView')() return super(CeedApp, self).build(root) def _clear_all(self): self.funcs_container.clear_all() self.stages_container.clear_all() def on_start(self): if self.external_function_plugin_package: register_external_functions(self.function_factory, self.external_function_plugin_package) if self.external_stage_plugin_package: register_external_stages(self.stage_factory, self.external_stage_plugin_package) self.stage_factory.shape_factory = self.shape_factory remove_shapes_upon_deletion( self.stage_factory, self.shape_factory, self.stages_container.remove_shape_from_stage) self.shape_factory.shape_widgets_list = self.shapes_container self.ceed_data.stage_display_callback = \ self.stages_container.show_stage self.ceed_data.func_display_callback = \ self.funcs_container.show_function self.ceed_data.clear_all_callback = self._clear_all HighightButtonBehavior.init_class() self.ceed_data.create_file('') self.stage_factory.fbind('on_changed', self.changed_callback) for stage in self.stage_factory.stages_inst_default.values(): stage.fbind('on_changed', self.changed_callback) self.function_factory.fbind('on_changed', self.changed_callback) for func in self.function_factory.funcs_inst_default.values(): func.fbind('on_changed', self.changed_callback) self.shape_factory.fbind('on_changed', self.changed_callback) self.view_controller.fbind('on_changed', self.changed_callback) self.set_tittle() self.ceed_data.fbind('filename', self.set_tittle) self.ceed_data.fbind('config_changed', self.set_tittle) self.ceed_data.fbind('has_unsaved', self.set_tittle) self.ceed_data.fbind('read_only_file', self.set_tittle) self.view_controller.set_led_mode(self.view_controller.LED_mode_idle) def set_tittle(self, *largs): """Periodically called by the Kivy Clock to update the title. """ star = '' if self.ceed_data.has_unsaved or self.ceed_data.config_changed: star = '*' read_only = '' if self.ceed_data.read_only_file: read_only = ' - Read Only' if self.ceed_data.filename: filename = ' - {}'.format(self.ceed_data.filename) else: filename = ' - Unnamed File' Window.set_title('Ceed v{}, CPL lab{}{}{}'.format( ceed.__version__, star, filename, read_only)) def changed_callback(self, *largs, **kwargs): """Callback bound to anything that can change the Ceed data to indicate whether it needs to be re-saved. """ self.ceed_data.config_changed = True def check_close(self): if self.view_controller.stage_active or self.ceed_data.data_thread: self._close_message = 'Cannot close during an experiment.' return False self.player.stop() self.view_controller.stop_process() self.view_controller.finish_stop_process() if not self.ceed_data.ui_close(app_close=True): self._close_message = '' return False return True def handle_exception(self, *largs, **kwargs): processing = self._processing_error self._processing_error = True val = super(CeedApp, self).handle_exception(*largs, **kwargs) if not processing: self.view_controller.request_stage_end() self._processing_error = False return val def clean_up(self): super(CeedApp, self).clean_up() if self.ceed_data is not None: if self.ceed_data.backup_event is not None: self.ceed_data.backup_event.cancel() self.ceed_data.backup_event = None self.ceed_data.clear_all_callback = None if self.stage_factory is not None: self.stage_factory.funbind('on_changed', self.changed_callback) if self.function_factory is not None: self.function_factory.funbind('on_changed', self.changed_callback) if self.shape_factory is not None: self.shape_factory.funbind('on_changed', self.changed_callback) if self.view_controller is not None: self.view_controller.funbind('on_changed', self.changed_callback) for stage in self.stage_factory.stages_inst_default.values(): stage.funbind('on_changed', self.changed_callback) for func in self.function_factory.funcs_inst_default.values(): func.funbind('on_changed', self.changed_callback) if self.view_controller is not None: self.view_controller.stop_process() self.view_controller.finish_stop_process() if self.ceed_data is not None: self.ceed_data.stop_experiment() self.ceed_data.funbind('filename', self.set_tittle) self.ceed_data.funbind('config_changed', self.set_tittle) self.ceed_data.funbind('has_unsaved', self.set_tittle) self.ceed_data.funbind('read_only_file', self.set_tittle) self.dump_app_settings_to_file() self.player.clean_up() HighightButtonBehavior.uninit_class()
class CeedApp(BaseKivyApp): '''The app which runs the GUI. ''' __config_props__ = ('last_directory', ) last_directory = StringProperty('~') kv_loaded = False """For tests, we don't want to load kv multiple times. """ yesno_prompt = ObjectProperty(None, allownone=True) '''Stores a instance of :class:`YesNoPrompt` that is automatically created by this app class. That class is described in ``base_kivy_app/graphics.kv``. ''' function_factory = None # type: FunctionFactoryBase player = None # type: CeedPlayer view_controller = None # type: ControllerSideViewControllerBase ceed_data = None # type: CeedDataWriterBase data_serializer = None # type: DataSerializerBase stage_factory = None # type: StageFactoryBase shape_factory = ObjectProperty(None, rebind=True) # type: CeedPainter # remote_player = None # type: CeedRemotePlayer agreed_discard = False drag_controller = ObjectProperty(None, rebind=True) # type: CeedDragNDrop stages_container = ObjectProperty(None, rebind=True) # type: StageList funcs_container = ObjectProperty(None, rebind=True) # type: FuncList shapes_container = ObjectProperty(None, rebind=True) # type: ShapeList shape_groups_container = ObjectProperty( None, rebind=True) # type: ShapeGroupList pinned_graph = None """PinnedGraph into which the stage graph may be pinned. """ mea_align_widget = ObjectProperty(None, rebind=True) # type: MEAArrayAlign central_display = ObjectProperty(None, rebind=True) # type: BufferImage _processing_error = False @classmethod def get_config_classes(cls): d = super(CeedApp, cls).get_config_classes() d['function'] = FunctionFactoryBase d['view'] = ControllerSideViewControllerBase d['data'] = CeedDataWriterBase d['serializer'] = DataSerializerBase d['player'] = CeedPlayer return d def get_config_instances(self): d = super(CeedApp, self).get_config_instances() d['function'] = self.function_factory d['view'] = self.view_controller d['data'] = self.ceed_data d['serializer'] = self.data_serializer d['player'] = self.player return d def __init__(self, open_player_thread=True, **kwargs): self.drag_controller = CeedDragNDrop() self.function_factory = FunctionFactoryBase() register_all_functions(self.function_factory) self.stage_factory = StageFactoryBase( function_factory=self.function_factory, shape_factory=None) self.player = CeedPlayer(open_player_thread=open_player_thread) self.view_controller = ControllerSideViewControllerBase() self.ceed_data = CeedDataWriterBase() self.data_serializer = DataSerializerBase() super(CeedApp, self).__init__(**kwargs) self.load_app_settings_from_file() self.apply_app_settings() def load_app_kv(self): if CeedApp.kv_loaded: return CeedApp.kv_loaded = True base = dirname(__file__) # Builder.load_file(join(base, 'graphics', 'graphics.kv')) Builder.load_file(join(base, 'ceed_style.kv')) Builder.load_file(join(base, 'player', 'player_style.kv')) Builder.load_file(join(base, 'shape', 'shape_style.kv')) Builder.load_file(join(base, 'function', 'func_style.kv')) Builder.load_file(join(base, 'stage', 'stage_style.kv')) Builder.load_file(join(base, 'view', 'view_style.kv')) Builder.load_file(join(base, 'storage', 'storage_style.kv')) def build(self): self.load_app_kv() self.yesno_prompt = Factory.FlatYesNoPrompt() self.player.create_widgets() root = Factory.get('MainView')() return super(CeedApp, self).build(root) def _clear_all(self): self.funcs_container.clear_all() self.stages_container.clear_all() def on_start(self): self.stage_factory.shape_factory = self.shape_factory remove_shapes_upon_deletion( self.stage_factory, self.shape_factory, self.stages_container.remove_shape_from_stage) self.shape_factory.shape_widgets_list = self.shapes_container self.ceed_data.stage_display_callback = \ self.stages_container.show_stage self.ceed_data.func_display_callback = \ self.funcs_container.show_function self.ceed_data.clear_all_callback = self._clear_all HighightButtonBehavior.init_class() self.ceed_data.create_file('') self.stage_factory.fbind('on_changed', self.changed_callback) self.function_factory.fbind('on_changed', self.changed_callback) for func in self.function_factory.funcs_inst_default.values(): func.fbind('on_changed', self.changed_callback) self.shape_factory.fbind('on_changed', self.changed_callback) self.view_controller.fbind('on_changed', self.changed_callback) self.set_tittle() self.ceed_data.fbind('filename', self.set_tittle) self.ceed_data.fbind('config_changed', self.set_tittle) self.ceed_data.fbind('has_unsaved', self.set_tittle) self.ceed_data.fbind('read_only_file', self.set_tittle) self.view_controller.set_led_mode(self.view_controller.LED_mode_idle) def set_tittle(self, *largs): ''' Sets the title of the window using the currently running tab. This is called at 1Hz. ''' star = '' if self.ceed_data.has_unsaved or self.ceed_data.config_changed: star = '*' read_only = '' if self.ceed_data.read_only_file: read_only = ' - Read Only' if self.ceed_data.filename: filename = ' - {}'.format(self.ceed_data.filename) else: filename = ' - Unnamed File' Window.set_title('Ceed v{}, CPL lab{}{}{}'.format( ceed.__version__, star, filename, read_only)) def changed_callback(self, *largs, **kwargs): self.ceed_data.config_changed = True def check_close(self): if self.view_controller.stage_active or self.ceed_data.data_thread: self._close_message = 'Cannot close during an experiment.' return False self.player.stop() self.view_controller.stop_process() self.view_controller.finish_stop_process() if not self.ceed_data.ui_close(app_close=True): self._close_message = '' return False return True def handle_exception(self, *largs, **kwargs): processing = self._processing_error self._processing_error = True val = super(CeedApp, self).handle_exception(*largs, **kwargs) if not processing: self.view_controller.request_stage_end() self._processing_error = False return val def clean_up(self): super(CeedApp, self).clean_up() if self.ceed_data is not None: if self.ceed_data.backup_event is not None: self.ceed_data.backup_event.cancel() self.ceed_data.backup_event = None self.ceed_data.clear_all_callback = None if self.stage_factory is not None: self.stage_factory.funbind('on_changed', self.changed_callback) if self.function_factory is not None: self.function_factory.funbind('on_changed', self.changed_callback) if self.shape_factory is not None: self.shape_factory.funbind('on_changed', self.changed_callback) if self.view_controller is not None: self.view_controller.funbind('on_changed', self.changed_callback) for func in self.function_factory.funcs_inst_default.values(): func.funbind('on_changed', self.changed_callback) if self.view_controller is not None: self.view_controller.stop_process() self.view_controller.finish_stop_process() if self.ceed_data is not None: self.ceed_data.stop_experiment() self.ceed_data.funbind('filename', self.set_tittle) self.ceed_data.funbind('config_changed', self.set_tittle) self.ceed_data.funbind('has_unsaved', self.set_tittle) self.ceed_data.funbind('read_only_file', self.set_tittle) self.dump_app_settings_to_file() self.player.clean_up() HighightButtonBehavior.uninit_class()
def test_register_funcs(): from ceed.function.plugin import ConstFunc, LinearFunc function_factory = FunctionFactoryBase() count = 0 def count_changes(*largs): nonlocal count count += 1 function_factory.fbind('on_changed', count_changes) assert not function_factory.funcs_cls assert not function_factory.funcs_user assert not function_factory.funcs_inst assert not function_factory.funcs_inst_default assert not function_factory.get_classes() assert not function_factory.get_names() function_factory.register(ConstFunc) assert count assert function_factory.funcs_cls['ConstFunc'] is ConstFunc assert isinstance(function_factory.funcs_inst['Const'], ConstFunc) assert isinstance(function_factory.funcs_inst_default['Const'], ConstFunc) assert ConstFunc in function_factory.get_classes() assert 'ConstFunc' in function_factory.get_names() f = LinearFunc(function_factory=function_factory) count = 0 function_factory.register(LinearFunc, instance=f) assert count assert function_factory.funcs_cls['LinearFunc'] is LinearFunc assert function_factory.funcs_inst['Linear'] is f assert function_factory.funcs_inst_default['Linear'] is f assert LinearFunc in function_factory.get_classes() assert 'LinearFunc' in function_factory.get_names() assert not function_factory.funcs_user
def test_replace_ref_func_with_source_funcs( function_factory: FunctionFactoryBase): from ceed.function import FuncGroup, CeedFuncRef factory = function_factory const_cls = factory.get('ConstFunc') g1 = FuncGroup(function_factory=factory, name='g1') g2 = FuncGroup(function_factory=factory, name='g2') ref_g2 = function_factory.get_func_ref(func=g2) g1.add_func(ref_g2) f = const_cls(function_factory=factory, a=.9, duration=2) g2.add_func(f) f1 = const_cls(function_factory=factory, a=.1, duration=2, name='f1') function_factory.add_func(f1) ref_f1 = function_factory.get_func_ref(func=f1) g2.add_func(ref_f1) f2 = const_cls(function_factory=factory, a=.25, duration=2) g1.add_func(f2) f3 = const_cls(function_factory=factory, a=.75, duration=2, name='f3') function_factory.add_func(f3) ref_f3 = function_factory.get_func_ref(func=f3) g1.add_func(ref_f3) with pytest.raises(ValueError): g1.replace_ref_func_with_source(f2) with pytest.raises(ValueError): g1.replace_ref_func_with_source(ref_f1) f3_new, i = g1.replace_ref_func_with_source(ref_f3) assert i == 2 assert ref_f3 not in g1.funcs assert f3 not in g1.funcs assert not isinstance(f3_new, CeedFuncRef) assert isinstance(f3_new, f3.__class__) assert g1.funcs[i] is f3_new for name in f3.get_gui_props(): if name == 'name': continue assert getattr(f3, name) == getattr(f3_new, name) g2_new: FuncGroup g2_new, i = g1.replace_ref_func_with_source(ref_g2) assert i == 0 assert ref_g2 not in g1.funcs assert g2 not in g1.funcs assert not isinstance(g2_new, CeedFuncRef) assert isinstance(g2_new, FuncGroup) assert g1.funcs[i] is g2_new assert len(g2_new.funcs) == 2 assert g2_new.funcs[0] is not g2.funcs[0] assert g2_new.funcs[1] is not g2.funcs[1] assert isinstance(g2_new.funcs[0], f.__class__) assert isinstance(g2_new.funcs[1], ref_f1.__class__) assert isinstance(g2_new.funcs[1], CeedFuncRef) for name in f.get_gui_props(): if name == 'name': continue assert getattr(f, name) == getattr(g2_new.funcs[0], name) assert g2_new.funcs[1].func is f1
def test_recover_ref_funcs(function_factory: FunctionFactoryBase): from ceed.function import FuncGroup, CeedFuncRef f1 = function_factory.get('ConstFunc')(function_factory=function_factory, a=.5, name='f1', duration=1.2) f2 = function_factory.get('LinearFunc')(function_factory=function_factory, m=.5, b=.2, name='f2', duration=1.2) f3 = function_factory.get('ExponentialFunc')( function_factory=function_factory, A=.5, B=.2, tau1=1.3, tau2=1.5, name='f3', duration=1.2) f4 = function_factory.get('CosFunc')(function_factory=function_factory, f=.5, A=3.4, th0=7.5, b=12.2, name='f4', duration=1.2) g = FuncGroup(function_factory=function_factory, name='g') function_factory.add_func(f1) function_factory.add_func(f2) function_factory.add_func(f3) function_factory.add_func(f4) function_factory.add_func(g) g.add_func(function_factory.get_func_ref(name='f1')) g.add_func(function_factory.get_func_ref(name='f2')) g.add_func(function_factory.get_func_ref(name='f3')) g.add_func(function_factory.get_func_ref(name='f4')) funcs = function_factory.save_functions() assert len(funcs) == 5 recovered_funcs, name_mapping = function_factory.recover_funcs(funcs) assert len(recovered_funcs) == 5 assert len(name_mapping) == 5 for f_name in ('f1', 'f2', 'f3', 'f4', 'g'): assert f_name in name_mapping assert name_mapping[f_name] != f_name assert f_name in function_factory.funcs_inst assert name_mapping[f_name] in function_factory.funcs_inst for name in function_factory.funcs_inst[f_name].get_gui_props(): original_f = function_factory.funcs_inst[f_name] new_f = function_factory.funcs_inst[name_mapping[f_name]] if name == 'name': assert original_f.name != new_f.name assert new_f.name.startswith(original_f.name) continue assert getattr(original_f, name) == getattr(new_f, name) new_g: FuncGroup = function_factory.funcs_inst[name_mapping['g']] assert len(new_g.funcs) == 4 func: CeedFuncRef for func, name in zip(new_g.funcs, ('f1', 'f2', 'f3', 'f4')): assert isinstance(func, CeedFuncRef) assert func.func is function_factory.funcs_inst[name_mapping[name]]
def test_clear_funcs_with_ref(function_factory: FunctionFactoryBase): const_cls = function_factory.get('ConstFunc') f = const_cls(function_factory=function_factory, duration=4, a=.7, name='f') f2 = const_cls(function_factory=function_factory, duration=5, a=.9, name='f2') function_factory.add_func(f) function_factory.add_func(f2) assert function_factory.funcs_inst['f'] is f assert f in function_factory.funcs_user assert function_factory.funcs_inst['f2'] is f2 assert f2 in function_factory.funcs_user ref = function_factory.get_func_ref(name='f') function_factory.clear_added_funcs() # f should not have been removed, but f2 was removed assert ref.func is f assert f.has_ref assert function_factory.funcs_inst['f'] is f assert f in function_factory.funcs_user assert 'f2' not in function_factory.funcs_inst assert f2 not in function_factory.funcs_user function_factory.clear_added_funcs(force=True) assert ref.func is f assert f.has_ref assert 'f' not in function_factory.funcs_inst assert f not in function_factory.funcs_user function_factory.return_func_ref(ref) assert not f.has_ref
def test_remove_func_with_ref(function_factory: FunctionFactoryBase): const_cls = function_factory.get('ConstFunc') f = const_cls(function_factory=function_factory, duration=4, a=.7, name='f') f2 = const_cls(function_factory=function_factory, duration=5, a=.9, name='f2') f3 = const_cls(function_factory=function_factory, duration=5, a=.9, name='f3') function_factory.add_func(f) function_factory.add_func(f2) function_factory.add_func(f3) assert function_factory.funcs_inst['f'] is f assert f in function_factory.funcs_user assert function_factory.funcs_inst['f2'] is f2 assert f2 in function_factory.funcs_user assert function_factory.funcs_inst['f3'] is f3 assert f3 in function_factory.funcs_user ref = function_factory.get_func_ref(name='f') ref3 = function_factory.get_func_ref(name='f3') assert not function_factory.remove_func(f) assert ref.func is f assert f.has_ref assert function_factory.funcs_inst['f'] is f assert f in function_factory.funcs_user assert function_factory.funcs_inst['f2'] is f2 assert f2 in function_factory.funcs_user assert function_factory.funcs_inst['f3'] is f3 assert f3 in function_factory.funcs_user assert function_factory.remove_func(f2) assert function_factory.funcs_inst['f'] is f assert f in function_factory.funcs_user assert 'f2' not in function_factory.funcs_inst assert f2 not in function_factory.funcs_user assert function_factory.funcs_inst['f3'] is f3 assert f3 in function_factory.funcs_user assert not function_factory.remove_func(f3) assert ref3.func is f3 assert f3.has_ref assert function_factory.funcs_inst['f'] is f assert f in function_factory.funcs_user assert function_factory.funcs_inst['f3'] is f3 assert f3 in function_factory.funcs_user assert function_factory.remove_func(f3, force=True) assert ref3.func is f3 assert f3.has_ref assert function_factory.funcs_inst['f'] is f assert f in function_factory.funcs_user assert 'f3' not in function_factory.funcs_inst assert f3 not in function_factory.funcs_user assert not function_factory.remove_func(f) assert ref.func is f assert f.has_ref assert function_factory.funcs_inst['f'] is f assert f in function_factory.funcs_user function_factory.return_func_ref(ref) assert not f.has_ref assert function_factory.remove_func(f) assert 'f' not in function_factory.funcs_inst assert f not in function_factory.funcs_user function_factory.return_func_ref(ref3) assert not f3.has_ref