Files
tagtimepy/ping.py

79 lines
3.0 KiB
Python

import re
import datetime
from dataclasses import dataclass
from typing import List
@dataclass
class Ping:
"""
A ping is a single line in the log file consisting of a UNIX time stamp,
followed by tags (where each individual string surrounded by spaces is a
tag), followed by optional comments between square brackets or parentheses.
The original Perl implementation puts a human readable representation of
the UNIX time stamp into square brackets. Here are two example pings:
1601557948 morning_pages [2020.10.01 09:12:28 THU]
1601560369 work_call another_tag [2020.10.01 09:52:49 THU]
"""
time: int # UNIX time stamp
tags: List[str] # each separate word is a tag
comments: List[str] # each string between [] or () is a comment
line: str = "" # the whole line as found in the log file
r_time = re.compile("^\s*\d{9,11}")
r_spaces = re.compile("\s+")
r_comment_parens = re.compile("\(([^\)]*)\)")
r_comment_square = re.compile("\[([^\]]*)\]")
def line_to_ping(line: str):
"""
Parses a string into a Ping object. Raises Exception on failure.
>>> line_to_ping(" 1601557948 t (c)")
Ping(time=1601557948, tags=['t'], comments=['c'], line=' 1601557948 t (c)')
"""
time = int(Ping.r_time.match(line).group())
tags = Ping.get_tags(line)
comments = Ping.r_comment_parens.findall(line) + \
Ping.r_comment_square.findall(line)
return Ping(time, tags, comments, line)
def get_tags(line):
"""Extracts the tags from a tag line."""
line = Ping.r_time.sub("", line)
line = Ping.r_comment_parens.sub("", line)
line = Ping.r_comment_square.sub("", line)
line = Ping.r_spaces.sub(" ", line)
return line.split()
def ping_to_line(ping, annotate_time=False, line_length=79) -> str:
tags = " ".join([t.strip() for t in ping.tags])
comments = " ".join(["[" + c.strip() + "]" for c in ping.comments])
line = "{} {} {}".format(ping.time, tags, comments)
if annotate_time:
line = Ping.add_time_annotation(ping.time, line, line_length)
return line
def add_time_annotation(time: int, line: str, line_length: int) -> str:
"""Appends human readable date/time in square brackets to line."""
remaining_length = line_length - len(line)
if remaining_length > 24:
strf = " [%Y.%m.%d %H:%M:%S %a]"
elif remaining_length > 18:
strf = " [%m.%d %H:%M:%S %a]"
elif remaining_length > 15:
strf = " [%d %H:%M:%S %a]"
elif remaining_length > 12:
strf = " [%H:%M:%S %a]"
elif remaining_length > 9:
strf = " [%H:%M %a]"
elif remaining_length > 5:
strf = " [%H:%M]"
else:
strf = " [%M]"
time_comment = datetime.datetime.fromtimestamp(time).strftime(strf)
remaining_length -= len(time_comment)
line += " " * remaining_length + time_comment
return line