How to organize Python code into collapsable / expandable chunks? - python

In Pycharm, there's "code structurure" side bar which provides a tree to navigate through the code, but, it is only useful when the code has classes and methods and objects. If nothing of that is in code then it is useless.
My question is: is there any way in which I dictate that this is a block, and I want to be able to collapse it and expand it? Something similar to Jupyter where the code is inherently divided to cells.
Currently, I'm doing this:
# ---------------------------------- chunck x blah blah -----------------------
EDIT:
Most of comments say that I'm dumb and I don't know how to code efficiently and that I should use functions and classes. Guys, I know how to use those, that's not my question. Thanks.

Turns out that the answer is very simple:
Select the code, right click, do custom folding

PyCharm allows you to define 'code cells' when you have 'Scientific Mode' enabled. These code cells are collapsible and expandable. To quote from the PyCharm website:
A “code cell” is a block of lines to be executed all at once in the
integrated Python console. You can define cells simply by adding
inline comments #%% to your regular Python files. PyCharm detects
these comments and shows you a special run icon in the left gutter.
Clicking this icon triggers the execution of a cell:
The only catch is that Scientific Mode and its code cell functionality are only available in PyCharm Professional Edition.

You can select a region, and press ctr+alt+t, then select <editor-fold...>. This will surround the region with a comment that makes the region collapsible. You can also do this manually by adding the following around the region:
# <editor-fold desc="This text is shown when collapsed">
# </editor-fold>

I sometimes use True conditional statements to create collapsible blocks in PyCharm and other IDEs. This also helps me to visually relate all indented code, access it when needed, and collapse it, when I'm focusing on other parts of my code.
if True:
# block code goes here
A fancier way is to use a descriptive string in the condition. The description stays visible for a collapsed block. You can also disable these with negation anytime, if needed.
if 'Define similarities':
Dot = lambda x, y: x # y
CosSim = lambda x, y: x # y / (x # x)**0.5 / (y # y)**0.5

Related

Python Jupyter/Notebook: How to display a variable as text on a cell without copy/paste

It happens to me that when reading/reviewing the code, I becomes easier if I can see the 'look' of the variable a function is processing.
For that, I'd like to display a 'static' version of an instance of that variable (as a visual aid).
That variable may not be there on another run of the notebook, that's why it has to be text, not output.
This is also useful when creating documentation within the notebook.
With this little function
#----------------------------------
def vdisplay(var):
"""Converts the var to a pretty string and inserts
it on a new cell just below the present one.
Then you have to change that 'next cell' type to Markdown and execute it.
"""
# To print the var nicely.
from pprint import pformat as pf
string_to_insert=f"""
This is how it looks like:
```
{pf(var)}
```
"""
# Create a code cell and insert a string in it
get_ipython().set_next_input(string_to_insert)
return
#----------------------------------
You can do this
# This is the data we want to show
x={i:str(i)*i for i in range(10)}
# Show it!
vdisplay(x)
Visually:
I use the mouse intentionally so you can see the steps. Using keyboard shortcuts is much quicker.
Story: I explored several venues. The last one was a combination of
%store var f.txt and %load f.txt but that involved some manual
work. The evolution of that method is the one above.

Setting NSSpeechSynthesizer mode from Python

I am using PyObjC bindings to try to get a spoken sound file from phonemes.
I figured out that I can turn speech into sound as follows:
import AppKit
ss = AppKit.NSSpeechSynthesizer.alloc().init()
ss.setVoice_('com.apple.speech.synthesis.voice.Alex')
ss.startSpeakingString_toURL_("Hello", AppKit.NSURL.fileURLWithPath_("hello.aiff"))
# then wait until ve.isSpeaking() returns False
Next for greater control I'd like to turn the text first into phonemes, and then speak them.
phonemes = ss.phonemesFromText_("Hello")
But now I'm stuck, because I know from the docs that to get startSpeakingString to accept phonemes as input, you first need to set NSSpeechSynthesizer.SpeechPropertyKey.Mode to "phoneme". And I think I'm supposed to use setObject_forProperty_error_ to set that.
There are two things I don't understand:
Where is NSSpeechSynthesizer.SpeechPropertyKey.Mode in PyObjC? I grepped the entire PyObjC directory and SpeechPropertyKey is not mentioned anywhere.
How do I use setObject_forProperty_error_ to set it? I think based on the docs that the first argument is the value to set (although it's called just "an object", so True in this case?), and the second is the key (would be phoneme in this case?), and finally there is an error callback. But I'm not sure how I'd pass those arguments in Python.
Where is NSSpeechSynthesizer.SpeechPropertyKey.Mode in PyObjC?
Nowhere.
How do I use setObject_forProperty_error_ to set it?
ss.setObject_forProperty_error_("PHON", "inpt", None)
"PHON" is the same as NSSpeechSynthesizer.SpeechPropertyKey.Mode.phoneme
"inpt" is the same as NSSpeechSynthesizer.SpeechPropertyKey.inputMode
It seems these are not defined anywhere in PyObjC, but I found them by firing up XCode and writing a short Swift snippet:
import Foundation
import AppKit
let synth = NSSpeechSynthesizer()
let x = NSSpeechSynthesizer.SpeechPropertyKey.Mode.phoneme
let y = NSSpeechSynthesizer.SpeechPropertyKey.inputMode
Now looking at x and y in the debugger show that they are the strings mentioned above.
As for how to call setObject_forProperty_error_, I simply tried passing in those strings and None as the error handler, and that worked.

How to execute python function as whole in VSCode (it splits and sends just the first line to an interpreter)

I'm getting used to VSCode in my daily Data Science remote workflow due to LiveShare feature.
So, upon executing functions it just executes the first line of code; if I mark the whole region then it does work, but it's cumbersome way of dealing with the issue.
I tried number of extensions, but none of them seem to solve the problem.
def gini_normalized(test, pred):
"""Simple normalized Gini based on Scikit-Learn's roc_auc_score"""
gini = lambda a, p: 2 * roc_auc_score(a, p) - 1
return gini(test, pred)
Executing the beginning of the function results in error:
def gini_normalized(test, pred):...
File "", line 1
def gini_normalized(test, pred):
^
SyntaxError: unexpected EOF while parsing
There's a solution for PyCharm: Python Smart Execute - https://plugins.jetbrains.com/plugin/11945-python-smart-execute. Also Atom's Hydrogen doesn't have such issue either.
Any ideas regarding VSCode?
Thanks!
I'm a developer on the VSCode DataScience features. Just to make sure that I'm understanding correctly. You would like the shift-enter command to send the entire function to the Interactive Window if you run it on the definition of the function?
If so, then yes, we don't currently support that. Shift-enter can run line by line or run a section of code that you manually highlight. If you want, you can use #%% lines in your code to put functions into code cells. Then when you are in a cell shift-enter will run that entire cell, might be the best current approach for you.
That smart execute does look interesting, if you would like to file that as a suggestion you can use our GitHub here to get it on our backlog to look at.
https://github.com/Microsoft/vscode-python
Hi you could click the symbol before each line and turn it into > (the indented codes of the function was hidden now). Then if you select the whole line and the next line, shift+enter could run them together.
enter image description here

Jupyter Notebook: How to relaunch all cells above when a crash occurs?

Question 1:
I am using jupyter 4 with python and I would need my script to do a relaunch all the cells above when a crash occurs.
Is this possible ?
Question 2:
If I need to relaunch all some cells, can I ask python to execute them according to some cell-id? I could then create a list of the cells id which have to be re-executed when catching an exception...
You can always relaunch all cells above the active cell using Cell > Run All Above. But when it comes to doing so programmatically and reliably, I've got both good and bad news for you.
Let's get the bad news regarding question 2 out of the way: NO
...at least not very reliably, because any ID of a cell would change if you insert or remove any other cell.
According to Execute specific cells through widgets and conditions on github:
We don't have the Ids of of cell in order to handle them
programatically.
And further down on the same post:
There are some APIs which can run cells identified by numbers, but
unfortunately the numbers change if you insert or delete a cell
somewhere above.
And now to the good news about the first question: YES
...but it's not 100% certain that it will solve your error handling needs as per the details in your question. But we'll get to that in a bit. Because the good news is that the answer to the question as it stands in the title
How to relaunch all cells above when a crash occurs?
is YES WE CAN!
The hard (maybe even impossible) part of this question is to implement it as a robust error handling method. If you're only interested in that, skip to the section The hard part at the end of my answer. For now, let's go on with the easy part that is to programmatically run the menu option Cell > Run All (as described in the answer by Nic Cottrell). You have two options:
Option 1 - Run all cells above by executing a cell:
If you insert the following snippet in a cell and run it, all cells above will be executed:
from IPython.display import Javascript
display(Javascript('IPython.notebook.execute_cells_above()'))
Option 2 - Run all cells above by clicking a button:
If you insert the following snippet in a cell and run it, all cells above will be executed when you click the appearing button:
Snippet:
from IPython.core.display import display, HTML
HTML('''<script> </script> <form action="javascript:IPython.notebook.execute_cells_above()"><input type="submit" id="toggleButton" value="Run all"></form>''')
Output:
THE HARD PART
So, how can we set this up to handle an error when a crash occurs? I'm not an expert on this, but I think I've been able to make a setup that will work for you. But it will most likely depend on the type of error in question and the rest of your work flow.
The following example builds on two different error messages. The first is a NameError that occurs when you try to assign a value to a variable that does not exist. And this will be useful since re-running some cells after an error will need an iterator that resets only when the notebook is restarted completely, and not when a cell is re-run as part of an error handling method. The name error will only occur when the kernel is restarted upon a fresh restart of your notebook. As part of the error handling, the value 0 is assigned to x1. When the cell is only re-run x1 will increase by 1.
The second error will serve as a proxy for your error, and is an AssignmentError that occurs each time you try to delete an element from a list that does not exist. And this leads us to the real challenge, since if your error handler re-runs all cells above every time the error is triggered, you'll quickly end up in a bad loop. But we'll handle that with a counter that exits the looping execution of cells after a few runs.
It's also a bit problematic that there does not seem to exist a functionality to rerun your existing cell, or the cell from where the run cells above functionality is initialized. But we'll handle that with another suggestion from the same github post as earlier:
Doing the following helps me to execute the cell right below the code
cell. You can also change the values to get cells in other parts of
the notebook.
display(Javascript('IPython.notebook.execute_cell_range(IPython.notebook.get_selected_index()+1, IPython.notebook.get_selected_index()+2)'))
Notebook with suggested work-flow:
Insert the four following snippets below in four cells. Click the menu option Cell > Run all once, and we're good to go!
Snippet 1 - Imports and setup
import sys
import os
from IPython.core.display import display, HTML
from IPython.display import Javascript
from random import randint
# Trigger to randomly raise en error in the next cell
ErrorTrigger = randint(0, 9)
# Assignment of variables at first run of the Norebook
try: x1
except NameError: x1 = None
if x1 is None:
%qtconsole # opens a qtconsole (for variable inspection and debugging)
x1 = 0 # counter for NameError
x2 = 0 # counter for assignment error (used in cells below)
mr = 0 # counter for manual relaunch by button
ErrorTriggers=[] # container for ErroTriggers
print('NameErrors = ', x1)
else:
x1 = x1 + 1
ErrorTriggers.append(ErrorTrigger)
#print('Executions:', x1, '||', 'Triggers:', ErrorTriggers)
Snippet 2 - Proxy for your error
# PROXY ERROR => INSERT YOUR CODE FROM HERE ################################################################
list1 = [1,2,3,4]
# 80 % chance of raising an error trying to delete an element that does not exist in the list
if ErrorTrigger > 2:
elemDelete = 8 # error
else:
elemDelete = 0 # not error
try:
del list1[elemDelete]
print('Executions:', x1, '||', 'Triggers:', ErrorTriggers)
print('Routine success on attempt', x2 + 1)
print('Error mesg: None')
ErrorTriggers=[]
x2 = 0 # reset error counter
# TO HERE #################################################################################################
except Exception:
x2 = x2 + 1
# Will end error handler after 5 attempts
if x2 < 3:
# As long as we're UNDER the attempt limit, the next cell executed by:
display(Javascript('IPython.notebook.execute_cell_range(IPython.notebook.get_selected_index()+1,'+
' IPython.notebook.get_selected_index()+2)'))
else:
# If we're OVER the attempt limit, it all ends here. The next cell is NOT run.
# And NEITHER is the last cell with the button to relaunch the whole thing.
print('Executions:', x1, '||', 'Triggers:', ErrorTriggers)
print('Routine aborted after attempt', x2)
print('Error msg:', sys.exc_info()[1]) # Returns a message describing the error
# reset variables
ErrorTriggers = []
x2 = 0
Snippet 3 - Cell to rerun all cells above as error handler
display(Javascript('IPython.notebook.execute_cells_above()'))
Snippet 4 - Cell to rerun the whole thing with en error probability of 20%
HTML('''<script> </script> <form action="javascript:IPython.notebook.execute_cells_above()"><input type="submit" id="toggleButton" value="Run again!"></form>''')
Screenshot after a few test runs:
I'll gladly add more details if the comments in the snippets are unclear.
But if you run the notebook a few times by clicking Run Again! and at the same time have a look at the output of cell 3, you'll quickly grasp how the whole thing is put together:
I'm running Notebook server 5.4.0 and I have an option Cell > Run All Above which seems to do exactly this.
In Jupyter, click in each of the cells you want to re-run after error and go to View > Cell Toolbar > Tags. Type 'raises-exception' (no quotes) in the box at the top of the cell and Add Tag.
In the next cell, put the following:
from IPython.display import Javascript
Javascript("IPython.notebook.execute_all_cells()")
Then select Cell > Run All.
This should catch the errors and run all the cells on an infinite loop until interrupted.
This is for jupyterlab
go to: Settings->Advanced Settings Editor->Keyboard Shortcuts
Paste the below code in the User Preferences window:
{
"shortcuts": [
{
"command": "notebook:run-all-above",
"keys": [
"Shift Backspace"
],
"selector": ".jp-Notebook.jp-mod-editMode"
}
]
}
click on save (top right of the user-preferences window)
This will be effective immediately. Here, two consecutive shift + backspace presses runs all cells above the selected line.
Notably, system defaults has empty templates for all menu commands, including this code (search for run-all-above).

VIM/Python Insert-Mode-Completion Popup Menu

I would like to create a VIM insert-mode-completion popup menu, preferably directly via the python vim module but also by calling vim commands if necessary. Per my requirements, if this is possible, what do I need to know?
Requirements
Modify the menu based on input. Either recolor and replace select characters ala easymotion plugin, or completely replace content, possibly resulting in a change of size.
Customizable navigation bindings, example:
j/k for vertical navigation (partial redraw)
h/l for category navigation/refinement (full redraw)
others as category/relationship shortcuts (full)
others as source cycling (full)
easymotion-style bindings (partial)
others for related functionality (none)
optionally, in lieu of the above bindings, a fuzzy filtering mode (capture all input) (full)
Hook to run action when menu is destroyed
Ability to replace previous word if menu item selected (easily done in normal mode... but, is there a better approach than calling :norm?)
Once again, I need to know if any of this is possible. If so, please provide specific documentation regarding the required capabilities, APIs, or functions. Well, enough to get me started.
If important, I'm not sure of the interface specifics yet but the menu itself may need to be quite large to accommodate the content.
Edit:
I haven't tried anything; rather I'm asking what I should read or know to implement the vim-specific functionality I need. All I now have is python code that accepts a sentence and a word in that sentence, determines the POS, lemmatises the word, and provides synonyms.
It should be clear by now this is a vim plugin providing thesaurus-like functionality, augmenting vim's built-in CTRL_X-CTRL_T functionality. Unfortunately synonymy is a complicated hierarchy, for example see thesaurus.com or wordnet. Below is a tree of the synonym selection process. To provide useful thesaurus functionality I would need to navigate this tree within the insert-mode-completion popup menu. By automatically inferring the POS the first step can be skipped, and of course it makes sense to initially merge and display all sense synonyms irrespective of relationship. However, to determine the POS I need access to the entire sentence, and I still need to be able to navigate a sense selection menu. I also want to be able to provide scratch buffer detailing word definitions and example sentences for the currently highlighted popup menu entry. Hence the necessity for a hook; to destroy the buffer when the menu is destroyed. All the other keybindings I've described would be conveniences to, for example, filter by relationship, open the informational scratch buffer, or switch POS.
POS Sense Relationship Synonym
N -> Sense 1 -> Relationship 1 -> Synonym 1
Synonym 2
...
Synonym n
-> Relationship 2 -> Synonym 1
...
Synonym n
-> Relationship 3 -> Synonym 1
...
Synonym n
Sense 2 -> Relationship 1 -> ...
Sense 3 -> Relationship 2 -> ...
V -> Sense 1 -> ...
A -> ...
Insert completion popup menus are great because they preserve context: surrounding text doesn't change, remains (mostly) visible, and windows aren't resized. I could provide the functionality I need in a separate buffer (such as a unite plugin), however I'd rather not.
After reading :h complete-functions:
If refresh="alway", complete-functions will be re-invoked each time leading text is changed. The purpose is to refine the matches, however this has little meaning for synonym-matching, where the word is already complete and instead will just be replaced. Aside from this, insert-completion popup menus only provide minimal key mappings: <CTRL-H>, CTRL-L>, <CTRL-Y>, <CTRL-E>, etc. Additional mappings can be added using pumvisible(), however such mappings affect all popup menus, and so would not be applicable. Of course I could use <expr> to check a global variable such as g:popup-menu-is-thesaurus, but this approach is basically a heap of hacks. For example, to display a new category in the menu, I could do something like:
:call Thesaurus#BindKey("h","w:Thesaurus#CategoryUp")
:call Thesaurus#BindKey("i","w:Thesaurus#InsertMode")
with:
function! Thesaurus#BindKey(key, function)
inoremap <expr> a:key a:function
endfunction
function! Thesaurus#CategoryUp()
if !b:popup-menu-is-thesaurus
return v:char
let b:thesaurus-category-index -= 1
endfunction
function! Thesaurus#InsertMode()
if !b:popup-menu-is-thesaurus
return v:char
let b:thesaurus-mode = "insert"
endfunction
function! Thesaurus#CompleteFunc(findstart, base)
if a:findstart
...
else
if b:thesaurus-mode = "insert"
return Thesaurus#FuzzyMatch(base)
else
return Thesaurus#Redraw()
endif
endif
endfunction
function! Thesaurus#Redraw()
...
endfunction
* Obviously I'm not very good with VimL. Also, am I using v:char correctly?
Of course I have no idea how to replace the previous word once an entry is selected, since the only way to enable fuzzy matching is to have a:base be empty.
Edit2: And how in the world do I get my completion-function triggered, preferably via the standard thesaurus-style completion shortcut, i_CTRL-X_CTRL-T? I don't want to lose my custom completions (omni and user-defined completion), and since the popup displays in the current buffer, unlike FuzzyFinder I can't override omnifunc.
Perhaps the ideal approach would be to have full control of the menu-drawing functionality to build the popup from scratch, and fake a new insert-completion popup menu mode using plugins such as tinymode, tinykeymap or submode.
Please keep in mind that the insert-mode completion popup menu is for completing matches e.g. offering foobar and foomatic when you type foo and trigger completion. There is no generic insert-mode menu with arbitrary actions, and it's probably a bad idea to implement such. That said, some plugins (e.g. FuzzyFinder) mis-use insert-mode completion menus for a dynamic choice selector (in a scratch buffer, so what get's completed is discarded there).
You'll find the full specification and an example at :help complete-function. If that doesn't satisfy you / leaves open questions, that's a sure sign that you're trying to use it for something it wasn't meant for.
Modify the menu based on input.
With each typed key, your 'completefunc' will be re-invoked, and it can offer a (reduced) set of matches.
Customizable navigation bindings
Bad idea. The user should customize this for all completions (using :imap <expr> with pumvisible() conditionals).
Hook to run action when menu is destroyed
The CompleteDone event has been added in recent Vim versions, but usually the only action should be "insert the match", which gets done automatically.
Ability to replace previous word if menu item selected
On the first invocation of your 'completefunc', your function can specify the base column, i.e. where the completion matches will start.

Categories