Python Twitter Bot Main Files not running all functions - python

I created an automatic Twitter bot with a group of friends during my university's Hackathon. As a new Python developer, I came across an issue where certain functions of my driver code were not being reached and never running. That's when I remembered that Python has an interpreter compiler.
We created a folder containing all of our bot's functions and then called all said functions in our main file. Our main file's code looks something like this:
from bot_functions.get_quote import quote_on_enable
from bot_functions.reply import reply_on_enable
from bot_functions.retweet import retweet_on_enable
while True:
quote_on_enable() # Always runs
reply_on_enable() # Sometimes runs
retweet_on_enable() # Code cannot be reached.
Examples of some of our function's code (functions are all in seperate files, but share the same folder:
def quote_on_enable(): # Purpose to run code infinitely.
while True:
try:
quote = get_quote() # Uses helper function above.
tweet = "..." + "\n\n" + "Komi-Translation: " + "\n" + quote
print('\n Tweeting: ' + '\n' + tweet)
api.update_status(tweet) # Actually tweeting
print("Next quote in 10 seconds.")
time.sleep(10) # Halts the loop for 'x' amount of time
except Exception as error:
print(error)
break
def reply_on_enable():
bot_id = int(api.verify_credentials().id_str)
mention_id = 1
message = "#{} ..."
while True:
mentions = api.mentions_timeline(since_id=mention_id) # Finding mention tweets
for mention in mentions:
print("Mention tweet found")
print(f"{mention.author.screen_name} - {mention.text}")
mention_id = mention.id
# Checking if the mention tweet is not a reply, we are not the author, and
# that the mention tweet contains one of the words in our 'words' list
# so that we can determine if the tweet might be a question.
if mention.in_reply_to_status_id is None and mention.author.id != bot_id:
try:
print("Attempting to reply...")
api.update_status(message.format(mention.author.screen_name), in_reply_to_status_id
id_str, auto_populate_reply_metadata = True)
print("Successfully replied :)")
except Exception as exc:
print(exc)
time.sleep(15) # The bot will only check for mentions every 15 seconds, unless you tweak this value
I believe that since all of our functions are calling while True, we will never be able to leave the function calls. How should I go about solving this issue? Is it possible for me to maintain the format I have going right now, or will I have to end up throwing all the functions into the main file? Thank you!I

The problem is not related to the file where your functions are.
You are first calling the quote_on_enable function and, because of the while True: loop inside, you stay inside until an exception is caught (because, in that case, you are calling a break).
So you call your second function, reply_on_enable, only when it happens. And once you are there, you are stuck inside because there is no way out its infinite while True: loop.
And this is why your third function is never reached.

By removing all my functions While True: loops as well as adding exceptions to all the proper locations, I have fixed this issue.

Related

print information in a corner when using python/ipython REPL -- and quitting it while thread is running

I am using a python library I wrote to interact with a custom USB device. The library needs to send and receive data. I also need to interactively call methods. At the moment I utilize two shells, one receiving only and the other sending only. The latter is in the (i)python REPL. It works but it is clumsy, so I want to consolidate the two things in a single shell, which will have the advantage to have access to data structures from both sides in one context. That works fine. The problem is in the UI.
In fact, the receiving part needs to asynchronously print some information. So I wrote something like the following:
#!/usr/bin/python
import threading
import time
import blessings
TOTAL=5
def print_time( thread_id, delay):
count = 0
t=blessings.Terminal()
while count < TOTAL:
time.sleep(delay)
count += 1
stuff = "Thread " + str(thread_id) + " " + str(time.ctime(time.time())) + " -- " + str(TOTAL - count) + " to go"
with t.location(t.width - len(stuff) - 1, thread_id):
print (stuff, end=None )
print("", end="") # just return the cursor
try:
t1 = threading.Thread( target = print_time, args = (1, 2, ) )
t1.start()
print ("Thread started")
except:
print ("Error: unable to start thread")
That is my __init__.py file for the module. It somewhat works, but it has two problems:
While the thread is running, you cannot exit the REPL neither with CTRL-D nor with sys.exit() (that is the reason I am using TOTAL=5 above, so your life is easier if you try this code). This is a problem since my actual thread needs to be an infinite loop. I guess one solution could be to exit via a custom call which will cause a break into that infinite loop, but is there anything better?
The cursor does not return correctly to its earlier position
if I remove the end="" in the line with the comment # just return the cursor, it sort of works, but obviously print an unwanted newline in the place the cursor was (which messes us other input and/or output which might be happening there, in addition to add that unwanted newline)
if I leave the end="" it does not return the cursor, not even if I add something to print, e.g. print(".", end="") -- the dots . are printed at the right place, but the blinking cursor and the input is printed at the top
I know these are two unrelated problem and I could have asked two separate questions, but I need an answer to both, or otherwise it's a moot point. Or alternatively, I am open to other solutions. I thought of a separate GTK window, and that might work, but it's a subpar solution, since I really would like this to work in CLI only (to keep it possible in a ssh-without-X-tunneling setup).
Using blessed instead of blessing does not have the problem with the cursor not returning to the previous position, even without anything outside of the with context.
Making the thread a daemon solves the other problem.

How can I end a 'try' loop in 'while' loop?

I'm in trouble about how to end a 'try' loop, which is occurred since I have the 'try', here is the code:
import time
class exe_loc:
mem = ''
lib = ''
main = ''
def wizard():
while True:
try:
temp_me = input('Please specify the full directory of the memory, usually it will be a folder called "mem"> ' )
if temp_me is True:
exe_loc.mem = temp_me
time.sleep(1)
else:
print('Error value! Please run this configurator again!')
sys.exit()
temp_lib = input('Please specify the full directory of the library, usually it will be a folder called "lib"> ')
if temp_lib is True:
exe_loc.lib = temp_lib
time.sleep(1)
else:
print('Invalid value! Please run this configurator again!')
sys.exit()
temp_main = input('Please specify the full main executable directory, usually it will be app main directory> ')
if temp_main is True:
exe_loc.main = temp_main
time.sleep(1)
I tried end it by using break, pass, and I even leaves it empty what I get is Unexpected EOF while parsing, I searched online and they said it is caused when the code blocks were not completed. Please show me if any of my code is wrong, thanks.
Btw, I'm using python 3 and I don't know how to be more specific for this question, kindly ask me if you did not understand. Sorry for my poor english.
EDIT: Solved by removing the try because I'm not using it, but I still wanna know how to end a try loop properly, thanks.
Your problem isn't the break, it's the overall, high-level shape of your try clause.
A try requires either an except or a finally block. You have neither, which means your try clause is never actually complete. So python keeps looking for the next bit until it reaches EOF (End Of File), at which point it complains.
The python docs explain in more detail, but basically you need either:
try:
do_stuff_here()
finally:
do_cleanup_here() # always runs, even if the above raises an exception
or
try:
do_stuff_here()
except SomeException:
handle_exception_here() # if do_stuff_here raised a SomeException
(You can also have both the except and finally.) If you don't need either the cleanup or the exception handling, that's even easier: just get rid of the try altogether, and have the block go directly under that while True.
Finally, as a terminology thing: try is not a loop. A loop is a bit of code that gets executed multiple times -- it loops. The try gets executed once. It's a "clause," not a "loop."
You have to also 'catch' the exception with the except statement, otherwise the try has no use.
So if you do something like:
try:
# some code here
except Exception:
# What to do if specified error is encountered
This way if anywhere in your try block an exception is raised it will not break your code, but it will be catched by your except.

Tweet Feels: Always returns the same Sentiment Score, regardless tags

I am trying to use this library to generate sentiment score for cryptocurrencies:
https://github.com/uclatommy/tweetfeels/blob/master/README.md
When I use the code from the example trump, it returns a sentiment score of -0.00082536637608123106.
I have changed the tags to the following:
btc_feels = TweetFeels(login, tracking=['bitcoin'])
btc_feels.start(20)
btc_feels.sentiment.value
and it still gives me the same value.
I did notice something strange when I installed the library.
from the instructions:
If for some reason pip did not install the vader lexicon:
python3 -m nltk.downloader vader_lexicon
When I ran this, I got:
/anaconda/lib/python3.6/runpy.py:125: RuntimeWarning:
'nltk.downloader' found in sys.modules after import of package 'nltk',
but prior to execution of 'nltk.downloader'; this may result in
unpredictable behaviour warn(RuntimeWarning(msg))
Could this be why it appears not to be working?
By default, tweetfeels creates a database in your current directory. The next time you start the program, it will continue using the same database, and pick up where it left off. I don't know what tweetfeels does to handle you changing the keyword on it, but this behaviour of tweetfeels could be a problem. The solution would be to use a different database for different keywords, and then pass in the location of your database to the TweetFeels constructor.
I don't know that much about Tweetfeels, it just sounded interesting, so I've downloaded the project, and I have a working script that will perform the sentiment analysis on any keyword I give it. I can add a copy of the script here, if you're still having problems getting TweetFeels to work.
Edit: here the script I am using
I am currently having the following problems with the script.
1) I was getting some error that was different from the one you'd got, but I was able to fix the issue by replacing the tweetfeels library from pip with the latest code in their Github repository.
2) If a sentiment value does not get reported, sometimes tweetfeels fails to come to a complete stop, without forcefully sending a ctrl+c keyboard interrupt.
import os, sys, time
from threading import Thread
from pathlib import Path
from tweetfeels import TweetFeels
consumer_key = 'em...'
consumer_secret = 'aF...'
access_token = '25...'
access_token_secret = 'd3...'
login = [consumer_key, consumer_secret, access_token, access_token_secret]
try:
kw = sys.argv[1]
except IndexError:
kw = "iota"
try:
secs = int(sys.argv[2])
except IndexError:
secs = 15
for arg in sys.argv:
if (arg == "-h" or arg == "--help"):
print("Gets sentiment from twitter.\n"
"Pass in a search term, and how frequently you would like the sentiment recalculated (defaults to 15 seconds).\n"
"The keyword can be a comma seperated list of keywords to look at.")
sys.exit(0)
db = Path(f"~/tweetfeels/{kw}.sqlite").expanduser()
if db.exists():
print("existing db detected. Continueing from where the last sentiment stream left off")
else:
#ensure the parent folder exists, the db will be created inside of this folder
Path(f"~/tweetfeels").expanduser().mkdir(exist_ok=True)
feels = TweetFeels(login, tracking=kw.split(","), db=str(db))
go_on = True
def print_feels(feels, seconds):
while go_on:
if feels.sentiment:
print(f"{feels.sentiment.volume} tweets analyzed from {feels.sentiment.start} to {feels.sentiment.end}")
print(f'[{time.ctime()}] Sentiment Score: {feels.sentiment.value}')
print(flush=True)
else:
print(f"The datastream has not reported a sentiment value.")
print(f"It takes a little bit for the first tweets to be analyzed (max of {feels._stream.retry_time_cap + seconds} seconds).")
print("If this problem persists, there may not be anyone tweeting about the keyword(s) you used")
print(flush=True)
time.sleep(seconds)
t = Thread(target=print_feels, kwargs={"feels":feels,"seconds":secs}, daemon=True)
print(f'Twitter posts containing the keyword(s) "{kw}" will be streamed, and a new sentiment value will be recalculated every {secs} seconds')
feels.start()
time.sleep(5)
t.start()
try:
input("Push enter at any time to stop the feed...\n\n")
except (Exception, KeyboardInterrupt) as e:
feels.stop()
raise e
feels.stop()
go_on = False
print(f"Stopping feed. It may take up to {feels._stream.retry_time_cap} for the feed to shut down.\n")
#we're waiting on the feels thread to stop
No, the same sentiment value that you see printed is not related to the warning you've got when downloading the dataset.
The problem with the same sentiment score is coming from these lines:
for s in sentiments:
pass
return s
I suspect that this unbound variable s remembers the previous value of the sentiment score.
But, the problem itself is that you are printing out the score right after you execute the start() function which starts a multi-threaded program to constantly update data from twitter - you should not expect the sentiment score to arrive right after you started the update.
Note that the examples in the README are shown from the Python terminal where they wait after the execution of start() function until the Timer completed. Disconnecting now... message appears.

How to make a script wait within an iteration until the Internet connection is reestablished?

I have a scraping code within a for loop, but it would take several hours to complete, and the program stops when my Internet connection breaks. What I (think I) need is a condition at the beginning of the scraper that tells Python to keep trying at that point.
I tried to use the answer from here:
for w in wordlist:
#some text processing, works fine, returns 'textresult'
if textresult == '___': #if there's nothing in the offline resources
bufferlist = list()
str1=str()
mlist=list() # I use these in scraping
br = mechanize.Browser()
tried=0
while True:
try:
br.open("http://the_site_to_scrape/")
# scraping, with several ifs. Each 'for w' iteration results with scrape_result string.
except (mechanize.HTTPError, mechanize.URLError) as e:
tried += 1
if isinstance(e,mechanize.HTTPError):
print e.code
else:
print e.reason.args
if tried > 4:
exit()
time.sleep(120)
continue
break
Works while I'm online. When the connection breaks, Python writes the 403 code and skips that word from wordlist, moves on to the next and does the same. How can I tell Python to wait for connection within the iteration?
EDIT: I would appreciate it if you could write at least some of the necessary commands and tell me where they should be placed in my code, because I've never dealt with exception loops.
EDIT - SOLUTION I applied Abhishek Jebaraj's modified solution. I just added a very simple exception handling command:
except:
print "connection interrupted"
time.sleep(30)
Also, Jebaraj's getcode command will raise an error. Before r.getcode, I used this:
import urllib
r = urllib.urlopen("http: the site ")
The top answer to this question helped me as well.
Write another while loop inside which will keep trying to connect to the internet.
It will break only when it receives status code of 200 and then you can continue with your program.
Kind of like
retry = True
while retry:
try:
r = br.open(//your site)
if r.getcode()/10==20:
retry = False
except:
// code to handle any exception
// rest of your code

syntaxError: 'continue' not properly in loop

I have been struggling with this error for a while now and there seems to be different opinions regarding why the interpreter complains about the 'continue'. So I would like to provide the erroneous code below.
import tweepy
import time
def writeHandlesToFile():
file = open("dataFile.txt","w")
try:
list = tweepy.Cursor(tweepy.api.followers,screen_name='someHandle',).items(100000)
print "cursor executed"
for item in list:
file.write(item.screen_name+"\n")
except tweepy.error.TweepError as e:
print "In the except method"
print e
time.sleep(3600)
continue
The reason I am particular on including the continue at the end is because I would like for the program to restart execution at the top from where it left off after the sleep in order to preserve the program state. I need the sleep in order to abide by the twitter api rate limits wherein the api only allows you to make a certain number of requests every hour.
So anyone who might see my mistake naive or otherwise please do point it out or please provide me with an alternative implementation without the use of the continue statement.
BTW I do not have tabs and spaces mixed as was suggested in another post.
Thank you for your help in advance.
continue is only allowed within a for or while loop. You can easily restructure your function to loop until a valid request.
def writeHandlesToFile():
while True:
with open("dataFile.txt","w") as f:
try:
lst = tweepy.Cursor(tweepy.api.followers,screen_name='someHandle',).items(100000)
print "cursor executed"
for item in lst:
f.write(item.screen_name+"\n")
break
except tweepy.error.TweepError as e:
print "In the except method"
print e
time.sleep(3600)
The problem might be in the way you are using continue
continue may only occur syntactically nested in a for or while loop,
but not nested in a function or class definition or finally statement
within that loop.6.1It continues with the next cycle of the nearest
enclosing loop.

Categories

Resources