jrnl/jrnl/plugins/util.py
Aaron Lichtman a8bd0bcd44
Add calendar heatmap display format (#1759)
* Add calendar heatmap exporter

Fix #743

* Lint fixes

* More lint fixes

* Surface total number of entries per month in heatmap

* Refactoring

* More refactoring

* Resolve last lint error

* Unbump version

* Add calendar export test scaffolding

* WIP: Test debugging + scaffolding

* Remove broken tests

* Remove args from .vscode/launch.json

* Discard changes to tests/bdd/features/format.feature

* Remove extraneous vscode files

* move NestedDict to utils file

* run formatter

* fix import error

* Address lints

---------

Co-authored-by: Micah Jerome Ellison <micah.jerome.ellison@gmail.com>
Co-authored-by: Jonathan Wren <jonathan@nowandwren.com>
2024-10-01 18:59:26 -07:00

63 lines
2.1 KiB
Python

# Copyright © 2012-2023 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html
from collections import Counter
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from jrnl.journals import Journal
class NestedDict(dict):
"""https://stackoverflow.com/a/74873621/8740440"""
def __missing__(self, x):
self[x] = NestedDict()
return self[x]
def get_tags_count(journal: "Journal") -> set[tuple[int, str]]:
"""Returns a set of tuples (count, tag) for all tags present in the journal."""
# Astute reader: should the following line leave you as puzzled as me the first time
# I came across this construction, worry not and embrace the ensuing moment of
# enlightment.
tags = [tag for entry in journal.entries for tag in set(entry.tags)]
# To be read: [for entry in journal.entries: for tag in set(entry.tags): tag]
tag_counts = {(tags.count(tag), tag) for tag in tags}
return tag_counts
def oxford_list(lst: list) -> str:
"""Return Human-readable list of things obeying the object comma)"""
lst = sorted(lst)
if not lst:
return "(nothing)"
elif len(lst) == 1:
return lst[0]
elif len(lst) == 2:
return lst[0] + " or " + lst[1]
else:
return ", ".join(lst[:-1]) + ", or " + lst[-1]
def get_journal_frequency_nested(journal: "Journal") -> NestedDict:
"""Returns a NestedDict of the form {year: {month: {day: count}}}"""
journal_frequency = NestedDict()
for entry in journal.entries:
date = entry.date.date()
if date.day in journal_frequency[date.year][date.month]:
journal_frequency[date.year][date.month][date.day] += 1
else:
journal_frequency[date.year][date.month][date.day] = 1
return journal_frequency
def get_journal_frequency_one_level(journal: "Journal") -> Counter:
"""Returns a Counter of the form {date (YYYY-MM-DD): count}"""
date_counts = Counter()
for entry in journal.entries:
# entry.date.date() gets date without time
date = str(entry.date.date())
date_counts[date] += 1
return date_counts