Why does my code stuck after speak function? - python-3.x

I try to create a Voice Assistant on python3
This is my function Speak (with pyttsx):
def speak(what):
print("Gosha: " + what)
speak_engine.say( what )
speak_engine.runAndWait()
speak_engine.stop()
in the main body it works fine, but in function execute_cmd, after Speak function my code stucks.
One part of execute_cmd:
def execute_cmd(cmd, voice):
global finished
finished = False
#import debug
if cmd == 'ctime':
now = datetime.datetime.now()
hours = str(now.hour)
minutes = str(now.minute)
if (now.minute < 10): minutes = '0' + minutes
speak("Now " + hours + ":" + minutes)
finished = True
finished will never True
This happens anywhere in the function
pls help me
(sorry for my eng, I'm from Russia)
UPD: I debugged my code and noticed, my code get stuck on speak_engine.runAndWait()
I know, many people have same problem, but their solutions didn't help me

I'm not sure I understand you problem. What exactly do you mean by your code getting "Stuck"? Since you said that your finished variable will never be False, I assume that the code runs through and doesn't get stuck. My best guess is that your code simply doesn't produce sound.
If that's the case, I could imagine it's due to the previous loop still being active. So maybe try adding the following to your speak() function:
ef speak(what):
print("Gosha: " + what)
try:
speak_engine.endLoop()
except Exception as e:
pass
speak_engine.say( what )
speak_engine.runAndWait()
speak_engine.stop()

Related

Message repeating even after explicitly checking for history in discord

I'm trying to make a discord bot and I've added functionality of the tasks repeating after 24 hours using tasks.loop after at an interval of 24 hours( 64800 seconds). Since the code is run on repl.it, I've used uptime robot to continuously send a ping after 5 minutes to make it running always in the repl.it.
My issue is that even after checking historyin the channel the message is getting send again as you can see in the below image. ( by checking here I mean the explanation which is the explanation that comes with the API). I'm using NASA api here.
Code snippet
def get_APOD():
image = requests.get("https://api.nasa.gov/planetary/apod?api_key="+apod)
json_data = json.loads(image.text)
description = json_data["url"]
explanation = "'" + json_data["explanation"]+ "'"
title = json_data["title"]
return description,explanation,title
#client.event
async def on_ready():
print('We have logged in as {0.user}'.format(client))
send_message.start()
#tasks.loop(seconds=64800.0)
async def send_message():
channel = client.get_channel(int(apod_channel))
messages = await channel.history(limit=1).flatten()
description,explanation,title = get_APOD()
if messages[0].content == explanation:
print("Its the same")
else:
await channel.send(description)
await channel.send(title)
await channel.send(explanation)
. Here you can see the messages repeating twice. It shouldn't by the code I've written here. Since it check for the history in the channel.
What is the issue here? Appreciate any help.
EDIT: When I restart the repl.it IDE the code will run alright and print "It's the same" as it should if the message is already sent but otherwise it's failing.

How to break out of loop when URL read is taking too long

Hi I have the following code to skip the particular URL if it is taking too long to read.
timeout = 30
loop begins below for different urlz {
timeout_start = time.time()
webpage = urlopen(urlz[i]).read()
if time.time() > timeout_start + timeout:
continue}
My question is; wont the program execute the line of code "webpage = urlopen(urlz[i]).read()" before moving down to check the if condition? In that case I think it wont detect if the page is taking too long (more than 30 seconds to read). I basically want to skip this URL and move on to the next one if the program is stuck for 30 seconds (i.e. we have run into a problem when reading this particular URL).
The urlopen() function has a timeout method inbuilt:
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
So in your code:
timeout = 30
loop begins below for different urlz {
try:
webpage = urlopen(urlz[i], timeout=timeout).read()
}

How to add poll/wait into python script for refreshing a tableau workbook extract?

I have written a python script to call the Tableau Rest API's and I have it working properly. It prompts the user to enter their login credentials, select the server, select the site, select the workbook and then finds all the necessary keys and submits an extract refresh request based on the workbook id. The server.workbooks.refresh method kicks off an extract refresh job on Tableau Server and I get the jobID back from the method return.
What I want to do next is build a process in the script to poll the Tableau Server with that jobID looking for the completion time and status, then post a message that the refresh is complete and close the script.
I looked up some youtube videos of how to do polling/waiting in python but I'm not sure how those methods can apply using the tableau server. I was hoping that someone has a snippet of code to do this polling related to a tableau server process?
with server.auth.sign_in(tableau_auth):
get_sites(server)
print(selected_site_id)
#tab_site = selected_site_id
# Get all projects on site
get_projects(server)
if input_resource_type.lower() == 'workbook':
# Get a list of workbooks
get_workbooks(server)
results = server.workbooks.refresh(selected_workbook_id)
print("refresh results: " + str(results))
I want the python script to keep running until the task associated to the JobID on Tableau Server is complete and has a successful status code.
Currently the code just kicks the refresh extract task off in Server and returns the JobID.
Is there anything your program needs to do while polling? If not, then put your polling code in a loop and use sleep so that you don't hit the server too frequently. When you determine that the task has completed, exit the loop.
This is a generic way to do polling, could be used with Tableau or anything else. Not the most efficient, but it's simple and it works.
Just to follow-up on how to resolve this for anyone else trying to do this. As jdigital said, this works pretty well... I added some comments into the code so the user is notified as the process is running:
jobid = results.id
complete_time = None
counter = 0
started = False
sleep_timer = 5
while complete_time is None:
extract = server.jobs.get_by_id(jobid)
if str(extract.finish_code) == "0":
complete_time = str(extract.completed_at)
else:
if extract.started_at is None:
print("refresh has not started")
else:
if started == False:
print("refresh started at " + str(extract.started_at))
started = True
if counter == 0:
print("refresh is running....")
else:
print("refresh is still running.....")
counter += 1
if complete_time is None:
time.sleep(sleep_timer)
refresh_time = counter * sleep_timer
print("############################################")
print(" Refreshed the " + str(workbook.name) + " workbook \n")
print(" Extract refresh started at " + str(extract.started_at) + "\n")
print(" Extract refresh completed at " + str(complete_time) + "\n")
print(" Extract took approximately " + str(refresh_time) + " seconds to refresh")
print("############################################")
I use this function to keep maximum number of jobs running
def wait_jobs_in_progress_to_finish(tableau_auth, max_jobs_in_progress=3, wait_seconds=10):
req = TSC.RequestOptions()
req.filter.add(TSC.Filter("progress", TSC.RequestOptions.Operator.LessThanOrEqual, 0))
if len(list(TSC.Pager(server.jobs, request_opts=req))) >= max_jobs_in_progress:
sleep(wait_seconds)
wait_jobs_in_progress_to_finish(tableau_auth, max_jobs_in_progress=max_jobs_in_progress, wait_seconds=wait_seconds)
else: return None
Maybe you will find usefull the whole code snippet for running Jobs from Schedule:
with server.auth.sign_in(tableau_auth):
# Select Schedule
all_schedules, pagination_item = server.schedules.get()
for schedule in all_schedules:
if schedule.name == 'Daily Morning':
schedule_id = schedule.id
print(schedule_id)
# Run all Tasks from this Schedule
tasks, pagination = server.tasks.get()
tasks = [task for task in tasks if task.schedule_id == schedule_id]
# Sort by priority
tasks.sort(key = lambda t: t.priority)
for task in tasks:
print("{}".format(task))
server.tasks.run(task)
wait_jobs_in_progress_to_finish(max_jobs_in_progress=3, wait_seconds=10)

why would python3 recursive function return null

I have this function that when hitting a rate limit will call itself again. It should eventually succeed and return the working data. It works normally then rate limiting works as expected, and finally when the data goes back to normal I get:
TypeError: 'NoneType' object is not subscriptable
def grabPks(pageNum):
# cloudflare blocks bots...use scraper library to get around this or build your own logic to store and use a manually generated cloudflare session cookie... I don't care 😎
req = scraper.get("sumurl.com/"+str(pageNum)).content
if(req == b'Rate Limit Exceeded'):
print("adjust the rate limiting because they're blocking us :(")
manPenalty = napLength * 3
print("manually sleeping for {} seconds".format(manPenalty))
time.sleep(manPenalty)
print("okay let's try again... NOW SERVING {}".format(pageNum))
grabPks(pageNum)
else:
tree = html.fromstring(req)
pk = tree.xpath("/path/small/text()")
resCmpress = tree.xpath("path/a//text()")
resXtend = tree.xpath("[path/td[2]/small/a//text()")
balance = tree.xpath("path/font//text()")
return pk, resCmpress, resXtend, balance
I've tried to move the return to outside of the else scope but then it throws:
UnboundLocalError: local variable 'pk' referenced before assignment
Your top level grabPks doesnt return anything if it is rate limited.
Think about this:
Call grabPks()
You're rate limited so you go into the if statement and call grabPks() again.
This time it succeeds so grabPks() returns the value to the function above it.
The first function now falls out of the if statement, gets to the end of the function and returns nothing.
Try return grabPks(pageNum) instead inside your if block.
well okay... I needed to return grabPKs to make it play nice...:
def grabPks(pageNum):
# cloudflare blocks bots...use scraper library to get around this or build your own logic to store and use a manually generated cloudflare session cookie... I don't care 😎
req = scraper.get("sumurl.com/"+str(pageNum)).content
if(req == b'Rate Limit Exceeded'):
print("adjust the rate limiting because they're blocking us :(")
manPenalty = napLength * 3
print("manually sleeping for {} seconds".format(manPenalty))
time.sleep(manPenalty)
print("okay let's try again... NOW SERVING {}".format(pageNum))
return grabPks(pageNum)
else:
tree = html.fromstring(req)
pk = tree.xpath("/path/small/text()")
resCmpress = tree.xpath("path/a//text()")
resXtend = tree.xpath("[path/td[2]/small/a//text()")
balance = tree.xpath("path/font//text()")
return pk, resCmpress, resXtend, balance

Creating loops to update a label in app jar

I'm trying to make a countdown timer in appJar and have a label that shows how much time is remaining until the end of the allotted amount of time. I've looked at the guides on appJar's website a fair amount and know of the two ways that they say you can create loops with their library. You can use .registerevent(function) or .after(delay_ms, function, *args). I've tried both of these ways and can't get either to work. I haven't managed to figure out how to get the .after function to work and every time I try to use the .registerevent function something doesn't work. My current issue is that I can get the function to run but it isn't actually working. That is, it says the block of code is running but the GUI ins't updating
Here are the specific lines of code in question
def introduction_bill(x):
global time_remaining, time_allotted
time_remaining = 120
time_allotted = 120
app.removeAllWidgets()
print("ran 'introduction_bill'")
app.addLabel('timer', 'Time remaining: 2:00')
app.addButtons(['start timer','update'], [start_timer, update_timer])
app.addButton('next introduction', next_introduction)
....
def update_timer():
global time_remaining, current_function
current_function = 'update timer'
time_remaining = end_time - t.time()
minutes = int(time_remaining // 60)
seconds = round(time_remaining % 60, 2)
app.setLabel('timer', 'Timer remaining: ' + str(minutes) + ':' + str(seconds))
print("ran 'update_timer'")
if time_remaining > -10:
app.registerEvent(update_timer)
def start_timer(x):
print("ran 'start_timer'")
global start_time, end_time
start_time = t.time()
end_time = start_time + time_allotted
update_timer()
And here is the code in its entirety
Keep in mind that I am still a beginner in coding so this code is both incomplete and very rough.
You can achieve what you want with both of the methods you mention.
With registerEvent() you should only call it once, it then takes care of scheduling your function. In your code, you are calling it repeatedly, which won't work.
With after() you have to take care of calling it again and again.
So, with your current code, you're better off using after():
In update_timer() try changing the call to app.registerEvent(update_timer) to be app.after(100, update_timer)
The timer should then update every 0.1 seconds.
However, if you click the Start Timer button again, you'll run into problems, so you might want to disable the button until the timer finishes.

Resources