How can I run the timer function in python bottle? - python

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.

Related

How to change code to avoid unreacheable error in 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.

Pytest patch function used by global variable

I need to test a code that has a global variable which is populated by a function that returns a value after making a connection to external server. For the pytest, I need to figure out a way so that the function does not get called.
I've tried patching both the global variable and the function, but neither worked.
Here's the python code - my_module.py:
import datetime
# %%
def server_function_1 ():
try:
return_val = "Assume the external server function returns a string"
except Exception as e:
print("Failed")
print(e)
raise e
else:
return return_val
finally:
# assume when called from the testing environment, the server connection will raise a exception
raise Exception("Cannot connect to server")
global_result_of_server_func = server_function_1()
# %%
def get_current_datetime_str():
return datetime.datetime.now().strftime('%Y%m%d.%H%M%S.%f')
# %%
def some_function():
return global_result_of_server_func, get_current_datetime_str()
Here's the pytest file - test_my_module.py:
# %%
import pytest
from unittest import mock
import datetime
import logging
import sys
# %%
import my_module
logger = logging.getLogger(__name__)
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
frozen_time = datetime.datetime(year=2022, month=6, day=1, hour=1, minute=0, second=0, microsecond=0)
mock_server_str = "Mock Server String"
# %%
class TestMyModule () :
def test_handler_1 (self):
with mock.patch("my_module.get_current_datetime_str", return_value=frozen_time.strftime('%Y%m%d.%H%M%S.%f')), \
mock.patch("my_module.global_result_of_server_func", new=mock_server_str):
test_server_val, test_frozen_time = my_module.some_function()
assert test_frozen_time == frozen_time.strftime('%Y%m%d.%H%M%S.%f')
assert test_server_val == mock_server_str
def test_handler_2 (self):
with mock.patch("my_module.get_current_datetime_str", return_value=frozen_time.strftime('%Y%m%d.%H%M%S.%f')), \
mock.patch("my_module.server_function_1", return_value=mock_server_str):
test_server_val, test_frozen_time = my_module.some_function()
assert test_frozen_time == frozen_time.strftime('%Y%m%d.%H%M%S.%f')
assert test_server_val == mock_server_str
What I am trying to achieve is that variable global_result_of_server_func gets the mock value, and the function server_function_1 doesn't get called and tries to make a connection to the server.
Thanks.
Delaying the import like the suggestion in this question didn't seem to make any difference.

Python Flask infinite loop use global list which can be extended

I would like to run an infinite loop in flask, which do something with a global list.
I'd like to append the list through an API call, and process data from the updated list.
What is the problem?
Usage: you run flask application, and call localhost:5000/ to append the list.
It will return the new list, but in the loop, it remains the initial list.
Thanks
import time
from flask import Flask
from multiprocessing import Process, Value
app = Flask(__name__)
stuff = [1, 2]
#app.route('/', methods=['GET'])
def index():
global stuff
stuff.append(max(stuff) + 1)
print('in request, stuff: ', stuff)
return ', '.join(map(str, stuff))
def print_stuff():
global stuff
print('in loop, stuff: ', stuff)
def record_loop(loop_on):
while True:
if loop_on.value == True:
print_stuff()
time.sleep(1)
if __name__ == "__main__":
recording_on = Value('b', True)
p = Process(target=record_loop, args=(recording_on,))
p.start()
app.run(debug=True, use_reloader=False)
p.join()
I found the working solution:
import time
from flask import Flask
from flask_apscheduler import APScheduler
app = Flask(__name__)
scheduler = APScheduler()
i = 0
def scheduleTask():
global i
print("This test runs every 1 seconds", i)
time.sleep(2)
#app.route('/')
def hello():
global i
i += 1
return str(i)
if __name__ == '__main__':
scheduler.add_job(id = 'Scheduled Task', func=scheduleTask, trigger="interval", seconds=1)
scheduler.start()
app.run(host="0.0.0.0")

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()

Twisted Python getPage

I tried to get support on this but I am TOTALLY confused.
Here's my code:
from twisted.internet import reactor
from twisted.web.client import getPage
from twisted.web.error import Error
from twisted.internet.defer import DeferredList
from sys import argv
class GrabPage:
def __init__(self, page):
self.page = page
def start(self, *args):
if args == ():
# We apparently don't need authentication for this
d1 = getPage(self.page)
else:
if len(args) == 2:
# We have our login information
d1 = getPage(self.page, headers={"Authorization": " ".join(args)})
else:
raise Exception('Missing parameters')
d1.addCallback(self.pageCallback)
dl = DeferredList([d1])
d1.addErrback(self.errorHandler)
dl.addCallback(self.listCallback)
def errorHandler(self,result):
# Bad thingy!
pass
def pageCallback(self, result):
return result
def listCallback(self, result):
print result
a = GrabPage('http://www.google.com')
data = a.start() # Not the HTML
I wish to get the HTML out which is given to pageCallback when start() is called. This has been a pita for me. Ty! And sorry for my sucky coding.
You're missing the basics of how Twisted operates. It all revolves around the reactor, which you're never even running. Think of the reactor like this:
(source: krondo.com)
Until you start the reactor, by setting up deferreds all you're doing is chaining them with no events from which to fire.
I recommend you give the Twisted Intro by Dave Peticolas a read. It's quick and it really gives you all the missing information that the Twisted documentation doesn't.
Anyways, here is the most basic usage example of getPage as possible:
from twisted.web.client import getPage
from twisted.internet import reactor
url = 'http://aol.com'
def print_and_stop(output):
print output
if reactor.running:
reactor.stop()
if __name__ == '__main__':
print 'fetching', url
d = getPage(url)
d.addCallback(print_and_stop)
reactor.run()
Since getPage returns a deferred, I'm adding the callback print_and_stop to the deferred chain. After that, I start the reactor. The reactor fires getPage, which then fires print_and_stop which prints the data from aol.com and then stops the reactor.
Edit to show a working example of OP's code:
class GrabPage:
def __init__(self, page):
self.page = page
########### I added this:
self.data = None
def start(self, *args):
if args == ():
# We apparently don't need authentication for this
d1 = getPage(self.page)
else:
if len(args) == 2:
# We have our login information
d1 = getPage(self.page, headers={"Authorization": " ".join(args)})
else:
raise Exception('Missing parameters')
d1.addCallback(self.pageCallback)
dl = DeferredList([d1])
d1.addErrback(self.errorHandler)
dl.addCallback(self.listCallback)
def errorHandler(self,result):
# Bad thingy!
pass
def pageCallback(self, result):
########### I added this, to hold the data:
self.data = result
return result
def listCallback(self, result):
print result
# Added for effect:
if reactor.running:
reactor.stop()
a = GrabPage('http://google.com')
########### Just call it without assigning to data
#data = a.start() # Not the HTML
a.start()
########### I added this:
if not reactor.running:
reactor.run()
########### Reference the data attribute from the class
data = a.data
print '------REACTOR STOPPED------'
print
########### First 100 characters of a.data:
print '------a.data[:100]------'
print data[:100]

Categories

Resources