-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PR: Add detection of external Spyder kernels #4670
Conversation
@@ -45,6 +45,7 @@ class ShellWidget(NamepaceBrowserWidget, HelpWidget, DebuggingWidget): | |||
focus_changed = Signal() | |||
new_client = Signal() | |||
sig_got_reply = Signal() | |||
sig_spyder_kernel = Signal() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's call this sig_is_spykernel
@@ -77,6 +78,14 @@ def is_running(self): | |||
else: | |||
return False | |||
|
|||
def is_spyder_kernel(self): | |||
""".""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing docstring
# attach it to other plugins | ||
self.shellwidget.sig_spyder_kernel.connect( | ||
lambda : self.sig_spyder_kernel.emit(self)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no need for these changes in client.py
. We can directly connect to the signal emitted by shellwidget
in ipythonconsole.py
.
So please remove the signal above and this code here.
spyder/plugins/ipythonconsole.py
Outdated
@@ -1390,6 +1390,13 @@ def process_finished(self, client): | |||
if self.variableexplorer is not None: | |||
self.variableexplorer.remove_shellwidget(id(client.shellwidget)) | |||
|
|||
def connect_shellwidget(self, client): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
connect_shellwidget -> connect_external_kernel_to_varexp
spyder/plugins/ipythonconsole.py
Outdated
kc = client.shellwidget.kernel_client | ||
self.process_started(client) | ||
client.shellwidget.set_namespace_view_settings() | ||
kc.stopped_channels.connect(lambda c=client: self.process_finished(c)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's rewrite this as
sw = client.shellwidget
kc = sw.kernel_client
self.process_started(client)
sw.set_namespace_view_settings()
kc.stopped_channels.connect(lambda c=client: self.process_finished(c))
spyder/plugins/ipythonconsole.py
Outdated
|
||
# Assign kernel manager and client to shellwidget | ||
client.shellwidget.kernel_client = kernel_client | ||
client.shellwidget.kernel_manager = kernel_manager | ||
client.sig_spyder_kernel.connect(self.connect_shellwidget) | ||
kernel_client.start_channels() | ||
client.shellwidget.is_spyder_kernel() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These three lines only apply when master_name is None
because we don't want to do it for clients connected to kernels already created by Spyder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe instead of master_name is None
should we create a validation with the external_kernel
variable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The validation is precisely done here. We iterate over all open clients in the IPython console to see if we're trying to connect to the kernel of a current client. If that's the case, we don't need to connect that kernel to the Variable Explorer because it's already connected.
If that fails, then it means we're trying to connect to an external kernel, in which case we want to connect it to the Variable Explorer (if it's a Spyder kernel, of course).
What you've done was the right thing to do :-)
spyder/plugins/ipythonconsole.py
Outdated
|
||
# Assign kernel manager and client to shellwidget | ||
client.shellwidget.kernel_client = kernel_client | ||
client.shellwidget.kernel_manager = kernel_manager | ||
client.sig_spyder_kernel.connect(self.connect_shellwidget) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be
client.shellwidget.sig_is_spkernel.connect(
self.connect_external_kernel_to_varexp)
spyder/plugins/ipythonconsole.py
Outdated
@@ -1390,6 +1390,18 @@ def process_finished(self, client): | |||
if self.variableexplorer is not None: | |||
self.variableexplorer.remove_shellwidget(id(client.shellwidget)) | |||
|
|||
def connect_external_kernel_to_varexp(self, shellwidget): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forgot about connecting to our Help, so let's rename this to connect_to_external_kernel
spyder/plugins/ipythonconsole.py
Outdated
@@ -1390,6 +1390,18 @@ def process_finished(self, client): | |||
if self.variableexplorer is not None: | |||
self.variableexplorer.remove_shellwidget(id(client.shellwidget)) | |||
|
|||
def connect_external_kernel_to_varexp(self, shellwidget): | |||
"""Connect a shellwidget to the variable explorer.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be
Connect an external kernel to the Variable Explorer and Help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, we need to be more specific
"""
Connect an external kernel to the Variable Explorer and Help, if
it is a Spyder kernel.
"""
This needs tests. For that, please copy the function called https://github.com/jupyter/jupyter_client/blob/master/jupyter_client/manager.py#L445 to ...
km = KernelManager(kernel_name=kernel_name)
if spykernel:
km._kernel_spec = SpyderKernelSpec()
... Using this function, you need to create two kernels (inside the same test): a regular kernel and a Spyder kernel. Then you connect a client to each one of them, run something in them (e.g. To get the connection file of those kernels, you need this km, kc = start_new_kernel()
kc.connection_file And to verify how many rows there are in the Variable Explorer, please use this (inside the test, of course :-): main_window.variableexplorer.visibility_changed(True)
nsb = main_window.variableexplorer.get_focus_widget()
assert nsb.editor.model.rowCount() == 1 |
And at end of test you need to shutdown those kernels with km.shutdown_kernel(now=True) |
spyder/app/tests/test_mainwindow.py
Outdated
@@ -105,6 +126,42 @@ def close_window(): | |||
# Tests | |||
#============================================================================== | |||
@flaky(max_runs=3) | |||
def test_kernel_connection(main_window, qtbot): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test_kernel_connection -> test_connection_to_external_kernel
spyder/app/tests/test_mainwindow.py
Outdated
@@ -105,6 +126,42 @@ def close_window(): | |||
# Tests | |||
#============================================================================== | |||
@flaky(max_runs=3) | |||
def test_kernel_connection(main_window, qtbot): | |||
"""Test that a kernel from Spyder is detected and attached to variable explorer.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change this to
Test that only Spyder kernels are connected to the Variable Explorer
spyder/app/tests/test_mainwindow.py
Outdated
shell = main_window.ipyconsole.get_current_shellwidget() | ||
qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) | ||
with qtbot.waitSignal(shell.executed): | ||
shell.execute('a = 0') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a = 10
spyder/app/tests/test_mainwindow.py
Outdated
|
||
# Assert that there are no variables in the variable explorer | ||
main_window.variableexplorer.visibility_changed(True) | ||
nsb = main_window.variableexplorer.get_focus_widget() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add qtbot.wait(500)
below this line to wait a little bit until the result appears in the Variable Explorer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remember that all these operations are asynchronous
spyder/app/tests/test_mainwindow.py
Outdated
shell = main_window.ipyconsole.get_current_shellwidget() | ||
qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) | ||
with qtbot.waitSignal(shell.executed): | ||
shell.execute('a = 0') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a = 10
spyder/app/tests/test_mainwindow.py
Outdated
# Assert that a variable is visible in the variable explorer | ||
main_window.variableexplorer.visibility_changed(True) | ||
nsb = main_window.variableexplorer.get_focus_widget() | ||
qtbot.waitUntil(lambda: nsb.editor.model.rowCount() == 1, timeout=500) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change this line simply to
qtbot.wait(500)
spyder/app/tests/test_mainwindow.py
Outdated
main_window.variableexplorer.visibility_changed(True) | ||
nsb = main_window.variableexplorer.get_focus_widget() | ||
qtbot.waitUntil(lambda: nsb.editor.model.rowCount() == 1, timeout=500) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove blank
spyder/plugins/ipythonconsole.py
Outdated
def _create_client_for_kernel(self, connection_file, hostname, sshkey, | ||
password): | ||
# Verifying if the connection file exists | ||
try: | ||
cf_path = osp.dirname(connection_file) | ||
cf_filename = osp.basename(connection_file) | ||
# To change a possible empty string to None | ||
falsy_to_none = lambda arg: arg if arg else None | ||
cf_path = falsy_to_none(cf_path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no need of that falsy_to_none
function. You can simply write
cf_path = cf_path if cf_path else None
main_window.ipyconsole._create_client_for_kernel(kc.connection_file, None, | ||
None, None) | ||
shell = main_window.ipyconsole.get_current_shellwidget() | ||
qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You forgot to remove them from here :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is needed to update the shell variable and get the current shellwidget (to execute the code in the new console with the kernel spyder), no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you're right! Then please remove the same lines at the beginning of the test because it makes no sense to have them there.
spyder/app/tests/test_mainwindow.py
Outdated
main_window.variableexplorer.visibility_changed(True) | ||
nsb = main_window.variableexplorer.get_focus_widget() | ||
qtbot.wait(500) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this blank line.
@dalthviz, you committed some garbage files and commented some tests too in your last commit, so please redo it and make a forced push to not have that commit as part of this PR. |
f47a817
to
d60775b
Compare
@ccordoba12 you are right, sorry for that, now it is ok 👍 |
@dalthviz, please move |
@dalthviz, after you solve my last (simple) comments, this is ready to be merged! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @dalthviz for your hard work on this one.
Fixes #4664