From 300383c1df88561232a8c61c53783ebaa8f6b016 Mon Sep 17 00:00:00 2001 From: Ryan Clary Date: Wed, 20 Jul 2022 14:41:25 -0700 Subject: [PATCH 01/15] Cleanup main configuration file. Alphabetize DEFAULTS and NAME_MAP. PEP8 --- spyder/config/main.py | 1117 +++++++++++++++++++++-------------------- 1 file changed, 559 insertions(+), 558 deletions(-) diff --git a/spyder/config/main.py b/spyder/config/main.py index 2155163f02b..3cc8dceb665 100644 --- a/spyder/config/main.py +++ b/spyder/config/main.py @@ -58,488 +58,488 @@ # Defaults # ============================================================================= DEFAULTS = [ - ('main', - { - 'opengl': 'software', - 'single_instance': True, - 'open_files_port': OPEN_FILES_PORT, - 'mac_open_file': False, - 'normal_screen_resolution': True, - 'high_dpi_scaling': False, - 'high_dpi_custom_scale_factor': False, - 'high_dpi_custom_scale_factors': '1.5', - 'vertical_tabs': False, - 'prompt_on_exit': False, - 'panes_locked': True, - 'window/size': (1260, 740), - 'window/position': (10, 10), - 'window/is_maximized': True, - 'window/is_fullscreen': False, - 'window/prefs_dialog_size': (1050, 530), - 'use_custom_margin': True, - 'custom_margin': 0, - 'use_custom_cursor_blinking': False, - 'show_internal_errors': True, - 'check_updates_on_startup': True, - 'cursor/width': 2, - 'completion/size': (300, 180), - 'report_error/remember_token': False, - 'show_dpi_message': True, - }), - ('toolbar', - { - 'enable': True, - 'toolbars_visible': True, - 'last_visible_toolbars': [], - }), - ('statusbar', - { - 'show_status_bar': True, - 'memory_usage/enable': True, - 'memory_usage/timeout': 2000, - 'cpu_usage/enable': False, - 'cpu_usage/timeout': 2000, - 'clock/enable': False, - 'clock/timeout': 1000, - }), - ('quick_layouts', - { - 'place_holder': '', - 'names': [], - 'order': [], - 'active': [], - 'ui_names': [] - }), - ('internal_console', - { - 'max_line_count': 300, - 'working_dir_history': 30, - 'working_dir_adjusttocontents': False, - 'wrap': True, - 'codecompletion/auto': False, - 'external_editor/path': 'SciTE', - 'external_editor/gotoline': '-goto:', - }), - ('main_interpreter', - { - 'default': True, - 'custom': False, - 'umr/enabled': True, - 'umr/verbose': True, - 'umr/namelist': [], - 'custom_interpreters_list': [], - 'custom_interpreter': '', - }), - ('ipython_console', - { - 'show_banner': True, - 'completion_type': 0, - 'show_calltips': True, - 'ask_before_closing': False, - 'show_reset_namespace_warning': True, - 'buffer_size': 500, - 'pylab': True, - 'pylab/autoload': False, - 'pylab/backend': 0, - 'pylab/inline/figure_format': 0, - 'pylab/inline/resolution': 72, - 'pylab/inline/width': 6, - 'pylab/inline/height': 4, - 'pylab/inline/bbox_inches': True, - 'startup/run_lines': '', - 'startup/use_run_file': False, - 'startup/run_file': '', - 'greedy_completer': False, - 'jedi_completer': False, - 'autocall': 0, - 'symbolic_math': False, - 'in_prompt': '', - 'out_prompt': '', - 'show_elapsed_time': False, - 'ask_before_restart': True, - # This is True because there are libraries like Pyomo - # that generate a lot of Command Prompts while running, - # and that's extremely annoying for Windows users. - 'hide_cmd_windows': True, - 'pdb_prevent_closing': True, - 'pdb_ignore_lib': False, - 'pdb_execute_events': True, - 'pdb_use_exclamation_mark': True, - 'pdb_stop_first_line': True - }), - ('variable_explorer', - { - 'check_all': CHECK_ALL, - 'dataframe_format': '.6g', # No percent sign to avoid problems - # with ConfigParser's interpolation - 'excluded_names': EXCLUDED_NAMES, - 'exclude_private': True, - 'exclude_uppercase': False, - 'exclude_capitalized': False, - 'exclude_unsupported': False, - 'exclude_callables_and_modules': True, - 'truncate': True, - 'minmax': False, - 'show_callable_attributes': True, - 'show_special_attributes': False - }), - ('plots', - { - 'mute_inline_plotting': True, - 'show_plot_outline': False, - 'auto_fit_plotting': True - }), - ('editor', - { - 'printer_header/font/family': SANS_SERIF, - 'printer_header/font/size': MEDIUM, - 'printer_header/font/italic': False, - 'printer_header/font/bold': False, - 'wrap': False, - 'wrapflag': True, - 'todo_list': True, - 'realtime_analysis': True, - 'realtime_analysis/timeout': 2500, - 'outline_explorer': True, - 'line_numbers': True, - 'blank_spaces': False, - 'edge_line': True, - 'edge_line_columns': '79', - 'indent_guides': False, - 'code_folding': True, - 'show_code_folding_warning': True, - 'scroll_past_end': False, - 'toolbox_panel': True, - 'close_parentheses': True, - 'close_quotes': True, - 'add_colons': True, - 'auto_unindent': True, - 'indent_chars': '* *', - 'tab_stop_width_spaces': 4, - 'check_eol_chars': True, - 'convert_eol_on_save': False, - 'convert_eol_on_save_to': 'LF', - 'tab_always_indent': False, - 'intelligent_backspace': True, - 'automatic_completions': True, - 'automatic_completions_after_chars': 3, - 'automatic_completions_after_ms': 300, - 'completions_hint': True, - 'completions_hint_after_ms': 500, - 'underline_errors': False, - 'highlight_current_line': True, - 'highlight_current_cell': True, - 'occurrence_highlighting': True, - 'occurrence_highlighting/timeout': 1500, - 'always_remove_trailing_spaces': False, - 'add_newline': False, - 'always_remove_trailing_newlines': False, - 'show_tab_bar': True, - 'show_class_func_dropdown': False, - 'max_recent_files': 20, - 'save_all_before_run': True, - 'focus_to_editor': True, - 'run_cell_copy': False, - 'onsave_analysis': False, - 'autosave_enabled': True, - 'autosave_interval': 60, - 'docstring_type': 'Numpydoc', - 'strip_trailing_spaces_on_modify': False, - }), - ('historylog', - { - 'enable': True, - 'wrap': True, - 'go_to_eof': True, - 'line_numbers': False, - }), - ('help', - { - 'enable': True, - 'max_history_entries': 20, - 'wrap': True, - 'connect/editor': False, - 'connect/ipython_console': False, - 'math': True, - 'automatic_import': True, - 'plain_mode': False, - 'rich_mode': True, - 'show_source': False, - 'locked': False, - }), - ('onlinehelp', - { - 'enable': True, - 'zoom_factor': .8, - 'handle_links': False, - 'max_history_entries': 20, - }), - ('outline_explorer', - { - 'enable': True, - 'show_fullpath': False, - 'show_all_files': False, - 'group_cells': True, - 'sort_files_alphabetically': False, - 'show_comments': True, - 'follow_cursor': True, - 'display_variables': False - }), - ('project_explorer', - { - 'name_filters': NAME_FILTERS, - 'show_all': True, - 'show_hscrollbar': True, - 'max_recent_projects': 10, - 'visible_if_project_open': True, - 'date_column': False, - 'single_click_to_open': False, - 'show_hidden': True, - 'size_column': False, - 'type_column': False, - 'date_column': False - }), - ('explorer', - { - 'enable': True, - 'name_filters': NAME_FILTERS, - 'show_hidden': False, - 'single_click_to_open': False, - 'size_column': False, - 'type_column': False, - 'date_column': True - }), - ('find_in_files', - { - 'enable': True, - 'supported_encodings': ["utf-8", "iso-8859-1", "cp1252"], - 'exclude': EXCLUDE_PATTERNS, - 'exclude_regexp': False, - 'search_text_regexp': False, - 'search_text': [''], - 'search_text_samples': [TASKS_PATTERN], - 'more_options': False, - 'case_sensitive': False, - 'exclude_case_sensitive': False, - 'max_results': 1000, - }), - ('breakpoints', - { - 'enable': True, - }), - ('completions', - { - 'enable': True, - 'enable_code_snippets': True, - 'completions_wait_for_ms': 200, - 'enabled_providers': {}, - 'provider_configuration': {}, - 'request_priorities': {} - }), - ('profiler', - { - 'enable': True, - }), - ('pylint', - { - 'enable': True, - 'history_filenames': [], - 'max_entries': 30, - 'project_dir': None, - }), - ('workingdir', - { - 'working_dir_adjusttocontents': False, - 'working_dir_history': 20, - 'console/use_project_or_home_directory': False, - 'console/use_cwd': True, - 'console/use_fixed_directory': False, - 'startup/use_project_or_home_directory': True, - 'startup/use_fixed_directory': False, - }), - ('tours', - { - 'enable': True, - 'show_tour_message': True, - }), - ('shortcuts', - { - # ---- Global ---- - # -- In app/spyder.py - '_/close pane': "Shift+Ctrl+F4", - '_/lock unlock panes': "Shift+Ctrl+F5", - '_/use next layout': "Shift+Alt+PgDown", - '_/use previous layout': "Shift+Alt+PgUp", - '_/maximize pane': "Ctrl+Alt+Shift+M", - '_/fullscreen mode': "F11", - '_/save current layout': "Shift+Alt+S", - '_/layout preferences': "Shift+Alt+P", - '_/spyder documentation': "F1", - '_/restart': "Shift+Alt+R", - '_/quit': "Ctrl+Q", - # -- In plugins/editor - '_/file switcher': 'Ctrl+P', - '_/symbol finder': 'Ctrl+Alt+P', - '_/debug': "Ctrl+F5", - '_/debug step over': "Ctrl+F10", - '_/debug continue': "Ctrl+F12", - '_/debug step into': "Ctrl+F11", - '_/debug step return': "Ctrl+Shift+F11", - '_/debug exit': "Ctrl+Shift+F12", - '_/run': "F5", - '_/configure': "Ctrl+F6", - '_/re-run last script': "F6", - # -- In plugins/init - '_/switch to help': "Ctrl+Shift+H", - '_/switch to outline_explorer': "Ctrl+Shift+O", - '_/switch to editor': "Ctrl+Shift+E", - '_/switch to historylog': "Ctrl+Shift+L", - '_/switch to onlinehelp': "Ctrl+Shift+D", - '_/switch to project_explorer': "Ctrl+Shift+P", - '_/switch to ipython_console': "Ctrl+Shift+I", - '_/switch to variable_explorer': "Ctrl+Shift+V", - '_/switch to find_in_files': "Ctrl+Shift+F", - '_/switch to explorer': "Ctrl+Shift+X", - '_/switch to plots': "Ctrl+Shift+G", - '_/switch to pylint': "Ctrl+Shift+C", - '_/switch to profiler': "Ctrl+Shift+R", - # -- In widgets/findreplace.py - 'find_replace/find text': "Ctrl+F", - 'find_replace/find next': "F3", - 'find_replace/find previous': "Shift+F3", - 'find_replace/replace text': "Ctrl+R", - 'find_replace/hide find and replace': "Escape", - # ---- Editor ---- - # -- In widgets/sourcecode/codeeditor.py - 'editor/code completion': CTRL+'+Space', - 'editor/duplicate line up': ( - "Ctrl+Alt+Up" if WIN else "Shift+Alt+Up"), - 'editor/duplicate line down': ( - "Ctrl+Alt+Down" if WIN else "Shift+Alt+Down"), - 'editor/delete line': 'Ctrl+D', - 'editor/transform to uppercase': 'Ctrl+Shift+U', - 'editor/transform to lowercase': 'Ctrl+U', - 'editor/indent': 'Ctrl+]', - 'editor/unindent': 'Ctrl+[', - 'editor/move line up': "Alt+Up", - 'editor/move line down': "Alt+Down", - 'editor/go to new line': "Ctrl+Shift+Return", - 'editor/go to definition': "Ctrl+G", - 'editor/toggle comment': "Ctrl+1", - 'editor/blockcomment': "Ctrl+4", - 'editor/unblockcomment': "Ctrl+5", - 'editor/start of line': "Meta+A", - 'editor/end of line': "Meta+E", - 'editor/previous line': "Meta+P", - 'editor/next line': "Meta+N", - 'editor/previous char': "Meta+B", - 'editor/next char': "Meta+F", - 'editor/previous word': "Ctrl+Left", - 'editor/next word': "Ctrl+Right", - 'editor/kill to line end': "Meta+K", - 'editor/kill to line start': "Meta+U", - 'editor/yank': 'Meta+Y', - 'editor/rotate kill ring': 'Shift+Meta+Y', - 'editor/kill previous word': 'Meta+Backspace', - 'editor/kill next word': 'Meta+D', - 'editor/start of document': 'Ctrl+Home', - 'editor/end of document': 'Ctrl+End', - 'editor/undo': 'Ctrl+Z', - 'editor/redo': 'Ctrl+Shift+Z', - 'editor/cut': 'Ctrl+X', - 'editor/copy': 'Ctrl+C', - 'editor/paste': 'Ctrl+V', - 'editor/delete': 'Del', - 'editor/select all': "Ctrl+A", - # -- In widgets/editor.py - 'editor/inspect current object': 'Ctrl+I', - 'editor/breakpoint': 'F12', - 'editor/conditional breakpoint': 'Shift+F12', - 'editor/run selection': "F9", - 'editor/run to line': 'Shift+F9', - 'editor/run from line': CTRL + '+F9', - 'editor/go to line': 'Ctrl+L', - 'editor/go to previous file': CTRL + '+Shift+Tab', - 'editor/go to next file': CTRL + '+Tab', - 'editor/cycle to previous file': 'Ctrl+PgUp', - 'editor/cycle to next file': 'Ctrl+PgDown', - 'editor/new file': "Ctrl+N", - 'editor/open last closed':"Ctrl+Shift+T", - 'editor/open file': "Ctrl+O", - 'editor/save file': "Ctrl+S", - 'editor/save all': "Ctrl+Alt+S", - 'editor/save as': 'Ctrl+Shift+S', - 'editor/close all': "Ctrl+Shift+W", - 'editor/last edit location': "Ctrl+Alt+Shift+Left", - 'editor/previous cursor position': "Alt+Left", - 'editor/next cursor position': "Alt+Right", - 'editor/previous warning': "Ctrl+Alt+Shift+,", - 'editor/next warning': "Ctrl+Alt+Shift+.", - 'editor/zoom in 1': "Ctrl++", - 'editor/zoom in 2': "Ctrl+=", - 'editor/zoom out': "Ctrl+-", - 'editor/zoom reset': "Ctrl+0", - 'editor/close file 1': "Ctrl+W", - 'editor/close file 2': "Ctrl+F4", - 'editor/run cell': CTRL + '+Return', - 'editor/run cell and advance': 'Shift+Return', - 'editor/debug cell': 'Alt+Shift+Return', - 'editor/go to next cell': 'Ctrl+Down', - 'editor/go to previous cell': 'Ctrl+Up', - 'editor/re-run last cell': 'Alt+Return', - 'editor/split vertically': "Ctrl+{", - 'editor/split horizontally': "Ctrl+_", - 'editor/close split panel': "Alt+Shift+W", - 'editor/docstring': "Ctrl+Alt+D", - 'editor/autoformatting': "Ctrl+Alt+I", - 'editor/show in external file explorer': '', - # -- In Breakpoints - '_/switch to breakpoints': "Ctrl+Shift+B", - # ---- Consoles (in widgets/shell) ---- - 'console/inspect current object': "Ctrl+I", - 'console/clear shell': "Ctrl+L", - 'console/clear line': "Shift+Escape", - # ---- In Pylint ---- - 'pylint/run analysis': "F8", - # ---- In Profiler ---- - 'profiler/run profiler': "F10", - # ---- In widgets/ipythonconsole/shell.py ---- - 'ipython_console/new tab': "Ctrl+T", - 'ipython_console/reset namespace': "Ctrl+Alt+R", - 'ipython_console/restart kernel': "Ctrl+.", - 'ipython_console/inspect current object': "Ctrl+I", - 'ipython_console/clear shell': "Ctrl+L", - 'ipython_console/clear line': "Shift+Escape", - 'ipython_console/enter array inline': "Ctrl+Alt+M", - 'ipython_console/enter array table': "Ctrl+M", - # ---- In widgets/arraybuider.py ---- - 'array_builder/enter array inline': "Ctrl+Alt+M", - 'array_builder/enter array table': "Ctrl+M", - # ---- In widgets/variableexplorer/arrayeditor.py ---- - 'variable_explorer/copy': 'Ctrl+C', - # ---- In widgets/variableexplorer/namespacebrowser.py ---- - 'variable_explorer/search': 'Ctrl+F', - 'variable_explorer/refresh': 'Ctrl+R', - # ---- In widgets/plots/figurebrowser.py ---- - 'plots/copy': 'Ctrl+C', - 'plots/previous figure': 'Ctrl+PgUp', - 'plots/next figure': 'Ctrl+PgDown', - 'plots/save': 'Ctrl+S', - 'plots/save all': 'Ctrl+Alt+S', - 'plots/close': 'Ctrl+W', - 'plots/close all': 'Ctrl+Shift+W', - 'plots/zoom in': "Ctrl++", - 'plots/zoom out': "Ctrl+-", - # ---- In widgets/explorer ---- - 'explorer/copy file': 'Ctrl+C', - 'explorer/paste file': 'Ctrl+V', - 'explorer/copy absolute path': 'Ctrl+Alt+C', - 'explorer/copy relative path': 'Ctrl+Alt+Shift+C', - # ---- In plugins/findinfiles/plugin ---- - 'find_in_files/find in files': 'Alt+Shift+F', - }), - ('appearance', APPEARANCE), - ] + ('appearance', APPEARANCE), + ('breakpoints', + { + 'enable': True, + }), + ('completions', + { + 'enable': True, + 'enable_code_snippets': True, + 'completions_wait_for_ms': 200, + 'enabled_providers': {}, + 'provider_configuration': {}, + 'request_priorities': {} + }), + ('editor', + { + 'printer_header/font/family': SANS_SERIF, + 'printer_header/font/size': MEDIUM, + 'printer_header/font/italic': False, + 'printer_header/font/bold': False, + 'wrap': False, + 'wrapflag': True, + 'todo_list': True, + 'realtime_analysis': True, + 'realtime_analysis/timeout': 2500, + 'outline_explorer': True, + 'line_numbers': True, + 'blank_spaces': False, + 'edge_line': True, + 'edge_line_columns': '79', + 'indent_guides': False, + 'code_folding': True, + 'show_code_folding_warning': True, + 'scroll_past_end': False, + 'toolbox_panel': True, + 'close_parentheses': True, + 'close_quotes': True, + 'add_colons': True, + 'auto_unindent': True, + 'indent_chars': '* *', + 'tab_stop_width_spaces': 4, + 'check_eol_chars': True, + 'convert_eol_on_save': False, + 'convert_eol_on_save_to': 'LF', + 'tab_always_indent': False, + 'intelligent_backspace': True, + 'automatic_completions': True, + 'automatic_completions_after_chars': 3, + 'automatic_completions_after_ms': 300, + 'completions_hint': True, + 'completions_hint_after_ms': 500, + 'underline_errors': False, + 'highlight_current_line': True, + 'highlight_current_cell': True, + 'occurrence_highlighting': True, + 'occurrence_highlighting/timeout': 1500, + 'always_remove_trailing_spaces': False, + 'add_newline': False, + 'always_remove_trailing_newlines': False, + 'show_tab_bar': True, + 'show_class_func_dropdown': False, + 'max_recent_files': 20, + 'save_all_before_run': True, + 'focus_to_editor': True, + 'run_cell_copy': False, + 'onsave_analysis': False, + 'autosave_enabled': True, + 'autosave_interval': 60, + 'docstring_type': 'Numpydoc', + 'strip_trailing_spaces_on_modify': False, + }), + ('explorer', + { + 'enable': True, + 'name_filters': NAME_FILTERS, + 'show_hidden': False, + 'single_click_to_open': False, + 'size_column': False, + 'type_column': False, + 'date_column': True + }), + ('find_in_files', + { + 'enable': True, + 'supported_encodings': ["utf-8", "iso-8859-1", "cp1252"], + 'exclude': EXCLUDE_PATTERNS, + 'exclude_regexp': False, + 'search_text_regexp': False, + 'search_text': [''], + 'search_text_samples': [TASKS_PATTERN], + 'more_options': False, + 'case_sensitive': False, + 'exclude_case_sensitive': False, + 'max_results': 1000, + }), + ('help', + { + 'enable': True, + 'max_history_entries': 20, + 'wrap': True, + 'connect/editor': False, + 'connect/ipython_console': False, + 'math': True, + 'automatic_import': True, + 'plain_mode': False, + 'rich_mode': True, + 'show_source': False, + 'locked': False, + }), + ('historylog', + { + 'enable': True, + 'wrap': True, + 'go_to_eof': True, + 'line_numbers': False, + }), + ('internal_console', + { + 'max_line_count': 300, + 'working_dir_history': 30, + 'working_dir_adjusttocontents': False, + 'wrap': True, + 'codecompletion/auto': False, + 'external_editor/path': 'SciTE', + 'external_editor/gotoline': '-goto:', + }), + ('ipython_console', + { + 'show_banner': True, + 'completion_type': 0, + 'show_calltips': True, + 'ask_before_closing': False, + 'show_reset_namespace_warning': True, + 'buffer_size': 500, + 'pylab': True, + 'pylab/autoload': False, + 'pylab/backend': 0, + 'pylab/inline/figure_format': 0, + 'pylab/inline/resolution': 72, + 'pylab/inline/width': 6, + 'pylab/inline/height': 4, + 'pylab/inline/bbox_inches': True, + 'startup/run_lines': '', + 'startup/use_run_file': False, + 'startup/run_file': '', + 'greedy_completer': False, + 'jedi_completer': False, + 'autocall': 0, + 'symbolic_math': False, + 'in_prompt': '', + 'out_prompt': '', + 'show_elapsed_time': False, + 'ask_before_restart': True, + # This is True because there are libraries like Pyomo + # that generate a lot of Command Prompts while running, + # and that's extremely annoying for Windows users. + 'hide_cmd_windows': True, + 'pdb_prevent_closing': True, + 'pdb_ignore_lib': False, + 'pdb_execute_events': True, + 'pdb_use_exclamation_mark': True, + 'pdb_stop_first_line': True + }), + ('main', + { + 'opengl': 'software', + 'single_instance': True, + 'open_files_port': OPEN_FILES_PORT, + 'mac_open_file': False, + 'normal_screen_resolution': True, + 'high_dpi_scaling': False, + 'high_dpi_custom_scale_factor': False, + 'high_dpi_custom_scale_factors': '1.5', + 'vertical_tabs': False, + 'prompt_on_exit': False, + 'panes_locked': True, + 'window/size': (1260, 740), + 'window/position': (10, 10), + 'window/is_maximized': True, + 'window/is_fullscreen': False, + 'window/prefs_dialog_size': (1050, 530), + 'use_custom_margin': True, + 'custom_margin': 0, + 'use_custom_cursor_blinking': False, + 'show_internal_errors': True, + 'check_updates_on_startup': True, + 'cursor/width': 2, + 'completion/size': (300, 180), + 'report_error/remember_token': False, + 'show_dpi_message': True, + }), + ('main_interpreter', + { + 'default': True, + 'custom': False, + 'umr/enabled': True, + 'umr/verbose': True, + 'umr/namelist': [], + 'custom_interpreters_list': [], + 'custom_interpreter': '', + }), + ('onlinehelp', + { + 'enable': True, + 'zoom_factor': .8, + 'handle_links': False, + 'max_history_entries': 20, + }), + ('outline_explorer', + { + 'enable': True, + 'show_fullpath': False, + 'show_all_files': False, + 'group_cells': True, + 'sort_files_alphabetically': False, + 'show_comments': True, + 'follow_cursor': True, + 'display_variables': False + }), + ('plots', + { + 'mute_inline_plotting': True, + 'show_plot_outline': False, + 'auto_fit_plotting': True + }), + ('profiler', + { + 'enable': True, + }), + ('project_explorer', + { + 'name_filters': NAME_FILTERS, + 'show_all': True, + 'show_hscrollbar': True, + 'max_recent_projects': 10, + 'visible_if_project_open': True, + 'date_column': False, + 'single_click_to_open': False, + 'show_hidden': True, + 'size_column': False, + 'type_column': False, + 'date_column': False + }), + ('pylint', + { + 'enable': True, + 'history_filenames': [], + 'max_entries': 30, + 'project_dir': None, + }), + ('quick_layouts', + { + 'place_holder': '', + 'names': [], + 'order': [], + 'active': [], + 'ui_names': [] + }), + ('shortcuts', + { + # ---- Global ---- + # -- In app/spyder.py + '_/close pane': "Shift+Ctrl+F4", + '_/lock unlock panes': "Shift+Ctrl+F5", + '_/use next layout': "Shift+Alt+PgDown", + '_/use previous layout': "Shift+Alt+PgUp", + '_/maximize pane': "Ctrl+Alt+Shift+M", + '_/fullscreen mode': "F11", + '_/save current layout': "Shift+Alt+S", + '_/layout preferences': "Shift+Alt+P", + '_/spyder documentation': "F1", + '_/restart': "Shift+Alt+R", + '_/quit': "Ctrl+Q", + # -- In plugins/editor + '_/file switcher': 'Ctrl+P', + '_/symbol finder': 'Ctrl+Alt+P', + '_/debug': "Ctrl+F5", + '_/debug step over': "Ctrl+F10", + '_/debug continue': "Ctrl+F12", + '_/debug step into': "Ctrl+F11", + '_/debug step return': "Ctrl+Shift+F11", + '_/debug exit': "Ctrl+Shift+F12", + '_/run': "F5", + '_/configure': "Ctrl+F6", + '_/re-run last script': "F6", + # -- In plugins/init + '_/switch to help': "Ctrl+Shift+H", + '_/switch to outline_explorer': "Ctrl+Shift+O", + '_/switch to editor': "Ctrl+Shift+E", + '_/switch to historylog': "Ctrl+Shift+L", + '_/switch to onlinehelp': "Ctrl+Shift+D", + '_/switch to project_explorer': "Ctrl+Shift+P", + '_/switch to ipython_console': "Ctrl+Shift+I", + '_/switch to variable_explorer': "Ctrl+Shift+V", + '_/switch to find_in_files': "Ctrl+Shift+F", + '_/switch to explorer': "Ctrl+Shift+X", + '_/switch to plots': "Ctrl+Shift+G", + '_/switch to pylint': "Ctrl+Shift+C", + '_/switch to profiler': "Ctrl+Shift+R", + # -- In widgets/findreplace.py + 'find_replace/find text': "Ctrl+F", + 'find_replace/find next': "F3", + 'find_replace/find previous': "Shift+F3", + 'find_replace/replace text': "Ctrl+R", + 'find_replace/hide find and replace': "Escape", + # ---- Editor ---- + # -- In widgets/sourcecode/codeeditor.py + 'editor/code completion': CTRL + '+Space', + 'editor/duplicate line up': ( + "Ctrl+Alt+Up" if WIN else "Shift+Alt+Up"), + 'editor/duplicate line down': ( + "Ctrl+Alt+Down" if WIN else "Shift+Alt+Down"), + 'editor/delete line': 'Ctrl+D', + 'editor/transform to uppercase': 'Ctrl+Shift+U', + 'editor/transform to lowercase': 'Ctrl+U', + 'editor/indent': 'Ctrl+]', + 'editor/unindent': 'Ctrl+[', + 'editor/move line up': "Alt+Up", + 'editor/move line down': "Alt+Down", + 'editor/go to new line': "Ctrl+Shift+Return", + 'editor/go to definition': "Ctrl+G", + 'editor/toggle comment': "Ctrl+1", + 'editor/blockcomment': "Ctrl+4", + 'editor/unblockcomment': "Ctrl+5", + 'editor/start of line': "Meta+A", + 'editor/end of line': "Meta+E", + 'editor/previous line': "Meta+P", + 'editor/next line': "Meta+N", + 'editor/previous char': "Meta+B", + 'editor/next char': "Meta+F", + 'editor/previous word': "Ctrl+Left", + 'editor/next word': "Ctrl+Right", + 'editor/kill to line end': "Meta+K", + 'editor/kill to line start': "Meta+U", + 'editor/yank': 'Meta+Y', + 'editor/rotate kill ring': 'Shift+Meta+Y', + 'editor/kill previous word': 'Meta+Backspace', + 'editor/kill next word': 'Meta+D', + 'editor/start of document': 'Ctrl+Home', + 'editor/end of document': 'Ctrl+End', + 'editor/undo': 'Ctrl+Z', + 'editor/redo': 'Ctrl+Shift+Z', + 'editor/cut': 'Ctrl+X', + 'editor/copy': 'Ctrl+C', + 'editor/paste': 'Ctrl+V', + 'editor/delete': 'Del', + 'editor/select all': "Ctrl+A", + # -- In widgets/editor.py + 'editor/inspect current object': 'Ctrl+I', + 'editor/breakpoint': 'F12', + 'editor/conditional breakpoint': 'Shift+F12', + 'editor/run selection': "F9", + 'editor/run to line': 'Shift+F9', + 'editor/run from line': CTRL + '+F9', + 'editor/go to line': 'Ctrl+L', + 'editor/go to previous file': CTRL + '+Shift+Tab', + 'editor/go to next file': CTRL + '+Tab', + 'editor/cycle to previous file': 'Ctrl+PgUp', + 'editor/cycle to next file': 'Ctrl+PgDown', + 'editor/new file': "Ctrl+N", + 'editor/open last closed': "Ctrl+Shift+T", + 'editor/open file': "Ctrl+O", + 'editor/save file': "Ctrl+S", + 'editor/save all': "Ctrl+Alt+S", + 'editor/save as': 'Ctrl+Shift+S', + 'editor/close all': "Ctrl+Shift+W", + 'editor/last edit location': "Ctrl+Alt+Shift+Left", + 'editor/previous cursor position': "Alt+Left", + 'editor/next cursor position': "Alt+Right", + 'editor/previous warning': "Ctrl+Alt+Shift+,", + 'editor/next warning': "Ctrl+Alt+Shift+.", + 'editor/zoom in 1': "Ctrl++", + 'editor/zoom in 2': "Ctrl+=", + 'editor/zoom out': "Ctrl+-", + 'editor/zoom reset': "Ctrl+0", + 'editor/close file 1': "Ctrl+W", + 'editor/close file 2': "Ctrl+F4", + 'editor/run cell': CTRL + '+Return', + 'editor/run cell and advance': 'Shift+Return', + 'editor/debug cell': 'Alt+Shift+Return', + 'editor/go to next cell': 'Ctrl+Down', + 'editor/go to previous cell': 'Ctrl+Up', + 'editor/re-run last cell': 'Alt+Return', + 'editor/split vertically': "Ctrl+{", + 'editor/split horizontally': "Ctrl+_", + 'editor/close split panel': "Alt+Shift+W", + 'editor/docstring': "Ctrl+Alt+D", + 'editor/autoformatting': "Ctrl+Alt+I", + 'editor/show in external file explorer': '', + # -- In Breakpoints + '_/switch to breakpoints': "Ctrl+Shift+B", + # ---- Consoles (in widgets/shell) ---- + 'console/inspect current object': "Ctrl+I", + 'console/clear shell': "Ctrl+L", + 'console/clear line': "Shift+Escape", + # ---- In Pylint ---- + 'pylint/run analysis': "F8", + # ---- In Profiler ---- + 'profiler/run profiler': "F10", + # ---- In widgets/ipythonconsole/shell.py ---- + 'ipython_console/new tab': "Ctrl+T", + 'ipython_console/reset namespace': "Ctrl+Alt+R", + 'ipython_console/restart kernel': "Ctrl+.", + 'ipython_console/inspect current object': "Ctrl+I", + 'ipython_console/clear shell': "Ctrl+L", + 'ipython_console/clear line': "Shift+Escape", + 'ipython_console/enter array inline': "Ctrl+Alt+M", + 'ipython_console/enter array table': "Ctrl+M", + # ---- In widgets/arraybuider.py ---- + 'array_builder/enter array inline': "Ctrl+Alt+M", + 'array_builder/enter array table': "Ctrl+M", + # ---- In widgets/variableexplorer/arrayeditor.py ---- + 'variable_explorer/copy': 'Ctrl+C', + # ---- In widgets/variableexplorer/namespacebrowser.py ---- + 'variable_explorer/search': 'Ctrl+F', + 'variable_explorer/refresh': 'Ctrl+R', + # ---- In widgets/plots/figurebrowser.py ---- + 'plots/copy': 'Ctrl+C', + 'plots/previous figure': 'Ctrl+PgUp', + 'plots/next figure': 'Ctrl+PgDown', + 'plots/save': 'Ctrl+S', + 'plots/save all': 'Ctrl+Alt+S', + 'plots/close': 'Ctrl+W', + 'plots/close all': 'Ctrl+Shift+W', + 'plots/zoom in': "Ctrl++", + 'plots/zoom out': "Ctrl+-", + # ---- In widgets/explorer ---- + 'explorer/copy file': 'Ctrl+C', + 'explorer/paste file': 'Ctrl+V', + 'explorer/copy absolute path': 'Ctrl+Alt+C', + 'explorer/copy relative path': 'Ctrl+Alt+Shift+C', + # ---- In plugins/findinfiles/plugin ---- + 'find_in_files/find in files': 'Alt+Shift+F', + }), + ('statusbar', + { + 'show_status_bar': True, + 'memory_usage/enable': True, + 'memory_usage/timeout': 2000, + 'cpu_usage/enable': False, + 'cpu_usage/timeout': 2000, + 'clock/enable': False, + 'clock/timeout': 1000, + }), + ('toolbar', + { + 'enable': True, + 'toolbars_visible': True, + 'last_visible_toolbars': [], + }), + ('tours', + { + 'enable': True, + 'show_tour_message': True, + }), + ('variable_explorer', + { + 'check_all': CHECK_ALL, + 'dataframe_format': '.6g', # No percent sign to avoid problems + # with ConfigParser's interpolation + 'excluded_names': EXCLUDED_NAMES, + 'exclude_private': True, + 'exclude_uppercase': False, + 'exclude_capitalized': False, + 'exclude_unsupported': False, + 'exclude_callables_and_modules': True, + 'truncate': True, + 'minmax': False, + 'show_callable_attributes': True, + 'show_special_attributes': False + }), + ('workingdir', + { + 'working_dir_adjusttocontents': False, + 'working_dir_history': 20, + 'console/use_project_or_home_directory': False, + 'console/use_cwd': True, + 'console/use_fixed_directory': False, + 'startup/use_project_or_home_directory': True, + 'startup/use_fixed_directory': False, + }), +] NAME_MAP = { @@ -550,81 +550,82 @@ # These options change on spyder startup or are tied to a specific OS, # not good for version control 'transient': [ - ('main', [ - 'completion/size', - 'crash', - 'current_version', - 'historylog_filename', - 'spyder_pythonpath', - 'window/position', - 'window/prefs_dialog_size', - 'window/size', - 'window/state', - ] - ), - ('toolbar', [ - 'last_visible_toolbars', - ] - ), - ('editor', [ - 'autosave_mapping', - 'bookmarks', - 'filenames', - 'layout_settings', - 'recent_files', - 'splitter_state', - ] - ), - ('explorer', [ - 'file_associations', - ]), - ('find_in_files', [ - 'path_history' - 'search_text', - 'exclude_index', - 'search_in_index', - ] - ), - ('main_interpreter', [ - 'custom_interpreters_list', - 'custom_interpreter', - 'executable', - ] - ), - ('onlinehelp', [ - 'zoom_factor', - ] - ), - ('outline_explorer', [ - 'expanded_state', - 'scrollbar_position', - ], - ), - ('project_explorer', [ - 'current_project_path', - 'expanded_state', - 'recent_projects', - 'max_recent_projects', - 'scrollbar_position', - ] - ), - ('quick_layouts', []), # Empty list means use all options - ('run', [ - 'breakpoints', - 'configurations', - 'defaultconfiguration', - 'default/wdir/fixed_directory', - ] - ), - ('workingdir', [ - 'console/fixed_directory', - 'startup/fixed_directory', - ] - ), - ('pylint', [ - 'history_filenames', - ] - ), + ('editor', + [ + 'autosave_mapping', + 'bookmarks', + 'filenames', + 'layout_settings', + 'recent_files', + 'splitter_state', + ]), + ('explorer', + [ + 'file_associations', + ]), + ('find_in_files', + [ + 'path_history' + 'search_text', + 'exclude_index', + 'search_in_index', + ]), + ('main', + [ + 'completion/size', + 'crash', + 'current_version', + 'historylog_filename', + 'spyder_pythonpath', + 'window/position', + 'window/prefs_dialog_size', + 'window/size', + 'window/state', + ]), + ('main_interpreter', + [ + 'custom_interpreters_list', + 'custom_interpreter', + 'executable', + ]), + ('onlinehelp', + [ + 'zoom_factor', + ]), + ('outline_explorer', + [ + 'expanded_state', + 'scrollbar_position', + ]), + ('project_explorer', + [ + 'current_project_path', + 'expanded_state', + 'recent_projects', + 'max_recent_projects', + 'scrollbar_position', + ]), + ('quick_layouts', []), # Empty list means use all options + ('run', + [ + 'breakpoints', + 'configurations', + 'defaultconfiguration', + 'default/wdir/fixed_directory', + ]), + ('toolbar', + [ + 'last_visible_toolbars', + ]), + ('workingdir', + [ + 'console/fixed_directory', + 'startup/fixed_directory', + ]), + ('pylint', + [ + 'history_filenames', + ]), ] } @@ -639,4 +640,4 @@ # or if you want to *rename* options, then you need to do a MAJOR update in # version, e.g. from 3.0.0 to 4.0.0 # 3. You don't need to touch this value if you're just adding a new option -CONF_VERSION = '71.0.0' +CONF_VERSION = '70.4.0' From ab2b13b191ff326e77acfafc531f84d55193f559 Mon Sep 17 00:00:00 2001 From: Ryan Clary Date: Wed, 20 Jul 2022 14:24:01 -0700 Subject: [PATCH 02/15] Add pythonpath_manager to configuration manager --- spyder/config/main.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spyder/config/main.py b/spyder/config/main.py index 3cc8dceb665..69ca5cebf64 100644 --- a/spyder/config/main.py +++ b/spyder/config/main.py @@ -308,6 +308,11 @@ 'max_entries': 30, 'project_dir': None, }), + ('pythonpath_manager', + { + 'paths': {}, + 'prepend': False, + }), ('quick_layouts', { 'place_holder': '', @@ -605,6 +610,7 @@ 'max_recent_projects', 'scrollbar_position', ]), + ('pythonpath_manager', []), # Empty list means use all options ('quick_layouts', []), # Empty list means use all options ('run', [ From 5b9f6af8c74bceb3f5a135bb0a00b5e7290accf5 Mon Sep 17 00:00:00 2001 From: Ryan Clary Date: Thu, 21 Jul 2022 10:38:12 -0700 Subject: [PATCH 03/15] Rename get_spyder_pythonpath to get_spyder_active_pythonpath --- spyder/app/mainwindow.py | 2 +- spyder/plugins/editor/plugin.py | 6 +++--- spyder/plugins/profiler/plugin.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spyder/app/mainwindow.py b/spyder/app/mainwindow.py index 7737a6ca1e5..3d1f1330b4b 100644 --- a/spyder/app/mainwindow.py +++ b/spyder/app/mainwindow.py @@ -1714,7 +1714,7 @@ def get_spyder_pythonpath_dict(self): return path_dict - def get_spyder_pythonpath(self): + def get_spyder_active_pythonpath(self): """ Return Spyder PYTHONPATH. """ diff --git a/spyder/plugins/editor/plugin.py b/spyder/plugins/editor/plugin.py index 26fe24f7e6e..2eb83bf288a 100644 --- a/spyder/plugins/editor/plugin.py +++ b/spyder/plugins/editor/plugin.py @@ -1783,7 +1783,7 @@ def set_current_filename(self, filename, editorwindow=None, focus=True): def set_path(self): for finfo in self.editorstacks[0].data: - finfo.path = self.main.get_spyder_pythonpath() + finfo.path = self.main.get_spyder_active_pythonpath() #------ Refresh methods def refresh_file_dependent_actions(self): @@ -2073,7 +2073,7 @@ def new(self, fname=None, editorstack=None, text=None): # See: spyder-ide/spyder#12596 finfo = self.editorstacks[0].new(fname, enc, text, default_content, empty=True) - finfo.path = self.main.get_spyder_pythonpath() + finfo.path = self.main.get_spyder_active_pythonpath() self._clone_file_everywhere(finfo) current_editor = current_es.set_current_filename(finfo.filename) self.register_widget_shortcuts(current_editor) @@ -2265,7 +2265,7 @@ def _convert(fname): finfo = self.editorstacks[0].load( filename, set_current=False, add_where=add_where, processevents=processevents) - finfo.path = self.main.get_spyder_pythonpath() + finfo.path = self.main.get_spyder_active_pythonpath() self._clone_file_everywhere(finfo) current_editor = current_es.set_current_filename(filename, focus=focus) diff --git a/spyder/plugins/profiler/plugin.py b/spyder/plugins/profiler/plugin.py index e19bc89209d..ed08246e1ed 100644 --- a/spyder/plugins/profiler/plugin.py +++ b/spyder/plugins/profiler/plugin.py @@ -158,7 +158,7 @@ def analyze(self, filename): Path to file to analyze. """ # TODO: how to get access to this in a better way? - pythonpath = self.main.get_spyder_pythonpath() + pythonpath = self.main.get_spyder_active_pythonpath() wdir, args = None, [] runconf = get_run_configuration(filename) From 6ed37572aeb60410da9bc378915233c988921706 Mon Sep 17 00:00:00 2001 From: Ryan Clary Date: Thu, 21 Jul 2022 10:41:29 -0700 Subject: [PATCH 04/15] Rename get_spyder_pythonpath_dict to get_spyder_pythonpath --- spyder/app/mainwindow.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spyder/app/mainwindow.py b/spyder/app/mainwindow.py index 3d1f1330b4b..a1b40697a27 100644 --- a/spyder/app/mainwindow.py +++ b/spyder/app/mainwindow.py @@ -760,7 +760,7 @@ def setup(self): from spyder.plugins.help.utils.sphinxify import CSS_PATH, DARK_CSS_PATH logger.info("*** Start of MainWindow setup ***") logger.info("Updating PYTHONPATH") - path_dict = self.get_spyder_pythonpath_dict() + path_dict = self.get_spyder_pythonpath() self.update_python_path(path_dict) logger.info("Applying theme configuration...") @@ -1693,7 +1693,7 @@ def save_python_path(self, new_path_dict): logger.error(str(e)) CONF.set('main', 'spyder_pythonpath', self.get_spyder_pythonpath()) - def get_spyder_pythonpath_dict(self): + def get_spyder_pythonpath(self): """ Return Spyder PYTHONPATH. @@ -1718,14 +1718,14 @@ def get_spyder_active_pythonpath(self): """ Return Spyder PYTHONPATH. """ - path_dict = self.get_spyder_pythonpath_dict() + path_dict = self.get_spyder_pythonpath() path = [k for k, v in path_dict.items() if v] return path def update_python_path(self, new_path_dict): """Update python path on Spyder interpreter and kernels.""" # Load previous path - path_dict = self.get_spyder_pythonpath_dict() + path_dict = self.get_spyder_pythonpath() # Save path if path_dict != new_path_dict: @@ -1733,7 +1733,7 @@ def update_python_path(self, new_path_dict): self.save_python_path(new_path_dict) # Load new path - new_path_dict_p = self.get_spyder_pythonpath_dict() # Includes project + new_path_dict_p = self.get_spyder_pythonpath() # Includes project # Any plugin that needs to do some work based on this signal should # connect to it on plugin registration @@ -1773,7 +1773,7 @@ def pythonpath_changed(self): self.project_path = () if projects: self.project_path = tuple(projects.get_pythonpath()) - path_dict = self.get_spyder_pythonpath_dict() + path_dict = self.get_spyder_pythonpath() self.update_python_path(path_dict) #---- Preferences From df0eff3e005c1ee328dde9e7a62ce5a240285222 Mon Sep 17 00:00:00 2001 From: Ryan Clary Date: Thu, 21 Jul 2022 10:56:33 -0700 Subject: [PATCH 05/15] Build spyder pythonpath dictionary in get_spyder_pythonpath. Use the configuration manager and the projects paths to build pythonpath dictionary. Projects plugin to connect update_python_path on project change instead of pythonpath_changed. --- spyder/app/mainwindow.py | 27 ++++++++++++--------------- spyder/plugins/projects/plugin.py | 2 +- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/spyder/app/mainwindow.py b/spyder/app/mainwindow.py index a1b40697a27..d01167e0381 100644 --- a/spyder/app/mainwindow.py +++ b/spyder/app/mainwindow.py @@ -1695,34 +1695,31 @@ def save_python_path(self, new_path_dict): def get_spyder_pythonpath(self): """ - Return Spyder PYTHONPATH. + Return Spyder PYTHONPATH, including project paths, as ordered + dictionary. - The returned ordered dictionary has the paths as keys and the state - as values. The state is `True` for active and `False` for inactive. - - Example: - OrderedDict([('/some/path, True), ('/some/other/path, False)]) + The returned dictionary has the paths as keys and the state as values. + The state is `True` for active and `False` for inactive. """ - self.load_python_path() - - path_dict = OrderedDict() - for path in self.path: - path_dict[path] = path not in self.not_active_path + path_dict = OrderedDict(CONF.get('pythonpath_manager', 'paths')) - for path in self.project_path: - path_dict[path] = True + projects = self.get_plugin(Plugins.Projects, error=False) + if projects: + for path in tuple(projects.get_pythonpath()): + path_dict[path] = True return path_dict def get_spyder_active_pythonpath(self): """ - Return Spyder PYTHONPATH. + Return Spyder PYTHONPATH, including project paths, as list of active + paths. """ path_dict = self.get_spyder_pythonpath() path = [k for k, v in path_dict.items() if v] return path - def update_python_path(self, new_path_dict): + def update_python_path(self, new_path_dict=None): """Update python path on Spyder interpreter and kernels.""" # Load previous path path_dict = self.get_spyder_pythonpath() diff --git a/spyder/plugins/projects/plugin.py b/spyder/plugins/projects/plugin.py index 90fac1ef201..6f17649ddfb 100644 --- a/spyder/plugins/projects/plugin.py +++ b/spyder/plugins/projects/plugin.py @@ -174,7 +174,7 @@ def on_initialize(self): lambda v: self.main.set_window_title()) self.main.restore_scrollbar_position.connect( self.restore_scrollbar_position) - self.sig_pythonpath_changed.connect(self.main.pythonpath_changed) + self.sig_pythonpath_changed.connect(self.main.update_python_path) self.register_project_type(self, EmptyProject) self.setup() From 29363e6e639bced9138ff32cede303b847c30a75 Mon Sep 17 00:00:00 2001 From: Ryan Clary Date: Thu, 21 Jul 2022 11:37:37 -0700 Subject: [PATCH 06/15] Update pythonpath configuration in update_python_path. Use configuration manager. Do not use save_python_path. --- spyder/app/mainwindow.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/spyder/app/mainwindow.py b/spyder/app/mainwindow.py index d01167e0381..00cdcd8edef 100644 --- a/spyder/app/mainwindow.py +++ b/spyder/app/mainwindow.py @@ -1720,21 +1720,20 @@ def get_spyder_active_pythonpath(self): return path def update_python_path(self, new_path_dict=None): - """Update python path on Spyder interpreter and kernels.""" - # Load previous path - path_dict = self.get_spyder_pythonpath() - - # Save path - if path_dict != new_path_dict: - # It doesn't include the project_path - self.save_python_path(new_path_dict) + """ + Update python path in configuration and on Spyder interpreter and + kernels. + """ + old_path = self.get_spyder_pythonpath() + if new_path_dict is not None: + CONF.set('pythonpath_manager', 'paths', dict(new_path_dict)) - # Load new path - new_path_dict_p = self.get_spyder_pythonpath() # Includes project + new_path = self.get_spyder_pythonpath() # Any plugin that needs to do some work based on this signal should # connect to it on plugin registration - self.sig_pythonpath_changed.emit(path_dict, new_path_dict_p) + # ??? Do we need to emit if old and new are same? + self.sig_pythonpath_changed.emit(old_path, new_path) @Slot() def show_path_manager(self): From 81ce2e59c3c09e69cfccebf670ce5c0d0e4ba52f Mon Sep 17 00:00:00 2001 From: Ryan Clary Date: Thu, 21 Jul 2022 15:13:25 -0700 Subject: [PATCH 07/15] Remove obsolete load_python_path, save_python_path, and pythonpath_changed --- spyder/app/mainwindow.py | 43 ---------------------------------------- 1 file changed, 43 deletions(-) diff --git a/spyder/app/mainwindow.py b/spyder/app/mainwindow.py index 00cdcd8edef..70ccf4b0072 100644 --- a/spyder/app/mainwindow.py +++ b/spyder/app/mainwindow.py @@ -128,8 +128,6 @@ class MainWindow(QMainWindow): QMainWindow.AllowTabbedDocks | QMainWindow.AllowNestedDocks | QMainWindow.AnimatedDocks ) - SPYDER_PATH = get_conf_path('path') - SPYDER_NOT_ACTIVE_PATH = get_conf_path('not_active_path') DEFAULT_LAYOUTS = 4 INITIAL_CWD = getcwd_or_home() @@ -1662,37 +1660,6 @@ def open_external_file(self, fname): # --- Path Manager # ------------------------------------------------------------------------ - def load_python_path(self): - """Load path stored in Spyder configuration folder.""" - if osp.isfile(self.SPYDER_PATH): - with open(self.SPYDER_PATH, 'r', encoding='utf-8') as f: - path = f.read().splitlines() - self.path = tuple(name for name in path if osp.isdir(name)) - - if osp.isfile(self.SPYDER_NOT_ACTIVE_PATH): - with open(self.SPYDER_NOT_ACTIVE_PATH, 'r', - encoding='utf-8') as f: - not_active_path = f.read().splitlines() - self.not_active_path = tuple(name for name in not_active_path - if osp.isdir(name)) - - def save_python_path(self, new_path_dict): - """ - Save path in Spyder configuration folder. - - `new_path_dict` is an OrderedDict that has the new paths as keys and - the state as values. The state is `True` for active and `False` for - inactive. - """ - path = [p for p in new_path_dict] - not_active_path = [p for p in new_path_dict if not new_path_dict[p]] - try: - encoding.writelines(path, self.SPYDER_PATH) - encoding.writelines(not_active_path, self.SPYDER_NOT_ACTIVE_PATH) - except EnvironmentError as e: - logger.error(str(e)) - CONF.set('main', 'spyder_pythonpath', self.get_spyder_pythonpath()) - def get_spyder_pythonpath(self): """ Return Spyder PYTHONPATH, including project paths, as ordered @@ -1762,16 +1729,6 @@ def _dialog_finished(result_code): self._path_manager.raise_() self._path_manager.setFocus() - def pythonpath_changed(self): - """Project's PYTHONPATH contribution has changed.""" - projects = self.get_plugin(Plugins.Projects, error=False) - - self.project_path = () - if projects: - self.project_path = tuple(projects.get_pythonpath()) - path_dict = self.get_spyder_pythonpath() - self.update_python_path(path_dict) - #---- Preferences def apply_settings(self): """Apply main window settings.""" From 015557448de2c18812e98e5af7e8ed0d1282bf62 Mon Sep 17 00:00:00 2001 From: Ryan Clary Date: Thu, 21 Jul 2022 14:31:31 -0700 Subject: [PATCH 08/15] Send pythonpath dictionary to PathManager. --- spyder/app/mainwindow.py | 8 ++++---- spyder/widgets/pathmanager.py | 23 +++++++++++------------ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/spyder/app/mainwindow.py b/spyder/app/mainwindow.py index 70ccf4b0072..8e60ea44160 100644 --- a/spyder/app/mainwindow.py +++ b/spyder/app/mainwindow.py @@ -1712,12 +1712,12 @@ def _dialog_finished(result_code): if self._path_manager is None: from spyder.widgets.pathmanager import PathManager projects = self.get_plugin(Plugins.Projects, error=False) - read_only_path = () + read_only_paths = () if projects: - read_only_path = tuple(projects.get_pythonpath()) + read_only_paths = tuple(projects.get_pythonpath()) - dialog = PathManager(self, self.path, read_only_path, - self.not_active_path, sync=True) + paths = self.get_spyder_pythonpath() + dialog = PathManager(self, paths, read_only_paths, sync=True) self._path_manager = dialog dialog.sig_path_changed.connect(self.update_python_path) dialog.redirect_stdio.connect(self.redirect_internalshell_stdio) diff --git a/spyder/widgets/pathmanager.py b/spyder/widgets/pathmanager.py index f562282f772..1852b42f418 100644 --- a/spyder/widgets/pathmanager.py +++ b/spyder/widgets/pathmanager.py @@ -33,15 +33,14 @@ class PathManager(QDialog): redirect_stdio = Signal(bool) sig_path_changed = Signal(object) - def __init__(self, parent, path=None, read_only_path=None, - not_active_path=None, sync=True): + def __init__(self, parent, paths=None, read_only_paths=None, sync=True): """Path manager dialog.""" super(PathManager, self).__init__(parent) - assert isinstance(path, (tuple, type(None))) + assert isinstance(paths, (OrderedDict, type(None))) - self.path = path or () - self.read_only_path = read_only_path or () - self.not_active_path = not_active_path or () + self.paths = paths or OrderedDict() + self.read_only_paths = read_only_paths or () + self.not_active_path = (k for k, v in self.paths.items() if not v) self.last_path = getcwd_or_home() self.original_path_dict = None @@ -185,7 +184,7 @@ def _create_item(self, path): item = QListWidgetItem(path) item.setIcon(ima.icon('DirClosedIcon')) - if path in self.read_only_path: + if path in self.read_only_paths: item.setFlags(Qt.NoItemFlags | Qt.ItemIsUserCheckable) item.setCheckState(Qt.Checked) elif path in self.not_active_path: @@ -200,14 +199,14 @@ def _create_item(self, path): @property def editable_bottom_row(self): """Maximum bottom row count that is editable.""" - read_only_count = len(self.read_only_path) + read_only_count = len(self.read_only_paths) max_row = self.listwidget.count() - read_only_count - 1 return max_row def setup(self): """Populate list widget.""" self.listwidget.clear() - for path in self.path + self.read_only_path: + for path in tuple(self.paths) + self.read_only_paths: item = self._create_item(path) self.listwidget.addItem(item) self.listwidget.setCurrentRow(0) @@ -323,7 +322,7 @@ def get_path_dict(self, read_only=False): for row in range(self.listwidget.count()): item = self.listwidget.item(row) path = item.text() - if path in self.read_only_path and not read_only: + if path in self.read_only_paths and not read_only: continue odict[path] = item.checkState() == Qt.Checked return odict @@ -350,7 +349,7 @@ def refresh(self): widget.setEnabled(False) self.remove_button.setEnabled(self.listwidget.count() - - len(self.read_only_path)) + - len(self.read_only_paths)) self.export_button.setEnabled(self.listwidget.count() > 0) # Ok button only enabled if actual changes occur @@ -492,7 +491,7 @@ def test(): dlg = PathManager( None, path=tuple(sys.path[4:-2]), - read_only_path=tuple(sys.path[-2:]), + read_only_paths=tuple(sys.path[-2:]), ) def callback(path_dict): From 24436e72adea256c91da18f4640b925c7f1bccf2 Mon Sep 17 00:00:00 2001 From: Ryan Clary Date: Thu, 21 Jul 2022 20:41:43 -0700 Subject: [PATCH 09/15] Add get_project_paths method --- spyder/app/mainwindow.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/spyder/app/mainwindow.py b/spyder/app/mainwindow.py index 8e60ea44160..cbd99472e5f 100644 --- a/spyder/app/mainwindow.py +++ b/spyder/app/mainwindow.py @@ -1669,13 +1669,19 @@ def get_spyder_pythonpath(self): The state is `True` for active and `False` for inactive. """ path_dict = OrderedDict(CONF.get('pythonpath_manager', 'paths')) + for path in self.get_project_paths(): + path_dict[path] = True + return path_dict + + def get_project_paths(self): + """Return project paths as tuple""" projects = self.get_plugin(Plugins.Projects, error=False) + proj_paths = () if projects: - for path in tuple(projects.get_pythonpath()): - path_dict[path] = True + proj_paths = tuple(projects.get_pythonpath()) - return path_dict + return proj_paths def get_spyder_active_pythonpath(self): """ @@ -1711,13 +1717,10 @@ def _dialog_finished(result_code): if self._path_manager is None: from spyder.widgets.pathmanager import PathManager - projects = self.get_plugin(Plugins.Projects, error=False) - read_only_paths = () - if projects: - read_only_paths = tuple(projects.get_pythonpath()) - paths = self.get_spyder_pythonpath() - dialog = PathManager(self, paths, read_only_paths, sync=True) + paths = OrderedDict(CONF.get('pythonpath_manager', 'paths')) + proj_paths = self.get_project_paths() + dialog = PathManager(self, paths=paths, read_only_paths=proj_paths) self._path_manager = dialog dialog.sig_path_changed.connect(self.update_python_path) dialog.redirect_stdio.connect(self.redirect_internalshell_stdio) From 2d519fafc76aaaa746b31bacd0d77c44cb9cca29 Mon Sep 17 00:00:00 2001 From: Ryan Clary <9618975+mrclary@users.noreply.github.com> Date: Fri, 22 Jul 2022 11:15:55 -0700 Subject: [PATCH 10/15] Provide persistent old_path attribute because get_spyder_pythonpath will always have latest project path. --- spyder/app/mainwindow.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/spyder/app/mainwindow.py b/spyder/app/mainwindow.py index cbd99472e5f..17f1341367c 100644 --- a/spyder/app/mainwindow.py +++ b/spyder/app/mainwindow.py @@ -568,9 +568,7 @@ def signal_handler(signum, frame=None): self.shortcut_queue = [] # Handle Spyder path - self.path = () - self.not_active_path = () - self.project_path = () + self.old_path = OrderedDict() self._path_manager = None # New API @@ -1697,7 +1695,6 @@ def update_python_path(self, new_path_dict=None): Update python path in configuration and on Spyder interpreter and kernels. """ - old_path = self.get_spyder_pythonpath() if new_path_dict is not None: CONF.set('pythonpath_manager', 'paths', dict(new_path_dict)) @@ -1705,8 +1702,9 @@ def update_python_path(self, new_path_dict=None): # Any plugin that needs to do some work based on this signal should # connect to it on plugin registration - # ??? Do we need to emit if old and new are same? - self.sig_pythonpath_changed.emit(old_path, new_path) + self.sig_pythonpath_changed.emit(self.old_path, new_path) + + self.old_path = new_path @Slot() def show_path_manager(self): From 21742a41c40c162669c491369ccbc726ade771ef Mon Sep 17 00:00:00 2001 From: Ryan Clary Date: Thu, 21 Jul 2022 21:42:36 -0700 Subject: [PATCH 11/15] Cleanup PathManager. Use path dictionary values and remove not_active_path attribute. Do not disable path in path dictionary if it is duplicate of project path. --- spyder/widgets/pathmanager.py | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/spyder/widgets/pathmanager.py b/spyder/widgets/pathmanager.py index 1852b42f418..66a8a83c271 100644 --- a/spyder/widgets/pathmanager.py +++ b/spyder/widgets/pathmanager.py @@ -40,7 +40,6 @@ def __init__(self, parent, paths=None, read_only_paths=None, sync=True): self.paths = paths or OrderedDict() self.read_only_paths = read_only_paths or () - self.not_active_path = (k for k, v in self.paths.items() if not v) self.last_path = getcwd_or_home() self.original_path_dict = None @@ -179,20 +178,20 @@ def _setup_bottom_toolbar(self): return [self.add_button, self.remove_button, self.import_button, self.export_button] - def _create_item(self, path): + def _create_item(self, path, read_only=False, active=True): """Helper to create a new list item.""" item = QListWidgetItem(path) item.setIcon(ima.icon('DirClosedIcon')) - if path in self.read_only_paths: + if read_only: item.setFlags(Qt.NoItemFlags | Qt.ItemIsUserCheckable) - item.setCheckState(Qt.Checked) - elif path in self.not_active_path: - item.setFlags(item.flags() | Qt.ItemIsUserCheckable) - item.setCheckState(Qt.Unchecked) else: item.setFlags(item.flags() | Qt.ItemIsUserCheckable) + + if active: item.setCheckState(Qt.Checked) + else: + item.setCheckState(Qt.Unchecked) return item @@ -206,8 +205,11 @@ def editable_bottom_row(self): def setup(self): """Populate list widget.""" self.listwidget.clear() - for path in tuple(self.paths) + self.read_only_paths: - item = self._create_item(path) + for path, active in self.paths.items(): + item = self._create_item(path, active=active) + self.listwidget.addItem(item) + for path in self.read_only_paths: + item = self._create_item(path, read_only=True) self.listwidget.addItem(item) self.listwidget.setCurrentRow(0) self.original_path_dict = self.get_path_dict() @@ -321,10 +323,9 @@ def get_path_dict(self, read_only=False): odict = OrderedDict() for row in range(self.listwidget.count()): item = self.listwidget.item(row) - path = item.text() - if path in self.read_only_paths and not read_only: - continue - odict[path] = item.checkState() == Qt.Checked + if bool(item.flags() & Qt.ItemIsEnabled) or read_only: + odict[item.text()] = item.checkState() == Qt.Checked + return odict def refresh(self): @@ -490,12 +491,15 @@ def test(): _ = qapplication() dlg = PathManager( None, - path=tuple(sys.path[4:-2]), + paths=OrderedDict({p: True for p in sys.path[4:-2]}), read_only_paths=tuple(sys.path[-2:]), ) def callback(path_dict): - sys.stdout.write(str(path_dict)) + sys.stdout.write( + '\n'.join([f'{k} : {v}' for k, v in path_dict.items()]) + ) + sys.stdout.write('\n') dlg.sig_path_changed.connect(callback) sys.exit(dlg.exec_()) From c338b674dbcacc76e49f5093bccf3df56640c438 Mon Sep 17 00:00:00 2001 From: Ryan Clary Date: Thu, 21 Jul 2022 21:43:33 -0700 Subject: [PATCH 12/15] Ensure that sig_pythonpath_changed is emitted after console restarts in project plugin --- spyder/plugins/projects/plugin.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spyder/plugins/projects/plugin.py b/spyder/plugins/projects/plugin.py index 6f17649ddfb..e7be7508184 100644 --- a/spyder/plugins/projects/plugin.py +++ b/spyder/plugins/projects/plugin.py @@ -532,7 +532,6 @@ def open_project(self, path=None, project=None, restart_consoles=True, self.sig_project_loaded.emit(workdir) else: self.sig_project_loaded.emit(path) - self.sig_pythonpath_changed.emit() self.watcher.start(path) if restart_consoles: @@ -542,6 +541,8 @@ def open_project(self, path=None, project=None, restart_consoles=True, if not open_successfully: QMessageBox.warning(self.get_widget(), "Project open", message) + self.sig_pythonpath_changed.emit() # Wait until console restart + def close_project(self): """ Close current project and return to a window without an active @@ -565,7 +566,6 @@ def close_project(self): self.sig_project_closed.emit(path) self.sig_project_closed[bool].emit(True) - self.sig_pythonpath_changed.emit() # Hide pane. self.set_conf('visible_if_project_open', @@ -576,6 +576,8 @@ def close_project(self): self.restart_consoles() self.watcher.stop() + self.sig_pythonpath_changed.emit() # Wait until console restart + def delete_project(self): """ Delete the current project without deleting the files in the directory. From 66d2d305c198f08d03de9963d1a7eb7649331943 Mon Sep 17 00:00:00 2001 From: Ryan Clary <9618975+mrclary@users.noreply.github.com> Date: Fri, 22 Jul 2022 09:34:44 -0700 Subject: [PATCH 13/15] Update pathmanager unit tests. Update call signatures. Aggregate common path lists. Remove nt constraint on test_button_state --- spyder/widgets/tests/test_pathmanager.py | 59 ++++++++++-------------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/spyder/widgets/tests/test_pathmanager.py b/spyder/widgets/tests/test_pathmanager.py index cbe2db383c5..8ca0a9a3f77 100644 --- a/spyder/widgets/tests/test_pathmanager.py +++ b/spyder/widgets/tests/test_pathmanager.py @@ -15,38 +15,42 @@ import pytest from qtpy.QtCore import Qt, QTimer from qtpy.QtWidgets import QMessageBox, QPushButton +from collections import OrderedDict # Local imports from spyder.py3compat import PY3 from spyder.utils.programs import is_module_installed from spyder.widgets import pathmanager as pathmanager_mod +PATHS = OrderedDict([(p, True) for p in sys.path[:-10]]) +ROPATHS = tuple(sys.path[-10:]) +WPATHS = OrderedDict([('p1', True), ('p2', True), ('p3', True)]) +WROPATHS = ('p4', 'p5', 'p6') + +SPATHS = OrderedDict([('/spam', True), ('/bar', True)]) +SROPATHS = ('/foo',) + @pytest.fixture def pathmanager(qtbot, request): """Set up PathManager.""" - path, read_only_path, not_active_path = request.param + paths, read_only_paths = request.param widget = pathmanager_mod.PathManager( None, - path=tuple(path), - read_only_path=tuple(read_only_path), - not_active_path=tuple(not_active_path)) + paths=paths, + read_only_paths=read_only_paths) qtbot.addWidget(widget) return widget -@pytest.mark.parametrize('pathmanager', - [(sys.path[:-10], sys.path[-10:], ())], - indirect=True) +@pytest.mark.parametrize('pathmanager', [(PATHS, ROPATHS)], indirect=True) def test_pathmanager(pathmanager, qtbot): """Run PathManager test""" pathmanager.show() assert pathmanager -@pytest.mark.parametrize('pathmanager', - [(sys.path[:-10], sys.path[-10:], ())], - indirect=True) +@pytest.mark.parametrize('pathmanager', [(PATHS, ROPATHS)], indirect=True) def test_check_uncheck_path(pathmanager): """ Test that checking and unchecking a path in the PathManager correctly @@ -60,9 +64,7 @@ def test_check_uncheck_path(pathmanager): @pytest.mark.skipif(os.name != 'nt' or not is_module_installed('win32con'), reason=("This feature is not applicable for Unix " "systems and pywin32 is needed")) -@pytest.mark.parametrize('pathmanager', - [(['p1', 'p2', 'p3'], ['p4', 'p5', 'p6'], [])], - indirect=True) +@pytest.mark.parametrize('pathmanager', [(WPATHS, WROPATHS)], indirect=True) def test_export_to_PYTHONPATH(pathmanager, mocker): # Import here to prevent an ImportError when testing on unix systems from spyder.utils.environ import (get_user_env, set_user_env, @@ -77,9 +79,10 @@ def test_export_to_PYTHONPATH(pathmanager, mocker): mocker.patch.object(pathmanager_mod.QMessageBox, 'question', return_value=pathmanager_mod.QMessageBox.Yes) + expected_pathlist = list(WPATHS) + list(WROPATHS) + # Assert that PYTHONPATH is synchronized correctly with Spyder's path list pathmanager.export_pythonpath() - expected_pathlist = ['p1', 'p2', 'p3', 'p4', 'p5', 'p6'] env = get_user_env() assert env['PYTHONPATH'] == expected_pathlist @@ -87,7 +90,7 @@ def test_export_to_PYTHONPATH(pathmanager, mocker): # is synchronized with Spyder's path list pathmanager.listwidget.item(1).setCheckState(Qt.Unchecked) pathmanager.export_pythonpath() - expected_pathlist = ['p1', 'p3', 'p4', 'p5', 'p6'] + expected_pathlist.pop(1) env = get_user_env() assert env['PYTHONPATH'] == expected_pathlist @@ -100,7 +103,8 @@ def test_export_to_PYTHONPATH(pathmanager, mocker): # is synchronized with Spyder's path list pathmanager.listwidget.item(2).setCheckState(Qt.Unchecked) pathmanager.export_pythonpath() - expected_pathlist = ['p3', 'p1', 'p4', 'p5', 'p6'] + p3 = expected_pathlist.pop(1) + expected_pathlist.insert(0, p3) env = get_user_env() assert env['PYTHONPATH'] == expected_pathlist @@ -109,9 +113,7 @@ def test_export_to_PYTHONPATH(pathmanager, mocker): set_user_env(listdict2envdict(env)) -@pytest.mark.parametrize('pathmanager', - [(sys.path[:-10], sys.path[-10:], ())], - indirect=True) +@pytest.mark.parametrize('pathmanager', [(PATHS, ROPATHS)], indirect=True) def test_invalid_directories(qtbot, pathmanager): """Check [site/dist]-packages are invalid paths.""" if os.name == 'nt': @@ -134,9 +136,7 @@ def interact_message_box(): pathmanager.add_path(path) -@pytest.mark.parametrize('pathmanager', - [(('/spam', '/bar'), ('/foo', ), ())], - indirect=True) +@pytest.mark.parametrize('pathmanager', [(SPATHS, SROPATHS)], indirect=True) def test_remove_item_and_reply_no(qtbot, pathmanager): """Check that the item is not removed after answering 'No'.""" pathmanager.show() @@ -160,9 +160,7 @@ def interact_message_box(): assert pathmanager.count() == count -@pytest.mark.parametrize('pathmanager', - [(('/spam', '/bar'), ('/foo', ), ())], - indirect=True) +@pytest.mark.parametrize('pathmanager', [(SPATHS, SROPATHS)], indirect=True) def test_remove_item_and_reply_yes(qtbot, pathmanager): """Check that the item is indeed removed after answering 'Yes'.""" pathmanager.show() @@ -186,9 +184,7 @@ def interact_message_box(): assert pathmanager.count() == (count - 1) -@pytest.mark.parametrize('pathmanager', - [((), (), ())], - indirect=True) +@pytest.mark.parametrize('pathmanager', [(None, ())], indirect=True) def test_add_repeated_item(qtbot, pathmanager, tmpdir): """ Check behavior when an unchecked item that is already on the list is added. @@ -226,12 +222,7 @@ def interact_message_box(): assert all(pathmanager.get_path_dict().values()) -@pytest.mark.skipif(os.name != 'nt' or not is_module_installed('win32con'), - reason=("This feature is not applicable for Unix " - "systems and pywin32 is needed")) -@pytest.mark.parametrize('pathmanager', - [(('/spam', '/bar'), ('/foo', ), ())], - indirect=True) +@pytest.mark.parametrize('pathmanager', [(SPATHS, SROPATHS)], indirect=True) def test_buttons_state(qtbot, pathmanager, tmpdir): """Check buttons are enabled/disabled based on items and position.""" pathmanager.show() From ae590b13ebe09755585b50a4471128cbb038cac5 Mon Sep 17 00:00:00 2001 From: Ryan Clary <9618975+mrclary@users.noreply.github.com> Date: Fri, 22 Jul 2022 11:10:46 -0700 Subject: [PATCH 14/15] PEP8 --- spyder/app/mainwindow.py | 4 ++-- spyder/plugins/profiler/plugin.py | 4 ---- spyder/widgets/tests/test_pathmanager.py | 1 - 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/spyder/app/mainwindow.py b/spyder/app/mainwindow.py index 17f1341367c..556d1cdce67 100644 --- a/spyder/app/mainwindow.py +++ b/spyder/app/mainwindow.py @@ -119,6 +119,7 @@ #============================================================================== qInstallMessageHandler(qt_message_handler) + #============================================================================== # Main Window #============================================================================== @@ -1656,8 +1657,7 @@ def open_external_file(self, fname): .format(fpath=osp.normpath(fpath), fname=fname) ) - # --- Path Manager - # ------------------------------------------------------------------------ + # ---- Path Manager def get_spyder_pythonpath(self): """ Return Spyder PYTHONPATH, including project paths, as ordered diff --git a/spyder/plugins/profiler/plugin.py b/spyder/plugins/profiler/plugin.py index ed08246e1ed..320b79d9968 100644 --- a/spyder/plugins/profiler/plugin.py +++ b/spyder/plugins/profiler/plugin.py @@ -8,9 +8,6 @@ Profiler Plugin. """ -# Standard library imports -import os.path as osp - # Third party imports from qtpy.QtCore import Signal @@ -22,7 +19,6 @@ from spyder.plugins.mainmenu.api import ApplicationMenus from spyder.plugins.profiler.confpage import ProfilerConfigPage from spyder.plugins.profiler.widgets.main_widget import (ProfilerWidget, - ProfilerWidgetActions, is_profiler_installed) from spyder.plugins.run.widgets import get_run_configuration diff --git a/spyder/widgets/tests/test_pathmanager.py b/spyder/widgets/tests/test_pathmanager.py index 8ca0a9a3f77..58c51cb9b4a 100644 --- a/spyder/widgets/tests/test_pathmanager.py +++ b/spyder/widgets/tests/test_pathmanager.py @@ -18,7 +18,6 @@ from collections import OrderedDict # Local imports -from spyder.py3compat import PY3 from spyder.utils.programs import is_module_installed from spyder.widgets import pathmanager as pathmanager_mod From 00410a0bd7e924062dfc4ad6217be415c905a992 Mon Sep 17 00:00:00 2001 From: Ryan Clary <9618975+mrclary@users.noreply.github.com> Date: Thu, 28 Jul 2022 14:00:15 -0700 Subject: [PATCH 15/15] Import existing obsolete path and not_active_path files to modern configuration and remove the files. Revert this commit for a future release. --- spyder/app/mainwindow.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/spyder/app/mainwindow.py b/spyder/app/mainwindow.py index 556d1cdce67..b588b046005 100644 --- a/spyder/app/mainwindow.py +++ b/spyder/app/mainwindow.py @@ -571,6 +571,7 @@ def signal_handler(signum, frame=None): # Handle Spyder path self.old_path = OrderedDict() self._path_manager = None + self.load_python_path() # TODO: Remove on later release # New API self._APPLICATION_TOOLBARS = OrderedDict() @@ -1658,6 +1659,38 @@ def open_external_file(self, fname): ) # ---- Path Manager + def load_python_path(self): + """ + Load paths stored in Spyder configuration folder, add them to the + modern configuration, and remove the obsolete files. + + TODO: Remove on later release + """ + SPYDER_PATH = get_conf_path('path') + SPYDER_NOT_ACTIVE_PATH = get_conf_path('not_active_path') + + path_dict = OrderedDict() + if osp.isfile(SPYDER_PATH): + with open(SPYDER_PATH, 'r', encoding='utf-8') as f: + paths = f.read().splitlines() + for path in paths: + if osp.isdir(path): + path_dict[path] = True + os.remove(SPYDER_PATH) # No longer use file + logger.info(f"Removed obsolete '{SPYDER_PATH}'") + + if osp.isfile(SPYDER_NOT_ACTIVE_PATH): + with open(SPYDER_NOT_ACTIVE_PATH, 'r', encoding='utf-8') as f: + paths = f.read().splitlines() + for path in paths: + if osp.isdir(path): + path_dict[path] = False + os.remove(SPYDER_NOT_ACTIVE_PATH) # No longer use file + logger.info(f"Removed obsolete '{SPYDER_NOT_ACTIVE_PATH}'") + + if path_dict: + self.update_python_path(path_dict) + def get_spyder_pythonpath(self): """ Return Spyder PYTHONPATH, including project paths, as ordered