Merge pull request 'MIL-001: project setup' (#19) from mil-001-project-setup into main
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 6s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 6s
This commit was merged in pull request #19.
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
GMAIL_ADDRESS=
|
||||||
|
GMAIL_TOKEN=
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
# Secrets: personal use only, never committed
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*.egg-info/
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
|
||||||
|
# Test and tool caches
|
||||||
|
.pytest_cache/
|
||||||
|
.ruff_cache/
|
||||||
|
.mypy_cache/
|
||||||
|
.coverage
|
||||||
|
htmlcov/
|
||||||
|
|
||||||
|
# Generated documentation
|
||||||
|
docs/doxygen/
|
||||||
|
|
||||||
|
# Editors and OS
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Doxygen configuration for the birthday wisher (Python).
|
||||||
|
# Run from the repository root: doxygen Doxyfile
|
||||||
|
# Output goes to docs/doxygen/ (git-ignored).
|
||||||
|
|
||||||
|
PROJECT_NAME = "Birthday Wisher"
|
||||||
|
PROJECT_BRIEF = "Sends a random birthday letter by e-mail (Udemy 100 Days of Code, day 32)"
|
||||||
|
OUTPUT_DIRECTORY = docs/doxygen
|
||||||
|
INPUT = src README.md
|
||||||
|
FILE_PATTERNS = *.py *.md
|
||||||
|
RECURSIVE = YES
|
||||||
|
USE_MDFILE_AS_MAINPAGE = README.md
|
||||||
|
|
||||||
|
OPTIMIZE_OUTPUT_JAVA = YES
|
||||||
|
EXTRACT_ALL = YES
|
||||||
|
EXTRACT_PRIVATE = NO
|
||||||
|
JAVADOC_AUTOBRIEF = YES
|
||||||
|
AUTOLINK_SUPPORT = YES
|
||||||
|
SOURCE_BROWSER = YES
|
||||||
|
|
||||||
|
GENERATE_HTML = YES
|
||||||
|
GENERATE_LATEX = NO
|
||||||
|
QUIET = YES
|
||||||
|
WARN_IF_UNDOCUMENTED = YES
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
name,email,year,month,day
|
||||||
|
Alice Example,alice@example.com,1990,3,14
|
||||||
|
Bob Example,bob@example.com,1985,10,17
|
||||||
|
Carol Example,carol@example.com,2001,10,17
|
||||||
|
Dave Example,dave@example.com,1978,12,24
|
||||||
|
@@ -0,0 +1,7 @@
|
|||||||
|
Dear [NAME],
|
||||||
|
|
||||||
|
Happy birthday!
|
||||||
|
|
||||||
|
All the best for the year!
|
||||||
|
|
||||||
|
Angela
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
Hey [NAME],
|
||||||
|
|
||||||
|
Happy birthday! Have a wonderful time today and eat lots of cake!
|
||||||
|
|
||||||
|
Lots of love,
|
||||||
|
|
||||||
|
Angela
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
Dear [NAME],
|
||||||
|
|
||||||
|
It's your birthday! Have a great day!
|
||||||
|
|
||||||
|
All my love,
|
||||||
|
|
||||||
|
Angela
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=68"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "birthday-wisher"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Sends a random birthday letter by e-mail to everyone whose birthday is today (Udemy 100 Days of Code, day 32)."
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.13"
|
||||||
|
license = { file = "LICENSE" }
|
||||||
|
dependencies = []
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
dev = ["pytest>=8"]
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
where = ["src"]
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
pythonpath = ["src"]
|
||||||
|
testpaths = ["tests"]
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
"""!
|
||||||
|
@file __init__.py
|
||||||
|
@brief Birthday wisher: sends a random birthday letter to everyone whose birthday is today.
|
||||||
|
"""
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
"""!
|
||||||
|
@file constants.py
|
||||||
|
@brief Constants of the birthday wisher: file names, placeholder, SMTP settings.
|
||||||
|
"""
|
||||||
|
|
||||||
|
## Name of the CSV file with the people and their birth dates.
|
||||||
|
BIRTHDAYS_FILE: str = "birthdays.csv"
|
||||||
|
|
||||||
|
## Folder with the letter templates.
|
||||||
|
LETTER_TEMPLATES_DIR: str = "letter_templates"
|
||||||
|
|
||||||
|
## File name pattern of a letter template (the number is 1 to LETTER_COUNT).
|
||||||
|
LETTER_FILE_PATTERN: str = "letter_{number}.txt"
|
||||||
|
|
||||||
|
## Number of letter templates the program chooses from.
|
||||||
|
LETTER_COUNT: int = 3
|
||||||
|
|
||||||
|
## Placeholder in a letter that is replaced by the person's name.
|
||||||
|
NAME_PLACEHOLDER: str = "[NAME]"
|
||||||
|
|
||||||
|
## Columns of the CSV file.
|
||||||
|
CSV_COLUMNS: tuple[str, ...] = ("name", "email", "year", "month", "day")
|
||||||
|
|
||||||
|
## SMTP server of Gmail.
|
||||||
|
SMTP_HOST: str = "smtp.gmail.com"
|
||||||
|
|
||||||
|
## SMTP port that expects STARTTLS.
|
||||||
|
SMTP_PORT: int = 587
|
||||||
|
|
||||||
|
## Subject of the e-mail.
|
||||||
|
EMAIL_SUBJECT: str = "Happy Birthday"
|
||||||
|
|
||||||
|
## Environment variable with the sender's e-mail address.
|
||||||
|
ENV_SENDER_ADDRESS: str = "GMAIL_ADDRESS"
|
||||||
|
|
||||||
|
## Environment variable with the sender's app password (token).
|
||||||
|
ENV_SENDER_TOKEN: str = "GMAIL_TOKEN"
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
"""Smoke test: the package imports and the constants are consistent."""
|
||||||
|
|
||||||
|
from birthday_wisher import constants
|
||||||
|
|
||||||
|
|
||||||
|
def test_letter_file_pattern_has_number_placeholder() -> None:
|
||||||
|
assert "{number}" in constants.LETTER_FILE_PATTERN
|
||||||
|
|
||||||
|
|
||||||
|
def test_csv_columns_start_with_name_and_email() -> None:
|
||||||
|
assert constants.CSV_COLUMNS[:2] == ("name", "email")
|
||||||
|
|
||||||
|
|
||||||
|
def test_smtp_port_expects_starttls() -> None:
|
||||||
|
assert constants.SMTP_PORT == 587
|
||||||
Reference in New Issue
Block a user