PyAutoGui while loop interruption - python-3.x

So I have been searching the Internet trying to figure out what I am doing wrong here. Basically, I want to create a script that will prompt the user to enter a number, then perform the ctrl-v paste operation that many times. I have tried variation upon variation of the below, but it is just not working.
The commands work fine outside the loop, but the moment I try to loop it, the program just crashes. I am probably missing something obvious, but I have been trying to find that something for the last 2 hours without any luck. Any help is appreciated.
import time
import pyautogui
x = input()
time.sleep(5) #delays the next process by 5 seconds
def work():
global x
pyautogui.hotkey('ctrl','v')
time.sleep(.25)
pyautogui.press('enter')
time.sleep(.25)
x = x - 1
try:
while x > 0:
work()
else:
pass
except KeyboardInterrupt:
pass

OK i figured this out. x > 0 was the problem. As the code stands now x is a string and you can't compare a string to an integer.
So what i did was add this after the user input
x = int(x)
Now it works perfectly. If i had run the program from the command window i would have found this problem hours ago. I will know better for next time.

Related

Trying to make a can counter on a PI 4 in python, Strugging with code for two sensors running at the same time

So I work in the beverage industry and I decided to try and make a can counter using a Raspberry PI4. It needs to use two industrial sensors on the GPIO that detect the cans.
Full Disclosure I have just been googling most code and reading when I get errors in terminal to try and fix the issue. I have done some rudimentary C# and C++ programming doing PLC stuff but it's nothing like what i'm trying to do right now. Just some simple statements for conversions and formulas.
I have had it counting via the sensor on a very rudimentary code
import RPi.GPIO as GPIO
import time
GPIN = 16
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIN, GPIO.IN)
counting = 0
while True:
while GPIO.input(GPIN) == 0:
time.sleep(0.1)
counting = counting + 1
print(counting)
while GPIO.input(GPIN) == 1:
time.sleep(0.1)
This counts in the terminal. It is of note I need to count the on and off state with a slight delay to keep accidental double counts from happening. I have even added in a GUI with guizero that makes it count in a window. although currently I cannot replicate that from what I remember working and i foolishly didn't save that as i was trying to get to the next stage, but the rough of it was instead of the print(counting) section in the above code I had the app.display() info.
Problem is I need it to count 2 sensors at the same time, one before the can rejector and one after. So I did some reading and figured I needed to run two (or maybe 3) loops at the same time. as I have 2 sensors that need a constant loop, plus it seems like a need another loop that runs and refreshes the GUI. I got turned into threading and have been trying to implement it as that seems like what I want but haven't been able to make heads or tails of it. I can get the GUI to display, but the sensors don't read. If I switch back to my simple code it counts away. Im having trouble meshing the two together.
import threading
from guizero import App, Text, PushButton
import RPi.GPIO as GPIO
import time
GPIN1 = 16
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIN1, GPIO.IN)
GPIN2 = 15
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIN2, GPIO.IN)
counting1 = 0
counting2 = 0
counting3 = counting1 - counting2
def sensor1():
global counting1
while GPIO.input(GPIN1) == 0:
time.sleep(0.1)
counting1 = counting1 + 1
while GPIO.input(GPIN1) == 1:
time.sleep(0.1)
def sensor2():
global counting2
while GPIO.input(GPIN2) == 0:
time.sleep(0.1)
counting2 = counting2 + 1
while GPIO.input(GPIN2) == 1:
time.sleep(0.1)
x = threading.Thread(target=sensor1)
y = threading.Thread(target=sensor2)
x.start()
y.start()
while True:
app = App(title="Can Count")
message = Text(app, text="Total")
message = Text(app, text=(counting1))
message = Text(app, text="Rejected")
message = Text(app, text=(counting3))
app.display()
I'm just a bit stumped I'm sure my way isn't the best way to do this, any advice, tips or pointers in the right direction would be appreciated. I'm trying to crash course youtube python tutorials on the side but I am still coming up short.
It seems like I can get the display to show updates if i close the window via the x it restarts the window and shows the update but I have tried a few different things with guizero using a def text(): above that code and text.repeat(10, text) thinking this would redraw the screen but that doesn't work or breaks the gui or the code.
Also I know I call PushButton and don't use it, but the end goal will have a simple reset the counter button.. Just haven't got there yet.

Python program stops after for-loop with input inside it is finished

Im writing the code in text editor and execute it by double clicking the code. The code is fairly simple:
n_inp = int(input("N: "))
num = []
for i in range(n_inp):
num.append(int(input("Number: " )))
print(num)
but for some reason the program just stopped after the loop is finished. It never prints the num, the program just closed. I tried using sleep command after the print(num) to see if it changes anything but it doesnt. Is there a problem with the code? Or should i just use some IDE to execute it? Thanks in advance.
edit: the code runs fine when executed from command prompt, i just wont run a code by double clicking again.
but i tried the same code in python3 it's working correctly...
num prints the output like....
N: 3
Number: 12
Number: 13
Number: 14
[12, 13, 14]
You are not able to see the output because it will close the terminal immediately after printing the output. You can just add sleep after the print(num) statement. Try the following code.
import time
n_inp = int(input("N: "))
num = []
for i in range(n_inp):
num.append(int(input("Number: " )))
print(num)
time.sleep(10)
or add one more input() after the print statement so that it will wait until you press any other button.
n_inp = int(input("N: "))
num = []
for i in range(n_inp):
num.append(int(input("Number: " )))
print(num)
input()

How To Print Strings From Python App to a Browser Text-Field within a Flash Game

I want this small python program to be able to output strings into a text-field within a flash game on Google Chrome. The key press emulations work, however the print function obviously only returns the printed code to console.
I tried a few workarounds using a for loop to push the string values into a .press and .release functions, but (not only is this not optimal code) it (as far as I could tell) can't be done.
def click():
username=textentry.get()
time.sleep(2)
for i in range(1000):
print(username)
keyboard.press(Key.tab)
keyboard.release(Key.tab)
print(f'{i:03}')
keyboard.press(Key.enter)
keyboard.release(Key.enter)
keyboard.press(Key.shift)
keyboard.press(Key.tab)
keyboard.release(Key.tab)
keyboard.release(Key.shift)
Prints fine to console, and the key presses and releases are working. Only issue is that text doesn't get sent to anything outside the console.
My ideal situation is that you can simply start the program and then click into the text-fields (one for username, the other for the 3-code integer) and it will do the rest for you, running through username-associated 000 ints until it gets the friend code.
This program IS not (and couldn't) guess somebody's password. It's for a harmless flash game called stick empires.
The question seems unsolvable (I could be wrong, but after researching for hours and hours the reoccurring answer is that it can't be done.) But here's a semi-work around:
If you use pynputs .type("") function, you can essentially queue up key presses in your operating system as though you yourself were typing a string out. To do this as I requested above, with the first textfield needing a username to be entered, and the second textfield needing a 3 digit integer (iterating up from 000 to 999 for all possibilities) I had to use two for-loops and call a bunch of functions. It looks pretty ugly but it is functional.
#Click function to run inputs
def click():
t = 0; j = 0
lst = []
keyboard = Controller()
username = textentry.get()
a = len(username)
time.sleep(2)
for i in range(1000):
for j in range(a):
keyboard.press(username[j])
keyboard.release(username[j])
j += 1
keyboard.press(Key.tab)
keyboard.release(Key.tab)
lst.append(f'{i:03}')
keyboard.type(lst[i])
keyboard.press(Key.enter)
keyboard.release(Key.enter)
keyboard.press(Key.shift)
keyboard.press(Key.tab)
time.sleep(0.02)
keyboard.release(Key.tab)
keyboard.release(Key.shift)
i += 1
j = 0

How to set timeout for a block of code which is not a function python3

After spending a lot of hours looking for a solution in stackoverflow, I did not find a good solution to set a timeout for a block of code. There are approximations to set a timeout for a function. Nevertheless, I would like to know how to set a timeout without having a function. Let's take the following code as an example:
print("Doing different things")
for i in range(0,10)
# Doing some heavy stuff
print("Done. Continue with the following code")
So, How would you break the for loop if it has not finished after x seconds? Just continue with the code (maybe saving some bool variables to know that timeout was reached), despite the fact that the for loop did not finish properly.
i think implement this efficiently without using functions not possible , look this code ..
import datetime as dt
print("Doing different things")
# store
time_out_after = dt.timedelta(seconds=60)
start_time = dt.datetime.now()
for i in range(10):
if dt.datetime.now() > time_started + time_out:
break
else:
# Doing some heavy stuff
print("Done. Continue with the following code")
the problem : the timeout will checked in the beginning of every loop cycle, so it may be take more than the specified timeout period to break of the loop, or in worst case it maybe not interrupt the loop ever becouse it can't interrupt the code that never finish un iteration.
update :
as op replayed, that he want more efficient way, this is a proper way to do it, but using functions.
import asyncio
async def test_func():
print('doing thing here , it will take long time')
await asyncio.sleep(3600) # this will emulate heaven task with actual Sleep for one hour
return 'yay!' # this will not executed as the timeout will occur early
async def main():
# Wait for at most 1 second
try:
result = await asyncio.wait_for(test_func(), timeout=1.0) # call your function with specific timeout
# do something with the result
except asyncio.TimeoutError:
# when time out happen program will break from the test function and execute code here
print('timeout!')
print('lets continue to do other things')
asyncio.run(main())
Expected output:
doing thing here , it will take long time
timeout!
lets continue to do other things
note:
now timeout will happen after exactly the time you specify. in this example code, after one second.
you would replace this line:
await asyncio.sleep(3600)
with your actual task code.
try it and let me know what do you think. thank you.
read asyncio docs:
link
update 24/2/2019
as op noted that asyncio.run introduced in python 3.7 and asked for altrnative on python 3.6
asyncio.run alternative for python older than 3.7:
replace
asyncio.run(main())
with this code for older version (i think 3.4 to 3.6)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
You may try the following way:
import time
start = time.time()
for val in range(10):
# some heavy stuff
time.sleep(.5)
if time.time() - start > 3: # 3 is timeout in seconds
print('loop stopped at', val)
break # stop the loop, or sys.exit() to stop the script
else:
print('successfully completed')
I guess it is kinda viable approach. Actual timeout is greater than 3 seconds and depends on the single step execution time.

Additional loop when stoping while loop

I've created a function using the carriage return from this and threading trick to exit loop from this. The function will keep counting until a keystroke is detected.
Everything works fine except an additional line is printed whenever I kill the loop.
For example in console:
Press anything to stop it: 6 #<------------- pressed enter
Press anything to stop it: 7 #<------------- additional line produced
import _thread
import time
import sys
def input_thread(list):
input()
list.append(None)
def do_stuff():
counter = 0
list = []
_thread.start_new_thread(input_thread,(list,))
while not list:
time.sleep(0.1)
sys.stdout.write("Press anything to stop it: %d \r" % (counter))
sys.stdout.flush()
counter += 1
How can I prevent extra line being printed? I suspect it has something to do with the while loop has to finish additional loop in order to exit. If the answer to this question is too obvious please let me know the keyword to search for.
Thanks a million!

Resources