tangled
alpha
login
or
join now
cuducos.me
/
triathlon-live-calendar
0
fork
atom
๐ Calendar file generator for triathlonlive.tv upcoming events
triathlon-live-calendar.fly.dev
0
fork
atom
overview
issues
pulls
pipelines
Refactors the logger
Eduardo Cuducos
4 years ago
0da40f94
e94afba1
+71
-15
3 changed files
expand all
collapse all
unified
split
triathlon_live_calendar
__main__.py
logger.py
scraper.py
+24
-4
triathlon_live_calendar/__main__.py
···
1
1
import asyncio
2
2
+
from logging import CRITICAL, DEBUG, ERROR, INFO, WARNING
2
3
from os import getenv
3
4
from pathlib import Path
4
5
from typing import Optional
5
6
6
6
-
from typer import Typer, Option
7
7
+
from typer import Typer, Option, echo
7
8
from uvicorn import run # type: ignore
8
9
9
10
from triathlon_live_calendar.calendar import calendar
···
12
13
13
14
DEFAULT_HOST = "0.0.0.0"
14
15
DEFAULT_PORT = 5000
16
16
+
DEFAULT_LOG_LEVEL = "info"
15
17
PORT_HELP = "[default: 5000 or PORT from environment variable]"
18
18
+
LEVELS = {
19
19
+
"critical": CRITICAL,
20
20
+
"error": ERROR,
21
21
+
"warning": WARNING,
22
22
+
"info": INFO,
23
23
+
"debug": DEBUG,
24
24
+
}
16
25
17
26
app = Typer()
18
27
···
27
36
return DEFAULT_PORT
28
37
29
38
39
39
+
def get_log_level(value: str) -> str:
40
40
+
if value not in LEVELS.keys():
41
41
+
echo(f"Invalid log level: {value}. Options are: {', '.join(LEVELS.keys())}")
42
42
+
return DEFAULT_LOG_LEVEL
43
43
+
44
44
+
return value
45
45
+
46
46
+
30
47
@app.command()
31
48
def web(
32
49
host: str = DEFAULT_HOST,
33
50
port: Optional[int] = Option(None, callback=get_port, help=PORT_HELP),
34
34
-
log_level: Optional[str] = None,
51
51
+
log_level: Optional[str] = Option(None, callback=get_log_level),
35
52
reload: Optional[bool] = None,
36
53
):
37
54
"""Starts the web server."""
···
46
63
47
64
48
65
@app.command()
49
49
-
def generate(path: Path, verbose: bool = False):
66
66
+
def generate(
67
67
+
path: Path,
68
68
+
log_level: str = Option(DEFAULT_LOG_LEVEL, callback=get_log_level),
69
69
+
):
50
70
"""Generates the calendar .ics file"""
51
51
-
logger = Logger(use_typer_echo=True) if verbose else None
71
71
+
logger = Logger(LEVELS[log_level])
52
72
contents = asyncio.run(calendar(logger))
53
73
path.write_text(str(contents))
54
74
+46
-10
triathlon_live_calendar/logger.py
···
1
1
-
import logging
2
1
from dataclasses import dataclass
2
2
+
from functools import cached_property, wraps
3
3
+
from logging import INFO, Formatter, StreamHandler, getLogger
4
4
+
from sys import stdout
3
5
from typing import Iterable, Union
4
6
5
5
-
from typer import echo
7
7
+
8
8
+
def multiline(func):
9
9
+
@wraps(func)
10
10
+
def normalized(self, text: Union[str, Iterable[str]]):
11
11
+
if not isinstance(text, str):
12
12
+
text = "\n".join(text)
13
13
+
14
14
+
return func(self, text)
15
15
+
16
16
+
return normalized
6
17
7
18
8
19
@dataclass
9
20
class Logger:
10
10
-
use_typer_echo: bool = False
21
21
+
log_level: int = INFO
11
22
12
12
-
def info(self, text: Union[str, Iterable[str]]) -> None:
13
13
-
if not isinstance(text, str):
14
14
-
text = "\n".join(text)
23
23
+
def __post_init__(self):
24
24
+
self.logger = getLogger()
25
25
+
self.logger.setLevel(self.log_level)
26
26
+
self.logger.addHandler(self.handler)
15
27
16
16
-
if self.use_typer_echo:
17
17
-
echo(text)
18
18
-
else:
19
19
-
logging.info(text)
28
28
+
@cached_property
29
29
+
def handler(self):
30
30
+
handler = StreamHandler(stdout)
31
31
+
handler.setLevel(self.log_level)
32
32
+
handler.setFormatter(
33
33
+
Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
34
34
+
)
35
35
+
return handler
36
36
+
37
37
+
@multiline
38
38
+
def critical(self, text):
39
39
+
self.logger.critical(text)
40
40
+
41
41
+
@multiline
42
42
+
def debug(self, text):
43
43
+
self.logger.debug(text)
44
44
+
45
45
+
@multiline
46
46
+
def error(self, text):
47
47
+
self.logger.error(text)
48
48
+
49
49
+
@multiline
50
50
+
def info(self, text):
51
51
+
self.logger.info(text)
52
52
+
53
53
+
@multiline
54
54
+
def warning(self, text):
55
55
+
self.logger.warning(text)
+1
-1
triathlon_live_calendar/scraper.py
···
37
37
if logger:
38
38
tz, *_ = tzname
39
39
local = begin.to(tz).format(DATETIME_FORMAT[:-2])
40
40
-
logger.info((f"Parsed {url}", f" Title: {title}", f" Begin: {local}"))
40
40
+
logger.debug((f"Parsed {url}", f" Title: {title}", f" Begin: {local}"))
41
41
42
42
return Event(
43
43
name=title,