-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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: Run cells through a function instead of pasting their contents to the console #7310
Conversation
Hello @bcolsen! Thanks for updating the PR.
Comment last updated on October 27, 2018 at 20:09 Hours UTC |
@bcolsen, thanks for this, it looks very interesting! But since we're moving all our kernel code to this new package: https://github.com/spyder-ide/spyder-kernels (see also PR #7306), you need to create a PR there for your changes to our |
@ccordoba12 I rebased and made a PR against the spyder-kernels repo and everything still works. There is still some code repetition in the functions and I need to add/fix the tests, but first I would like to know if my approach here is viable before cleaning it up. It works well for my use cases and I'm going to try to use it at work this next week to test it out |
@bcolsen, I'm very sorry for not reviewing your work for so long. I took a quick look at the current status of this PR at it looks quite good (minus some refactoring to avoid repeated code, as you said). Please merge with master to fix the conflicts and implement a test for this. |
Also, it should be possible to turn on/off the old behavior with an option. |
Ok, I assume you need the corresponding PR in spyder-kernels to be merged first for the tests here to pass, right? I'l, try to take a look at that as soon as I can. |
Yes I'll need kernel side merged to pass the tests, but it not quite ready yet. I'll focus on that code next. I'll let you know when it's ready for review. |
@bcolsen Since Spyder-Kernels was merged a while back, are you planning to finish this one? Any updates? Thanks! |
The the corresponding spyder-kernel PR is spyder-ide/spyder-kernels#7 has not yet been merged, but is waiting for review. That's why it's failing tests. I have one more fuction to clean up in the PR and tests, then it's good to go. I think I can finish it up this week. |
One other note on this implementation that could be seen as a regression. Unlike the current method of running cells this method is unable to have the last line of the cell produce output in the IPython console. Output is only produced from print functions and other methods of writing to stdout and stderr just like running a file. |
@@ -1025,6 +1026,61 @@ def run_script(self, filename, wdir, args, debug, post_mortem, | |||
"<br><br>Please open a new one and try again." | |||
) % osp.basename(filename), QMessageBox.Ok) | |||
|
|||
def run_cell(self, code, cell_name, filename): |
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 function has some similar code to run_script
above but I would need to re-factor both functions to not have some repeat. I'm not should what all the code in run script does so I'm hesitant to touch it too much.
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.
Ok, I'll try to refactor both methods here in your branch, after you address my review.
I've been using this for the past couple of weeks and I ran into a problem with the traceback links. The code snipit shown in the traceback was showing the wrong line of code because the code line in the traceback was taken from the unsaved file and the code that was running was only in the editor. A solution to this would be to save the file before executing the code cell but that was one of the things we were trying to avoid. So I decided to execute with the ipython
And now the tracebacks don't have the right file name so the links don't work(I might be able to fix this) but the code snipit and the code lines are correct. So everything is now better than before. |
Now the traceback links work too |
I'm more happy about this now that the code cells are still executed as IPython cells and tracebacks links work. This is now better than before in every way unless you were editing cells in the qt console but I think that would be uncommon since editing in the editor is more convenient. @ccordoba12 After the spyder kernel package is merged this should pass the tests (hopefully) and be ready for review. |
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.
@bcolsen, this is really nice!! Thanks a lot for working on it!
About our tests: I'd also like to see a simple test that checks that our old method of cell evaluation works as expected (since the new method is going to become the default one).
spyder/plugins/editor/plugin.py
Outdated
@@ -193,6 +193,8 @@ def setup_page(self): | |||
run_selection_group = QGroupBox(_("Run selection")) | |||
focus_box = newcb(_("Maintain focus in the Editor after running cells " | |||
"or selections"), 'focus_to_editor') | |||
run_cell_box = newcb(_("Use the run cell function to execute code " | |||
"cells"), 'run_cell_func') |
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 change the text of this checkbox to
Execute cells using a function instead of by pasting their contents to the console
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.
@CAM-Gerlach, do you have a better suggestion?
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 conservative edit would be Run code cells using a function instead of pasting their contents directly
, but I'd favor something like Don't print cell contents when running code cells in the console
for the label since it is more direct at naming the actual effect of the option for the end user (which may not be obvious from the previous) rather than an implementation detail. Either way, the tooltip could read Run code cells using the runcell() function in the console rather than pasting their full contents, for a cleaner console history
.
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 runcell()
function is just the implementation of not having the full cell contents in the history and the console, so it likely doesn't need to be mentioned
For more clarity, I can flip the setting in the code and go for:
Copy full cell contents to the console when running code cells
With the setting unchecked by default.
The tool tip could read:
When running a code cell the full contents of the cell will be copied to the console and the history
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 runcell() function is just the implementation of not having the full cell contents in the history and the console, so it likely doesn't need to be mentioned
Agreed, that's my opinion as well.
Copy full contents to the console when running code cells
I guess that could be a little clearer, although I don't feel that strongly a about it. As a minor refinement, I'd suggest Show full cell contents in the console when running code cells
. While I'm normally very opposed to repetition, I think its necessary here for clarity. Regarding the tooltip, a suggested revision would be Print code cell contents to the Console and include them in the History Log when running cells
.
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 also agree with
Copy full cell contents to the console when running code cells
and making the option False
. Thanks @bcolsen!
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 I'll go for:
Copy full cell contents to the console when running code cells
I like 'copy' in there because it's more than just shown or printed into the console, it's more like what would happen if you copied and pasted the cell into the console manually.
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.
+1 from me.
self.run_cell_func = state | ||
|
||
def set_introspector(self, introspector): | ||
self.introspector = introspector |
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 method (set_introspector
) is not needed anymore (it was part of the old code completion architecture). Please remove it and merge your branch with master to have the latest changes to our tests.
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.
Oops. This code is actually freshly rebased, but I just did a poor job on the manual conflict merge there
@@ -1025,6 +1026,61 @@ def run_script(self, filename, wdir, args, debug, post_mortem, | |||
"<br><br>Please open a new one and try again." | |||
) % osp.basename(filename), QMessageBox.Ok) | |||
|
|||
def run_cell(self, code, cell_name, filename): |
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.
Ok, I'll try to refactor both methods here in your branch, after you address my review.
if client is None: | ||
client = self.get_current_client() | ||
|
||
is_internal_kernal = False |
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.
is_internal_kernal
-> is_internal_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.
Also, we need to change this a little bit. runcell
will also work in external Spyder kernels (i.e. kernels started with python -m spyder_kernels.console
).
So we need to add a method to client
that detects if kernels are of Spyder kind or not, and then avoid using runcell
to run the code if they are not.
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 might be best left for another PR (I can make the issue) since this is true for the run_script
function above using runfile()
instead of %run
on internal consoles as well. The changes might as well be made at the some time.
I guess currently the run_script
function wouldn't work too well on a remote machine unless the local files were mirrored in the remote machine. If this is the case one solution would be to run the contents of the whole file through runcell. Of course having real remote file editing would be better, but in the near term it could make remote kernels more friendly.
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 might be best left for another PR (I can make the issue)
Ok, no problem. Please open the issue then, I'll take care of it.
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 wasn't able to fully test it since the Spyder Kernels changes haven't yet gone through but I made note of some UI text, style and convention/best practice issues.
spyder/plugins/editor/plugin.py
Outdated
@@ -193,6 +193,8 @@ def setup_page(self): | |||
run_selection_group = QGroupBox(_("Run selection")) | |||
focus_box = newcb(_("Maintain focus in the Editor after running cells " | |||
"or selections"), 'focus_to_editor') | |||
run_cell_box = newcb(_("Use the run cell function to execute code " | |||
"cells"), 'run_cell_func') |
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 conservative edit would be Run code cells using a function instead of pasting their contents directly
, but I'd favor something like Don't print cell contents when running code cells in the console
for the label since it is more direct at naming the actual effect of the option for the end user (which may not be obvious from the previous) rather than an implementation detail. Either way, the tooltip could read Run code cells using the runcell() function in the console rather than pasting their full contents, for a cleaner console history
.
spyder/plugins/editor/plugin.py
Outdated
@@ -1464,6 +1469,9 @@ def register_editorstack(self, editorstack): | |||
editorstack.exec_in_extconsole.connect( | |||
lambda text, option: | |||
self.exec_in_extconsole.emit(text, option)) | |||
editorstack.run_cell_in_ipyclient.connect( | |||
lambda code, cell_name, filename: |
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.
By PEP 8, a hanging indent should be 4 spaces, except for in function definitions. Spyder's automatic behavior (which I assume you relied on) is incorrect, which in fact prompted one of my very first issues here.
@@ -688,20 +690,25 @@ def get_selection_as_executable_code(self): | |||
else: | |||
lines.append(ls) | |||
|
|||
return ls.join(lines) | |||
# Adding removed lines back to have correct traceback line numbers |
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.
Imperative tense ("Add removed lines...")
@@ -2426,10 +2433,31 @@ def advance_cell(self, reverse=False): | |||
term.setFocus() | |||
|
|||
def re_run_last_cell(self): | |||
text = self.get_current_editor().get_last_cell_as_executable_code() | |||
text, line = self.get_current_editor().\ |
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.
Per PEP 8 and our convention, we're using ()
for line continuations for all new code. So
text, line = (self.get_current_editor()
.get_last_cell_as_executable_code())
def _run_cell_text(self, text, line): | ||
"""Run a cell text in the console | ||
|
||
text(str): the text in the cell |
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.
Are you going for Googldoc here? If so, the correct format is:
Args:
text (str): The text in the cell.
line (int): The cell starting line.
self._run_cell_text(text, line) | ||
|
||
def _run_cell_text(self, text, line): | ||
"""Run a cell text in the console |
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.
"Run a cell text"? Also, period.
@@ -914,6 +916,63 @@ def run_script(self, filename, wdir, args, debug, post_mortem, | |||
"<br><br>Please open a new one and try again." | |||
) % osp.basename(filename), QMessageBox.Ok) | |||
|
|||
def run_cell(self, code, cell_name, filename): | |||
"""Run cell in current or dedicated 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.
Period.
I actually changed a bit of code in this latest commit so the copy cells go through the same code as the function cells. This way the copy cells and the function cells behave the same way with respect to dedicated cells (i.e. if there is a dedicated console for that file the code cells only run in that console.) |
@bcolsen, please rebase in top of master to get the latest fixes to our tests. @bcolsen and @CAM-Gerlach, it's really bad practice to discuss at length things unrelated to the main purpose of a PR (in this case why PyLS is failing on Windows) because it derails the discussion and impacts future reading of the PR contents. This is something @CAM-Gerlach is fan of and I'm going to ask him to stop doing it. @CAM-Gerlach, for next time, please open a new issue or discuss things in our internal Gitter channel. |
@ccordoba12 You're right, of course, we (and particularly I) got way off topic. My apologies for that. I posted it as a separate issue, #8153 |
@ccordoba12 Sorry for the noise on this thread. Rebased. I made some changes since the last review have the copy cells go through the same code as the function cells. This way the copy cells and the function cells behave the same way with respect to dedicated cells (i.e. if there is a dedicated console for that file the code cells only run in that console.) |
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.
Great job @bcolsen! What a terrific improvement!!
Pull Request Checklist
modified the
spyder/defaults
directory, or added new icons/assetsDescription of Changes
This PR makes a function that runs a cell instead of copying the cell contents into the current console. With this function the tracebacks give the correct lines in the file the cell was run from!! Also if the file is run in a dedicated console the code cells will also run in that console regardless of the console in focus.
Implementation
A variable with the cell contents is made in the ipython namespace of the console so there will be no interference with user variables. The function executes this code then deletes the variable. The function displays an error if it is run from the console. I can leave the variable so the function can run the last cell, but it's not obvious that it won't reflect any subsequent changes to the block in the editor.
Issue(s) Resolved
Fixes #7113
Fixes #7760