Add new -today-in-history, -month, -day, and -year search filters (#1145)

* Introduce -reminisce, -month, -day, and -year
* Update expected_args in parse_args tests
* Add check before creating compare_d
* Misc changes
* Implement testing for -month, -day, -year, and -reminisce
* Compress tests into one Scenario Outline
* Fix failing tests by updating dates_similar journal
* Create 'we set current date and time to' step
* Use time.parse in reminisce
* Update dates_similar journal
* Make 'Searching in a journal' test shorter
* Lint
* Implement reminiscing test
* Add combination tests
* Finalize tests
* Finalize pytests
* Simplify reminisce tests
* Change reminsice help (since it also shows today's entries)
* Re-do tests; use various tests
* Remove old test data
* Better scenario description
* Standardize format for compare_d
* Rename -reminisce to -today-in-history
This commit is contained in:
Karim Rahal 2021-01-17 00:55:27 +02:00 committed by GitHub
parent 18058c74e5
commit f0e8fa2060
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 184 additions and 0 deletions

View file

@ -214,6 +214,96 @@ Feature: Searching in a journal
| But I'm better. | But I'm better.
""" """
Scenario Outline: Searching by month
Given we use the config "<config>.yaml"
And we use the password "test" if prompted
When we run "jrnl -month 9 --short"
Then the output should be "2020-09-24 09:14 The third entry finally after weeks without writing."
And we flush the output
When we run "jrnl -month Sept --short"
Then the output should be "2020-09-24 09:14 The third entry finally after weeks without writing."
And we flush the output
When we run "jrnl -month September --short"
Then the output should be "2020-09-24 09:14 The third entry finally after weeks without writing."
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
| basic_dayone |
Scenario Outline: Searching by day
Given we use the config "<config>.yaml"
And we use the password "test" if prompted
When we run "jrnl -day 31 --short"
Then the output should be "2020-08-31 14:32 A second entry in what I hope to be a long series."
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
| basic_dayone |
Scenario Outline: Searching by year
Given we use the config "<config>.yaml"
And we use the password "test" if prompted
When we run "jrnl 2019-01-01 01:01: I like this year."
And we run "jrnl -year 2019 --short"
Then the output should be "2019-01-01 01:01 I like this year."
And we flush the output
When we run "jrnl -year 19 --short"
Then the output should be "2019-01-01 01:01 I like this year."
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
| basic_dayone |
Scenario Outline: Combining month, day, and year search terms
Given we use the config "<config>.yaml"
And we use the password "test" if prompted
When we run "jrnl -month 08 -day 29 --short"
Then the output should be "2020-08-29 11:11 Entry the first."
And we flush the output
When we run "jrnl -day 29 -year 2020 --short"
Then the output should be "2020-08-29 11:11 Entry the first."
And we flush the output
When we run "jrnl -month 09 -year 2020 --short"
Then the output should be "2020-09-24 09:14 The third entry finally after weeks without writing."
And we flush the output
When we run "jrnl -month 08 -day 29 -year 2020 --short"
Then the output should be "2020-08-29 11:11 Entry the first."
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
| basic_dayone |
Scenario Outline: Searching today in history
Given we use the config "<config>.yaml"
And we use the password "test" if prompted
And we set current date and time to "2020-08-31 14:32"
When we run "jrnl 2019-08-31 01:01: Hi, from last year."
And we run "jrnl -today-in-history --short"
Then the output should be
"""
2019-08-31 01:01 Hi, from last year.
2020-08-31 14:32 A second entry in what I hope to be a long series.
"""
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
| basic_dayone |
Scenario: Loading a DayOne Journal Scenario: Loading a DayOne Journal
Given we use the config "dayone.yaml" Given we use the config "dayone.yaml"
When we run "jrnl -from 'feb 2013'" When we run "jrnl -from 'feb 2013'"

View file

@ -17,6 +17,7 @@ import keyring
import toml import toml
import yaml import yaml
import jrnl.time
from jrnl import Journal from jrnl import Journal
from jrnl import __version__ from jrnl import __version__
from jrnl import plugins from jrnl import plugins
@ -159,6 +160,11 @@ def disable_keyring(context):
keyring.core.set_keyring(NoKeyring()) keyring.core.set_keyring(NoKeyring())
@given('we set current date and time to "{dt}"')
def set_datetime(context, dt):
context.now = dt
@when('we change directory to "{path}"') @when('we change directory to "{path}"')
def move_up_dir(context, path): def move_up_dir(context, path):
os.chdir(path) os.chdir(path)
@ -197,6 +203,7 @@ def open_editor_and_enter(context, method, text=""):
patch("subprocess.call", side_effect=_mock_editor) as mock_editor, \ patch("subprocess.call", side_effect=_mock_editor) as mock_editor, \
patch("getpass.getpass", side_effect=_mock_getpass(password)) as mock_getpass, \ patch("getpass.getpass", side_effect=_mock_getpass(password)) as mock_getpass, \
patch("sys.stdin.isatty", return_value=True), \ patch("sys.stdin.isatty", return_value=True), \
patch("jrnl.time.parse", side_effect=_mock_time_parse(context)), \
patch("jrnl.config.get_config_path", side_effect=lambda: context.config_path), \ patch("jrnl.config.get_config_path", side_effect=lambda: context.config_path), \
patch("jrnl.install.get_config_path", side_effect=lambda: context.config_path) \ patch("jrnl.install.get_config_path", side_effect=lambda: context.config_path) \
: :
@ -289,6 +296,18 @@ def _mock_input(inputs):
return prompt_return return prompt_return
def _mock_time_parse(context):
original_parse = jrnl.time.parse
if "now" not in context:
return original_parse
def wrapper(input, *args, **kwargs):
input = context.now if input == "now" else input
return original_parse(input, *args, **kwargs)
return wrapper
@when('we run "{command}" and enter') @when('we run "{command}" and enter')
@when('we run "{command}" and enter nothing') @when('we run "{command}" and enter nothing')
@when('we run "{command}" and enter "{inputs}"') @when('we run "{command}" and enter "{inputs}"')
@ -322,6 +341,7 @@ def run_with_input(context, command, inputs=""):
patch("getpass.getpass", side_effect=_mock_getpass(password)) as mock_getpass, \ patch("getpass.getpass", side_effect=_mock_getpass(password)) as mock_getpass, \
patch("sys.stdin.read", side_effect=text) as mock_read, \ patch("sys.stdin.read", side_effect=text) as mock_read, \
patch("subprocess.call", side_effect=_mock_editor) as mock_editor, \ patch("subprocess.call", side_effect=_mock_editor) as mock_editor, \
patch("jrnl.time.parse", side_effect=_mock_time_parse(context)), \
patch("jrnl.config.get_config_path", side_effect=lambda: context.config_path), \ patch("jrnl.config.get_config_path", side_effect=lambda: context.config_path), \
patch("jrnl.install.get_config_path", side_effect=lambda: context.config_path) \ patch("jrnl.install.get_config_path", side_effect=lambda: context.config_path) \
: :
@ -406,6 +426,7 @@ def run(context, command, text=""):
patch("getpass.getpass", side_effect=_mock_getpass(password)) as mock_getpass, \ patch("getpass.getpass", side_effect=_mock_getpass(password)) as mock_getpass, \
patch("subprocess.call", side_effect=_mock_editor) as mock_editor, \ patch("subprocess.call", side_effect=_mock_editor) as mock_editor, \
patch("sys.stdin.read", side_effect=lambda: text), \ patch("sys.stdin.read", side_effect=lambda: text), \
patch("jrnl.time.parse", side_effect=_mock_time_parse(context)), \
patch("jrnl.config.get_config_path", side_effect=lambda: context.config_path), \ patch("jrnl.config.get_config_path", side_effect=lambda: context.config_path), \
patch("jrnl.install.get_config_path", side_effect=lambda: context.config_path) \ patch("jrnl.install.get_config_path", side_effect=lambda: context.config_path) \
: :

View file

@ -189,6 +189,9 @@ class Journal:
def filter( def filter(
self, self,
tags=[], tags=[],
month=None,
day=None,
year=None,
start_date=None, start_date=None,
end_date=None, end_date=None,
starred=False, starred=False,
@ -220,11 +223,19 @@ class Journal:
if contains: if contains:
contains_lower = contains.casefold() contains_lower = contains.casefold()
# Create datetime object for comparison below
# this approach allows various formats
if month or day or year:
compare_d = time.parse(f"{month or 1}.{day or 1}.{year or 1}")
result = [ result = [
entry entry
for entry in self.entries for entry in self.entries
if (not tags or tagged(entry.tags)) if (not tags or tagged(entry.tags))
and (not starred or entry.starred) and (not starred or entry.starred)
and (not month or entry.date.month == compare_d.month)
and (not day or entry.date.day == compare_d.day)
and (not year or entry.date.year == compare_d.year)
and (not start_date or entry.date >= start_date) and (not start_date or entry.date >= start_date)
and (not end_date or entry.date <= end_date) and (not end_date or entry.date <= end_date)
and (not exclude or not excluded(entry.tags)) and (not exclude or not excluded(entry.tags))

View file

@ -176,6 +176,30 @@ def parse_args(args=[]):
reading.add_argument( reading.add_argument(
"-on", dest="on_date", metavar="DATE", help="Show entries on this date" "-on", dest="on_date", metavar="DATE", help="Show entries on this date"
) )
reading.add_argument(
"-today-in-history",
dest="today_in_history",
action="store_true",
help="Show entries of today over the years",
)
reading.add_argument(
"-month",
dest="month",
metavar="DATE",
help="Show entries on this month of any year",
)
reading.add_argument(
"-day",
dest="day",
metavar="DATE",
help="Show entries on this day of any month",
)
reading.add_argument(
"-year",
dest="year",
metavar="DATE",
help="Show entries of a specific year",
)
reading.add_argument( reading.add_argument(
"-from", "-from",
dest="start_date", dest="start_date",

View file

@ -15,6 +15,7 @@ from .config import get_config_path
from .editor import get_text_from_editor from .editor import get_text_from_editor
from .editor import get_text_from_stdin from .editor import get_text_from_stdin
from .exception import UserAbort from .exception import UserAbort
from . import time
def run(args): def run(args):
@ -77,6 +78,10 @@ def _is_write_mode(args, config, **kwargs):
args.edit, args.edit,
args.export, args.export,
args.end_date, args.end_date,
args.today_in_history,
args.month,
args.day,
args.year,
args.limit, args.limit,
args.on_date, args.on_date,
args.short, args.short,
@ -206,8 +211,16 @@ def _search_journal(args, journal, **kwargs):
if args.on_date: if args.on_date:
args.start_date = args.end_date = args.on_date args.start_date = args.end_date = args.on_date
if args.today_in_history:
now = time.parse("now")
args.day = now.day
args.month = now.month
journal.filter( journal.filter(
tags=args.text, tags=args.text,
month=args.month,
day=args.day,
year=args.year,
start_date=args.start_date, start_date=args.start_date,
end_date=args.end_date, end_date=args.end_date,
strict=args.strict, strict=args.strict,

View file

@ -18,6 +18,10 @@ def expected_args(**kwargs):
"delete": False, "delete": False,
"edit": False, "edit": False,
"end_date": None, "end_date": None,
"today_in_history": False,
"month": None,
"day": None,
"year": None,
"excluded": [], "excluded": [],
"export": False, "export": False,
"filename": None, "filename": None,
@ -147,6 +151,27 @@ def test_on_date_alone():
assert cli_as_dict("-on 'saturday'") == expected_args(on_date="saturday") assert cli_as_dict("-on 'saturday'") == expected_args(on_date="saturday")
def test_month_alone():
assert cli_as_dict("-month 1") == expected_args(month="1")
assert cli_as_dict("-month 01") == expected_args(month="01")
assert cli_as_dict("-month January") == expected_args(month="January")
assert cli_as_dict("-month Jan") == expected_args(month="Jan")
def test_day_alone():
assert cli_as_dict("-day 1") == expected_args(day="1")
assert cli_as_dict("-day 01") == expected_args(day="01")
def test_year_alone():
assert cli_as_dict("-year 2021") == expected_args(year="2021")
assert cli_as_dict("-year 21") == expected_args(year="21")
def test_today_in_history_alone():
assert cli_as_dict("-today-in-history") == expected_args(today_in_history=True)
def test_short_alone(): def test_short_alone():
assert cli_as_dict("--short") == expected_args(short=True) assert cli_as_dict("--short") == expected_args(short=True)