From b1732c07c51810b3d19e272017c77c5f84475fb0 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Wed, 27 May 2026 08:20:30 -0400 Subject: [PATCH] Reformat code to pythonic standards --- util/convert.py | 7 +++-- util/drawing.py | 66 ++++++++++++++++++++++++++++++--------------- util/environment.py | 3 +++ util/odds.py | 41 +++++++++++++++++++--------- util/scrape.py | 57 +++++++++++++++++++++++++++++---------- 5 files changed, 123 insertions(+), 51 deletions(-) diff --git a/util/convert.py b/util/convert.py index d274555..1ea7da5 100644 --- a/util/convert.py +++ b/util/convert.py @@ -1,6 +1,3 @@ -import re - - class InvalidStringException(Exception): """Raised when a string cannot be converted to an integer.""" pass @@ -25,4 +22,6 @@ def convert_string_to_integer(data: str) -> int | Exception: else: return int(data) except ValueError as exc: - raise InvalidStringException("The string could not be converted to an integer.") from exc \ No newline at end of file + raise InvalidStringException( + "The string could not be converted to an integer.", + ) from exc \ No newline at end of file diff --git a/util/drawing.py b/util/drawing.py index 294d3df..b8179a9 100644 --- a/util/drawing.py +++ b/util/drawing.py @@ -4,11 +4,12 @@ Utility functions for drawing data processing """ import os - from datetime import datetime, timedelta + from dotenv import load_dotenv -from data.database import PowerballDraw, MegaMillionsDraw, Table +from data.database import MegaMillionsDraw, PowerballDraw, Table + load_dotenv() @@ -38,13 +39,17 @@ def check_table_name2(table_name: Table) -> dict | None: return game_dict[table_name] if table_name in game_dict.keys() else None -def get_next_draw_date(game: str | None, from_date: str | None = None) -> str | None: +def get_next_draw_date( + game: str | None, from_date: str | None = None, +) -> str | None: """ - Gets the next drawing date from the current or specified date for the given game + Gets the next drawing date from the current or specified date for the + given game If the current date is the next drawing date, the current date is returned :param game: megamillions or powerball - :param from_date: date to get next drawing date from, if omitted the current date is used + :param from_date: date to get next drawing date from, if omitted the + current date is used :return: next drawing date Examples: @@ -55,7 +60,7 @@ def get_next_draw_date(game: str | None, from_date: str | None = None) -> str | """ target_days = { "powerball": [0, 2, 5], - "mega-millions": [1, 4] + "mega-millions": [1, 4], } return_date = None @@ -77,13 +82,18 @@ def get_next_draw_date(game: str | None, from_date: str | None = None) -> str | return return_date.strftime(return_date_format) -def get_previous_draw_date(game: str | None, from_date: str | None = None) -> str | None: +def get_previous_draw_date( + game: str | None, from_date: str | None = None, +) -> str | None: """ - Gets the previous drawing date from the current or specified date for the given game - If the current date is a drawing date, the next previous date will be returned + Gets the previous drawing date from the current or specified date for the + given game + If the current date is a drawing date, the next previous date will be + returned :param game: megamillions or powerball - :param from_date: date to get previous drawing date from, if omitted the current date is used + :param from_date: date to get previous drawing date from, if omitted the + current date is used :return: previous drawing date Examples: @@ -94,7 +104,7 @@ def get_previous_draw_date(game: str | None, from_date: str | None = None) -> st """ target_days = { "powerball": [0, 2, 5], - "mega-millions": [1, 4] + "mega-millions": [1, 4], } return_date = None @@ -110,7 +120,8 @@ def get_previous_draw_date(game: str | None, from_date: str | None = None) -> st else: return_date = datetime.strptime(from_date, return_date_format) - # to ensure the current date is not returned if it is a draw date, subtract a day first + # to ensure the current date is not returned if it is a draw date, + # subtract a day first return_date -= timedelta(days=1) while return_date.weekday() not in target_days[game]: @@ -126,32 +137,45 @@ def get_powerball_object(draw_date: str, draw_result: dict) -> PowerballDraw: :return: PowerballDraw object Examples: - >>> get_powerball_object(draw_date='2026-02-28', draw_result={'main_balls': [6, 20, 35, 54, 65], 'powerball': 10, 'multiplier': 4}) - PowerballDraw(draw_date=datetime(2026, 2, 28), main_ball1=6, main_ball2=20, main_ball3=35, main_ball4=54, main_ball5=65, powerball=10, power_play=4) + >>> get_powerball_object(draw_date='2026-02-28', draw_result={ + 'main_balls': [6, 20, 35, 54, 65], 'powerball': 10, 'multiplier': 4}) + PowerballDraw(draw_date=datetime(2026, 2, 28), main_ball1=6, + main_ball2=20, main_ball3=35, main_ball4=54, main_ball5=65, powerball=10, + power_play=4) """ draw_date = datetime.strptime(draw_date, '%Y-%m-%d').date() mb1, mb2, mb3, mb4, mb5 = draw_result['main_balls'] pb = draw_result['powerball'] power_play = draw_result['multiplier'] - return PowerballDraw(draw_date=draw_date,main_ball1=mb1, main_ball2=mb2, main_ball3=mb3, main_ball4=mb4, - main_ball5=mb5, powerball=pb, power_play=power_play) + return PowerballDraw( + draw_date=draw_date, main_ball1=mb1, main_ball2=mb2, main_ball3=mb3, + main_ball4=mb4, + main_ball5=mb5, powerball=pb, power_play=power_play, + ) -def get_mega_millions_object(draw_date: str, draw_result: dict) -> MegaMillionsDraw: +def get_mega_millions_object( + draw_date: str, draw_result: dict, +) -> MegaMillionsDraw: """ :param draw_date: date for the drawing data :param draw_result: drawing results for the draw_date :return: MegaMillionsDraw object Examples: - >>> get_mega_millions_object(draw_date='2010-02-02', draw_result={'main_balls': [6, 7, 26, 27, 49], 'mega-ball': 9, 'megaplier': 4}) - MegaMillionsDraw(draw_date=date, main_ball1=6, main_ball2=7, main_ball3=26, main_ball4=27, main_ball5=49, mega_ball=9, megaplier=4) + >>> get_mega_millions_object(draw_date='2010-02-02', draw_result={ + 'main_balls': [6, 7, 26, 27, 49], 'mega-ball': 9, 'megaplier': 4}) + MegaMillionsDraw(draw_date=date, main_ball1=6, main_ball2=7, + main_ball3=26, main_ball4=27, main_ball5=49, mega_ball=9, megaplier=4) """ draw_date = datetime.strptime(draw_date, '%Y-%m-%d').date() mb1, mb2, mb3, mb4, mb5 = draw_result['main_balls'] mega = draw_result['mega-ball'] megaplier = draw_result['multiplier'] - return MegaMillionsDraw(draw_date=draw_date, main_ball1=mb1, main_ball2=mb2, main_ball3=mb3, main_ball4=mb4, - main_ball5=mb5, mega_ball=mega, megaplier=megaplier) + return MegaMillionsDraw( + draw_date=draw_date, main_ball1=mb1, main_ball2=mb2, main_ball3=mb3, + main_ball4=mb4, + main_ball5=mb5, mega_ball=mega, megaplier=megaplier, + ) diff --git a/util/environment.py b/util/environment.py index c367809..23b21bb 100644 --- a/util/environment.py +++ b/util/environment.py @@ -4,10 +4,13 @@ Utility function for loading project environment variables """ import os + from dotenv import load_dotenv + load_dotenv() + def load_environment_variables() -> dict: return { k: v for k, v in os.environ.items() diff --git a/util/odds.py b/util/odds.py index 4c7f9e5..a3d9217 100644 --- a/util/odds.py +++ b/util/odds.py @@ -9,15 +9,18 @@ from math import comb def calculate_odds(pool_size: int, draw_count: int) -> int: """ - Calculate the total number of possible combinations in a set of numbers with a specific draw count. + Calculate the total number of possible combinations in a set of numbers + with a specific draw count. :param pool_size: Total count of numbers in the pool :param draw_count: The count of numbers to draw from the pool :return: The total number of possible combinations Example: - If a lottery game has a main ball pool of 49 numbers from which 5 numbers are drawn and a pool of - 18 numbers from which 1 number is drawn (game ball), calculate the odds of winning that game. + If a lottery game has a main ball pool of 49 numbers from which 5 + numbers are drawn and a pool of + 18 numbers from which 1 number is drawn (game ball), calculate the + odds of winning that game. >>> calculate_odds(pool_size=49, draw_count=5) 1906884 @@ -26,7 +29,10 @@ def calculate_odds(pool_size: int, draw_count: int) -> int: """ if draw_count < 0 or draw_count > pool_size: - raise ValueError('Integer values must be positive and draw counts must be less than pool size.') + raise ValueError( + 'Integer values must be positive and draw counts must be less ' + 'than pool size.', + ) total_combinations = comb(pool_size, draw_count) return total_combinations @@ -35,29 +41,40 @@ def get_odds_of_winning( main_ball_draw_pool: int, main_ball_draw_count: int, game_ball_draw_pool: int, - game_ball_draw_count: int + game_ball_draw_count: int, ) -> str: """ Calculate the odds of winning a specific lottery game with one draw :param main_ball_draw_pool: Total count of numbers in the main ball pool - :param main_ball_draw_count: The count of numbers to draw from the main ball pool + :param main_ball_draw_count: The count of numbers to draw from the + main ball pool :param game_ball_draw_pool: Total count of numbers in the game ball pool - :param game_ball_draw_count: The count of numbers to draw from the game ball pool + :param game_ball_draw_count: The count of numbers to draw from the + game ball pool :return: The odds of winning a specific lottery game with one draw Example: - To calculate the odds of winning a lottery game with 5 numbers drawn from a main ball pool of 49 and + To calculate the odds of winning a lottery game with 5 numbers + drawn from a main ball pool of 49 and 1 number drawn from a game ball pool of 19 numbers. - >>> get_odds_of_winning(main_ball_draw_pool=49, main_ball_draw_count=5, game_ball_draw_pool=18, game_ball_draw_count=1) + >>> get_odds_of_winning(main_ball_draw_pool=49, + main_ball_draw_count=5, game_ball_draw_pool=18, + game_ball_draw_count=1) 'The odds of winning are 1 in 34,323,912' """ - if (main_ball_draw_count < 0 or main_ball_draw_count > main_ball_draw_pool or - game_ball_draw_count < 0 or game_ball_draw_count > game_ball_draw_pool): - raise ValueError('Integer values must be positive and draw counts must be less than pool size.') + if ( + main_ball_draw_count < 0 or main_ball_draw_count > + main_ball_draw_pool or + game_ball_draw_count < 0 or game_ball_draw_count > + game_ball_draw_pool): + raise ValueError( + 'Integer values must be positive and draw counts must be less ' + 'than pool size.', + ) main_ball_odds = calculate_odds(main_ball_draw_pool, main_ball_draw_count) game_ball_odds = calculate_odds(game_ball_draw_pool, game_ball_draw_count) diff --git a/util/scrape.py b/util/scrape.py index e9f8265..454b1d2 100755 --- a/util/scrape.py +++ b/util/scrape.py @@ -4,19 +4,23 @@ Utility functions for scraping web data relative to selected games """ import httpx -from dateutil import parser, utils from bs4 import BeautifulSoup +from dateutil import parser, utils from util.environment import load_environment_variables + project_variables: dict = load_environment_variables() + def scrape_game_history(game: str, year: int = utils.today().year) -> dict: """ - Scrape game data from the url provided. This function requires specific environment variables be present + Scrape game data from the url provided. This function requires + specific environment variables be present in order to function properly. :param:game The target game to scrape. - :param:year The year to scrape. If no year is provided, scrapes games from the current year. + :param:year The year to scrape. If no year is provided, scrapes + games from the current year. :return: dict() @@ -32,18 +36,37 @@ def scrape_game_history(game: str, year: int = utils.today().year) -> dict: url = f"{project_variables['LP_BASE_SCRAPE_URL']}{game}/numbers/{year}" page = httpx.get(url) soup = BeautifulSoup(page.text, 'html.parser') - results = soup.find_all(project_variables['LP_RESULT_CONTAINER'], class_=project_variables['LP_RESULT_CLASS']) + results = soup.find_all( + project_variables['LP_RESULT_CONTAINER'], + class_=project_variables['LP_RESULT_CLASS'], + ) for result in results: pick5 = [] - draw_date = parser.parse(result.find(project_variables['LP_DRAW_DATE_CONTAINER'], - class_=project_variables['LP_DRAW_DATE_CLASS']).text).date().strftime('%Y-%m-%d') - main_balls = result.find_all(project_variables['LP_BALL_CONTAINER'], class_=project_variables['LP_BALL_CLASS']) - game_ball = result.find(project_variables['LP_BALL_CONTAINER'], - class_=[project_variables['LP_POWERBALL_CLASS'], project_variables['LP_MEGABALL_CLASS']]) - multiplier = result.find(project_variables['LP_BALL_CONTAINER'], - class_=[project_variables['LP_POWERBALL_MULTIPLIER_CLASS'], - project_variables['LP_MEGA_MILLIONS_MULTIPLIER_CLASS']]) + draw_date = parser.parse( + result.find( + project_variables['LP_DRAW_DATE_CONTAINER'], + class_=project_variables['LP_DRAW_DATE_CLASS'], + ).text, + ).date().strftime('%Y-%m-%d') + main_balls = result.find_all( + project_variables['LP_BALL_CONTAINER'], + class_=project_variables['LP_BALL_CLASS'], + ) + game_ball = result.find( + project_variables['LP_BALL_CONTAINER'], + class_=[ + project_variables['LP_POWERBALL_CLASS'], + project_variables['LP_MEGABALL_CLASS'], + ], + ) + multiplier = result.find( + project_variables['LP_BALL_CONTAINER'], + class_=[ + project_variables['LP_POWERBALL_MULTIPLIER_CLASS'], + project_variables['LP_MEGA_MILLIONS_MULTIPLIER_CLASS'], + ], + ) for ball in main_balls: pick5.append(int(ball.text.strip())) @@ -55,8 +78,14 @@ def scrape_game_history(game: str, year: int = utils.today().year) -> dict: multiplier = 1 if game == 'mega-millions': - drawings[draw_date] = {'main_balls': pick5, 'mega-ball': game_ball, 'multiplier': multiplier} + drawings[draw_date] = { + 'main_balls': pick5, 'mega-ball': game_ball, + 'multiplier': multiplier, + } elif game == 'powerball': - drawings[draw_date] = {'main_balls': pick5, 'powerball': game_ball, 'multiplier': multiplier} + drawings[draw_date] = { + 'main_balls': pick5, 'powerball': game_ball, + 'multiplier': multiplier, + } return drawings