Mofongo
Mofongo

Reputation: 131

Cleaner way to write repeated code in python?

Using selenium I'm downloading some files from a webpage. On Monday's I need to download the info for Friday, Saturday, and Sunday. Every other day I only need yesterday. I wrote an if/else statement to accomplish this and just copy and pasted the code into the else statement. There must be a more pythonic way to write this but I'm still new to this.

today = datetime.date.today()
yesterday = str(today - timedelta(days=1))
if today.weekday() == 0:
    fri = str(today - timedelta(days=3))
    sat = str(today - timedelta(days=2))
    weekend = [fri, sat, yesterday]
    for day in weekend:
        # Needs to go first otherwise page won't load
        date_field = driver.find_element_by_xpath(
            """//*[@id="id blah blah"]""")
        date_field.send_keys(day)
        org_list = driver.find_element_by_xpath(
            """//*[@id="id blah blah"]/option[text()=\"string\"]""").click()

        delay = 5
        try:
            table_chk = WebDriverWait(driver, delay).until(
                EC.presence_of_element_located((By.XPATH, """//*[@id="id blah blah"]""")))
            export_btn = driver.find_element_by_xpath(
                """//*[@id="id blah blah"]""")
            export_btn.click()
            date_field = driver.find_element_by_xpath(
                """//*[@id="id blah blah"]""")
            date_field.clear()
            org_list = driver.find_element_by_xpath(
                """//*[@id="id blah blah"]/option[1]""").click()
        except TimeoutException:
            print("Loading took too much time!")
        time.sleep(2)
else:
    # Needs to go first otherwise it doesn't work
    date_field = driver.find_element_by_xpath(
        """//*[@id="id blah blah"]""")
    date_field.send_keys(yesterday)
    org_list = driver.find_element_by_xpath(
        """//*[@id="id blah blah"]/option[text()=\"string\"]""").click()

    delay = 5
    try:
        table_chk = WebDriverWait(driver, delay).until(
            EC.presence_of_element_located((By.XPATH, """//*[@id="id blah blah"]""")))
        export_btn = driver.find_element_by_xpath(
            """//*[@id="id blah blah"]""")
        export_btn.click()
    except TimeoutException:
        print("Loading took too much time!")

How can I efficiently repeat the code but have it run multiple times on Monday for Fri, Sat, Sun and just once for the day before, every other day of the week?

Upvotes: 0

Views: 61

Answers (1)

ShadowRanger
ShadowRanger

Reputation: 155363

Make it always loop, but programmatically define the collection to loop over as a single element most of the time, and multiple days when needed:

today = datetime.date.today()
# No need to define yesterday; we'll make it as needed next
if today.weekday() == 0:
    # Today is Monday, quickly get the days for Friday-Sunday
    days = [today - timedelta(days=i) for i in (3, 2, 1)]
else:
    # Today is not Monday, just check yesterday
    days = [today - timedelta(days=1)]
# days is now either one element list of just yesterday, or the whole weekend
# loop runs once or three times, as needed, with the same code
for day in days:
    # Complete body of original for day in weekend: loop goes here

If you really want to get code duplication to a minimum, you could reduce the code before the loop to:

today = datetime.date.today()
num_days_to_check = 3 if today.weekday() == 0 else 1
days = [today - timedelta(days=i) for i in range(num_days_to_check, 0, -1)]

since really, all that differs is how many prior days you need to check, 1 or 3, so the conditional can simplify to a one-liner choosing between the two, and the rest is just based on that initial decision point.

Upvotes: 1

Related Questions