feat: Add .gitignore, LICENSE, README, pyproject.toml, and kalente source files
- Added .gitignore file to specify files and directories to ignore in version control. - Added LICENSE file with MIT license. - Added README.md file with project information and license details. - Added pyproject.toml file with project metadata and dependencies. - Added kalente source files for generating PDF calendars. - Implemented functions for generating weekly calendars, converting HTML to PDF, and CLI parsing. - Created a template for rendering weekly calendars in HTML format.
This commit is contained in:
commit
60cfcc70dd
7 changed files with 242 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
venv/
|
||||
*.pyc
|
||||
__pycache__/
|
||||
*.pdf
|
19
LICENSE
Normal file
19
LICENSE
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2023 Kumi Mitterer <kalente@kumi.email>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
10
README.md
Normal file
10
README.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Kalente
|
||||
|
||||
Kalente is a simple Python script for generating PDF calendars. It can be used
|
||||
to generate weekly calendars at the moment, but it will be extended to support
|
||||
monthly and yearly calendars as well.
|
||||
|
||||
## License
|
||||
|
||||
Kalente is licensed under the MIT license. See the `LICENSE` file for more
|
||||
information.
|
32
pyproject.toml
Normal file
32
pyproject.toml
Normal file
|
@ -0,0 +1,32 @@
|
|||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "kalente"
|
||||
version = "0.1.0"
|
||||
authors = [
|
||||
{ name="Kumi Mitterer", email="kalente@kumi.email" },
|
||||
]
|
||||
description = "Simple Python script to generate a printable calendar"
|
||||
readme = "README.md"
|
||||
license = { file="LICENSE" }
|
||||
requires-python = ">=3.10"
|
||||
classifiers = [
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: OS Independent",
|
||||
]
|
||||
dependencies = [
|
||||
"holidays",
|
||||
"pdfkit",
|
||||
"jinja2",
|
||||
"python-dateutil",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
"Homepage" = "https://kumig.it/kumitterer/kalente"
|
||||
"Bug Tracker" = "https://kumig.it/kumitterer/kalente/issues"
|
||||
|
||||
[project.scripts]
|
||||
kalente = "kalente.__main__:main"
|
0
src/kalente/__init__.py
Normal file
0
src/kalente/__init__.py
Normal file
121
src/kalente/__main__.py
Normal file
121
src/kalente/__main__.py
Normal file
|
@ -0,0 +1,121 @@
|
|||
import holidays
|
||||
import pdfkit
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from datetime import date, timedelta
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
from dateutil.parser import parse
|
||||
|
||||
|
||||
def get_week(
|
||||
for_date: date = None,
|
||||
country_code: Optional[str] = None,
|
||||
date_format: str = "%b %d, %Y",
|
||||
):
|
||||
week_days = []
|
||||
|
||||
for_date = for_date or date.today()
|
||||
week_start = for_date - timedelta(days=for_date.weekday())
|
||||
week_end = week_start + timedelta(days=6)
|
||||
|
||||
if country_code:
|
||||
holiday_list = holidays.CountryHoliday(
|
||||
country_code, years=[for_date.year, week_end.year, week_start.year]
|
||||
)
|
||||
else:
|
||||
holiday_list = {}
|
||||
|
||||
for i in range(7):
|
||||
day = week_start + timedelta(days=i)
|
||||
day_info = {
|
||||
"day": day.strftime("%A"),
|
||||
"date": day.strftime(date_format),
|
||||
"holiday": holiday_list.get(day),
|
||||
"is_weekend": (day.weekday() in [5, 6]),
|
||||
}
|
||||
week_days.append(day_info)
|
||||
return week_days
|
||||
|
||||
|
||||
def generate_weekly_html(week):
|
||||
file_loader = FileSystemLoader(Path(__file__).parent.absolute() / "templates")
|
||||
env = Environment(loader=file_loader)
|
||||
template = env.get_template("weekly.html")
|
||||
return template.render(week=week)
|
||||
|
||||
|
||||
def convert_html_to_pdf(content, output_filename):
|
||||
options = {
|
||||
"page-size": "A4",
|
||||
"orientation": "Landscape",
|
||||
}
|
||||
pdfkit.from_string(content, output_filename, options=options)
|
||||
|
||||
|
||||
def main():
|
||||
parser = ArgumentParser()
|
||||
|
||||
parser.add_argument(
|
||||
"--country",
|
||||
"-c",
|
||||
help="Country code for the holidays",
|
||||
required=False,
|
||||
default=None,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output", "-o", help="Output filename", required=False, default="calendar.pdf"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--date",
|
||||
"-d",
|
||||
help="Date to generate the calendar for",
|
||||
required=False,
|
||||
default=None,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--date-format",
|
||||
"-f",
|
||||
help="Date format to use",
|
||||
required=False,
|
||||
default="%b %d, %Y",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--type",
|
||||
"-t",
|
||||
help="Type of calendar to generate",
|
||||
required=False,
|
||||
default="weekly",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.country:
|
||||
country_code = args.country.upper()
|
||||
assert (
|
||||
country_code in holidays.list_supported_countries()
|
||||
), f"Country code {country_code} is not supported"
|
||||
|
||||
else:
|
||||
country_code = None
|
||||
|
||||
if args.date:
|
||||
try:
|
||||
for_date = parse(args.date).date()
|
||||
except ValueError:
|
||||
raise ValueError(f"Unrecognized date format {args.date}")
|
||||
else:
|
||||
for_date = None
|
||||
|
||||
if args.type != "weekly":
|
||||
raise NotImplementedError(f"Calendar type {args.type} is not supported")
|
||||
|
||||
week = get_week(for_date, country_code, args.date_format)
|
||||
html_content = generate_weekly_html(week)
|
||||
convert_html_to_pdf(html_content, args.output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
56
src/kalente/templates/weekly.html
Normal file
56
src/kalente/templates/weekly.html
Normal file
|
@ -0,0 +1,56 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
th {
|
||||
border: 1px solid black;
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
font-size: large;
|
||||
background-color: #dddddd;
|
||||
}
|
||||
td {
|
||||
border: 1px solid black;
|
||||
height: 675px;
|
||||
vertical-align: top;
|
||||
padding: 5px;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
.holiday {
|
||||
background-color: #ff9999; /* For holidays - Red */
|
||||
}
|
||||
.saturday {
|
||||
background-color: #99ccff; /* For Saturday - Blue */
|
||||
}
|
||||
.sunday {
|
||||
background-color: #99ff99; /* For Sunday - Green */
|
||||
}
|
||||
h2 {
|
||||
font-size: 32px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Weekly Calendar</h2>
|
||||
<table>
|
||||
<tr>
|
||||
{% for day in week %}
|
||||
<th>{{ day.day }}<br>{{ day.date }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
<tr>
|
||||
{% for day in week %}
|
||||
<td class="{% if day.holiday %}holiday{% elif day.is_weekend and day.day == 'Saturday' %}saturday{% elif day.is_weekend and day.day == 'Sunday' %}sunday{% endif %}">
|
||||
{% if day.holiday %}
|
||||
<b>{{ day.holiday }}</b>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue