def warning(self, message): """ Simple wrapper around the standard Python logger's warning method. Fires the `eva.logger.warning` trigger. """ self.logger.warning(message) gossip.trigger('eva.logger.warning', message=message)
def info(self, message): """ Simple wrapper around the standard Python logger's info method. Fires the `eva.logger.info` trigger. """ self.logger.info(message) gossip.trigger('eva.logger.info', message=message)
def critical(self, message): """ Simple wrapper around the standard Python logger's critical method. Fires the `eva.logger.critical` trigger. """ self.logger.critical(message) gossip.trigger('eva.logger.critical', message=message)
def test_pre_trigger_callback(checkpoint): called_args = [] hook = define('somehook') @hook.add_pre_trigger_callback def pre_trigger_callback(registration, kwargs): # pylint: disable=unused-variable called_args.append((registration, kwargs)) assert not called_args trigger('somehook') assert not called_args @register('somehook') def callback(**kwargs): # pylint: disable=unused-argument checkpoint() assert not called_args trigger('somehook', x=1, y=2, z=3) assert len(called_args) == 1 assert called_args[0][-1] == {'x': 1, 'y': 2, 'z': 3} assert called_args[0][0].func is callback
def set_input_audio(self, audio, content_type): """ Same as :func:`set_input_text` except it works for the input audio and content type. Not very many plugins will end up using this as it involves modifying the audio query or command that was sent by the Eva client. This method fires the ``eva.pre_set_input_audio`` and ``eva.post_set_input_audio`` triggers. :param audio: The audio to be set as the input audio for this interaction. :type audio: binary string :param content_type: The content type of this binary audio data. :type content_type: string """ plugin_id = get_calling_plugin() gossip.trigger('eva.pre_set_input_audio', audio=audio, content_type=content_type, plugin_id=plugin_id, context=self) self.input_audio = audio self.input_audio_content_type = content_type gossip.trigger('eva.post_set_input_audio', audio=audio, content_type=content_type, plugin_id=plugin_id, context=self)
def error(self, message): """ Simple wrapper around the standard Python logger's error method. Fires the `eva.logger.error` trigger. """ self.logger.error(message) gossip.trigger('eva.logger.error', message=message)
def job_succeeded(event): """ A callback function that gets called when an `APScheduler <https://apscheduler.readthedocs.io/en/latest/>`_ job succeeds. Currently will simply fire the `eva.scheduler.job_succeeded` trigger with the success event object. """ gossip.trigger('eva.scheduler.job_succeeded', event=event)
def test_non_reentrant_hooks(counter): hook_name = 'nonreentrant_hook' @gossip.register(hook_name, reentrant=False) def handler(): # pylint: disable=unused-variable counter.add(1) gossip.trigger(hook_name) gossip.trigger(hook_name) assert counter == 1
def test_token_unregister_from_hook(checkpoint, token, hook_name): # pylint: disable=unused-variable @gossip.register(hook_name, token=token) def handler(): gossip.unregister_token(token) gossip.register(hook_name)(checkpoint) gossip.trigger(hook_name) assert checkpoint.called
def test_uninstall(blueprint, checkpoint): blueprint.register('a')(checkpoint) blueprint.install() gossip.trigger('a') assert checkpoint.called checkpoint.reset() blueprint.uninstall() gossip.trigger('a') assert not checkpoint.called
def test_normal_hooks_can_reenter(counter): counter.set(5) @gossip.register('reentrant_hook') def handler(): # pylint: disable=unused-variable counter.sub(1) if counter: gossip.trigger('reentrant_hook') gossip.trigger('reentrant_hook') assert counter == 0
def boot(): """ The function that runs the Eva boot sequence and loads all the plugins. Fires the `eva.pre_boot` and `eva.post_boot` triggers. """ log.info('Beginning Eva boot sequence') gossip.trigger('eva.pre_boot') load_plugins() gossip.trigger('eva.post_boot') log.info('Eva booted successfully')
def test_mute_group(checkpoint): @gossip.register('a.b.c') def handler(): checkpoint() gossip.get_group("a").forbid_muting() with pytest.raises(CannotMuteHooks): with gossip.mute_context(['a.b.c']): gossip.trigger('a.b.c') assert not checkpoint.called
def test_token_unregister_from_hook_multiple_token_registrants(checkpoint, token, hook_name): # pylint: disable=unused-variable @gossip.register(hook_name, token=token) def handler(): gossip.unregister_token(token) gossip.register(hook_name)(checkpoint) # the second token registration should not be called! gossip.register(hook_name, token=token)(checkpoint) gossip.trigger(hook_name) assert checkpoint.num_times == 1
def test_unregister_no_op_remove_dependencies(timeline): timeline.register(needs=['1'], provides=['0']) timeline.register(needs=['2'], provides=['1']) hook = timeline.get_hook() registration = hook.register_no_op(provides=['2']) timeline.trigger() registration.unregister() with pytest.raises(CannotResolveDependencies) as caught: gossip.trigger(hook.full_name) assert caught.value.unmet_dependencies == set(['2'])
def session_end(self): if time.time() - self._session_start_time < config.root.plugin_config.notifications.notification_threshold: return result = "successfully" if session.results.is_success() else "unsuccessfully" hostname = socket.gethostname().split(".")[0] body = "{0}\n\n{1}".format(session.results, session.id) message = Message("Slash session in {0} ended {1}".format(hostname, result), body) gossip.trigger("slash-gossip.prepare_notification", message=message) self._notify(message.title, message.body)
def test_registers_on_none(restore_plugins_on_cleanup, checkpoint): @slash.plugins.active # pylint: disable=unused-variable class SamplePlugin(PluginInterface): def get_name(self): return 'sample' @plugins.registers_on(None) def some_method_here(self): checkpoint() gossip.trigger('slash.some_method_here') assert not checkpoint.called
def test_mute_hook(checkpoint): @gossip.register('a.b.c') def handler(): checkpoint() hook = gossip.define('a.b.d') hook.forbid_muting() assert not hook.can_be_muted() with gossip.mute_context(['a.b.c']): gossip.trigger('a.b.c') assert not checkpoint.called
def test_blueprint(blueprint, checkpoint): @blueprint.register('a.b') def handler(): # pylint: disable=unused-variable checkpoint() gossip.trigger('a.b') assert not checkpoint.called blueprint.install() gossip.trigger('a.b') assert checkpoint.called
def test_registers_on_with_private_methods(restore_plugins_on_cleanup, checkpoint): @slash.plugins.active # pylint: disable=unused-variable class SamplePlugin(PluginInterface): def get_name(self): return 'sample' @plugins.registers_on('some_hook') def _handler(self): checkpoint() assert not checkpoint.called gossip.trigger('some_hook') assert checkpoint.called
def test_token_unregister_from_hook_multiple_token_registrants( checkpoint, token, hook_name): # pylint: disable=unused-variable @gossip.register(hook_name, token=token) def handler(): gossip.unregister_token(token) gossip.register(hook_name)(checkpoint) # the second token registration should not be called! gossip.register(hook_name, token=token)(checkpoint) gossip.trigger(hook_name) assert checkpoint.num_times == 1
def test_mute_trigger(checkpoint): @gossip.register('a.b.c') def handler(): checkpoint() with gossip.mute_context(['a.b.c']): gossip.trigger('a.b.c') assert not checkpoint.called gossip.trigger('a.b.c') assert checkpoint.called
def test_registers_on_none(restore_plugins_on_cleanup, checkpoint): @slash.plugins.active class SamplePlugin(PluginInterface): def get_name(self): return 'sample' @plugins.registers_on(None) def some_method_here(self): checkpoint() gossip.trigger('slash.some_method_here') assert not checkpoint.called
def test_multiple_functions_same_hook(blueprint, checkpoint): # pylint: disable=unused-argument called = set() @blueprint.register('a') def handler1(): # pylint: disable=unused-variable called.add(1) @blueprint.register('a') def handler2(): # pylint: disable=unused-variable called.add(2) blueprint.install() gossip.trigger('a') assert called == set([1, 2])
def test_registers_on_with_private_methods(restore_plugins_on_cleanup, checkpoint): @slash.plugins.active class SamplePlugin(PluginInterface): def get_name(self): return 'sample' @plugins.registers_on('some_hook') def _handler(self): checkpoint() assert not checkpoint.called gossip.trigger('some_hook') assert checkpoint.called
def pytest_runtest_setup(item): logging.debug( f"\n<---------runtest_setup {'.'.join(item.listnames()[-2:])}---------------->\n" ) gossip.trigger("runtest_setup") configured_hw = configured_hardware(item._request) if not configured_hw: hardware = dict() hardware['machines'] = get_local_config( item.config.getoption("--hardware")) item.session.__initialized_hardware = hardware hardware = configured_hardware(item._request) assert hardware, "Couldnt find configured hardware in pytest_runtest_setup" first_machine = next(iter(hardware['machines'].values())) hut_conn_format = "HUT connection string:\n\n{}\n\n" if first_machine.get('password', None): conn_string = f"sshpass -p {next(iter(hardware['machines'].values()))['password']} ssh -o StrictHostKeyChecking=no {next(iter(hardware['machines'].values()))['user']}@{next(iter(hardware['machines'].values()))['ip']}" else: conn_string = f"ssh -i {os.path.expanduser('~')}/.ssh/anyvision-devops.pem {first_machine['user']}@{first_machine['ip']}" logging.info(hut_conn_format.format(conn_string)) outcome = yield # This will now go to base_config fixture function try: outcome.get_result() except Exception as e: try: base_config = item._request.getfixturevalue('base_config') item.funcargs['base_config'] = base_config except FixtureLookupError as fe: # We got an exception trying to init base_config fixture logging.error("error trying to init base_config fixture") # We got an exception trying to init some other fixture, so base_config is available raise e base_config = item.funcargs['base_config'] logging.debug("cleaning between tests..") init_cluster_structure(base_config, item.function.__cluster_config) if base_config.clusters: concurrently.run([(cluster.clear_plugins) for _, cluster in base_config.clusters.items()]) concurrently.run([(host.clear_plugins) for _, host in base_config.hosts.items()]) _trigger_stage_hooks(base_config, item._request, "setup") logging.debug("done runtest_setup") logging.debug("\n-----------------runtest call---------------\n")
def test_blueprint_register_prefix(blueprint, checkpoint): @gossip.register('a') def handler(): # pylint: disable=unused-variable pass @blueprint.register('a') def handler(): # pylint: disable=function-redefined checkpoint() assert len(gossip.get_all_registrations()) == 1 blueprint.install(group='group') gossip.trigger('a') assert not checkpoint.called gossip.trigger('group.a') assert checkpoint.called
def load_plugins(): """ The function that is called during Eva's boot sequence. Will fetch the plugin directory , load all of the plugins' info files, load all of the plugin's configurations, and enable all the required plugins and their dependencies specified in Eva's configuration file. Fires the `eva.plugins_loaded` trigger. """ # Get all plugins. plugin_dir = get_plugin_directory() load_plugin_directory(plugin_dir) # Get all user-defined configurations. config_dir = conf['eva']['config_directory'] if '~' in config_dir: config_dir = os.path.expanduser(config_dir) load_plugin_configs(config_dir) # Enable all necessary plugins. enable_plugins() gossip.trigger('eva.plugins_loaded') log.info('Plugins loaded successfully')
def set_output_text(self, text, responding=True): """ The bread and butter method of the context object. This method is used by nearly every plugin as it's used to tell Eva what the response to the client should be. This method fires the ``eva.pre_set_output_text`` and ``eva.post_set_output_text`` triggers. :param text: The text to be set as output for the client. :type text: string :param responding: ``True`` if the text provided is a response to the client. ``False`` if you're simply modifying the output text without claiming to be the primary plugin to respond to the query or command. Leaving this as ``True`` means other plugins will be able to tell that the client's query has already been answered (by checking the boolean variable returned by :func:`response_ready`). If a plugin is simply prepending/appending text or making slight modifications to the output, it should use ``responding=False`` so as to allow follow-up questions to be routed to the appropriate plugin. :type responding: boolean """ plugin_id = get_calling_plugin() gossip.trigger('eva.pre_set_output_text', text=text, responding=responding, plugin_id=plugin_id, context=self) self.output_text = text self.responded = responding gossip.trigger('eva.post_set_output_text', text=text, responding=responding, plugin_id=plugin_id, context=self)
def set_output_audio(self, audio, content_type): """ Similar to :func:`set_output_text` except for the audio data and content type. This method will be used primarily by the text-to-speech plugins. :param audio: The audio binary data to send back to the client. :type audio: binary string :param content_type: The content type of the binary audio data. :type content_type: string """ plugin_id = get_calling_plugin() gossip.trigger('eva.pre_set_output_audio', audio=audio, content_type=content_type, plugin_id=plugin_id, context=self) self.output_audio = audio self.output_audio_content_type = content_type gossip.trigger('eva.post_set_output_audio', audio=audio, content_type=content_type, plugin=plugin, context=self)
def set_input_text(self, text): """ Method used to set the input text of the current interaction. This function is primarily used by voice recognition plugins to convert input audio into input text when clients don't provide any. This method fires the ``eva.pre_set_input_text`` and ``eva.post_set_input_text`` triggers. :param text: The text that will now become the input text from the client. :type text: string """ plugin_id = get_calling_plugin() gossip.trigger('eva.pre_set_input_text', text=text, plugin_id=plugin_id, context=self) self.input_text = text gossip.trigger('eva.post_set_input_text', text=text, plugin_id=plugin_id, context=self)
def test_registers_on_kwargs(class_level_needs, class_level_provides): needs_decorator = plugins.needs('other_requirement') provides_decorator = plugins.provides('another_provided_requirement') @slash.plugins.active # pylint: disable=unused-variable @maybe_decorate(needs_decorator, class_level_needs) @maybe_decorate(provides_decorator, class_level_provides) class SamplePlugin(PluginInterface): def get_name(self): return 'sample' @plugins.registers_on('some.hook', provides=['provided_requirement'], needs=['some_requirement'], tags=['tag']) @maybe_decorate(needs_decorator, not class_level_needs) @maybe_decorate(provides_decorator, not class_level_provides) def plugin_method(self): pass @gossip.register('some.hook', provides=['some_requirement', 'other_requirement']) def _unused(): pass gossip.trigger('some.hook') hook = gossip.get_hook('some.hook') [registration] = [ reg for reg in hook.get_registrations() if reg.func.__name__ == 'plugin_method' ] assert registration.tags == {'tag'} assert registration.needs == frozenset( ['some_requirement', 'other_requirement']) assert registration.provides == frozenset( ['provided_requirement', 'another_provided_requirement'])
def publish(message, channel='eva_messages'): """ A helper function used to broadcast messages to all available Eva clients. :todo: Needs to be thoroughly tested (especially with audio data). :param message: The message to send to clients. :type message: string :param channel: The channel to publish in. The default channel that clients should be listening on is called 'eva_messages'. :type channel: string """ log.info('Ready to publish message') gossip.trigger('eva.pre_publish', message=message) pubsub = get_pubsub() log.info('Publishing message: %s' %message) gossip.trigger('eva.publish', message=message) pubsub.publish(channel, message) gossip.trigger('eva.post_publish', message=message)
def test_toggle_hooks(should_raise): events = [] toggle = gossip.Toggle() assert toggle.is_off() @gossip.register('start') def malicious(): events.append('malicious') if should_raise: raise CustomException() @gossip.register('start', toggles_on=toggle) def start(): events.append('start') @gossip.register('end', toggles_off=toggle) def end(): events.append('end') if should_raise: with pytest.raises(CustomException): gossip.trigger('start') else: gossip.trigger('start') assert toggle.is_on() == (not should_raise) gossip.trigger('end') assert toggle.is_off() assert len(events) == len(set(events)) if should_raise: assert 'start' not in events assert 'end' not in events else: assert events.index('malicious') < events.index('start') assert 'end' in events
def trigger(self): gossip.trigger(self.hook_name)
def trigger(self): gossip.trigger(self.name, **self.kwargs)
def _after_login(self): self.components.system_component.refresh() gossip.trigger('infinidat.sdk.after_login', system=self)
def test_trigger_no_hook_registered(): result = gossip.trigger("unregistered") # pylint: disable=assignment-from-no-return assert result is None
def _request(self, http_method, path, assert_success=True, **kwargs): """ Sends a request to the system API interface :returns: :class:`.Response` """ check_version = kwargs.pop("check_version", True) if check_version and not self._checked_version and config.root.check_version_compatibility: self._checked_version = True try: self.system.check_version() except: self._checked_version = False raise returned = None kwargs.setdefault("timeout", self._default_request_timeout) raw_data = kwargs.pop("raw_data", False) data = kwargs.pop("data", NOTHING) sent_json_object = None headers = kwargs.pop('headers', None) if headers is None: headers = {} else: headers = headers.copy() if data is not NOTHING: headers['Content-type'] = 'application/json' if raw_data: sent_json_object = data else: data = translate_special_values(data) sent_json_object = data data = json.dumps(data) else: assert raw_data is False, "Cannot handle raw_data with no data" url_params = kwargs.pop('params', None) if url_params is not None: url_params = translate_special_values(url_params) specified_address = kwargs.pop("address", None) urls = self._get_possible_urls(specified_address) for url in urls: full_url = _join_path(url, URL(path)) if http_method != "get" and not self._interactive and not path.startswith("/api/internal/"): full_url = self._with_approved(full_url) hostname = full_url.hostname api_request = requests.Request(http_method, full_url, data=data if data is not NOTHING else None, params=url_params, headers=headers) for preprocessor in self._preprocessors: preprocessor(api_request) _logger.debug("{0} <-- {1} {2}", hostname, http_method.upper(), api_request.url) if data is not NOTHING: if data != api_request.data: sent_json_object = json.loads(api_request.data) self._log_sent_data(hostname, data, sent_json_object) prepared = self._session.prepare_request(api_request) gossip.trigger('infinidat.sdk.before_api_request', request=prepared) start_time = flux.current_timeline.time() try: response = self._session.send(prepared, **kwargs) except Exception as e: e.api_request_obj = api_request raise end_time = flux.current_timeline.time() gossip.trigger('infinidat.sdk.after_api_request', request=prepared, response=response) response.start_time = start_time response.end_time = end_time elapsed = get_timedelta_total_seconds(response.elapsed) _logger.debug("{0} --> {1} {2} (took {3:.04f}s)", hostname, response.status_code, response.reason, elapsed) returned = Response(response, data) resp_data = "..." if self._no_reponse_logs else returned.get_json() if self._use_pretty_json and returned.get_json() is not None: logged_response_data = json.dumps( returned.get_json(), indent=4, separators=(',', ': ')) else: logged_response_data = resp_data _logger.debug("{0} --> {1}", hostname, logged_response_data) if response.status_code != httplib.SERVICE_UNAVAILABLE: if specified_address is None: # need to remember our next API target self._active_url = url break return returned
def test_end(self): self.current_test.report_end() gossip.trigger('backslash.report_test_end', ended_test=self.current_test) self.current_test = None
def test_start(self): self.current_test = self.current_session.report_test_start( test_logical_id=context.test.__slash__.id, name=str(context.test)) gossip.trigger('backslash.report_test_start', started_test=self.current_test)
def handler(): # pylint: disable=unused-variable counter.sub(1) if counter: gossip.trigger('reentrant_hook')
def test_trigger_hook_with_unsupported_tags(): gossip.define('group.some_hook', tags=("some_tag",)) gossip.trigger('group.some_hook', tags=("fake_tag",)) gossip.get_or_create_group('group').set_strict() with pytest.raises(UnsupportedHookTags): gossip.trigger_with_tags('group.some_hook', tags=("fake_tag",))
def handler(): # pylint: disable=unused-variable counter.add(1) gossip.trigger(hook_name)
def session_start(self): self.client = BackslashClient(self.server_address) self.current_session = self.client.report_session_start( logical_id=context.session.id) gossip.trigger('backslash.report_session_start', started_session=self.current_session)