Skip to content

Commit

Permalink
Merge from 5.x: PR #19068
Browse files Browse the repository at this point in the history
Fixes #19003
  • Loading branch information
dalthviz committed Aug 18, 2022
2 parents fb7facd + 40216aa commit 49c3c77
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 40 deletions.
112 changes: 112 additions & 0 deletions spyder/app/tests/test_mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -5776,5 +5776,117 @@ def test_visible_plugins(main_window, qtbot):
assert set(selected) == set(visible_plugins)


@pytest.mark.slow
def test_cwd_is_synced_when_switching_consoles(main_window, qtbot, tmpdir):
"""
Test that the current working directory is synced between the IPython
console and other plugins when switching consoles.
"""
ipyconsole = main_window.ipyconsole
workdir = main_window.workingdirectory
files = main_window.get_plugin(Plugins.Explorer)

# Wait for the window to be fully up
shell = ipyconsole.get_current_shellwidget()
qtbot.waitUntil(lambda: shell._prompt_html is not None,
timeout=SHELL_TIMEOUT)

# Create two new clients and change their cwd's
for i in range(2):
sync_dir = tmpdir.mkdir(f'test_sync_{i}')
ipyconsole.create_new_client()
shell = ipyconsole.get_current_shellwidget()
qtbot.waitUntil(lambda: shell._prompt_html is not None,
timeout=SHELL_TIMEOUT)
with qtbot.waitSignal(shell.executed):
shell.execute(f'cd {str(sync_dir)}')

# Switch between clients and check that the cwd is in sync with other
# plugins
for i in range(3):
ipyconsole.get_widget().tabwidget.setCurrentIndex(i)
shell_cwd = ipyconsole.get_current_shellwidget().get_cwd()
assert shell_cwd == workdir.get_workdir() == files.get_current_folder()


@pytest.mark.slow
def test_console_initial_cwd_is_synced(main_window, qtbot, tmpdir):
"""
Test that the initial current working directory for new consoles is synced
with other plugins.
"""
ipyconsole = main_window.ipyconsole
workdir = main_window.workingdirectory
files = main_window.get_plugin(Plugins.Explorer)

# Wait for the window to be fully up
shell = ipyconsole.get_current_shellwidget()
qtbot.waitUntil(lambda: shell._prompt_html is not None,
timeout=SHELL_TIMEOUT)

# Open console from Files in tmpdir
files.get_widget().treewidget.open_interpreter([str(tmpdir)])
shell = ipyconsole.get_current_shellwidget()
qtbot.waitUntil(lambda: shell._prompt_html is not None,
timeout=SHELL_TIMEOUT)
assert shell.get_cwd() == str(tmpdir) == workdir.get_workdir() == \
files.get_current_folder()

# Check that a new client has the same initial cwd as the current one
ipyconsole.create_new_client()
shell = ipyconsole.get_current_shellwidget()
qtbot.waitUntil(lambda: shell._prompt_html is not None,
timeout=SHELL_TIMEOUT)
qtbot.wait(500)
assert shell.get_cwd() == str(tmpdir) == workdir.get_workdir() == \
files.get_current_folder()

# Check new clients with a fixed directory
ipyconsole.set_conf('console/use_cwd', False, section='workingdir')
ipyconsole.set_conf(
'console/use_fixed_directory',
True,
section='workingdir'
)

fixed_dir = str(tmpdir.mkdir('fixed_dir'))
ipyconsole.set_conf(
'console/fixed_directory',
fixed_dir,
section='workingdir'
)

ipyconsole.create_new_client()
shell = ipyconsole.get_current_shellwidget()
qtbot.waitUntil(lambda: shell._prompt_html is not None,
timeout=SHELL_TIMEOUT)
qtbot.wait(500)
assert shell.get_cwd() == fixed_dir == workdir.get_workdir() == \
files.get_current_folder()

# Check when opening projects
project_path = str(tmpdir.mkdir('test_project'))
main_window.projects.open_project(path=project_path)
qtbot.wait(500)

shell = ipyconsole.get_current_shellwidget()
qtbot.waitUntil(lambda: shell._prompt_html is not None,
timeout=SHELL_TIMEOUT)
qtbot.wait(500)
assert shell.get_cwd() == project_path == workdir.get_workdir() == \
files.get_current_folder()

# Check when closing projects
main_window.projects.close_project()
qtbot.wait(500)

shell = ipyconsole.get_current_shellwidget()
qtbot.waitUntil(lambda: shell._prompt_html is not None,
timeout=SHELL_TIMEOUT)
qtbot.wait(500)
assert shell.get_cwd() == get_home_dir() == workdir.get_workdir() == \
files.get_current_folder()


if __name__ == "__main__":
pytest.main()
12 changes: 8 additions & 4 deletions spyder/plugins/explorer/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ class Explorer(SpyderDockablePlugin):
New path for renamed folder.
"""

sig_interpreter_opened = Signal(str)
sig_open_interpreter_requested = Signal(str)
"""
This signal is emitted to request opening an interpreter with the given
path as working directory.
Expand Down Expand Up @@ -177,7 +177,7 @@ def on_initialize(self):
widget.sig_file_created.connect(self.sig_file_created)
widget.sig_open_file_requested.connect(self.sig_open_file_requested)
widget.sig_open_interpreter_requested.connect(
self.sig_interpreter_opened)
self.sig_open_interpreter_requested)
widget.sig_module_created.connect(self.sig_module_created)
widget.sig_removed.connect(self.sig_file_removed)
widget.sig_renamed.connect(self.sig_file_renamed)
Expand Down Expand Up @@ -207,7 +207,7 @@ def on_preferences_available(self):
@on_plugin_available(plugin=Plugins.IPythonConsole)
def on_ipython_console_available(self):
ipyconsole = self.get_plugin(Plugins.IPythonConsole)
self.sig_interpreter_opened.connect(
self.sig_open_interpreter_requested.connect(
ipyconsole.create_client_from_path)
self.sig_run_requested.connect(
lambda fname:
Expand Down Expand Up @@ -240,7 +240,7 @@ def on_preferences_teardown(self):
@on_plugin_teardown(plugin=Plugins.IPythonConsole)
def on_ipython_console_teardown(self):
ipyconsole = self.get_plugin(Plugins.IPythonConsole)
self.sig_interpreter_opened.disconnect(
self.sig_open_interpreter_requested.disconnect(
ipyconsole.create_client_from_path)
self.sig_run_requested.disconnect()

Expand All @@ -260,6 +260,10 @@ def chdir(self, directory, emit=True):
"""
self.get_widget().chdir(directory, emit=emit)

def get_current_folder(self):
"""Get folder displayed at the moment."""
return self.get_widget().get_current_folder()

def refresh(self, new_path=None, force_current=True):
"""
Refresh history.
Expand Down
1 change: 1 addition & 0 deletions spyder/plugins/explorer/widgets/explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,7 @@ def setup(self):
self.open_interpreter_action = self.create_action(
DirViewActions.OpenInterpreter,
text=_("Open IPython console here"),
icon=self.create_icon('ipython_console'),
triggered=lambda: self.open_interpreter(),
)

Expand Down
23 changes: 15 additions & 8 deletions spyder/plugins/ipythonconsole/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ def on_projects_available(self):
def on_working_directory_available(self):
working_directory = self.get_plugin(Plugins.WorkingDirectory)
working_directory.sig_current_directory_changed.connect(
self._set_working_directory)
self.save_working_directory)

@on_plugin_teardown(plugin=Plugins.Preferences)
def on_preferences_teardown(self):
Expand Down Expand Up @@ -379,7 +379,7 @@ def on_projects_teardown(self):
def on_working_directory_teardown(self):
working_directory = self.get_plugin(Plugins.WorkingDirectory)
working_directory.sig_current_directory_changed.disconnect(
self._set_working_directory)
self.save_working_directory)

def update_font(self):
"""Update font from Preferences"""
Expand Down Expand Up @@ -426,11 +426,6 @@ def _remove_old_std_files(self):
except Exception:
pass

@Slot(str)
def _set_working_directory(self, new_dir):
"""Set current working directory on the main widget."""
self.get_widget().set_working_directory(new_dir)

# ---- Public API
# -------------------------------------------------------------------------

Expand Down Expand Up @@ -784,7 +779,7 @@ def set_current_client_working_directory(self, directory):

def set_working_directory(self, dirname):
"""
Set current working directory for the `workingdirectory` and `explorer`
Set current working directory in the Working Directory and Files
plugins.
Parameters
Expand All @@ -798,6 +793,18 @@ def set_working_directory(self, dirname):
"""
self.get_widget().set_working_directory(dirname)

@Slot(str)
def save_working_directory(self, dirname):
"""
Save current working directory on the main widget to start new clients.
Parameters
----------
new_dir: str
Path to the new current working directory.
"""
self.get_widget().save_working_directory(dirname)

def update_working_directory(self):
"""Update working directory to console current working directory."""
self.get_widget().update_working_directory()
Expand Down
2 changes: 1 addition & 1 deletion spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py
Original file line number Diff line number Diff line change
Expand Up @@ -2283,7 +2283,7 @@ def get_cwd_of_new_client():

# Simulate a specific directory
cwd_dir = str(tmpdir.mkdir('ipyconsole_cwd_test'))
ipyconsole.get_widget().set_working_directory(cwd_dir)
ipyconsole.get_widget().save_working_directory(cwd_dir)

# Get cwd of new client and assert is the expected one
assert get_cwd_of_new_client() == cwd_dir
Expand Down
22 changes: 14 additions & 8 deletions spyder/plugins/ipythonconsole/widgets/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ def __init__(self, parent, id_,
handlers={},
stderr_obj=None,
stdout_obj=None,
fault_obj=None):
fault_obj=None,
initial_cwd=None):
super(ClientWidget, self).__init__(parent)
SaveHistoryMixin.__init__(self, history_filename)

Expand All @@ -123,6 +124,7 @@ def __init__(self, parent, id_,
self.reset_warning = reset_warning
self.ask_before_restart = ask_before_restart
self.ask_before_closing = ask_before_closing
self.initial_cwd = initial_cwd

# --- Other attrs
self.context_menu_actions = context_menu_actions
Expand Down Expand Up @@ -220,8 +222,8 @@ def _when_prompt_is_ready(self):
# To show if special console is valid
self._check_special_console_error()

# Set the initial current working directory
self._set_initial_cwd()
# Set the initial current working directory in the kernel
self._set_initial_cwd_in_kernel()

self.shellwidget.sig_prompt_ready.disconnect(
self._when_prompt_is_ready)
Expand Down Expand Up @@ -351,11 +353,12 @@ def _connect_control_signals(self):
page_control.sig_show_find_widget_requested.connect(
self.container.find_widget.show)

def _set_initial_cwd(self):
"""Set initial cwd according to preferences."""
logger.debug("Setting initial working directory")
def _set_initial_cwd_in_kernel(self):
"""Set the initial cwd in the kernel."""
logger.debug("Setting initial working directory in the kernel")
cwd_path = get_home_dir()
project_path = self.container.get_active_project_path()
emit_cwd_change = True

# This is for the first client
if self.id_['int_id'] == '1':
Expand All @@ -377,7 +380,9 @@ def _set_initial_cwd(self):
)
else:
# For new clients
if self.get_conf(
if self.initial_cwd is not None:
cwd_path = self.initial_cwd
elif self.get_conf(
'console/use_project_or_home_directory',
section='workingdir'
):
Expand All @@ -386,6 +391,7 @@ def _set_initial_cwd(self):
cwd_path = project_path
elif self.get_conf('console/use_cwd', section='workingdir'):
cwd_path = self.container.get_working_directory()
emit_cwd_change = False
elif self.get_conf(
'console/use_fixed_directory',
section='workingdir'
Expand All @@ -397,7 +403,7 @@ def _set_initial_cwd(self):
)

if osp.isdir(cwd_path):
self.shellwidget.set_cwd(cwd_path)
self.shellwidget.set_cwd(cwd_path, emit_cwd_change=emit_cwd_change)

# ----- Public API --------------------------------------------------------
@property
Expand Down
Loading

0 comments on commit 49c3c77

Please sign in to comment.