From 5cea7c9b8413f030b5c2e9203f1a4340743ad7a9 Mon Sep 17 00:00:00 2001 From: Matteo Pelliccione Date: Sat, 3 Feb 2024 00:34:23 +0100 Subject: [PATCH 1/2] Refactoring of project structure (#4) * Refactoring * Refactoring * gitignore resources folder * Refactoring * README to reflect changes to project structure --- .gitignore | 11 ++--- README.md | 3 +- env.example | 6 +-- pyproject.toml | 18 ++++++++ requirements.txt | 6 +-- src/fantaformazionireminder/__init__.py | 0 src/fantaformazionireminder/config.py | 28 ++++++++++++ .../constants/__init__.py | 0 .../constants/notifications_interval.py | 0 .../fantaformazionireminder/main.py | 44 +++++++------------ src/fantaformazionireminder/utils/__init__.py | 0 .../utils/clean_dates.py | 17 +++---- .../utils/default_dates.py | 20 ++++----- .../utils/expiry_message.py | 3 +- 14 files changed, 89 insertions(+), 67 deletions(-) create mode 100644 pyproject.toml create mode 100644 src/fantaformazionireminder/__init__.py create mode 100644 src/fantaformazionireminder/config.py create mode 100644 src/fantaformazionireminder/constants/__init__.py rename config.py => src/fantaformazionireminder/constants/notifications_interval.py (100%) rename main.py => src/fantaformazionireminder/main.py (92%) create mode 100644 src/fantaformazionireminder/utils/__init__.py rename clean_wiki_data.py => src/fantaformazionireminder/utils/clean_dates.py (79%) rename write_default_dates.py => src/fantaformazionireminder/utils/default_dates.py (68%) rename utils.py => src/fantaformazionireminder/utils/expiry_message.py (99%) diff --git a/.gitignore b/.gitignore index 59e2c08..de0bfe8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Specific -data/ +resources/ # Byte-compiled / optimized / DLL files __pycache__/ @@ -88,7 +88,7 @@ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: -# .python-version +.python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. @@ -160,10 +160,7 @@ cython_debug/ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ +.idea/ # IDEs -.vscode/ - -TODO.md -.python-version \ No newline at end of file +.vscode/ \ No newline at end of file diff --git a/README.md b/README.md index 7ba551c..9ae81be 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ Before running the bot, you'll need the following: ```bash pip install -r requirements.txt + pip install -e . ``` 4. Create a `.env` file in the project directory. @@ -67,7 +68,7 @@ Before running the bot, you'll need the following: 5. Start the bot: ```bash - python main.py + python src\fantaformazionireminder\main.py ``` Now, your Fanta Formazioni Reminder bot should be up and running. diff --git a/env.example b/env.example index 4a16102..5bff23e 100644 --- a/env.example +++ b/env.example @@ -5,9 +5,9 @@ TOKEN=YOUR_BOT_TOKEN BOT_USERNAME=@your_username_bot # Filepaths -SAVED_DATES_FILEPATH=data/saved_dates.pkl -CHAT_IDS_FILEPATH=data/chat_ids.pkl +SAVED_DATES_FILEPATH=saved_dates.pkl +CHAT_IDS_FILEPATH=chat_ids.pkl # Serie A Calendar SERIE_A_CALENDAR_URL=https://fixturedownload.com/download/serie-a-2023-WEuropeStandardTime.csv -SERIE_A_CALENDAR_PATH=data/seriea_calendar.csv \ No newline at end of file +SERIE_A_CALENDAR_PATH=seriea_calendar.csv \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..42ddcab --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,18 @@ +[project] +name = "fantaformazionireminder" +version = "0.1.0" +dependencies = [ + "python-dotenv", + "python-telegram-bot[job_queue]>=20.5", + "requests", +] +requires-python = ">=3.11.4" +authors = [{ name = "Matteo Pelliccione", email = "mat.pelliccione@gmail.com" }] +description = "Telegram Bot to remind you of Fantacalcio's line-up" +readme = "README.md" +license = { file = "LICENSE" } +classifiers = ["Programming Language :: Python :: 3.11.4"] + +[build-system] +requires = ["setuptools >= 69.0"] +build-backend = "setuptools.build_meta" diff --git a/requirements.txt b/requirements.txt index 39d7390..bbb57d5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -python-dotenv==1.0.0 -python-telegram-bot[job_queue]==20.5 -requests==2.31.0 \ No newline at end of file +python-dotenv==1.0.1 +python-telegram-bot[job-queue]>=20.5 +requests==2.31.0 diff --git a/src/fantaformazionireminder/__init__.py b/src/fantaformazionireminder/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/fantaformazionireminder/config.py b/src/fantaformazionireminder/config.py new file mode 100644 index 0000000..c0c36e1 --- /dev/null +++ b/src/fantaformazionireminder/config.py @@ -0,0 +1,28 @@ +import os +from typing import Final + +from dotenv import load_dotenv + +# Load .env +load_dotenv() + + +# Values +BASE_RESOURCES_PATH: Final = os.path.join( + os.getcwd(), "src\\fantaformazionireminder\\resources" +) + +TOKEN: Final[str] = os.getenv("TOKEN") +BOT_USERNAME: Final[str] = os.getenv("BOT_USERNAME") + +SAVED_DATES_FILEPATH: Final[str] = os.path.join( + BASE_RESOURCES_PATH, os.getenv("SAVED_DATES_FILEPATH") +) +CHAT_IDS_FILEPATH: Final[str] = os.path.join( + BASE_RESOURCES_PATH, os.getenv("CHAT_IDS_FILEPATH") +) + +SERIE_A_CALENDAR_PATH: Final = os.path.join( + BASE_RESOURCES_PATH, os.getenv("SERIE_A_CALENDAR_PATH") +) +SERIE_A_CALENDAR_URL: Final = os.getenv("SERIE_A_CALENDAR_URL") diff --git a/src/fantaformazionireminder/constants/__init__.py b/src/fantaformazionireminder/constants/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/config.py b/src/fantaformazionireminder/constants/notifications_interval.py similarity index 100% rename from config.py rename to src/fantaformazionireminder/constants/notifications_interval.py diff --git a/main.py b/src/fantaformazionireminder/main.py similarity index 92% rename from main.py rename to src/fantaformazionireminder/main.py index a4cec23..accd26a 100644 --- a/main.py +++ b/src/fantaformazionireminder/main.py @@ -1,9 +1,8 @@ -import os import pickle from datetime import datetime, time, timedelta -from typing import Final -from dotenv import load_dotenv +import config +from constants.notifications_interval import NOTIFICATIONS_INTERVAL from telegram import Update from telegram.ext import ( Application, @@ -13,34 +12,23 @@ MessageHandler, filters, ) +from utils.expiry_message import get_expiry_message +from src.fantaformazionireminder.utils.default_dates import write_default_dates -from config import NOTIFICATIONS_INTERVAL -from utils import get_expiry_message -from write_default_dates import write_default_dates - -# Env -# Load environment variables from .env file -load_dotenv() - -# Access constants from environment variables -TOKEN: Final[str] = os.getenv("TOKEN") -BOT_USERNAME: Final[str] = os.getenv("BOT_USERNAME") - -SAVED_DATES_FILEPATH: Final[str] = os.getenv("SAVED_DATES_FILEPATH") -CHAT_IDS_FILEPATH: Final[str] = os.getenv("CHAT_IDS_FILEPATH") # Load active chat IDs from a file or initialize an empty list try: - with open(CHAT_IDS_FILEPATH, "rb") as file: + with open(config.CHAT_IDS_FILEPATH, "rb") as file: print(f"[CHAT_ID][FILE_OPEN] File {file.name} opened!") active_chat_ids = pickle.load(file) except FileNotFoundError: print("[CHAT_ID][FILE_NOT_FOUND] File not found") active_chat_ids = [] + # Load saved dates from a file or initialize an empty list try: - with open(SAVED_DATES_FILEPATH, "rb") as file: + with open(config.SAVED_DATES_FILEPATH, "rb") as file: print(f"[DATE][FILE_OPEN] File {file.name} opened!") saved_dates = pickle.load(file) except FileNotFoundError: @@ -49,7 +37,7 @@ ) write_default_dates() try: - with open(SAVED_DATES_FILEPATH, "rb") as file: + with open(config.SAVED_DATES_FILEPATH, "rb") as file: print(f"[DATE][FILE_OPEN] File {file.name} opened!") saved_dates = pickle.load(file) except FileNotFoundError: @@ -63,7 +51,7 @@ async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE): if chat_id not in active_chat_ids: active_chat_ids.append(chat_id) - with open(CHAT_IDS_FILEPATH, "wb") as file: + with open(config.CHAT_IDS_FILEPATH, "wb") as file: pickle.dump(active_chat_ids, file) print( f"[CHAT_ID][FILE_UPDATE] {active_chat_ids[-1]} saved in file {file.name}" @@ -183,7 +171,7 @@ async def save_date(update, date_str: str): try: # Parse the date string to a datetime object date_obj = datetime.strptime(date_str, "%d/%m/%Y,%H:%M") - saved_date_obj = (date_obj - timedelta(minutes=5)) + saved_date_obj = date_obj - timedelta(minutes=5) if date_obj < datetime.now(): await update.message.reply_text( @@ -199,7 +187,7 @@ async def save_date(update, date_str: str): saved_dates.append((chat_id, saved_date_obj)) # Save the updated list to the file - with open(SAVED_DATES_FILEPATH, "wb") as file: + with open(config.SAVED_DATES_FILEPATH, "wb") as file: pickle.dump(saved_dates, file) print( f"[DATE][FILE_UPDATE] {saved_dates[-1]} saved in file {file.name}" @@ -264,8 +252,8 @@ async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE): ) if message_type == "group" or message_type == "supergroup": - if BOT_USERNAME in text: - new_text: str = text.replace(BOT_USERNAME, "").strip() + if config.BOT_USERNAME in text: + new_text: str = text.replace(config.BOT_USERNAME, "").strip() response: str = handle_response(new_text) else: return @@ -380,7 +368,7 @@ def remove_expired_dates(): ] # Save the updated list to the file - with open(SAVED_DATES_FILEPATH, "wb") as file: + with open(config.SAVED_DATES_FILEPATH, "wb") as file: pickle.dump(updated_saved_dates, file) saved_dates = updated_saved_dates @@ -389,7 +377,7 @@ def remove_expired_dates(): # Application if __name__ == "__main__": print("[SELF] Starting bot...") - app = Application.builder().token(TOKEN).build() + app = Application.builder().token(config.TOKEN).build() job_queue = app.job_queue # Cleanup @@ -428,4 +416,4 @@ def remove_expired_dates(): # Polling print("[SELF] Polling...") - app.run_polling(poll_interval=1) \ No newline at end of file + app.run_polling(poll_interval=1) diff --git a/src/fantaformazionireminder/utils/__init__.py b/src/fantaformazionireminder/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/clean_wiki_data.py b/src/fantaformazionireminder/utils/clean_dates.py similarity index 79% rename from clean_wiki_data.py rename to src/fantaformazionireminder/utils/clean_dates.py index 5dbad85..dfdd137 100644 --- a/clean_wiki_data.py +++ b/src/fantaformazionireminder/utils/clean_dates.py @@ -1,20 +1,13 @@ import csv -import os from datetime import datetime, timedelta -from typing import Final, List +from typing import List import requests -from dotenv import load_dotenv -# Load .env -load_dotenv() +from fantaformazionireminder import config -# Constants -CSV_PATH: Final = os.getenv("SERIE_A_CALENDAR_PATH") -CSV_URL: Final = os.getenv("SERIE_A_CALENDAR_URL") - -def download_csv(url, dest_path) -> None: +def __download_csv(url, dest_path) -> None: response = requests.get(url) with open(dest_path, "wb") as file: file.write(response.content) @@ -22,10 +15,10 @@ def download_csv(url, dest_path) -> None: def get_cleaned_dates() -> List[datetime]: # Download the CSV file - download_csv(CSV_URL, CSV_PATH) + __download_csv(config.SERIE_A_CALENDAR_URL, config.SERIE_A_CALENDAR_PATH) # Read the data from the CSV file - with open(CSV_PATH, newline="", encoding="utf-8") as csvfile: + with open(config.SERIE_A_CALENDAR_PATH, newline="", encoding="utf-8") as csvfile: reader = csv.DictReader(csvfile) # Initialize a dictionary to store the earliest date for each round diff --git a/write_default_dates.py b/src/fantaformazionireminder/utils/default_dates.py similarity index 68% rename from write_default_dates.py rename to src/fantaformazionireminder/utils/default_dates.py index b5e5efd..c4e54d1 100644 --- a/write_default_dates.py +++ b/src/fantaformazionireminder/utils/default_dates.py @@ -1,27 +1,22 @@ -import os import pickle -from dotenv import load_dotenv -from typing import Final -from clean_wiki_data import get_cleaned_dates +import config +from utils.clean_dates import get_cleaned_dates -# Load .env -load_dotenv() - -# Constants -SAVED_DATES_FILEPATH: Final = os.getenv("SAVED_DATES_FILEPATH") def __load_saved_dates(): try: - with open(SAVED_DATES_FILEPATH, "rb") as file: + with open(config.SAVED_DATES_FILEPATH, "rb") as file: return pickle.load(file) except FileNotFoundError: return [] + def __save_dates(saved_dates): - with open(SAVED_DATES_FILEPATH, "wb") as file: + with open(config.SAVED_DATES_FILEPATH, "wb") as file: pickle.dump(saved_dates, file) + def write_default_dates(): # Load the existing saved_dates or initialize an empty list saved_dates = __load_saved_dates() @@ -37,5 +32,6 @@ def write_default_dates(): print("[DEFAULT_DATE][FILE_UPDATE] Default dates added to saved_dates.") + if __name__ == "__main__": - write_default_dates() \ No newline at end of file + write_default_dates() diff --git a/utils.py b/src/fantaformazionireminder/utils/expiry_message.py similarity index 99% rename from utils.py rename to src/fantaformazionireminder/utils/expiry_message.py index e792835..8002db6 100644 --- a/utils.py +++ b/src/fantaformazionireminder/utils/expiry_message.py @@ -1,9 +1,10 @@ from datetime import timedelta + # TODO better handling of time_difference to let the message be more variable def get_expiry_message(time_difference: timedelta, saved_date: any): processed_time = time_difference.total_seconds() - + if processed_time >= 80000: time_word = "24 ore" elif processed_time >= 59 and processed_time <= 61: From cc24f0888b98f941d53346f21854ba1f6c6c71de Mon Sep 17 00:00:00 2001 From: Matteo Pelliccione Date: Sun, 11 Aug 2024 21:08:23 +0200 Subject: [PATCH 2/2] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9ae81be..55d1a3f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Fanta Formazioni Reminder +# Fanta Formazioni Reminder Bot Fanta Formazioni Reminder is a Telegram Bot written in Python that helps users manage and stay updated with their fantasy football (FantaCalcio) team lineups. This bot provides reminders and notifications for important events related to fantasy football, such as upcoming matchdays and deadlines for setting up your team's lineup.