How to change code to avoid unreacheable error in python - python

Wrote this telegram bot. Pycharm gives me error 'The last two lines are unreacheable'. What is the solution? Without 'while true' part code isn't working
import telebot
import gspread
import datetime
import schedule
import time
bot_token = '____'
googlesheet_id = '___'
bot = telebot.TeleBot(bot_token)
gc = gspread.service_account(filename='.json')
sh = gc.open('___')
wks = sh.worksheet('sheet1')
CHAT_ID = "___"
def check_date():
current_date = datetime.datetime.now()
current_date_string = current_date.strftime('%d.%m.%Y')
sh = gc.open('___')
search_data = wks.find(current_date_string)
list = wks.row_values(search_data.row)
bot.send_message(CHAT_ID, '%s expires today' % (list[0]))
schedule.every().day.at("12:00:00").do(check_date)
while True:
schedule.run_pending()
time.sleep(1)
if __name__ == '__main__':
bot.polling(none_stop=True)

You (roughly) wrote
def check_date():
...
while True:
do_thing_one()
if __name__ == '__main__':
do_thing_two()
The last two lines, testing __name__ and doing thing two, are useless, they will never execute.
Why are they unreachable?
Because of the thing one while loop,
which never lets us get down to attempt thing two.
Notice that the while loop is not part of
the check_date function.
If you were to indent that section four spaces,
then the check_date function would never exit
but we would be able to do thing two.
It does not appear that thing two,
the .polling() call, relates to check_date.
Perhaps there is some unseen linkage behind
the scenes.

Related

Set timer for a Django view execution

I'm struggling trying to prevent a Django view from being executed more than once within an hour period. In other words, if the function runs at 15:00, all future requests for all users should be ignored until 17:00 when it's allowed to run once more again.
Tried with a timer, but it does get reset every time the view is called. Maybe someone can point me in the right direction? Thanks!!!
import threading as th
def hello():
print("hello, world")
def webhook(request):
tm = th.Timer(3600, hello)
if request.method == 'POST' and not tm.is_alive():
tm.start()
code_to.ecexute()
return HttpResponse("Webhook received!")
Ultimately, this is what I did and it seems to work fine. I actually need it to run no more than once a day, hence the conditional below.
Thanks for all the suggestions!!!
def webhook2 (request):
today = datetime.now().date()
with open('timestamp.txt') as f:
tstamp = f.read()
last_run = datetime.strptime(tstamp, '%Y-%m-%d')
last_run_date = datetime.date(last_run)
print ("last run: " + str(last_run_date))
if last_run_date < today:
file = open("timestamp.txt" ,"w")
file.write(str(today))
file.close()
if request.method == 'POST':
msg = str(request.body)
final_msg=msg[2:-1]
print("Data received from Webhook is: ", request.body)
# creates a google calendar event
function_logic()
return HttpResponse("Webhook received! Event added to calendar")
else:
print ("we already have a record for today")
return HttpResponse("Not adding a record. We already have one for today.")
Your timer is being reset everytime because it is inside a function that is execute everytime when request is being made.
You should try to set the timer globally, such as outside your function. ( be aware when your script will re-run, timer will be reset again ).
import threading as th
def hello():
print("hello, world")
tm = None
def webhook(request):
# check here if timer is dead then process the request.
if timer_is_dead || tm is None:
# accessing global value and setting it for first time
if tm is None:
global tm
tm = th.Timer(3600, hello)
tm.start()
if request.method == 'POST' and not tm.is_alive():
code_to.ecexute()
# start timer again for next hour
return HttpResponse("Webhook received!")
else:
return HttResponse("Not Allowed")
Edit: Handling first request and then starting timer

Trying to run multiple functions at once?

I am really new to web scraping.
I am trying to code software that monitors multiple share prices at once and must Identify when there is a change in the price and must show me the new price.
I have got it working that whenever there is a change in price it shows me the new price but it only works with one share and since it is in a while loop it won't break and move on to the next share.
I don't want to jump out of the while loop since it will stop monitoring the price. Then the browser will close and selenium must reopen it when wanting to see the new price which will take longer.
I am trying to create a function for each share I want to monitor.
I can't seem to get it to work that it will monitor more than one share at once. I have tried threading but then only one share price shows up.
Excuse all the imported libraries I just experimented
Any help will be appreciated.
import requests
import time
import tkinter
from selenium import webdriver
import time
from selenium.webdriver.firefox.options import Options
global driver
import threading
from multiprocessing import *
import os
options = Options()
options.headless = True
driver = webdriver.Firefox(options = options, executable_path=...driver path...)
counter_for_mtn = 0 # I only use counter for printing the first price
def MTN():#mtn is the name of the share
global counter_for_mtn
url = 'https://www.google.com/search?q=mtn+shares&safe=strict&sxsrf=ALeKk02Dyba3hHbg1S4YeLOFhw4FPfhqdQ:1588770127528&source=lnms&tbm=fin&sa=X&ved=2ahUKEwjl2dL4pZ_pAhUMZMAKHU1WDGAQ_AUoAXoECBkQAw&biw=1920&bih=969#scso=_XLWyXpmmE8uEhbIPpf-ooAY1:0'
driver.get(url)
while True:
value_mtn = driver.find_element_by_xpath('/html/body/div[6]/div[2]/div[9]/div[1]/div[2]/div/div[2]/div[2]/div/div/div/div/div/sticky-header/div[2]/div/div[1]/div/div[1]/div/div/div/div/div/div/g-card-section/div/g-card-section/span[1]/span/span[1]').text
if counter_for_mtn == 0:
print('MTN: '+ str(value_mtn))
counter_for_mtn =1
try:
if mtn_old_price != value_mtn:
print('MTN: '+str(value_mtn))
except:
pass
mtn_old_price = value_mtn
counter_for_sasol = 0#only use counter to print out the first price
def Sasol():#sasol is the name of the share
global counter_for_sasol
url = 'https://www.google.com/search?q=sasol+shares&safe=strict&sxsrf=ALeKk004QjkQ84tFd8TP8ikaQc3yhNRkrQ:1588772136446&source=lnms&tbm=fin&sa=X&ved=2ahUKEwjpkMm2rZ_pAhV4Q0EAHZ7jCWEQ_AUoAXoECBkQAw&biw=1920&bih=969'
driver.get(url)
while True:
value = driver.find_element_by_xpath('/html/body/div[6]/div[2]/div[9]/div[1]/div[2]/div/div[2]/div[2]/div/div/div/div/div/sticky-header/div[2]/div/div[1]/div/div[1]/div/div/div/div/div/div/g-card-section/div/g-card-section/span[1]/span/span[1]').text
if counter_for_sasol == 0:
print('SASOL: ' + str(value))
counter_for_sasol = 1
try:
if old_price != value:
print('SASOL: ' + str(value))
except:
pass
old_price = value
thread1 = threading.Thread(target = MTN())
thread1.start()
thread2 = threading.Thread(target = Sasol())
thread2.start()
how do I get both Functions Sasol() and MTN() to run at the same exact time?
This works (using toy functions) although technically I'm not sure you can say that they are running at the exact same time:
import sys,time,threading,random
def f():
for i in range(10):
print(f'{i}:f',file=sys.stdout)
time.sleep(random.random())
def g():
for i in range(10):
print(f'{i}:g',file=sys.stdout)
time.sleep(random.random())
if __name__ == '__main__':
threads = [threading.Thread(target=func) for func in [f,g]]
for t in threads:
t.start()
This also works - using single function passing a different argument to each thread - in your case the argument(s) would be unique string(s) specific to the things you want to retrieve.
import sys,time,threading,random
def f(s):
for i in range(10):
print(f'{i}:{s}',file=sys.stdout)
time.sleep(random.random())
if __name__ == '__main__':
threads = [threading.Thread(target=f,args=(arg,)) for arg in ['one','two']]
for t in threads:
t.start()

How can I run the timer function in python bottle?

I'd like to print 't' and 's' on localhost. But it doesn't work with timer function. Here is what I tried.
import requests
import pandas as pd
import time
from bottle import route, run
def timer(n):
while True:
url2 = 'https://api.bittrex.com/api/v1.1/public/getticker?market=USDT-BTC'
res = requests.get(url2).json()
BTC = pd.json_normalize(res['result'])
t = time.ctime()
s = BTC.to_html(index=False)
time.sleep(n)
timer(5)
#route('/')
def index():
return t, s
run(host='localhost', port=8080)
Without more details around what exactly isn't working, it's tough to give a comprehensive answer. But one thing that surely needs to change is where you define t and s. As #Pygirl states in her comment, you'll need to define those globally:
import requests
import pandas as pd
import time
from bottle import route, run
t = ''
s = ''
def timer(n):
while True:
url2 = 'https://api.bittrex.com/api/v1.1/public/getticker?market=USDT-BTC'
res = requests.get(url2).json()
BTC = pd.json_normalize(res['result'])
# Must declare t and s as globals since you're changing their referents.
global t
global s
t = time.ctime()
s = BTC.to_html(index=False)
time.sleep(n)
timer(5)
#route('/')
def index():
return '{}: {}'.format(t, s)
run(host='localhost', port=8080)
An alternative to defining them globally is to create a top-level dict with two items in it (t and s), and simply modify those items as needed; no need for global in that case.

Problem getting function to run for a specific amount of time

I'm trying to run a function in python for a specific amount of time (say 100 sec), and then move on to run another function for a specific amount of time.
I've tried creating a counter and using while counter < (some frame number). I've also tried using datetime by doing something like
end_time = datetime.now() + timedelta(seconds=100)
while datetime.now() < end_time:
These things don't seem to be working and I don't know why.
Here is my current version of the code:
class FicTracAout90deg(object):
def run(self, gain_yaw = 1):
end_time = datetime.now() + timedelta(seconds=10)
while datetime.now() < end_time:
for item in self.pubsub.listen():
message = item['data']
try:
data = json.loads(message)
except TypeError:
continue
if data['type'] == 'reset':
self.time_start = time.time()
self.heading_rate_calc.reset(self.time_start)
else:
time_curr = time.time()
heading = data['heading']
intx = data['intx']
inty = data['inty']
velx = data['velx']
vely = data['vely']
velheading = data['deltaheading']
self.accum_heading += velheading
self.accum_x += velx
self.accum_y += vely
time_elapsed = time_curr - self.time_start
I'm running this with the following code:
from analogoutNoise import FicTracAoutNoise
from analogout90deg import FicTracAout90deg
import time
#for a certain amount of time run block 1
#Block 1
for x in range(2):
client = FicTracAout90deg()
client.run(1)
The 'run' function never seems to stop, and I don't understand why.
Likely the issue is that the line for item in self.pubsub.listen(): never returns a value and so it doesn't finish executing. If this statement doesn't finish execution then the rest of the code is not run and the outer loop is not checked.
Please post a SSCCE. In order to get your script to run, I had to add from datetime import datetime, timedelta. The following code does work, and is similar structurally to yours:
from datetime import datetime, timedelta
from time import sleep
tBegin = datetime.now()
tEnd = tBegin + timedelta(seconds=100)
while datetime.now() < tEnd:
print(datetime.now())
sleep(10)
print(datetime.now())
Since this works, it seems to me that the problem is not with the time endpoints, but rather with the internals of your while loop. It can perform a very large number of iterations in 100 sec., which means it's pinning the processor for all that time and accumulating a lot of garbage. It's probably better to think up a different approach, as #iamchoosinganame suggested.

How to make a loop that calculates running time?

I'm making a simple client/server program in Python 3 and in the client I would like a clock or printout of the running time. I'm trying to make it in a loop that starts at the beginning of the program, but in a thread so the rest of the code keeps going.
class time_thread():
def run(self):
loop = 0
while (zetime > -1):
print(zetime);
zetime = zetime + 1;
time_thread.start()
zetime = 0
This is what I have so far, but it doesn't work. It says:
time_thread has no attribute start()
I'm new to this and haven't used threads before, so I'm not sure how to go about this. Is there a better way?
I think this is what you're looking for:
import time, sys
zetime = 0
while (zetime > -1):
sys.stdout.write("\r" + str(zetime))
sys.stdout.flush()
time.sleep(1)
zetime = zetime + 1;
First of all , to use Thread module, you have to inherit the class Thread on your class, so you can use their methods like start.
To calculate time, you can use datetime.
from datetime import datetime
from time import sleep
start_time = datetime.now()
sleep(5) # code that you want to calculate.
end_time = datetime.now()
print(end_time - start_time)
Just place this
So let's say you define a function elapsed_time such as:
import time, sys
def elapsed_time(time_start):
''' time_start: a time.time()
Goal: print the elapsed time since time_start '''
# Allow to stop the counting once bool_time = False in the main program
global bool_elapsed_time
# loop while the condition
while bool_elapsed_time == True:
# Note: erase and write below does not work in spyder but in a shell yes
print ("Elapsed time: {} seconds".format(int(time.time() - time_start))),
sys.stdout.flush()
print ("\r"),
time.sleep(1)
# erase the line with elapsed time to clean the shell at the end
sys.stdout.flush()
print ("\r"),
Then in your program:
import threading
bool_elapsed_time = True
t = threading.Thread(name='child procs', target=elapsed_time, args=(time.time(),))
t.start()
## Here add the job you want to do as an example:
time.sleep(10)
bool_elapsed_time = False #to stop the elapsed time printing
Should do the job you want to do.
Note: I used python 2.7 so it might be slightly different with 3.x

Categories

Resources