Making loading animation script in Python 2.7 - python

I am trying to make a python program that writes the follwing to a terminal:
Frame 1 -- Loading
Frame 2 -- Loading.
Frame 3 -- Loading..
Frame 4 -- Loading...
Frame 5 -- Loading
This would all be a function so that it repeats itself. The one problem I am having is that I have no idea how to reset the number of dots to zero after they equal three. My current code is below, any suggestions would be nice.
import pickle
import time
from sys import stdout
stdout.write("Loading")
def loaddot():
stdout.write(".")
time.sleep(.5)
loaddot()
loaddot()

Here is my attempt:
import time
from sys import stdout
def loaddot():
stdout.write("."*(dots%3 + 1))
time.sleep(.5)
dots = 0
while(True):
dots += 1
stdout.write("Loading")
loaddot()
stdout.flush()
print
I believe there are better ways to do it in Python. I have not worked with the language that much, but this comes from what I know and my background in other languages.

To do something like this, you really should be using the curses library. There exist several hacks to get the screen to clear, or backspace characters, but none compare to the UI features of curses:
http://docs.python.org/2.7/library/curses.html

You need to clear the screen, if you are on a linux system simply use the os library
import os
import time
while True:
for i in range(3):
print "Loading."<br>
time.sleep(3)<br>
os.system("clear")<br>
print "Loading.."<br>
time.sleep(3)<br>
os.system("clear")<br>
print "Loading..."<br>
time.sleep(3)<br>
os.system("clear")<br>

Related

Detect if Python script is running in focus [duplicate]

I would like to get the active window on the screen using python.
For example, the management interface of the router where you enter the username and password as admin
That admin interface is what I want to capture using python to automate the entry of username and password.
What imports would I require in order to do this?
On windows, you can use the python for windows extensions (http://sourceforge.net/projects/pywin32/):
from win32gui import GetWindowText, GetForegroundWindow
print GetWindowText(GetForegroundWindow())
Below code is for python 3:
from win32gui import GetWindowText, GetForegroundWindow
print(GetWindowText(GetForegroundWindow()))
(Found this on http://scott.sherrillmix.com/blog/programmer/active-window-logger/)
Thanks goes to the answer by Nuno André, who showed how to use ctypes to interact with Windows APIs. I have written an example implementation using his hints.
The ctypes library is included with Python since v2.5, which means that almost every user has it. And it's a way cleaner interface than old and dead libraries like win32gui (last updated in 2017 as of this writing). ((Update in late 2020: The dead win32gui library has come back to life with a rename to pywin32, so if you want a maintained library, it's now a valid option again. But that library is 6% slower than my code.))
Documentation is here: https://docs.python.org/3/library/ctypes.html (You must read its usage help if you wanna write your own code, otherwise you can cause segmentation fault crashes, hehe.)
Basically, ctypes includes bindings for the most common Windows DLLs. Here is how you can retrieve the title of the foreground window in pure Python, with no external libraries needed! Just the built-in ctypes! :-)
The coolest thing about ctypes is that you can Google any Windows API for anything you need, and if you want to use it, you can do it via ctypes!
Python 3 Code:
from typing import Optional
from ctypes import wintypes, windll, create_unicode_buffer
def getForegroundWindowTitle() -> Optional[str]:
hWnd = windll.user32.GetForegroundWindow()
length = windll.user32.GetWindowTextLengthW(hWnd)
buf = create_unicode_buffer(length + 1)
windll.user32.GetWindowTextW(hWnd, buf, length + 1)
# 1-liner alternative: return buf.value if buf.value else None
if buf.value:
return buf.value
else:
return None
Performance is extremely good: 0.01 MILLISECONDS on my computer (0.00001 seconds).
Will also work on Python 2 with very minor changes. If you're on Python 2, I think you only have to remove the type annotations (from typing import Optional and -> Optional[str]). :-)
Enjoy!
Win32 Technical Explanations:
The length variable is the length of the actual text in UTF-16 (Windows Wide "Unicode") CHARACTERS. (It is NOT the number of BYTES.) We have to add + 1 to add room for the null terminator at the end of C-style strings. If we don't do that, we would not have enough space in the buffer to fit the final real character of the actual text, and Windows would truncate the returned string (it does that to ensure that it fits the super important final string Null-terminator).
The create_unicode_buffer function allocates room for that many UTF-16 CHARACTERS.
Most (or all? always read Microsoft's MSDN docs!) Windows APIs related to Unicode text take the buffer length as CHARACTERS, NOT as bytes.
Also look closely at the function calls. Some end in W (such as GetWindowTextLengthW). This stands for "Wide string", which is the Windows name for Unicode strings. It's very important that you do those W calls to get proper Unicode strings (with international character support).
PS: Windows has been using Unicode for a long time. I know for a fact that Windows 10 is fully Unicode and only wants the W function calls. I don't know the exact cutoff date when older versions of Windows used other multi-byte string formats, but I think it was before Windows Vista, and who cares? Old Windows versions (even 7 and 8.1) are dead and unsupported by Microsoft.
Again... enjoy! :-)
UPDATE in Late 2020, Benchmark vs the pywin32 library:
import time
import win32ui
from typing import Optional
from ctypes import wintypes, windll, create_unicode_buffer
def getForegroundWindowTitle() -> Optional[str]:
hWnd = windll.user32.GetForegroundWindow()
length = windll.user32.GetWindowTextLengthW(hWnd)
buf = create_unicode_buffer(length + 1)
windll.user32.GetWindowTextW(hWnd, buf, length + 1)
return buf.value if buf.value else None
def getForegroundWindowTitle_Win32UI() -> Optional[str]:
# WARNING: This code sometimes throws an exception saying
# "win32ui.error: No window is is in the foreground."
# which is total nonsense. My function doesn't fail that way.
return win32ui.GetForegroundWindow().GetWindowText()
iterations = 1_000_000
start_time = time.time()
for x in range(iterations):
foo = getForegroundWindowTitle()
elapsed1 = time.time() - start_time
print("Elapsed 1:", elapsed1, "seconds")
start_time = time.time()
for x in range(iterations):
foo = getForegroundWindowTitle_Win32UI()
elapsed2 = time.time() - start_time
print("Elapsed 2:", elapsed2, "seconds")
win32ui_pct_slower = ((elapsed2 / elapsed1) - 1) * 100
print("Win32UI library is", win32ui_pct_slower, "percent slower.")
Typical result after doing multiple runs on an AMD Ryzen 3900x:
My function: 4.5769994258880615 seconds
Win32UI library: 4.8619983196258545 seconds
Win32UI library is 6.226762715455125 percent slower.
However, the difference is small, so you may want to use the library now that it has come back to life (it had previously been dead since 2017). But you're going to have to deal with that library's weird "no window is in the foreground" exception, which my code doesn't suffer from (see the code comments in the benchmark code).
Either way... enjoy!
The following script should work on Linux, Windows and Mac. It is currently only tested on Linux (Ubuntu Mate Ubuntu 15.10).
Prerequisites
For Linux:
Install wnck (sudo apt-get install python-wnck on Ubuntu, see libwnck.)
For Windows:
Make sure win32gui is available
For Mac:
Make sure AppKit is available
The script
#!/usr/bin/env python
"""Find the currently active window."""
import logging
import sys
logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
level=logging.DEBUG,
stream=sys.stdout)
def get_active_window():
"""
Get the currently active window.
Returns
-------
string :
Name of the currently active window.
"""
import sys
active_window_name = None
if sys.platform in ['linux', 'linux2']:
# Alternatives: https://unix.stackexchange.com/q/38867/4784
try:
import wnck
except ImportError:
logging.info("wnck not installed")
wnck = None
if wnck is not None:
screen = wnck.screen_get_default()
screen.force_update()
window = screen.get_active_window()
if window is not None:
pid = window.get_pid()
with open("/proc/{pid}/cmdline".format(pid=pid)) as f:
active_window_name = f.read()
else:
try:
from gi.repository import Gtk, Wnck
gi = "Installed"
except ImportError:
logging.info("gi.repository not installed")
gi = None
if gi is not None:
Gtk.init([]) # necessary if not using a Gtk.main() loop
screen = Wnck.Screen.get_default()
screen.force_update() # recommended per Wnck documentation
active_window = screen.get_active_window()
pid = active_window.get_pid()
with open("/proc/{pid}/cmdline".format(pid=pid)) as f:
active_window_name = f.read()
elif sys.platform in ['Windows', 'win32', 'cygwin']:
# https://stackoverflow.com/a/608814/562769
import win32gui
window = win32gui.GetForegroundWindow()
active_window_name = win32gui.GetWindowText(window)
elif sys.platform in ['Mac', 'darwin', 'os2', 'os2emx']:
# https://stackoverflow.com/a/373310/562769
from AppKit import NSWorkspace
active_window_name = (NSWorkspace.sharedWorkspace()
.activeApplication()['NSApplicationName'])
else:
print("sys.platform={platform} is unknown. Please report."
.format(platform=sys.platform))
print(sys.version)
return active_window_name
print("Active window: %s" % str(get_active_window()))
For Linux users:
All the answers provided required additional modules like "wx" that had numerous errors installing ("pip" failed on build), but I was able to modify this solution quite easily -> original source. There were bugs in the original (Python TypeError on regex)
import sys
import os
import subprocess
import re
def get_active_window_title():
root = subprocess.Popen(['xprop', '-root', '_NET_ACTIVE_WINDOW'], stdout=subprocess.PIPE)
stdout, stderr = root.communicate()
m = re.search(b'^_NET_ACTIVE_WINDOW.* ([\w]+)$', stdout)
if m != None:
window_id = m.group(1)
window = subprocess.Popen(['xprop', '-id', window_id, 'WM_NAME'], stdout=subprocess.PIPE)
stdout, stderr = window.communicate()
else:
return None
match = re.match(b"WM_NAME\(\w+\) = (?P<name>.+)$", stdout)
if match != None:
return match.group("name").strip(b'"')
return None
if __name__ == "__main__":
print(get_active_window_title())
The advantage is it works without additional modules. If you want it to work across multiple platforms, it's just a matter of changing the command and regex strings to get the data you want based on the platform (with the standard if/else platform detection shown above sys.platform).
On a side note: import wnck only works with python2.x when installed with "sudo apt-get install python-wnck", since I was using python3.x the only option was pypie which I have not tested. Hope this helps someone else.
There's really no need to import any external dependency for tasks like this. Python comes with a pretty neat foreign function interface - ctypes, which allows for calling C shared libraries natively. It even includes specific bindings for the most common Win32 DLLs.
E.g. to get the PID of the foregorund window:
import ctypes
from ctypes import wintypes
user32 = ctypes.windll.user32
h_wnd = user32.GetForegroundWindow()
pid = wintypes.DWORD()
user32.GetWindowThreadProcessId(h_wnd, ctypes.byref(pid))
print(pid.value)
In Linux under X11:
xdo_window_id = os.popen('xdotool getactivewindow').read()
print('xdo_window_id:', xdo_window_id)
will print the active window ID in decimal format:
xdo_window_id: 67113707
Note xdotool must be installed first:
sudo apt install xdotool
Note wmctrl uses hexadecimal format for window ID.
This only works on windows
import win32gui
import win32process
def get_active_executable_name():
try:
process_id = win32process.GetWindowThreadProcessId(
win32gui.GetForegroundWindow()
)
return ".".join(psutil.Process(process_id[-1]).name().split(".")[:-1])
except Exception as exception:
return None
I'll recommend checking out this answer for making it work on linux, mac and windows.
I'd been facing same problem with linux interface (Lubuntu 20).
What I do is using wmctrl and execute it with shell command from python.
First, Install wmctrl
sudo apt install wmctrl
Then, Add this code :
import os
os.system('wmctrl -a "Mozilla Firefox"')
ref wmctrl :
https://askubuntu.com/questions/21262/shell-command-to-bring-a-program-window-in-front-of-another
In Linux:
If you already have installed xdotool, you can just use:
from subprocess import run
def get__focused_window():
return run(['xdotool', 'getwindowfocus', 'getwindowpid', 'getwindowname'], capture_output=True).stdout.decode('utf-8').split()
While I was writing this answer I've realised that there were also:
A reference about "xdotool" on comments
& another slightly similar "xdotool" answer
So, I've decided to mention them here, too.
Just wanted to add in case it helps, I have a function for my program (It's a software for my PC's lighting I have this simple few line function:
def isRunning(process_name):
foregroundWindow = GetWindowText(GetForegroundWindow())
return process_name in foregroundWindow
Try using wxPython:
import wx
wx.GetActiveWindow()

Concurrent.futures.map initializes code from beginning

I am a fairly beginner programmer with python and in general with not that much experience, and currently I'm trying to parallelize a process that is heavily CPU bound in my code. I'm using anaconda to create environments and Visual Code to debug.
A summary of the code is as following :
from tkinter import filedialog
import myfuncs as mf, concurrent.futures
file_path = filedialog.askopenfilename('Ask for a file containing data')
# import data from file_path
a = input('Ask the user for input')
Next calculations are made from these and I reach a stage where I need to iterate of a list of lists. These lists may contain up to two values and calls are made to a separate file.
For example the inputs are :
sub_data1 = [test1]
sub_data2 = [test1, test2]
dataset = [sub_data1, sub_data2]
This is the stage I use concurrent.futures.ProcessPoolExecutor()-instance and its .map() method :
with concurrent.futures.ProcessPoolExecutor() as executor:
sm_res = executor.map(mf.process_distr, dataset)
While inside a myfuncs.py, the mf.process_distr() function works like this :
def process_distr(tests):
sm_reg = []
for i in range(len(tests)):
if i==0:
# do stuff
sm_reg.append(result1)
else:
# do stuff
sm_reg.append(result2)
return sm_reg
The problem is that when I try to execute this code on the main.py file, it seems that the main.py starts running multiple times, and asks for user inputs and file dialog pops up multiple times (same amount as cores count).
How can I resolve this matter?
Edit: After reading more into it, encapsulating the whole main.py code with:
if __name__ == '__main__':
did the trick. Thank you to anyone who gave time to help with my rookie problem.

Saving video file the time and date in filename

Expected Behavior
Automatically run a program to record a video for a short length of time.
Save the video to a unique filename within a specific directory (to avoid overwriting). Ideally, this filename would include the date and time.
Actual Behavior
Success
Filename is always video.h264.
I have tried all sorts of things that I have found on the net, but they only result in the file name showing part of the code. Annoyingly it worked once, but saved it to somewhere I was not expecting and I changed the code before I realized it had worked!
Full File
# Import Libraries
import os #Gives Python access to Linux commands
import time #Proves time related commands
import RPi.GPIO as GPIO #Gives Python access to the GPIO pins
GPIO.setmode(GPIO.BCM) #Set the GPIO pin naming mode
GPIO.setwarnings(False) #Supress warnings
# Set GPIO pins 18 as output pin
LEDReady = 18 #Red
GPIO.setup(LEDReady,GPIO.OUT)
GPIO.output (LEDReady,GPIO.HIGH)
from subprocess import call
call(["raspivid", "-o", "video.h264", "-t", "50000n"])
time.sleep(10) #Sleep for 10 seconds
GPIO.output (LEDReady,GPIO.LOW)
Adding DATE=$(date +"%Y-%m-%d_%H%M")
and changing video.h264 to $DATE.h264 results in a syntax error for $DATE.
Tantalizingly, I have a file called 20180308_021941.h264 which is exactly what I am after, but I cannot tell you how I managed it!
P.S. the Red LED lighting up is so that I can tell if the Raspberry Pi has fired up properly and has run the Python script.
Thank you for taking the trouble to read this.
Try adding this
from datetime import datetime
date = datetime.now().strftime("%Y%m%d%H:%M:%S")
Then change your call to this
videoFile = date + ".h264"
call(["raspivid", "-o", videoFile, "-t", "50000n"])

Why PyAutoGui LocateOnScreen() only Returns None

Here's the code that I'm trying to run:
import pyautogui
r=pyautogui.locateOnScreen('C:\Users\David\Desktop\index.png',grayscale=False)
print r
It has to be a pixel-perfect match in order to be found. To allow for any sort of deviance you can invoke a confidence parameter.
For example:
loc = pyautogui.locateOnScreen(image, grayscale=True, confidence=.5)
However, in order to use the confidence parameter you have to have opencv_python installed. This is easy to install with pip:
./python -m pip install opencv_python
After that is in place, you should be able to account for minor differences.
I was encountering the same problem, what I did is
import pyautogui
r= None
while r is None:
r=pyautogui.locateOnScreen('C:\Users\David\Desktop\index.png',grayscale=False)
print r
I think its just because that it takes time to locate image. If you found a better solution share with me :)
I had the similar problem.
My fault was I had saved the compare picture as jpg first and then as png in MS paint.
Be sure to save the compare picture as png format. After this the Locate function worked for me.
I had same issue and kept returning None value.
I did several trials and found the solution for me.
OS : MacOS
I saved photo with my system screenshot tool ( command+shift+5) and saved. it seems it's different pixel info as what it's displayed in my screen.
Therefore I used pyautogui screenshot instead to save the photo which I wanted to.
pyautogui.screenshot('num7_.png', region=(260,360, 110, 100))
After that, it's working good regardless of grayscale parameter.
pyautogui.locateOnScreen('num7_.png')
Box(left=260, top=360, width=110, height=100)
The locateOnScreen() function returns None if the image wasn't found on the screen. Remember, the match has to be pixel-perfect in order to match it, so be sure to crop index.png to the smallest recognizable size to prevent extra details from ruining your match. Also, make sure the thing you are looking for is not obscured by any other windows on top of it.
I got this working by using the following:
r = None
while r is None:
r = pyautogui.locateOnScreen('rbin.PNG', grayscale = True)
print icon_to_click + ' now loaded'
The key is to make grayscale = True.
The official documentation says;
The Locate Functions
NOTE: As of version 0.9.41, if the locate functions can’t find the provided image,
they’ll raise ImageNotFoundException instead of returning None.
So you can decide whether an exception was raise or not. Also you should try for a finite number of times not a While True loop.
retry_counter = 0
while retry_counter < 5:
try:
result = pyautogui.locateOnScreen(IMAGE_PATH_TO_FIND)
if result:
time.sleep(1)
retry_counter = 10 # to break the loop
except:
time.sleep(1) # retry after some time, i.e. 1 sec
retry_counter += 1
I found that if you program a pause of 1 or 2 seconds (using time.sleep), then it is able to locate the image. It also takes time for python to locate the image (my computer took about 5 seconds).
I had that problem but then i crop the photo into specific part then it was locating and yes it takes time.
or this can also work.
b = pyautogui.center('calc7key.png')
I found a way to fix my problem. Only search for an image as small as possible. A picture that is only 1 pixel is found after 3 seconds. And when i try to search for an image over 500x500 then it won't find anything.
I think that the library pyautogui needs several recognition points. For example, Number seven on calculator:
The number seven on the calculator of windows 10. In this format, I´ve got the location on the screen.
Thank you for your comments
My problem was I was trying to take a snip of the calculator button. That must make a different pixel match because I tried every other option in here and nothing was working. I did a print screen then cropped it to the button I wanted and it worked.
Before
import pyautogui
image = '9.png'
loc = pyautogui.locateOnScreen(image, grayscale=True, confidence=.5)
print (loc)
Error:
None
>>>
Solution
import pyautogui
import time
time.sleep(5)
image = '9.png'
loc = pyautogui.locateOnScreen(image, grayscale=True, confidence=.5)
print (loc)
Summary: Just add this two lines:
import time
time.sleep(5)
Output
Box(left=1686, top=248, width=70, height=47)
>>>
import time
time.sleep(5)
If you have taken screenshot with snipping tool it wont work, so take screenshot with "prt sc" or command prompt. This worked for me!
I am sure most of you guys know this, but if you forget to run your python script or IDE (wether that be Visual Studio, Python IDLE, etc.) as an administrator, then pyautogui will not be able to use the click command. It will still be able to move the mouse around, but it just won’t be able to click (this is true for all operating systems, they prevent any software that dose not have administrative privileges from clicking and i think it also prevents the software from using the keyboard but I am not sure. The OS dose this as a security measure so no software can do malicious things on your computer without your consent, like for instance: prompting the user to allow the software administrator access, and then taking control of the mouse and keyboard to click the “Yes” button for the user). If you’re using Linux or Mac then I am sure you know: you would have to use the “sudo” command. Hope this helps someone ;)

Python: how to switch between workspaces using Xlib?

How do I switch between my window manager's workspaces using Python with Xlib module?
This is my most promising attempt:
#!/usr/bin/python
from Xlib import X, display, error, Xatom, Xutil
import Xlib.protocol.event
screen = Xlib.display.Display().screen()
root = screen.root
def sendEvent(win, ctype, data, mask=None):
""" Send a ClientMessage event to the root """
data = (data+[0]*(5-len(data)))[:5]
ev = Xlib.protocol.event.ClientMessage(window=win, client_type=ctype, data=(32,(data)))
if not mask:
mask = (X.SubstructureRedirectMask|X.SubstructureNotifyMask)
root.send_event(ev, event_mask=mask)
# switch to desktop 2
sendEvent(root, Xlib.display.Display().intern_atom("_NET_CURRENT_DESKTOP"), [2])
The above code is shamelessly stolen from various places in the PyPanel source; unfortunately, it doesn't do anything, not even generate a warning / exception. Am I missing something here?
I'm using Python and PyGTK. Xlib seems to be the right choice for switching desktops. I don't intend to use wnck (buggy Python module) or similar, but I'd appreciate any pointers anyway.
I might add that this is my first attempt at writing a Python application using Xlib (or PyGTK).
Apparently you need to work on the same Display object and then flush it at the end. Something like:
display = Xlib.display.Display()
screen = display.screen()
root = screen.root
# ...
sendEvent(root, display.intern_atom("_NET_CURRENT_DESKTOP"), [1, X.CurrentTime])
display.flush()
Credit: Idea from a very similar thread (which almost works).
P.S. By the way, the desktop number starts from 0.

Categories