Copy and paste Python functions in Emacs - python

I have a program that looks something like (this is a silly example to illustrate my point, what it does is not very important)
count = 0
def average(search_term):
average = 0
page = 0
current = download(search_term, page)
while current:
def add_up(downloaded):
results = downloaded.body.get_results()
count += len(results)
return sum(result.score for result in results)
total = average*count
total += add_up(current)
average = total/count
print('Average so far: {:2f}'.format(average))
page += 1
current = download(search_term, page)
If I have the cursor on any of the lines 8–11 and press a key combination I want Emacs to copy or kill the add_up function, and then I want to move the cursor to line 2 and press a key combination and paste the function there, with the correct level of indentation for the context it is pasted in.
Is this possible, and if so, how would I do that?

With python-mode.el py-kill-def and yank would do the job.
However, there are some restrictions. py-kill-def must be called from inside def in question. So needs to go upward from line 11 first.
Also indenting after insert poses some problems: as indent is syntax, sometimes Emacs can't know which indentation is wanted. In example below have an indent of 4 first and of 8 in add_up probably is not wanted - however it's legal code. After indenting first line in body of add_up, py-indent-and-forward should be convenient for the remaining.
def average(search_term):
average = 0
def add_up(downloaded):
results = downloaded.body.get_results()
count += len(results)
return sum(result.score for result in results)
page = 0
current = download(search_term, page)
while current:
total = average*count
total += add_up(current)
average = total/count
print('Average so far: {:2f}'.format(average))
page += 1
current = download(search_term, page)

For this type of thing I usually use expand-region, which I choose to bind to C-=.
Using your example I can select the add_up() function by pressing C-= once, kill the region normally (C-k), move to line 2, and yank as usual (C-y).
Depending on what else you have configured for Python you may have to clean up some whitespace, or it may get cleaned up for you. For example, aggressive-indent would be helpful.
One manual option would be to reindent the pasted code with something like C-x C-x M-\.

I've been using smart-shift (available in Melpa) for this sort of thing. global-smart-shift-mode to enable (beware, it binds keys). Select the block you want to move (I'd use expand-region like Chris), and the default keybind C-S-c <arrow> starts moving it. Once you're shifting, the arrows (without C-S-c) shift further. Horizontal shifts use the major mode's indent offset (python-indent-offset for python.el).

Related

How do I run a conditional statement "only once" and every time it changes?

I might be asking a simple question. I have a python program that runs every minute. But I would like a block of code to only run once the condition changes? My code looks like this:
# def shortIndicator():
a = int(indicate_5min.value5)
b = int(indicate_10min.value10)
c = int(indicate_15min.value15)
if a + b + c == 3:
print("Trade posible!")
else:
print("Trade NOT posible!")
# This lets the processor work more than it should.
"""run_once = 0 # This lets the processor work more than it should.
while 1:
if run_once == 0:
shortIndicator()
run_once = 1"""
I've run it without using a function. But then I get an output every minute. I've tried to run it as a function, when I enable the commented code it sort of runs, but also the processing usage is more. If there perhaps a smarter way of doing this?
It's really not clear what you mean, but if you only want to print a notification when the result changes, add another variable to rembember the previous result.
def shortIndicator():
return indicate_5min.value5 and indicate_10min.value10 and indicate_15min.value15
previous = None
while True:
indicator = shortIndicator()
if previous is None or indicator != previous:
if indicator:
print("Trade possible!")
else:
print("Trade NOT possible!")
previous = indicator
# take a break so as not to query too often
time.sleep(60)
Initializing provious to None creates a third state which is only true the first time the while loop executes; by definition, the result cannot be identical to the previous result because there isn't really a previous result the first time.
Perhaps also notice the boolean shorthand inside the function, which is simpler and more idiomatic than converting each value to an int and checking their sum.
I'm guessing the time.sleep is what you were looking for to reduce the load of running this code repeatedly, though that part of the question remains really unclear.
Finally, check the spelling of possible.
If I understand it correctly, you can save previous output to a file, then read it at the beginning of program and print output only if previous output was different.

Parsing with multiple loops opening files

I'm trying to count the number of lines contained by a file that looks like this:
-StartACheck
---Lines--
-EndACheck
-StartBCheck
---Lines--
-EndBCheck
with this:
count=0
z={}
for line in file:
s=re.search(r'\-+Start([A-Za-z0-9]+)Check',line)
if s:
e=s.group(1)
for line in file:
z.setdefault(e,[]).append(count)
q=re.search(r'\-+End',line)
if q:
count=0
break
for a,b in z.items():
print(a,len(b))
I want to basically store the number of lines present inside ACheck , BCheck etc in a dictionary but I keep getting the wrong output
Something like this
A,15
B,9
etc
I found out that even though the code should work, it doesn't because of the way the file is opened. I can't change the way it is opened and was looking for an implementation that only opens the file once but counts the same things and gives the exact same output without all the added functions of the newer python version.
This kind of problem can be resolved with a finite state machine. This is a complex matter that would need more explanation than what I could write here. You should look into it to further understand what you can do with it.
But first of all, I'm going to do a few presumptions:
The input file doesn't have any errors
If you have more than one section with the same name, you want their count to be combined
Even though you have tagged this question python 2.7, because you are using print(), I'll presume you are using python 3.x
Here's my suggestion:
import re
input_filename = "/home/evens/Temporaire/StackOverflow/Input_file-39339007.txt"
matchers = {
'start_section' : re.compile(r'\-+Start([A-Za-z0-9]+)Check'),
'end_section' : re.compile(r'\-+End'),
}
inside_section = False # Am I inside a section ?
section_name = None # Which section am I in ?
tally = {} # Sums of each section
with open(input_filename) as file_read:
for line in file_read:
line_matches = {k: v.match(line) for (k, v) in matchers.items()}
if inside_section:
if line_matches['end_section']:
future_inside_section = False
else:
future_inside_section = True
if section_name in tally:
tally[section_name] += 1
else:
tally[section_name] = 1
else:
if line_matches['start_section']:
future_inside_section = True
section_name = line_matches['start_section'].group(1)
# Just before we go in the future
inside_section = future_inside_section
for (a,b) in tally.items():
print('Total of all "{}" sections: {}'.format(a, b))
What this code does is determine :
How it should change its state (Am I going to be inside or outside a section on the next line?)
What else should be done:
Change the name of the section I'm in ?
Count this line in the present section ?
But even this code has its problems:
It doesn't check to see if a section start has a matching section end (-StartACheck could be ended by -EndATotallyInvalidCheck)
It doesn't handle the case where two consecutive section starts (or ends) are detected (Error? Nested sections?)
It doesn't handle the case where there are lines outside a section
And probably other corner cases.
How you want to handle these cases is up to you
This code could probably be further simplified but I don't want to be too complex for now.
Hope this helps. Don't hesitate to ask if you need further explanations.

Python issue with replace statement?

I've been write this practice program for while now, the whole purpose of the code is to get user input and generate passwords, everything almost works, but the replace statements are driving me nuts. Maybe one of you smart programmers can help me, because I'm kinda new to this whole field of programming. The issue is that replace statement only seems to work with the first char in Strng, but not the others one. The other funcs blower the last run first and then the middle one runs.
def Manip(Strng):
#Strng = 'jayjay'
print (Strng.replace('j','h',1))
#Displays: 'hayjay'
print (Strng.replace('j','h',4))
#Displays: 'hayhay'
return
def Add_nums(Strng):
Size=len(str(Strng))
Total_per = str(Strng).count('%')
# Get The % Spots Position, So they only get replaced with numbers during permutation
currnt_Pos = 0
per = [] # % position per for percent
rGen = ''
for i in str(Strng):
if i == str('%'):
per.append(currnt_Pos)
currnt_Pos+=1
for num,pos in zip(str(self.ints),per):
rGen = Strng.replace(str(Strng[pos]),str(num),4);
return rGen
for pos in AlphaB: # DataBase Of The Positions Of Alphabets
for letter in self.alphas: #letters in The User Inputs
GenPass=(self.forms.replace(self.forms[pos],letter,int(pos)))
# Not Fully Formatted yet; you got something like Cat%%%, so you can use another function to change % to nums
# And use the permutations function to generate other passwrds and then
# continue to the rest of this for loop which will generate something like cat222 or cat333
Add_nums(GenPass) # The Function That will add numbers to the Cat%%%
print (rGen);exit()

Can you use Python-docx to underline part of a paragraph that is on the same run?

I am new to python and new to programming so please forgive my ignorance.
I am using python-docx to automatically format a document as I need it. In our database application we have a good number of forms that are updated periodically in batches. They all follow pretty much the same format and we are given the newly updated document not formatted for our needs.
So I have a couple questions for what I am trying to do:
1) In each document, there is a number such as 5.1 at the beginning of the document. After the number I need to place a tab and then underline the remainder of the paragraph. I cannot figure out, and maybe it is not possible with the way I am looking at it, but I cannot put a tab in a certain spot or figure out how to underline the remaining of the paragraph because there is only a single run only and I cannot find any way to split a single run into two runs. What i have been able to do is to open the document and use pyautogui to move the number of spaces over to the right using pyautogui.press('right') in a loop after counting how many numbers there are in the 1st paragraph. But that is not preferred i think.
I thought that maybe i could insert the text into a string, then split the number from the rest of the words, and then use python-docx to remove the old text and then insert the new text with the different formatting(runs). Is that the best way to do this or are there better ways?
This is currently how I am performing this task but it does not allow me to bold. I would like to perform the whole task using python-docx so that i am not as dependent using the gui to make the changes
def JITitleNumberLength():
doc = docx.Document('1ji.docx')
p0 = doc.paragraphs[0]
p0Size = len(p0.text) #finds length of title in paragraph 0
JI_Title = p0.text
JI_Title_List = list(JI_Title)
#print(JI_Title_List[2])
JI_Index_Length = 0 #Returns the amount of numbers in the title of the Jury Instruction
counter = 0
while (counter < p0Size) and True:
#print(JI_Title_List[counter], ' ', JI_Index_Length)
if (JI_Title_List[counter] == '1' or
JI_Title_List[counter] == '2' or
JI_Title_List[counter] == '3' or
JI_Title_List[counter] == '4' or
JI_Title_List[counter] == '5' or
JI_Title_List[counter] == '6' or
JI_Title_List[counter] == '7' or
JI_Title_List[counter] == '8' or
JI_Title_List[counter] == '9' or
JI_Title_List[counter] == '0' or
JI_Title_List[counter] == '.'):
#print('If Statement True')
JI_Index_Length = JI_Index_Length + 1
else:
#print('False')
False
counter = counter + 1
return JI_Index_Length
def OpenDocumentForAutoGUI():
os.system("start " + '1ji.docx')
time.sleep(1) #causes delay to allow document to full open before next command runs
def main():
TitleNumberLength = int(JITitleNumberLength())
for i in range(TitleNumberLength):
pyautogui.press('right')
pyautogui.press(['delete', 'tab']) #removes space and inserts tab between number and instruction name
2) In the middle of a paragraph, there will be different options given in a format of [option 1] [option 2] [option 3]. I would like to create a content control that would give a drop down option of these three options. No where that i have read has there been something to content controls with docx. Is there any way to do this or just manually doing this with pyautogui the only option i have? Basically my thought is that i would search the paragraphs for the brackets [] and then input them into a content control somehow, and if need be, use pyautogui which i prefer to stay away from if possible.
I havent even begun the code for this part yet, my only thought would be to put each option into a list and then recall from the list after using pyautogui to manually move the mouse to click on the developer tab in word and then select the content control as there is no keyboard shortcut to bring in a content control. I would really prefer not to do this because then the screen resolution plays a big part and only specific screen resolutions would work.
Sorry - I am pretty sure that run-level formatting is the most granular that you can get. It should be trivial to add the code to create a second Run in the paragraph and apply an underline style to it.
No idea on drop-down list boxes
Two stylistic tips:
You can use 'in' and the constant string.digits with a concatenation operator to simplify your very long if statement
if JI_Title_List[counter] in (string.digits+'.') ....
You can use += to say x = x +; e.g. x+=1 is x = x + 1
counter += 1
JI_Index_Length +=1

Bubble sort error with nested (high scores) list - python

For my software major work I have to create a program. In summary, the high scores list needs to be sorted before it can be written to file. To do this, I am using a bubble sort and I can't use the inbuilt sort function. The text file that the data is being read from is stored in a nested list. The text file looks like this:
NameOne
10
NameTwo
15
NameThree
9
This is the bubble sort code I have but does not work:
b_not_sorted = True
while b_not_sorted:
counter = 0
b_not_sorted = False
for counter in range(len(highest_scores) - 1):
if highest_scores[counter] < highest_scores[counter + 1]:
b_not_sorted = True
highest_scores[counter], highest_scores[counter+1] = highest_scores[counter+1], highest_scores[counter]
counter = counter + 1
I need the scores to be sorted from highest to lowest. Any help would be greatly appreciated and you will be credited appropriately in my program credits :). Thanks.
Here's a hint:
Check how many times your outer while loop is running. It should be running more than once, correct? What will always happen that causes the loop to exit, no matter what?
Try going through the code line by line and seeing what happens at every point.
The statement b_not_sorted = False at the end of the outer loop results in the outer loop exiting after executing only once. You need to move that statement to another part of your code. Try changing the name of b_not_sorted to I_still_need_to_go_through_the_list in your head:
Obviously in the first line:
while I_still_need_to_go_through_the_list:
it should be True, since you haven't gone over the list at all. You don't know if it's in order or not.
and after the line:
if highest_scores[counter] < highest_scores[counter + 1]:
Of course then we still need to make another pass, since we just made a change to the list and need to make sure no further changes are needed.
But what if no changes are made? I_still_need_to_go_through_the_list should be False then. Hmmm. If we put I_still_need_to_go_through_the_list = False right before the for loop, then it will be False unless we make changes to the list, which is exactly what we want.
You're doing b_not_sorted = False right after the first iteration, but it shouldn't be there! The algorithm just stops before it finishes the sorting.
You should instead do b_not_sorted = True only if highest_scores[counter] < highest_scores[counter + 1]
Also, the swapping code can look much nicer in Python. Instead of using temp_var just do this:
highest_scores[counter], highest_scores[counter+1] = highest_scores[counter+1], highest_scores[counter]
Python style guide suggests that you shoudn't write == True or == False in if statements. Do it like this:
while b_not_sorted:

Categories