r/Python • • Jul 10 '20

I Made This This post has:

9777 upvotes,

967 downvotes

and 452 comments!

9.2k Upvotes

429 comments sorted by

View all comments

Show parent comments

321

u/Krukerfluk Jul 10 '20
import praw

reddit = praw.Reddit(
    client_id='***',
    client_secret='***',
    username='***',
    password='***',
    user_agent='***')

while True:
    submission = reddit.submission(id='***')
    ratio = submission.upvote_ratio
    ups = round((ratio * submission.score) / (2 * ratio - 1)) if ratio != 0.5 else round(submission.score / 2)
    downs = ups - submission.score
    edited_body = str(ups) + ' upvotes,' + '\n\n' + str(downs) + ' downvotes' + "\n\n" "and " + \
                  str(submission.num_comments) + ' comments!'
    submission.edit(edited_body)

I'm new to python so there is probably a better way to do this

158

u/Holek Jul 10 '20

add a sleep there for a minute or two just not to kill your API access

115

u/Krukerfluk Jul 10 '20

Just added an 90sec delay

thanks for the tip!

88

u/SpontaneousAge Jul 10 '20

90s isn't even necessary. 5s or something is fine as well, just continuously is bad. Reddit is pretty lean, but if you're too hardcore they will block you too.

66

u/throwaway_the_fourth Jul 10 '20

And OP doesn't have to do anything because PRAW automatically takes care of following the rate limit.

14

u/Ph0X Jul 10 '20

Hmm, but if the rate limit is, let's say, 100 calls in 15m, then praw will probably let you do 100 calls in 30s, and then lock you out for the remaining 14m, right?

Still good to have reasonable sleep regardless. There's no point in updated every second.

33

u/throwaway_the_fourth Jul 10 '20

It's actually pretty smart! The rate limit is 600 requests in 10 minutes, and PRAW chooses how long to sleep such that the requests will be evenly spread out across the timeframe.

→ More replies (1)

19

u/Turtvaiz Jul 10 '20

PRAW throttles requests based on response headers

12

u/Holek Jul 10 '20

This is something I wouldn't expect from an API library if I only picked it up. A welcome change in a sea of mediocrity

→ More replies (2)

33

u/throwaway_the_fourth Jul 10 '20

PRAW takes care of following the rate limit for you, so no need to add extra sleeps.

68

u/ManvilleJ Jul 10 '20 edited Jul 10 '20

github.

also replace that string concatenation with an f string and you don't need all string casting with this method and its the fastest & most readable way to do it

edited_body = f'{ups} upvotes, \n\n {downs} downvotes \n\n and {submission.num_comments} comments!'

edit: fstrings are the fastest: https://realpython.com/python-f-strings/

34

u/__ah Jul 10 '20

f strings deserve to be wayyy more popular. Shame they only became a thing very recently in 3.6, so many tutorials won't have had it.

5

u/Ph0X Jul 10 '20

Right, since it's not backward compatible, including them means a lot of people not running the latest python will be confused why it doesn't work.

4

u/M1sterNinja Jul 10 '20

I'm finishing a Codecademy course, and learned fstring outside of it. I've bashed my head against their interfaces a few times thinking something was wrong with my fstring, when in reality they are running a lower python version. : (

4

u/SquintingSquire Jul 11 '20

Python 3.6 is 3.6 years old now.

→ More replies (2)

17

u/[deleted] Jul 10 '20 edited Jul 10 '20

Kudos for the script. It's always fun to see live data :)

Here's my proposal. Didn't test everything since I don't have the credentials and stuff but it will give you the gist on how the design to transform it into a reusable CLI.

Thanks for sharing the source.

import os
import argparse
import praw


CLIENT_ID = os.environ.get('CLIENT_ID')
CLIENT_SECRET = os.environ.get('CLIENT_SECRET')
USER_AGENT = os.environ.get('USER_AGENT')



def get_reddit_client(
        username,
        password,
        client_id=None,
        client_secret=None,
        user_agent=None,
        ):

    if not client_id:
        client_id = CLIENT_ID
    if not client_secret:
        client_secret = CLIENT_SECRET
    if not user_agent:
        user_agent = USER_AGENT

    reddit = praw.Reddit(
        client_id=client_id,
        client_secret=client_secret,
        username=username,
        password=password,
        user_agent=user_agent)

    return reddit

def main(args):
    args.username
    args.password
    reddit = get_reddit_client(
        args.username,
        args.password,
        args.client_id,
        args.client_secret,
        args.user_agent,
        )

    while True:
        subm = reddit.submission(id=args.id)
        if subm.upvote_ratio != 0.5:
            ups = round(
                (subm.upvote_ratio * subm.score) / (2 * subm.upvote_ratio - 1))
        else:
            ups = round(subm.score / 2)
        downs = ups - subm.score

        edited_body = (
            '{} upvotes\n\n'
            '{} downvotes\n\n'
            '{} comments\n\n'
            )
        edited_body = edited_body.format(ups, downs, subm.num_comments)

        subm.edit(edited_body)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        prog='reddit_stats', description='Track and Post reddit stats')

    parser.add_argument(
        'id', type=str, help="reddit post's id")
    parser.add_argument(
        'username', type=str, help="reddit's account username")
    parser.add_argument(
        'password', type=str, help="reddit's account password")
    # Let user override values source from the environment variables
    parser.add_argument(
        '-ci', '--client_id', type=str, help="reddit's api client_id")
    parser.add_argument(
        '-cs', '--client_secret', type=str, help="reddit's api client_secret")
    parser.add_argument(
        '-ua', '--user_agent', type=str, help="custom user agent")

    args = parser.parse_args()
    main(args)

Edit: Typo

4

u/ManvilleJ Jul 10 '20

I know a lot of people like arg-parse, but python-fire is actually awesome: https://github.com/google/python-fire

12

u/[deleted] Jul 10 '20

https://github.com/google/python-fire

Do you really need to install six, termcolor and whatever to just normalize the arguments for this tiny script?

Didn't know about this lib and i will definitively take a look since it's from Google but IMHO:

this culture of injecting unnecessary sub modules just to fix one thing that the core lib already does is something for node/javascript projects.

6

u/ManvilleJ Jul 10 '20

It is a nice project that makes adding CLI capabilities simple and easy. I prefer the developer efficiency. Should I use urllib instead of requests? maybe, but if it works and I don't have to think about it, good.

Here is my repo of little fun examples of python fire and other stuff stuff. https://github.com/manvillej/fun_examples/tree/master/google_fire

3

u/[deleted] Jul 10 '20

Should I use urllib instead of requests?

Nope. If you read the description from the docs:

is a package that collects several modules for working with URLs

You will notice that is not their goal to help you consume web services. urllibs consume you manipulate url and web requests and a "raw" way. Requests project had a different goal. Two projects, same scenario, different scopes and goals.

→ More replies (3)
→ More replies (1)
→ More replies (6)

9

u/CompSciSelfLearning Jul 10 '20
client_id='hunter2',
 client_secret='hunter2',

    username='hunter2',     password='hunter2',     user_agent='hunter2'

Am I doing this right?

12

u/[deleted] Jul 10 '20

I would've used string formatting for the edited_body as it's more robust and looks cleaner but other that great! Thanks for sharing!

45

u/discobrisco Jul 10 '20

Nah f strings are the only way to go.

→ More replies (6)
→ More replies (17)