Add support to save journals to multiple files in a directory

Update FolderJournal reference to entry __unicode__ method to __str__
Remove DayOne test made obsolete by FolderJournal
Fix FolderJournal path tests for Windows paths
Apply Black linting
This commit is contained in:
Micah Jerome Ellison 2020-02-29 12:35:05 -08:00
parent a3c81d46fe
commit 6985de2844
5 changed files with 37 additions and 32 deletions

View file

@ -23,9 +23,3 @@ Feature: Zapped Dayone bugs stay dead!
2014-04-24 09:00 Ran 6.2 miles today in 1:02:03. 2014-04-24 09:00 Ran 6.2 miles today in 1:02:03.
| I'm feeling sore because I forgot to stretch. | I'm feeling sore because I forgot to stretch.
""" """
Scenario: Opening an folder that's not a DayOne folder gives a nice error message
Given we use the config "empty_folder.yaml"
When we run "jrnl Herro"
Then we should get an error
Then we should see the message "is a directory, but doesn't seem to be a DayOne journal either"

View file

@ -15,7 +15,7 @@ Feature: Testing a journal with a root directory and multiple files in the forma
When we run "jrnl 23 July 2013: Testing folder journal." When we run "jrnl 23 July 2013: Testing folder journal."
Then we should see the message "Entry added" Then we should see the message "Entry added"
When the journal directory is listed When the journal directory is listed
Then the output should contain "2013/07/23.txt" Then the output should contain "2013/07/23.txt" or "2013\07\23.txt"
Scenario: Adding multiple entries to a Folder journal should generate multiple date files Scenario: Adding multiple entries to a Folder journal should generate multiple date files
@ -24,9 +24,8 @@ Feature: Testing a journal with a root directory and multiple files in the forma
And we run "jrnl 3/7/2014: Second entry of journal." And we run "jrnl 3/7/2014: Second entry of journal."
Then we should see the message "Entry added" Then we should see the message "Entry added"
When the journal directory is listed When the journal directory is listed
Then the output should contain "2013/07/23.txt" Then the output should contain "2013/07/23.txt" or "2013\07\23.txt"
And the output should contain "2014/03/07.txt" Then the output should contain "2014/03/07.txt" or "2014\03\07.txt"
Scenario: Out of order entries to a Folder journal should be listed in date order Scenario: Out of order entries to a Folder journal should be listed in date order
Given we use the config "empty_folder.yaml" Given we use the config "empty_folder.yaml"

View file

@ -210,10 +210,11 @@ def check_output_time_inline(context, text):
@then("the output should contain") @then("the output should contain")
@then('the output should contain "{text}"') @then('the output should contain "{text}"')
def check_output_inline(context, text=None): @then('the output should contain "{text}" or "{text2}"')
def check_output_inline(context, text=None, text2=None):
text = text or context.text text = text or context.text
out = context.stdout_capture.getvalue() out = context.stdout_capture.getvalue()
assert text in out, text assert text in out or text2 in out, text or text2
@then('the output should not contain "{text}"') @then('the output should not contain "{text}"')
@ -269,15 +270,17 @@ def check_journal_entries(context, number, journal_name="default"):
journal = open_journal(journal_name) journal = open_journal(journal_name)
assert len(journal.entries) == number assert len(journal.entries) == number
@when('the journal directory is listed')
@when("the journal directory is listed")
def list_journal_directory(context, journal="default"): def list_journal_directory(context, journal="default"):
files=[] files = []
with open(install.CONFIG_FILE_PATH) as config_file: with open(install.CONFIG_FILE_PATH) as config_file:
config = yaml.load(config_file, Loader=yaml.FullLoader) config = yaml.load(config_file, Loader=yaml.FullLoader)
journal_path = config['journals'][journal] journal_path = config["journals"][journal]
for root, dirnames, f in os.walk(journal_path): for root, dirnames, f in os.walk(journal_path):
for file in f: for file in f:
print(os.path.join(root,file)) print(os.path.join(root, file))
@then("fail") @then("fail")
def debug_fail(context): def debug_fail(context):

View file

@ -23,7 +23,7 @@ def make_key(password):
length=32, length=32,
# Salt is hard-coded # Salt is hard-coded
salt=b"\xf2\xd5q\x0e\xc1\x8d.\xde\xdc\x8e6t\x89\x04\xce\xf8", salt=b"\xf2\xd5q\x0e\xc1\x8d.\xde\xdc\x8e6t\x89\x04\xce\xf8",
iterations=100000, iterations=100_000,
backend=default_backend(), backend=default_backend(),
) )
key = kdf.derive(password) key = kdf.derive(password)

View file

@ -8,11 +8,12 @@ import codecs
import os import os
import fnmatch import fnmatch
def get_files(journal_config): def get_files(journal_config):
"""Searches through sub directories starting with journal_config and find all text files""" """Searches through sub directories starting with journal_config and find all text files"""
filenames = [] filenames = []
for root, dirnames, f in os.walk(journal_config): for root, dirnames, f in os.walk(journal_config):
for filename in fnmatch.filter(f, '*.txt'): for filename in fnmatch.filter(f, "*.txt"):
filenames.append(os.path.join(root, filename)) filenames.append(os.path.join(root, filename))
return filenames return filenames
@ -25,11 +26,10 @@ class Folder(Journal.Journal):
self._diff_entry_dates = [] self._diff_entry_dates = []
super(Folder, self).__init__(**kwargs) super(Folder, self).__init__(**kwargs)
def open(self): def open(self):
filenames = [] filenames = []
self.entries = [] self.entries = []
filenames = get_files(self.config['journal']) filenames = get_files(self.config["journal"])
for filename in filenames: for filename in filenames:
with codecs.open(filename, "r", "utf-8") as f: with codecs.open(filename, "r", "utf-8") as f:
journal = f.read() journal = f.read()
@ -39,7 +39,7 @@ class Folder(Journal.Journal):
def write(self): def write(self):
"""Writes only the entries that have been modified into proper files.""" """Writes only the entries that have been modified into proper files."""
#Create a list of dates of modified entries. Start with diff_entry_dates # Create a list of dates of modified entries. Start with diff_entry_dates
modified_dates = self._diff_entry_dates modified_dates = self._diff_entry_dates
seen_dates = set(self._diff_entry_dates) seen_dates = set(self._diff_entry_dates)
for e in self.entries: for e in self.entries:
@ -48,26 +48,35 @@ class Folder(Journal.Journal):
modified_dates.append(e.date) modified_dates.append(e.date)
seen_dates.add(e.date) seen_dates.add(e.date)
#For every date that had a modified entry, write to a file # For every date that had a modified entry, write to a file
for d in modified_dates: for d in modified_dates:
write_entries=[] write_entries = []
filename = os.path.join(self.config['journal'], d.strftime("%Y"), d.strftime("%m"), d.strftime("%d")+".txt") filename = os.path.join(
self.config["journal"],
d.strftime("%Y"),
d.strftime("%m"),
d.strftime("%d") + ".txt",
)
dirname = os.path.dirname(filename) dirname = os.path.dirname(filename)
#create directory if it doesn't exist # create directory if it doesn't exist
if not os.path.exists(dirname): if not os.path.exists(dirname):
os.makedirs(dirname) os.makedirs(dirname)
for e in self.entries: for e in self.entries:
if e.date.year == d.year and e.date.month == d.month and e.date.day == d.day: if (
e.date.year == d.year
and e.date.month == d.month
and e.date.day == d.day
):
write_entries.append(e) write_entries.append(e)
journal = "\n".join([e.__unicode__() for e in write_entries]) journal = "\n".join([e.__str__() for e in write_entries])
with codecs.open(filename, 'w', "utf-8") as journal_file: with codecs.open(filename, "w", "utf-8") as journal_file:
journal_file.write(journal) journal_file.write(journal)
#look for and delete empty files # look for and delete empty files
filenames = [] filenames = []
filenames = get_files(self.config['journal']) filenames = get_files(self.config["journal"])
for filename in filenames: for filename in filenames:
if os.stat(filename).st_size <= 0: if os.stat(filename).st_size <= 0:
#print("empty file: {}".format(filename)) # print("empty file: {}".format(filename))
os.remove(filename) os.remove(filename)
def parse_editable_str(self, edited): def parse_editable_str(self, edited):