How to Create a Cursor or Loading Indicator for an Infinite Loop - python-3.x

I am scraping current follow requests from Instagram. I have a main infinite loop that it making the requests and prints OK when it is done. I want to display an animated cursor or loading progress while it is downloading names.
while 1:
response = requests.get(IG_CFR_PAGE, headers=headers(""), params=params, cookies=cookies)
if response.status_code == 200:
cfr = response.json()
for entry in cfr["data"]["data"]:
#print(entry["text"])
usernames.append(entry["text"])
if cfr["data"]["cursor"]!= None:
params['cursor'] = cfr["data"]["cursor"]
time.sleep(1)
else:
break
else:
print(response.status_code)
print("Error in request .... aborting")
break
print("ok")
I looked for tqdm but it takes an iterable. In my case, I am just looping over JSON keys in line for entry in cfr["data"]["data"]: and so I guess can't use it. I just need suggestions as to know what should I use to indicate that this script is actually doing something. I just need suggestions or pseudocode is fine to send me in a right direction... the actual programming code is not needed as I will do that myself.
Thank you

As far as I'm aware, most functions that allow you to change the mouse cursor in Python are available only from various GUI modules - most of the popular ones, such as tkinter, PyQt5, pygame or others.
The problem is that most of these may only work when you've created a window of the GUI, which is probably unnecessary or not a nice idea if you're not using the same GUI, or any GUI for that matter. Even then, some may only take effect when the mouse pointer hovers over a certain widget in that GUI.
Note:
I've only (unsuccessfully) tried doing this with pygame.cursors before. It may be convenient because it even lets you create a custom shape with strings, or use a system cursor. But it displays a pygame.error: video system not initialized if you try doing this without having called pygame.display.init() first. I tried creating a window and setting a cursor, but it didn't seem to take effect.
After a quick google search for other ways to set an animated cursor, I came across this SO answer which might offer some insight if you're on windows.
Overall, using a terminal animation may probably be better and easier, so
this is an attempt at a basic answer for a loading animation in a terminal window :
(Of course, for an indefinite length of loop, it doesn't make sense to store a percentage completion etc, so this just animates at an arbitrary pace and repeats when it reaches the end)
i, w, d = 0, 20, 10000
while True:
# Do whatever
# No print statements except this last one
i = (i+1)%(w*d)
l = i//d
print("\r Processing... |" + " "*l+ "█" + " "*(w-l-1) +"|", end='')
i is used for iteration, w is the length of the bar, and d used to create some sort of 'delay', so that the bar doesn't change at every single iteration, but some slower (visible) speed
Edit: Important Note: The '\r' that resets the cursor position doesn't work in every terminal - it may still move to a new line for the next print() instead of the start of the same line - but this should most likely be fine in your system Terminal/cmd etc... May not be a good idea to run this in IDLE :P
Edit 2: Based on your comment, for a blinking indicator (using the same approach) -
i, d = 0, 300000
while True:
i = (i+1)%d
print("\r Working... " + ("█" if i < d/2 else " "), end='')

Related

how to switch between windows in linux with command

I was studying about "AutoKey" and I understood that it interprets the keys as a button and create scripts..
image "AutoKey"
I'm using
"window.activate('Google Chrome')"
however it switches only to google chrome. How do you switch between two programs when you press a key?
Example:
"window.activate('Google Chrome')" - I'm on chrome
"window.activate('explorer.exe')" - I'm in the archive folder
I want them to toggle when I press a key
bar fedora
If you want them to toggle, then you have to find out where you are to start with. Start your script by getting the the window title...
NOTE: The following is untested code.
If it doesn't work and you can't easily figure out why, post on Gitter and we'll figure it out. The script below will fail as written because I don't think you can have empty except: clauses. The least you can do is add a pass statement to each of them so the error is ignored and doesn't throw an exception.
I assume that your window title strings are correct although explorer.exe gives me pause because I'm not sure that will run on Linux and AutoKey is a Linux X11 application. It does not work on Wayland or on Windows.
win = window.get_active_title()
if win == 'Google Chrome' :
try:
window.activate('explorer.exe')
except:
## do something if that didn't work
elif win == 'explorer.exe'
try:
window.activate('Google Chrome')
except:
## do something if that didn't work
else
## do something when neither is the active window
If one or both of those windows/apps aren't running when this script is launched, then something will fail. You can either try to launch them or do something else depending on your requirements.
I don't think the first API call can fail, but you can put that in a try: block too if necessary.
Also, when things look right, but still don't work, the first thing to try is to add long delays before/between all the API calls with something like time.sleep(1). Once the script works, you can reduce or eliminate the delays one at a time.

Prompt at the bottom of terminal and printout scrolls at the top in python

I am using Python 3.X and looking for a simplest way to have input at the lowest line and all print information scroll above it. For example if I have print("hello world"), it would print at the top and if I have name = input("What is your name"), it would be printed on the last line. It seems like there should be a super simple way to do it without using library like the rich.
So effectively you want the behavior that would occur when the terminal starts scrolling? Just dump a full screen of newlines when you start your program.
print('\n' * 200)

OpenCV destroyallWindow function should not work?

import cv2
img = cv2.imread('lena.jpg', -1)
cv2.imshow('image', img)
k = cv2.waitKey(0) & 0xFF
if k == 27:
cv2.destroyAllWindows()
elif k == ord('s'):
cv2.imwrite('lena_copy.png', img)
I am a beginner in OpenCV. As I was playing around with the functions, I noticed this error. This script, if I understand correctly should first show the image, then will either get destroyed or saved depending on if I press the escape key or s key. But the thing is no matter what key I pressed, the window gets destroyed. It's like I don't need the destroyAllWindows() function to destroy all my window, All I need is to press a random key. Is it because I misunderstand the purpose of destroyAllWindows() function or is it because of something else?
When you press the escape key, it will explicitly call destroyAllWindows. When you press s, it will first save the image and then the operating system will destroy all windows upon exit. If you press any other key, again, the OS will close and deallocate all windows upon exit.
From OpenCV docs:
You can call destroyWindow() or destroyAllWindows() to close the
window and de-allocate any associated memory usage. For a simple
program, you do not really have to call these functions because all
the resources and windows of the application are closed automatically
by the operating system upon exit.
The problem is with waitKey not destroyAllWindow. The latter works fine and does what it should do.
You must understand that when you display a window, (by imshow()) your application must have main events loop, in which all events related to interactions with the windows like clicking, resizing, moving, displaying etc. are processed. This main loop of GUI application is created and processed in waitKey() function invocation.
Your current flow is as follows:
show window
press any key
all windows are closed no matter what key was pressed because you didn't call waitKey again for k == 's'
.
if k == 27:
cv2.destroyAllWindows()
elif k == ord('s'):
cv2.imwrite('lena_copy.png', img)
cv2.waitKey(0)
by adding the last line, you start new events loop, and windows are still visible.

iPython/ Jupyter notebook clear only one line of output

How can I print the status of a Jupyter notebook on the previous line? I think I'm looking for something like clear_output(), but for only a single line.
Sample code:
from IPython.display import clear_output
import time
print('This is important info!')
for i in range(100):
print('Processing BIG data file {}'.format(i))
time.sleep(0.1)
clear_output(wait=True)
if i == 50:
print('Something bad happened on run {}. This needs to be visible at the end!'.format(i))
print('Done.')
When this runs it gives the behavior of over-writing the previous status line, but both of the lines marked as important (with exclamation points and everything!) are lost. When this is finished the display just says:
Done.
What it should say is:
This is important info!
Something bad happened on run 50. This needs to be visible at the end!
Done.
This post suggests using clear_output() and then reprinting everything. This seems impractical because the amount of data I really tend to display is big (lots of graphs, dataframes, ...).
Here's two SO links about clear_output().
Is there a way to make this work that doesn't involve reprinting everything?
I got it woking using the update function of the display handle:
from IPython.display import display
from time import sleep
print('Test 1')
dh = display('Test2',display_id=True)
sleep(1)
dh.update('Test3')
This will do it:
import IPython
IPython.display.display_javascript(r'''
var el = document.querySelector('.output_text:last-of-type > pre');
el.innerHTML = el.innerHTML.replace(/(\n.*$)/gm,""); ''', raw=True)
This simple escape sequence trick can do the job most of the time. \n and \r can do a lot if used properly.
\r: (Carriage Return) (CR) returns the cursor to the beginning of the new line without moving to a new line.
\n:(Line Feed) (LF) moves the cursor to the next line.
import time
print('This is important info!')
for i in range(100):
print("\r"+'Processing BIG data file {}'.format(i),end="")
time.sleep(0.1)
if i == 50:
print("\r"+'Something bad happened on run {}. This needs to be visible at the end!'.format(i))
print("\r"+'Done.')

Tkinter CPU activity after inserting text from file

If I take a 25MB/190,000 line text file and dump it into a text widget the process finishes quickly but I still see python.exe using 50%CPU for another minute or so afterwards. The bigger the file, the longer it takes for the CPU to drop off to 0% usage. When I start loading multiple files into different text widgets they load into the widget instantly but the CPU stays at 50% and the GUI runs horribly slow until it finishes whatever its doing in the backend. Can someone explain to me why the CPU is still being used and why its impacting performance if the text is already in the widget? What is it needing to do? Any way around this?
from tkinter import *
file = r"C:\path\to\large\file.txt"
def doit():
with open(file, 'r') as f:
txt.insert('end', ''.join(f))
f.close()
main = Tk()
txt = Text(main)
txt.grid(row=0)
btn = Button(main, text="click here", command=doit)
btn.grid(row=1, columnspan=2)
main.mainloop()
I thought maybe it was because im handling the file line by line instead of loading the entire file into RAM. I tried readlines() but I get the same results.
Most likely it is calculating where the line breaks go, for lines past the area currently visible on the screen. With the numbers you gave, the lines average over 130 characters long; if some of them are considerably over that, this is a situation that Tkinter is known to be slow in.
You could perhaps turn off word-wrap (by configuring the Text with wrap=NONE), which would probably require that you add a horizontal scroll bar. If that is unacceptable, it's possible that adding newlines of your own could help, if there's some natural point at which to insert them in your data.
Note that ''.join(f) is a rather inefficient way to read the entire file into a single string - just use f.read() for that.

Resources