diff --git a/spyder/app/tests/conftest.py b/spyder/app/tests/conftest.py index df64e2ae067..3080b582d06 100755 --- a/spyder/app/tests/conftest.py +++ b/spyder/app/tests/conftest.py @@ -252,8 +252,8 @@ def generate_run_parameters(mainwindow, filename, selected=None, file_run_params = StoredRunConfigurationExecutor( executor=executor, selected=selected, - display_dialog=False, - first_execution=False) + display_dialog=False + ) return {file_uuid: file_run_params} diff --git a/spyder/app/tests/test_mainwindow.py b/spyder/app/tests/test_mainwindow.py index 0d7734b3baa..6e1192383f8 100644 --- a/spyder/app/tests/test_mainwindow.py +++ b/spyder/app/tests/test_mainwindow.py @@ -69,7 +69,7 @@ WorkingDirSource, RunContext) from spyder.py3compat import qbytearray_to_str, to_text_string from spyder.utils.environ import set_user_env -from spyder.utils.misc import remove_backslashes +from spyder.utils.misc import remove_backslashes, rename_file from spyder.utils.clipboard_helper import CLIPBOARD_HELPER from spyder.utils.programs import find_program from spyder.widgets.dock import DockTitleBar @@ -6364,5 +6364,92 @@ def test_runfile_namespace(main_window, qtbot, tmpdir): assert "test_globals True" in control.toPlainText() +@pytest.mark.skipif( + os.name == 'nt', + reason="No quotes on Windows file paths" +) +def test_quotes_rename_ipy(main_window, qtbot, tmpdir): + """ + Test that we can run files with quotes in name, renamed files, + and ipy files. + """ + # create a file with a funky name + path = "a'b\"c\\.py" + file = tmpdir.join(path) + file.write("print(23 + 780)") + path = to_text_string(file) + main_window.editor.load(path) + + # Run file + shell = main_window.ipyconsole.get_current_shellwidget() + control = shell._control + qtbot.waitUntil( + lambda: shell.spyder_kernel_ready and shell._prompt_html is not None, + timeout=SHELL_TIMEOUT) + + with qtbot.waitSignal(shell.executed): + qtbot.mouseClick(main_window.run_button, Qt.LeftButton) + + assert "803" in control.toPlainText() + assert "error" not in control.toPlainText() + + code_editor = main_window.editor.get_focus_widget() + code_editor.set_text("print(22 + 780)") + + with qtbot.waitSignal(shell.executed): + qtbot.mouseClick(main_window.run_cell_button, Qt.LeftButton) + + assert "802" in control.toPlainText() + assert "error" not in control.toPlainText() + + # Make sure this works with ipy and renamed files too + + # Rename the file to IPython and emit the signal for that + rename_file(path, path[:-2] + "ipy") + explorer = main_window.get_plugin(Plugins.Explorer) + explorer.sig_file_renamed.emit(path, path[:-2] + "ipy") + + code_editor.set_text("print(21 + 780)") + + with qtbot.waitSignal(shell.executed): + qtbot.mouseClick(main_window.run_button, Qt.LeftButton) + + assert "801" in control.toPlainText() + assert "error" not in control.toPlainText() + assert "\\.ipy" in control.toPlainText() + + # Create an untitled file + main_window.editor.new() + + assert "untitled" in main_window.editor.get_current_filename() + + code_editor = main_window.editor.get_focus_widget() + code_editor.set_text("print(20 + 780)") + + with qtbot.waitSignal(shell.executed): + qtbot.mouseClick(main_window.run_cell_button, Qt.LeftButton) + + assert "800" in control.toPlainText() + assert "error" not in control.toPlainText() + assert "untitled" in control.toPlainText() + + # Save file in a new folder + code_editor.set_text("print(19 + 780)") + + with tempfile.TemporaryDirectory() as td: + + editorstack = main_window.editor.get_current_editorstack() + editorstack.select_savename = lambda fn: os.path.join(td, "fn.ipy") + main_window.editor.save() + with qtbot.waitSignal(shell.executed): + qtbot.mouseClick(main_window.run_cell_button, Qt.LeftButton) + + assert "799" in control.toPlainText() + assert "error" not in control.toPlainText() + assert "fn.ipy" in control.toPlainText() + main_window.editor.close_file() + + + if __name__ == "__main__": pytest.main() diff --git a/spyder/plugins/debugger/plugin.py b/spyder/plugins/debugger/plugin.py index 65ff1e89690..fe469cc6693 100644 --- a/spyder/plugins/debugger/plugin.py +++ b/spyder/plugins/debugger/plugin.py @@ -76,7 +76,7 @@ def on_initialize(self): self.python_editor_run_configuration = { 'origin': self.NAME, - 'extension': 'py', + 'extension': ['py', 'ipy'], 'contexts': [ { 'name': 'File' @@ -92,7 +92,7 @@ def on_initialize(self): self.executor_configuration = [ { - 'input_extension': 'py', + 'input_extension': ['py', 'ipy'], 'context': { 'name': 'File' }, @@ -102,7 +102,7 @@ def on_initialize(self): 'priority': 10 }, { - 'input_extension': 'py', + 'input_extension': ['py', 'ipy'], 'context': { 'name': 'Cell' }, @@ -112,7 +112,7 @@ def on_initialize(self): 'priority': 10 }, { - 'input_extension': 'py', + 'input_extension': ['py', 'ipy'], 'context': { 'name': 'Selection' }, diff --git a/spyder/plugins/editor/plugin.py b/spyder/plugins/editor/plugin.py index 2e4663d5051..731d522db03 100644 --- a/spyder/plugins/editor/plugin.py +++ b/spyder/plugins/editor/plugin.py @@ -263,13 +263,13 @@ def __init__(self, parent, ignore_last_opened_files=False): self.supported_run_extensions = [ { - 'input_extension': 'py', + 'input_extension': ['py', 'ipy'], 'contexts': [ {'context': {'name': 'File'}, 'is_super': True}, {'context': {'name': 'Selection'}, 'is_super': False}, {'context': {'name': 'Cell'}, 'is_super': False} ] - } + }, ] run = self.main.get_plugin(Plugins.Run, error=False) @@ -473,7 +473,7 @@ def update_run_focus_file(self): file_id = self.id_per_file.get(filename, None) self.sig_editor_focus_changed_uuid.emit(file_id) - def register_file_run_metadata(self, filename, filename_ext): + def register_file_run_metadata(self, filename): """Register opened files with the Run plugin.""" all_uuids = self.get_conf('file_uuids', default={}) file_id = all_uuids.get(filename, str(uuid.uuid4())) @@ -489,7 +489,7 @@ def register_file_run_metadata(self, filename, filename_ext): 'context': { 'name': 'File' }, - 'input_extension': filename_ext + 'input_extension': osp.splitext(filename)[1][1:] } self.file_per_id[file_id] = filename @@ -499,6 +499,41 @@ def register_file_run_metadata(self, filename, filename_ext): run = self.main.get_plugin(Plugins.Run, error=False) if run: run.register_run_configuration_metadata(self, metadata) + + def deregister_file_run_metadata(self, filename): + """Unregister files with the Run plugin.""" + if filename not in self.id_per_file: + return + + file_id = self.id_per_file.pop(filename) + self.file_per_id.pop(file_id) + self.metadata_per_id.pop(file_id) + + run = self.main.get_plugin(Plugins.Run, error=False) + if run is not None: + run.deregister_run_configuration_metadata(file_id) + + def change_register_file_run_metadata(self, old_filename, new_filename): + """Change registered run metadata when renaming files.""" + is_selected = False + run = self.main.get_plugin(Plugins.Run, error=False) + + if run is not None: + is_selected = ( + run.get_currently_selected_configuration() + == self.id_per_file.get(old_filename, None) + ) + + self.deregister_file_run_metadata(old_filename) + + # This avoids to register the run metadata of new_filename twice, which + # can happen for some rename operations. + if not self.id_per_file.get(new_filename): + self.register_file_run_metadata(new_filename) + + if is_selected: + run.switch_focused_run_configuration( + self.id_per_file[new_filename]) @Slot(dict) def report_open_file(self, options): @@ -517,7 +552,7 @@ def report_open_file(self, options): filename not in self.id_per_file and RunContext.File in ext_contexts ): - self.register_file_run_metadata(filename, filename_ext) + self.register_file_run_metadata(filename) able_to_run_file = True if not able_to_run_file: @@ -1724,10 +1759,9 @@ def register_editorstack(self, editorstack): editorstack.sig_close_file.connect(self.close_file_in_all_editorstacks) editorstack.sig_close_file.connect(self.remove_file_cursor_history) editorstack.file_saved.connect(self.file_saved_in_editorstack) - editorstack.file_renamed_in_data.connect( - self.file_renamed_in_data_in_editorstack) + editorstack.file_renamed_in_data.connect(self.renamed) editorstack.opened_files_list_changed.connect( - self.opened_files_list_changed) + self.opened_files_list_changed) editorstack.active_languages_stats.connect( self.update_active_languages) editorstack.sig_go_to_definition.connect( @@ -1741,7 +1775,7 @@ def register_editorstack(self, editorstack): editorstack.sig_update_code_analysis_actions.connect( self.update_todo_actions) editorstack.refresh_file_dependent_actions.connect( - self.refresh_file_dependent_actions) + self.refresh_file_dependent_actions) editorstack.refresh_save_all_action.connect(self.refresh_save_all_action) editorstack.sig_refresh_eol_chars.connect(self.refresh_eol_chars) editorstack.sig_refresh_formatting.connect(self.refresh_formatting) @@ -1789,13 +1823,8 @@ def clone_editorstack(self, editorstack): @Slot(str, str) def close_file_in_all_editorstacks(self, editorstack_id_str, filename): - run = self.main.get_plugin(Plugins.Run, error=False) if filename in self.id_per_file: - file_id = self.id_per_file.pop(filename) - self.file_per_id.pop(file_id) - self.metadata_per_id.pop(file_id) - if run is not None: - run.deregister_run_configuration_metadata(file_id) + self.deregister_file_run_metadata(filename) else: _, filename_ext = osp.splitext(filename) filename_ext = filename_ext[1:] @@ -1817,14 +1846,6 @@ def file_saved_in_editorstack(self, editorstack_id_str, editorstack.file_saved_in_other_editorstack(original_filename, filename) - @Slot(str, str, str) - def file_renamed_in_data_in_editorstack(self, editorstack_id_str, - original_filename, filename): - """A file was renamed in data in editorstack, this notifies others""" - for editorstack in self.editorstacks: - if str(id(editorstack)) != editorstack_id_str: - editorstack.rename_in_data(original_filename, filename) - #------ Handling editor windows def setup_other_windows(self): """Setup toolbars and menus for 'New window' instances""" @@ -2659,7 +2680,9 @@ def removed_tree(self, dirname): if osp.abspath(fname).startswith(dirname): self.close_file_from_name(fname) - def renamed(self, source, dest): + @Slot(str, str) + @Slot(str, str, str) + def renamed(self, source, dest, editorstack_id_str=None): """ Propagate file rename to editor stacks and autosave component. @@ -2669,12 +2692,20 @@ def renamed(self, source, dest): """ filename = osp.abspath(to_text_string(source)) index = self.get_filename_index(filename) - if index is not None: + + if index is not None or editorstack_id_str is not None: + self.change_register_file_run_metadata(filename, dest) + for editorstack in self.editorstacks: - editorstack.rename_in_data(filename, - new_filename=to_text_string(dest)) - self.editorstacks[0].autosave.file_renamed( - filename, to_text_string(dest)) + if ( + editorstack_id_str is None or + str(id(editorstack)) != editorstack_id_str + ): + editorstack.rename_in_data( + filename, new_filename=str(dest) + ) + + self.editorstacks[0].autosave.file_renamed(filename, str(dest)) def renamed_tree(self, source, dest): """Directory was renamed in file explorer or in project explorer.""" @@ -3075,48 +3106,52 @@ def handle_get_file_code(self, filename, save_all=True): # ------ Run files def add_supported_run_configuration(self, config: EditorRunConfiguration): origin = config['origin'] - extension = config['extension'] + extensions = config['extension'] contexts = config['contexts'] - - ext_contexts = [] - for context in contexts: - is_super = RunContext[context['name']] == RunContext.File - ext_contexts.append( - ExtendedContext(context=context, is_super=is_super)) - supported_extension = SupportedExtensionContexts( - input_extension=extension, contexts=ext_contexts) - self.supported_run_extensions.append(supported_extension) - - run = self.main.get_plugin(Plugins.Run, error=False) - if run: - run.register_run_configuration_provider( - self.NAME, [supported_extension]) - - actual_contexts = set({}) - ext_origins = self.run_configurations_per_origin.get(extension, {}) - - file_enabled = False - for context in contexts: - context_name = context['name'] - context_id = getattr(RunContext, context_name) - actual_contexts |= {context_id} - context_origins = ext_origins.get(context_id, set({})) - context_origins |= {origin} - ext_origins[context_id] = context_origins - if context_id == RunContext.File: - file_enabled = True - - ext_contexts = self.supported_run_configurations.get( - extension, set({})) - ext_contexts |= actual_contexts - self.supported_run_configurations[extension] = ext_contexts - self.run_configurations_per_origin[extension] = ext_origins - - for filename, filename_ext in list(self.pending_run_files): - if filename_ext == extension and file_enabled: - self.register_file_run_metadata(filename, filename_ext) - else: - self.pending_run_files -= {(filename, filename_ext)} + + if not isinstance(extensions, list): + extensions = [extensions] + + for extension in extensions: + ext_contexts = [] + for context in contexts: + is_super = RunContext[context['name']] == RunContext.File + ext_contexts.append( + ExtendedContext(context=context, is_super=is_super)) + supported_extension = SupportedExtensionContexts( + input_extension=extension, contexts=ext_contexts) + self.supported_run_extensions.append(supported_extension) + + run = self.main.get_plugin(Plugins.Run, error=False) + if run: + run.register_run_configuration_provider( + self.NAME, [supported_extension]) + + actual_contexts = set({}) + ext_origins = self.run_configurations_per_origin.get(extension, {}) + + file_enabled = False + for context in contexts: + context_name = context['name'] + context_id = getattr(RunContext, context_name) + actual_contexts |= {context_id} + context_origins = ext_origins.get(context_id, set({})) + context_origins |= {origin} + ext_origins[context_id] = context_origins + if context_id == RunContext.File: + file_enabled = True + + ext_contexts = self.supported_run_configurations.get( + extension, set({})) + ext_contexts |= actual_contexts + self.supported_run_configurations[extension] = ext_contexts + self.run_configurations_per_origin[extension] = ext_origins + + for filename, filename_ext in list(self.pending_run_files): + if filename_ext == extension and file_enabled: + self.register_file_run_metadata(filename) + else: + self.pending_run_files -= {(filename, filename_ext)} def remove_supported_run_configuration( self, diff --git a/spyder/plugins/editor/utils/autosave.py b/spyder/plugins/editor/utils/autosave.py index 7958ac8187b..f3629ddfad8 100644 --- a/spyder/plugins/editor/utils/autosave.py +++ b/spyder/plugins/editor/utils/autosave.py @@ -434,7 +434,7 @@ def file_renamed(self, old_name, new_name): old_hash = self.file_hashes[old_name] except KeyError: # This should not happen, but it does: spyder-ide/spyder#12396 - logger.error('KeyError when handling rename %s -> %s', + logger.debug('KeyError when handling rename %s -> %s', old_name, new_name) old_hash = None self.remove_autosave_file(old_name) diff --git a/spyder/plugins/editor/widgets/editor.py b/spyder/plugins/editor/widgets/editor.py index 0846be8b360..669bf727729 100644 --- a/spyder/plugins/editor/widgets/editor.py +++ b/spyder/plugins/editor/widgets/editor.py @@ -1898,8 +1898,8 @@ def save_as(self, index=None): # depend on the platform: long for 64bit, int for 32bit. Replacing # by long all the time is not working on some 32bit platforms # See spyder-ide/spyder#1094 and spyder-ide/spyder#1098. - self.file_renamed_in_data.emit(str(id(self)), - original_filename, filename) + self.file_renamed_in_data.emit( + original_filename, filename, str(id(self))) ok = self.save(index=new_index, force=True) self.refresh(new_index) @@ -3548,8 +3548,9 @@ def file_saved_in_editorstack(self, editorstack_id_str, # This method is never called in this plugin example. It's here only # to show how to use the file_saved signal (see above). @Slot(str, str, str) - def file_renamed_in_data_in_editorstack(self, editorstack_id_str, - original_filename, filename): + def file_renamed_in_data_in_editorstack( + self, original_filename, filename, editorstack_id_str + ): """A file was renamed in data in editorstack, this notifies others""" for editorstack in self.editorstacks: if str(id(editorstack)) != editorstack_id_str: diff --git a/spyder/plugins/externalconsole/plugin.py b/spyder/plugins/externalconsole/plugin.py index 475f5c1418e..dd8cf899e45 100644 --- a/spyder/plugins/externalconsole/plugin.py +++ b/spyder/plugins/externalconsole/plugin.py @@ -59,7 +59,7 @@ def on_initialize(self): self.editor_configurations = [ { 'origin': self.NAME, - 'extension': 'py', + 'extension': ['py'], 'contexts': [ { 'name': 'File' @@ -70,7 +70,7 @@ def on_initialize(self): self.executor_configuration = [ { - 'input_extension': 'py', + 'input_extension': ['py'], 'context': { 'name': 'File' }, @@ -78,7 +78,7 @@ def on_initialize(self): 'configuration_widget': ExternalConsolePyConfiguration, 'requires_cwd': True, 'priority': 2 - } + }, ] if os.name == 'nt': diff --git a/spyder/plugins/ipythonconsole/plugin.py b/spyder/plugins/ipythonconsole/plugin.py index 2b11180d960..40b9482e489 100644 --- a/spyder/plugins/ipythonconsole/plugin.py +++ b/spyder/plugins/ipythonconsole/plugin.py @@ -228,7 +228,7 @@ def on_initialize(self): self.python_editor_run_configuration = { 'origin': self.NAME, - 'extension': 'py', + 'extension': ['py', 'ipy'], 'contexts': [ { 'name': 'File' @@ -244,7 +244,7 @@ def on_initialize(self): self.executor_configuration = [ { - 'input_extension': 'py', + 'input_extension': ['py', 'ipy'], 'context': { 'name': 'File' }, @@ -254,7 +254,7 @@ def on_initialize(self): 'priority': 0 }, { - 'input_extension': 'py', + 'input_extension': ['py', 'ipy'], 'context': { 'name': 'Cell' }, @@ -264,7 +264,7 @@ def on_initialize(self): 'priority': 0 }, { - 'input_extension': 'py', + 'input_extension': ['py', 'ipy'], 'context': { 'name': 'Selection' }, diff --git a/spyder/plugins/profiler/plugin.py b/spyder/plugins/profiler/plugin.py index 968f7bbe0ad..553d40248c7 100644 --- a/spyder/plugins/profiler/plugin.py +++ b/spyder/plugins/profiler/plugin.py @@ -73,7 +73,7 @@ def on_initialize(self): self.executor_configuration = [ { - 'input_extension': 'py', + 'input_extension': ['py', 'ipy'], 'context': { 'name': 'File' }, @@ -81,7 +81,7 @@ def on_initialize(self): 'configuration_widget': ProfilerPyConfigurationGroup, 'requires_cwd': True, 'priority': 3 - } + }, ] @on_plugin_available(plugin=Plugins.Editor) diff --git a/spyder/plugins/pylint/plugin.py b/spyder/plugins/pylint/plugin.py index 2620d5ee1ab..1ecd2004459 100644 --- a/spyder/plugins/pylint/plugin.py +++ b/spyder/plugins/pylint/plugin.py @@ -86,7 +86,7 @@ def on_initialize(self): # Run configuration self.executor_configuration = [ { - 'input_extension': 'py', + 'input_extension': ['py'], 'context': { 'name': 'File' }, @@ -94,7 +94,7 @@ def on_initialize(self): 'configuration_widget': None, 'requires_cwd': False, 'priority': 4 - } + }, ] @on_plugin_available(plugin=Plugins.Editor) diff --git a/spyder/plugins/run/api.py b/spyder/plugins/run/api.py index bd258dac0d5..1881299b2d4 100644 --- a/spyder/plugins/run/api.py +++ b/spyder/plugins/run/api.py @@ -271,10 +271,6 @@ class StoredRunConfigurationExecutor(TypedDict): # configuration is executed. Otherwise not. display_dialog: bool - # True if the configuration has been executed in the past, False - # otherwise. - first_execution: bool - class RunConfigurationProvider(QObject): """ diff --git a/spyder/plugins/run/container.py b/spyder/plugins/run/container.py index 65f2843ecd5..d1193ee00a3 100644 --- a/spyder/plugins/run/container.py +++ b/spyder/plugins/run/container.py @@ -57,7 +57,6 @@ def setup(self): self.executor_use_count: Dict[str, int] = {} self.viewers_per_output: Dict[str, Set[str]] = {} - self.currently_selected_configuration: Optional[str] = None self.run_action = self.create_action( RunActions.Run, @@ -204,9 +203,7 @@ def run_file(self, selected_uuid=None, selected_executor=None): exec_params = self.get_last_used_executor_parameters( self.currently_selected_configuration) - first_execution = exec_params['first_execution'] display_dialog = exec_params['display_dialog'] - display_dialog = display_dialog or first_execution self.edit_run_configurations( display_dialog=display_dialog, @@ -258,7 +255,7 @@ def process_run_dialog_result(self, result): last_used_conf = StoredRunConfigurationExecutor( executor=executor_name, selected=ext_params['uuid'], - display_dialog=open_dialog, first_execution=False) + display_dialog=open_dialog) self.set_last_used_execution_params(uuid, last_used_conf) @@ -285,13 +282,20 @@ def process_run_dialog_result(self, result): def re_run_file(self): self.run_file(self.last_executed_file, selected_executor=None) + + @property + def currently_selected_configuration(self): + return self.metadata_model.get_current_run_configuration() def switch_focused_run_configuration(self, uuid: Optional[str]): uuid = uuid or None - if uuid is not None and uuid != self.currently_selected_configuration: + if uuid == self.currently_selected_configuration: + return + + self.metadata_model.set_current_run_configuration(uuid) + + if uuid is not None: self.run_action.setEnabled(True) - self.currently_selected_configuration = uuid - self.metadata_model.set_current_run_configuration(uuid) metadata = self.metadata_model[uuid] self.current_input_provider = metadata['source'] @@ -300,21 +304,23 @@ def switch_focused_run_configuration(self, uuid: Optional[str]): input_provider = self.run_metadata_provider[uuid] input_provider.focus_run_configuration(uuid) self.set_actions_status() - elif uuid is None: - self.run_action.setEnabled(False) - for context, act, mod in self.context_actions: - action, __ = self.context_actions[(context, act, mod)] - action.setEnabled(False) + return - for context, act, mod in self.re_run_actions: - action, __ = self.re_run_actions[(context, act, mod)] - action.setEnabled(False) + self.run_action.setEnabled(False) + + for context, act, mod in self.context_actions: + action, __ = self.context_actions[(context, act, mod)] + action.setEnabled(False) - for context_name, executor_name in self.run_executor_actions: - action, __ = self.run_executor_actions[ - (context_name, executor_name)] - action.setEnabled(False) + for context, act, mod in self.re_run_actions: + action, __ = self.re_run_actions[(context, act, mod)] + action.setEnabled(False) + + for context_name, executor_name in self.run_executor_actions: + action, __ = self.run_executor_actions[ + (context_name, executor_name)] + action.setEnabled(False) def set_actions_status(self): if self.current_input_provider is None: @@ -581,7 +587,6 @@ def register_run_configuration_provider( provider_name, set({})) for supported_extension_contexts in supported_extensions_contexts: - ext = supported_extension_contexts['input_extension'] for ext_context in supported_extension_contexts['contexts']: context = ext_context['context'] is_super = ext_context['is_super'] @@ -591,7 +596,11 @@ def register_run_configuration_provider( context_identifier = camel_case_to_snake_case(context_name) context['identifier'] = context_identifier setattr(RunContext, context_name, context_identifier) - provider_extensions_contexts |= {(ext, context_identifier)} + ext_list = supported_extension_contexts['input_extension'] + if not isinstance(ext_list, list): + ext_list = [ext_list] + for ext in ext_list: + provider_extensions_contexts |= {(ext, context_identifier)} if is_super: self.super_contexts |= {context_identifier} @@ -719,7 +728,6 @@ def register_executor_configuration( executor_count = self.executor_use_count.get(executor_id, 0) for config in configuration: - ext = config['input_extension'] context = config['context'] context_name = context['name'] context_id = context.get('identifier', None) @@ -738,9 +746,13 @@ def register_executor_configuration( output_formats.append(updated_out) config['output_formats'] = output_formats - self.executor_model.add_input_executor_configuration( - ext, context_id, executor_id, config) - executor_count += 1 + ext_list = config['input_extension'] + if not isinstance(ext_list, list): + ext_list = [ext_list] + for ext in ext_list: + self.executor_model.add_input_executor_configuration( + ext, context_id, executor_id, config) + executor_count += 1 self.executor_use_count[executor_id] = executor_count self.executor_model.set_executor_name(executor_id, executor_name) @@ -936,10 +948,10 @@ def get_last_used_executor_parameters( last_used_params = mru_executors_uuids.get( uuid, StoredRunConfigurationExecutor( - executor=None, - selected=None, - display_dialog=False, - first_execution=True) + executor=None, + selected=None, + display_dialog=False, + ) ) return last_used_params @@ -976,8 +988,7 @@ def get_last_used_execution_params( default = StoredRunConfigurationExecutor( executor=executor_name, selected=None, - display_dialog=False, - first_execution=True + display_dialog=False ) params = mru_executors_uuids.get(uuid, default) diff --git a/spyder/plugins/run/models.py b/spyder/plugins/run/models.py index 7dccce0eae5..b713675c137 100644 --- a/spyder/plugins/run/models.py +++ b/spyder/plugins/run/models.py @@ -175,6 +175,9 @@ def get_metadata_context_extension(self, uuid: str): def set_current_run_configuration(self, uuid: str): self.current_configuration = uuid + + def get_current_run_configuration(self): + return self.current_configuration def get_initial_index(self) -> int: return self.inverted_index[self.current_configuration] @@ -237,6 +240,8 @@ def pop(self, uuid: str) -> RunConfigurationMetadata: item = self.run_configurations.pop(uuid) self.metadata_index = dict(enumerate(self.run_configurations)) self.inverted_index = {v: k for k, v in self.metadata_index.items()} + if self.current_configuration not in self.inverted_index: + self.current_configuration = None self.dataChanged.emit(self.createIndex(0, 0), self.createIndex(len(self.metadata_index), 0)) return item diff --git a/spyder/plugins/run/plugin.py b/spyder/plugins/run/plugin.py index a5d7f070622..c70fe90b08a 100644 --- a/spyder/plugins/run/plugin.py +++ b/spyder/plugins/run/plugin.py @@ -62,16 +62,6 @@ class Run(SpyderPluginV2): focused `RunConfigurationProvider` """ - sig_switch_run_configuration_focus = Signal(str) - """ - Change the current run configuration to the one that is focused. - - Arguments - --------- - uuid: str - The run configuration identifier. - """ - # ---- SpyderPluginV2 API # ------------------------------------------------------------------------- @staticmethod @@ -94,9 +84,6 @@ def on_initialize(self): self.shortcut_actions = {} self.action_lock = Lock() - self.sig_switch_run_configuration_focus.connect( - self.switch_focused_run_configuration) - container = self.get_container() container.sig_run_action_created.connect( self.register_action_shortcuts) @@ -274,6 +261,12 @@ def register_run_configuration_metadata( """ self.get_container().register_run_configuration_metadata( provider, metadata) + + def get_currently_selected_configuration(self): + """ + Get currently selected configuration + """ + return self.get_container().currently_selected_configuration def deregister_run_configuration_metadata(self, uuid: str): """ diff --git a/spyder/plugins/run/tests/test_run.py b/spyder/plugins/run/tests/test_run.py index 53b25b760d7..a4f35592bd7 100644 --- a/spyder/plugins/run/tests/test_run.py +++ b/spyder/plugins/run/tests/test_run.py @@ -617,7 +617,6 @@ def test_run_plugin(qtbot, run_mock): assert stored_run_params['executor'] == test_executor_name assert stored_run_params['selected'] is None assert not stored_run_params['display_dialog'] - assert not stored_run_params['first_execution'] # The configuration gets run again with qtbot.waitSignal(executor_1.sig_run_invocation) as sig: @@ -780,7 +779,6 @@ def test_run_plugin(qtbot, run_mock): assert stored_run_params['executor'] == executor_name assert stored_run_params['selected'] == exec_conf_uuid assert not stored_run_params['display_dialog'] - assert not stored_run_params['first_execution'] # Test teardown functions executor_1.on_run_teardown(run)