Repository: spyder-ide/spyder
Pull request: PR: Add command line option to connect to an existing kernel at startup (IPython console)
<!--- Make sure to read the Contributing Guidelines:                   --->
<!--- https://github.com/spyder-ide/spyder/blob/master/CONTRIBUTING.md --->
<!--- and follow PEP 8, PEP 257 and Spyder's code style:               --->
<!--- https://github.com/spyder-ide/spyder/wiki/Dev:-Coding-Style      --->

## Description of Changes


* [x] Wrote at least one-line docstrings (for any new functions)
* [x] Added unit test(s) covering the changes (if testable)
<!--- Remember that an image/animation is worth a thousand words! --->
* [x] Included a screenshot or animation (if affecting the UI, see [Licecap](https://www.cockos.com/licecap/))


<!--- Explain what you've done and why --->




### Issue(s) Resolved

<!--- List the issue(s) below, in the form "Fixes #1234"; one per line --->

Fixes #23130


### Affirmation

By submitting this Pull Request or typing my (user)name below,
I affirm the [Developer Certificate of Origin](https://developercertificate.org)
with respect to all commits and content included in this PR,
and understand I am releasing the same under Spyder's MIT (Expat) license.

<!--- TYPE YOUR USER/NAME AFTER THE FOLLOWING: --->
I certify the above statement is true and correct: [Social-Mean](https://github.com/Social-Mean)

<!--- Thanks for your help making Spyder better for everyone! --->


Problem statement:
Add command line option to connect to an existing kernel
Can I connect to an existing kernel when I start Spyder?

Now, Spyder can connect to an existing kernel by clicking the menu icon of the ipython terminal, and selecting `connect to existing ipython kernel`, and inputting the JSON file name of the kernel.

But this needs manually operation. I need a way to connect to the existing kernel through the command line or through python code.

For example, 
```
spyder --existing-kernel kernel-123456.json
```
by command line options.

Is there a method to meet my needs, and if not, will it be supported in the future?

Hints from issue discussion:
Hi @Social-Mean sorry for the late response and thank you for the feedback! I think currently there is not a way to do that, sorry! However, I'm not sure if this is something that could be eventually achieved with the new remote development logic that has been worked on Spyder 6 🤔

Just in case, is the use case described here something that could be eventually covered by the remote development work @ccordoba12 ?
Hi @dalthviz thank you for your comment.

I think it is necessary for me to tell the background of my raising this issue here. 
I am developing a software and want to embed Python into the software so that users can call some functions to control my software to complete some functions. However, my software currently lacks a good editor. Since I usually use spyder as an editor to write Python code, I am thinking: If I could embed Spyder into my software, that would be awesome. The current way I think of using Spyder to send commands to my software is by connecting to the existing Python kernel of my software. But currently I have encountered a series of difficulties:
1. Starting the Python kernel would block my software.
2. I want to create a button in my software that, when clicked, will open the Spyder editor and automatically connect to the existing kernel of my software.

I'm not sure if this method is good or reasonable, after all, I'm not an expert on computers. This is just a method I came up with recently. If anyone has relevant experience in this area, please feel free to give comments and suggestions.
By the way, it seems to me that the remote development feature in Spyder 6 (via SSH) is connecting Spyder to a remote server kernel. But my software is a locally running software. I'm not sure if remote development works for me.
@Social-Mean, thanks for providing a good motivation for your use case. I think this is something we could add support for, but only if you're willing to give us a hand with the implementation.

This is crude description of what you'd need to do:

* Add the new command line option to `spyder/app/cli_options.py`. I suggest using `--connect-to-kernel` instead of the name you mentioned above.
* Handle the option in the `on_mainwindow_visible` method of IPython console plugin with the `create_client_for_kernel` method:

  https://github.com/spyder-ide/spyder/blob/210faf0d4bfe55e29a1bd784eefd702c61491199/spyder/plugins/ipythonconsole/plugin.py#L561-L562

* You can take a look at how we do something similar in the Projects plugin for inspiration:

  https://github.com/spyder-ide/spyder/blob/210faf0d4bfe55e29a1bd784eefd702c61491199/spyder/plugins/projects/plugin.py#L289-L306

Commit message: code format

Patch to review:
diff --git a/spyder/app/cli_options.py b/spyder/app/cli_options.py
index 9dee61ab853..b7083387859 100644
--- a/spyder/app/cli_options.py
+++ b/spyder/app/cli_options.py
@@ -157,6 +157,13 @@ def get_options(argv=None):
         default=None,
         help="Choose a configuration directory to use for Spyder."
     )
+    parser.add_argument(
+        '--connect-to-kernel',
+        type=str,
+        dest="connection_file",
+        default=None,
+        help="Start Spyder and connect to an existing ipython kernel."
+    )
 
     parser.add_argument('files', nargs='*')
     options = parser.parse_args(argv)
diff --git a/spyder/plugins/ipythonconsole/plugin.py b/spyder/plugins/ipythonconsole/plugin.py
index cd7374b3789..9dc211ce2d0 100644
--- a/spyder/plugins/ipythonconsole/plugin.py
+++ b/spyder/plugins/ipythonconsole/plugin.py
@@ -559,7 +559,12 @@ def on_close(self, cancelable=False):
         return self.get_widget().close_all_clients()
 
     def on_mainwindow_visible(self):
-        self.create_new_client(give_focus=False)
+        cli_options = self.get_command_line_options()
+        connection_file = cli_options.connection_file
+        if connection_file is not None:
+            self.create_client_for_kernel(connection_file)
+        else:
+            self.create_new_client(give_focus=False)
 
     # ---- Private methods
     # -------------------------------------------------------------------------


Code review comments:
diff_hunk: @@ -559,7 +559,12 @@ def on_close(self, cancelable=False):
         return self.get_widget().close_all_clients()
 
     def on_mainwindow_visible(self):
-        self.create_new_client(give_focus=False)
+        cli_options = self.get_command_line_options()
+        connection_file = cli_options.connection_file
+        if connection_file is not None:
+            self.create_client_for_kernel(connection_file)
path: spyder/plugins/ipythonconsole/plugin.py
text: @user1:
This needs to be `self.create_client_for_kernel(connection_file, give_focus=False)` to give focus to the Editor and not the console at startup.

So, you need to improve that method to make it possible. For that: 

* Please add the `give_focus` kwarg to create_client_for_kernel.
* Pass it to the main widget method here:

  https://github.com/spyder-ide/spyder/blob/210faf0d4bfe55e29a1bd784eefd702c61491199/spyder/plugins/ipythonconsole/plugin.py#L749-L751

* Add `give_focus` as a kwarg to the widget method too:

  https://github.com/spyder-ide/spyder/blob/210faf0d4bfe55e29a1bd784eefd702c61491199/spyder/plugins/ipythonconsole/widgets/main_widget.py#L1726-L1727

* Pass `give_focus` to the `ClientWidget` constructor:

  https://github.com/spyder-ide/spyder/blob/210faf0d4bfe55e29a1bd784eefd702c61491199/spyder/plugins/ipythonconsole/widgets/main_widget.py#L1765-L1774

diff_hunk: @@ -157,6 +157,13 @@ def get_options(argv=None):
         default=None,
         help="Choose a configuration directory to use for Spyder."
     )
+    parser.add_argument(
+        '--connect-to-kernel',
+        type=str,
+        dest="connection_file",
+        default=None,
+        help="Start Spyder and connect to an existing ipython kernel."
path: spyder/app/cli_options.py
text: @user1:
```suggestion
        help=(
            "Connect to an existing kernel whose info is available in a "
            "kernel-*.json file"
        )
```

Improve help for this new option.