Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add search #287

Draft
wants to merge 6 commits into
base: features
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 106 additions & 10 deletions kosmorro/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,15 @@
import os.path

from babel.dates import format_date
from kosmorrolib import Position, get_ephemerides, get_events, get_moon_phase
from kosmorrolib.exceptions import OutOfRangeDateError
from kosmorrolib import (
Position,
get_ephemerides,
get_events,
get_moon_phase,
search_events,
)
from kosmorrolib.exceptions import OutOfRangeDateError, InvalidDateRangeError
from kosmorrolib.enum import EventType
from datetime import date

from . import dumper, environment, debug
Expand All @@ -37,6 +44,7 @@
)
from .exceptions import (
InvalidOutputFormatError,
SearchDatesNotGivenError,
UnavailableFeatureError,
OutOfRangeDateError as DateRangeError,
)
Expand All @@ -55,6 +63,8 @@ def run():
if args.special_action is not None:
return 0 if args.special_action() else 1

search_enabled = args.search is not None

try:
compute_date = parse_date(args.date)
except ValueError as error:
Expand Down Expand Up @@ -105,14 +115,34 @@ def run():
try:
use_colors = not environment.NO_COLOR and args.colors

output = get_information(
compute_date,
position,
timezone,
output_format,
use_colors,
args.show_graph,
)
output = None
if search_enabled:
output = get_search_information(
args.search,
args.from_,
args.to,
timezone,
output_format,
use_colors,
args.show_graph,
)
else:
output = get_information(
compute_date,
position,
timezone,
output_format,
use_colors,
args.show_graph,
)
except SearchDatesNotGivenError as error:
print_stderr(colored(error.msg, "red"))
debug.debug_print(error)
return 5
except ValueError as error:
print_stderr(colored(error.args[0], color="red", attrs=["bold"]))
debug.debug_print(error)
return 4
except InvalidOutputFormatError as error:
print_stderr(colored(error.msg, "red"))
debug.debug_print(error)
Expand Down Expand Up @@ -204,13 +234,61 @@ def get_information(
timezone=timezone,
with_colors=colors,
show_graph=show_graph,
search_enabled=False,
)
except KeyError as error:
raise InvalidOutputFormatError(output_format, list(get_dumpers().keys()))
except OutOfRangeDateError as error:
raise DateRangeError(error.min_date, error.max_date)


def get_search_information(
requested_events: [EventType],
search_from: date,
search_to: date,
timezone: int,
output_format: str,
colors: bool,
show_graph: bool,
) -> dumper.Dumper:
try:
if search_from is None or search_to is None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm realizing that if user doesn't provide the --from argument, we could assert that we want to search from the current date by default? What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that makes sense to me!

raise SearchDatesNotGivenError

event_types = [EventType[event.upper()] for event in requested_events]
from_ = parse_date(search_from)
to = parse_date(search_to)
events_list = search_events(event_types, to, from_, timezone)

return get_dumpers()[output_format](
ephemerides=[],
moon_phase=None,
events=events_list,
date=None,
timezone=timezone,
with_colors=colors,
show_graph=show_graph,
search_enabled=True,
)
except InvalidDateRangeError as error:
print(
colored(
_(
"Search start date {start_search} must be before end date {end_search}"
).format(
start_search=format_date(error.start_date, "long"),
end_search=format_date(error.end_date, "long"),
),
"red",
)
)
except KeyError as error:
raise InvalidOutputFormatError(output_format, list(get_dumpers().keys()))
except OutOfRangeDateError as error:
print(colored(error.msg, "red"))
debug.debug_print(error)


def get_dumpers() -> {str: dumper.Dumper}:
return {
"txt": dumper.TextDumper,
Expand Down Expand Up @@ -308,6 +386,24 @@ def get_args(output_formats: [str]):
"Can also be set in the KOSMORRO_TIMEZONE environment variable."
),
)
parser.add_argument(
"--search",
"-s",
type=str,
nargs="*",
default=None,
help=_("Search for specific event types by date."),
)
parser.add_argument(
"--from",
dest="from_",
type=str,
default=None,
help=_("The date to begin searching for events."),
)
parser.add_argument(
"--to", type=str, default=None, help=_("The date to end searching for events.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we make --from optional as proposed, then we should perhaps rename this argument to --until?

)
parser.add_argument(
"--no-colors",
dest="colors",
Expand Down
7 changes: 5 additions & 2 deletions kosmorro/dumper.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import shutil
from pathlib import Path

from babel.dates import format_date, format_time
from babel.dates import format_date, format_time, format_datetime
from tabulate import tabulate
from termcolor import colored

Expand Down Expand Up @@ -60,6 +60,7 @@ def __init__(
timezone: int,
with_colors: bool,
show_graph: bool,
search_enabled: bool,
):
self.ephemerides = ephemerides
self.moon_phase = moon_phase
Expand All @@ -68,6 +69,7 @@ def __init__(
self.timezone = timezone
self.with_colors = with_colors
self.show_graph = show_graph
self.search_enabled = search_enabled

def get_date_as_string(self, capitalized: bool = False) -> str:
date = format_date(self.date, "full")
Expand Down Expand Up @@ -220,9 +222,10 @@ def get_events(self, events: [Event]) -> str:
if description is None:
continue

date_format = "MMM dd, yyyy hh:mm a" if self.search_enabled else "hh:mm a"
data.append(
[
self.style(format_time(event.start_time, "short"), "th"),
self.style(format_datetime(event.start_time, date_format), "th"),
description,
]
)
Expand Down
21 changes: 21 additions & 0 deletions kosmorro/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@ def __init__(self, min_date: date, max_date: date):
)


class InvalidDateRangeError(RuntimeError):
def __init__(self, start_date: date, end_date: date):
super().__init__()
self.start_date = start_date
self.end_date = end_date
self.msg = _(
"The start date {starting_date} must be before the end date {ending_date}"
).format(
starting_date=format_date(start_date, "long"),
ending_date=format_date(end_date, "long"),
)


class InvalidOutputFormatError(RuntimeError):
def __init__(self, output_format: str, accepted_extensions: [str]):
super().__init__()
Expand All @@ -53,6 +66,14 @@ def __init__(self, output_format: str, accepted_extensions: [str]):
)


class SearchDatesNotGivenError(RuntimeError):
def __init__(self):
super().__init__()
self.msg = _(
"Both 'from' and 'to' dates are required when searching for events."
)


class CompileError(RuntimeError):
def __init__(self, msg):
super().__init__()
Expand Down