From dc587f322aa3acae72579968050c6a3e09532b63 Mon Sep 17 00:00:00 2001 From: nicfb Date: Sun, 2 Oct 2022 00:50:02 -0500 Subject: [PATCH 1/5] feat: add event searching only parse from and to dates when searching toggle between date formats when searching refactoring change date formatting for searched events raise exception when search dates not given --- kosmorro/__main__.py | 116 +++++++++++++++++++++++++++++++++++++---- kosmorro/dumper.py | 7 ++- kosmorro/exceptions.py | 21 ++++++++ 3 files changed, 132 insertions(+), 12 deletions(-) diff --git a/kosmorro/__main__.py b/kosmorro/__main__.py index 5660cb4..18465a9 100644 --- a/kosmorro/__main__.py +++ b/kosmorro/__main__.py @@ -21,8 +21,15 @@ import sys 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 @@ -37,6 +44,7 @@ from .utils import ( ) from .exceptions import ( InvalidOutputFormatError, + SearchDatesNotGivenError, UnavailableFeatureError, OutOfRangeDateError as DateRangeError, ) @@ -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: @@ -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) @@ -204,6 +234,7 @@ 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())) @@ -211,6 +242,53 @@ def get_information( 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: + 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, @@ -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.") + ) parser.add_argument( "--no-colors", dest="colors", diff --git a/kosmorro/dumper.py b/kosmorro/dumper.py index 5d5c7e3..6a697dc 100644 --- a/kosmorro/dumper.py +++ b/kosmorro/dumper.py @@ -25,7 +25,7 @@ import subprocess 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 @@ -60,6 +60,7 @@ class Dumper(ABC): timezone: int, with_colors: bool, show_graph: bool, + search_enabled: bool, ): self.ephemerides = ephemerides self.moon_phase = moon_phase @@ -68,6 +69,7 @@ class Dumper(ABC): 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") @@ -220,9 +222,10 @@ class TextDumper(Dumper): 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, ] ) diff --git a/kosmorro/exceptions.py b/kosmorro/exceptions.py index c5e5ca3..68e4214 100644 --- a/kosmorro/exceptions.py +++ b/kosmorro/exceptions.py @@ -40,6 +40,19 @@ class OutOfRangeDateError(RuntimeError): ) +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__() @@ -53,6 +66,14 @@ class InvalidOutputFormatError(RuntimeError): ) +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__() From 16cbbb6db632537f9c810b3d2bf633a9c5a440ea Mon Sep 17 00:00:00 2001 From: nicfb Date: Thu, 3 Nov 2022 23:34:46 -0700 Subject: [PATCH 2/5] Parameter renamings, default start date to today --- kosmorro/__main__.py | 16 ++++++++-------- kosmorro/exceptions.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/kosmorro/__main__.py b/kosmorro/__main__.py index 18465a9..ee8cee2 100644 --- a/kosmorro/__main__.py +++ b/kosmorro/__main__.py @@ -120,7 +120,7 @@ def run(): output = get_search_information( args.search, args.from_, - args.to, + args.until, timezone, output_format, use_colors, @@ -245,20 +245,20 @@ def get_information( def get_search_information( requested_events: [EventType], search_from: date, - search_to: date, + search_until: date, timezone: int, output_format: str, colors: bool, show_graph: bool, ) -> dumper.Dumper: try: - if search_from is None or search_to is None: + if search_until is None: 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) + until = parse_date(search_until) + events_list = search_events(event_types, until, from_, timezone) return get_dumpers()[output_format]( ephemerides=[], @@ -398,11 +398,11 @@ def get_args(output_formats: [str]): "--from", dest="from_", type=str, - default=None, - help=_("The date to begin searching for events."), + default=today.strftime("%Y-%m-%d"), + help=_("The date to begin searching for events. Default is today."), ) parser.add_argument( - "--to", type=str, default=None, help=_("The date to end searching for events.") + "--until", type=str, default=None, help=_("The date to end searching for events.") ) parser.add_argument( "--no-colors", diff --git a/kosmorro/exceptions.py b/kosmorro/exceptions.py index 68e4214..5a6bb51 100644 --- a/kosmorro/exceptions.py +++ b/kosmorro/exceptions.py @@ -70,7 +70,7 @@ class SearchDatesNotGivenError(RuntimeError): def __init__(self): super().__init__() self.msg = _( - "Both 'from' and 'to' dates are required when searching for events." + "Search end date (--until) is required when searching events.'" ) From 1a030864af85d65a1fd06baf5fd44d3aca6de6f3 Mon Sep 17 00:00:00 2001 From: nicfb Date: Thu, 17 Nov 2022 22:31:26 -0800 Subject: [PATCH 3/5] gracefully exit when given invalid dates --- kosmorro/__main__.py | 19 +++++-------------- kosmorro/exceptions.py | 15 +-------------- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/kosmorro/__main__.py b/kosmorro/__main__.py index ee8cee2..1108878 100644 --- a/kosmorro/__main__.py +++ b/kosmorro/__main__.py @@ -135,6 +135,10 @@ def run(): use_colors, args.show_graph, ) + except InvalidDateRangeError as error: + print_stderr(colored(error, "red")) + debug.debug_print(error) + return 6 except SearchDatesNotGivenError as error: print_stderr(colored(error.msg, "red")) debug.debug_print(error) @@ -270,23 +274,10 @@ def get_search_information( 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) + raise DateRangeError(error.min_date, error.max_date) def get_dumpers() -> {str: dumper.Dumper}: diff --git a/kosmorro/exceptions.py b/kosmorro/exceptions.py index 5a6bb51..8229013 100644 --- a/kosmorro/exceptions.py +++ b/kosmorro/exceptions.py @@ -40,19 +40,6 @@ class OutOfRangeDateError(RuntimeError): ) -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__() @@ -70,7 +57,7 @@ class SearchDatesNotGivenError(RuntimeError): def __init__(self): super().__init__() self.msg = _( - "Search end date (--until) is required when searching events.'" + "Search end date (--until) is required when searching events." ) From 8ae5053471a2bec673937b6da8d50d5ab131ee99 Mon Sep 17 00:00:00 2001 From: nicfb Date: Mon, 21 Nov 2022 16:12:47 -0800 Subject: [PATCH 4/5] handle invalid events --- kosmorro/__main__.py | 13 +++++++++++-- kosmorro/exceptions.py | 12 ++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/kosmorro/__main__.py b/kosmorro/__main__.py index 1108878..fa5f051 100644 --- a/kosmorro/__main__.py +++ b/kosmorro/__main__.py @@ -47,6 +47,7 @@ from .exceptions import ( SearchDatesNotGivenError, UnavailableFeatureError, OutOfRangeDateError as DateRangeError, + InvalidEventTypeError, ) from kosmorro.i18n.utils import _ @@ -135,6 +136,10 @@ def run(): use_colors, args.show_graph, ) + except InvalidEventTypeError as error: + print_stderr(colored(error.msg, "red")) + debug.debug_print(error) + return 7 except InvalidDateRangeError as error: print_stderr(colored(error, "red")) debug.debug_print(error) @@ -258,8 +263,12 @@ def get_search_information( try: if search_until is None: raise SearchDatesNotGivenError - - event_types = [EventType[event.upper()] for event in requested_events] + + try: + event_types = [EventType[event.upper()] for event in requested_events] + except KeyError as error: + raise InvalidEventTypeError(error.args[0]) + from_ = parse_date(search_from) until = parse_date(search_until) events_list = search_events(event_types, until, from_, timezone) diff --git a/kosmorro/exceptions.py b/kosmorro/exceptions.py index 8229013..7ee91f5 100644 --- a/kosmorro/exceptions.py +++ b/kosmorro/exceptions.py @@ -19,6 +19,7 @@ from datetime import date from babel.dates import format_date from kosmorro.i18n.utils import _, SHORT_DATE_FORMAT +from kosmorrolib.enum import EventType class UnavailableFeatureError(RuntimeError): @@ -60,6 +61,17 @@ class SearchDatesNotGivenError(RuntimeError): "Search end date (--until) is required when searching events." ) +class InvalidEventTypeError(RuntimeError): + def __init__(self, invalid_event: EventType): + super().__init__() + self.invalid_event = invalid_event + supported_events = ', '.join([event.name for _, event in enumerate(EventType)]) + self.msg = _( + "Invalid event type {event}.\nSupported events are {events}." + ).format( + event=self.invalid_event, + events=supported_events, + ) class CompileError(RuntimeError): def __init__(self, msg): From 4a4d43888e552aafd4bcffcf1ba06a0ead316128 Mon Sep 17 00:00:00 2001 From: nicfb Date: Mon, 21 Nov 2022 16:19:17 -0800 Subject: [PATCH 5/5] code cleanup --- kosmorro/__main__.py | 9 ++- kosmorro/exceptions.py | 8 +-- kosmorro/locales/messages.pot | 100 +++++++++++++++++++++------------- 3 files changed, 71 insertions(+), 46 deletions(-) diff --git a/kosmorro/__main__.py b/kosmorro/__main__.py index fa5f051..2d81a30 100644 --- a/kosmorro/__main__.py +++ b/kosmorro/__main__.py @@ -263,12 +263,12 @@ def get_search_information( try: if search_until is None: raise SearchDatesNotGivenError - + try: event_types = [EventType[event.upper()] for event in requested_events] except KeyError as error: raise InvalidEventTypeError(error.args[0]) - + from_ = parse_date(search_from) until = parse_date(search_until) events_list = search_events(event_types, until, from_, timezone) @@ -402,7 +402,10 @@ def get_args(output_formats: [str]): help=_("The date to begin searching for events. Default is today."), ) parser.add_argument( - "--until", type=str, default=None, help=_("The date to end searching for events.") + "--until", + type=str, + default=None, + help=_("The date to end searching for events."), ) parser.add_argument( "--no-colors", diff --git a/kosmorro/exceptions.py b/kosmorro/exceptions.py index 7ee91f5..e43c88f 100644 --- a/kosmorro/exceptions.py +++ b/kosmorro/exceptions.py @@ -57,15 +57,14 @@ class InvalidOutputFormatError(RuntimeError): class SearchDatesNotGivenError(RuntimeError): def __init__(self): super().__init__() - self.msg = _( - "Search end date (--until) is required when searching events." - ) + self.msg = _("Search end date (--until) is required when searching events.") + class InvalidEventTypeError(RuntimeError): def __init__(self, invalid_event: EventType): super().__init__() self.invalid_event = invalid_event - supported_events = ', '.join([event.name for _, event in enumerate(EventType)]) + supported_events = ", ".join([event.name for _, event in enumerate(EventType)]) self.msg = _( "Invalid event type {event}.\nSupported events are {events}." ).format( @@ -73,6 +72,7 @@ class InvalidEventTypeError(RuntimeError): events=supported_events, ) + class CompileError(RuntimeError): def __init__(self, msg): super().__init__() diff --git a/kosmorro/locales/messages.pot b/kosmorro/locales/messages.pot index ec7403f..a48b017 100644 --- a/kosmorro/locales/messages.pot +++ b/kosmorro/locales/messages.pot @@ -8,103 +8,115 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2022-04-29 12:01+0000\n" +"POT-Creation-Date: 2022-11-21 16:17-0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.1\n" +"Generated-By: Babel 2.10.3\n" -#: kosmorro/__main__.py:82 +#: kosmorro/__main__.py:93 msgid "" "Save the planet and paper!\n" "Consider printing your PDF document only if really necessary, and use the" " other side of the sheet." msgstr "" -#: kosmorro/__main__.py:90 +#: kosmorro/__main__.py:101 msgid "" "PDF output will not contain the ephemerides, because you didn't provide " "the observation coordinates." msgstr "" -#: kosmorro/__main__.py:142 +#: kosmorro/__main__.py:181 msgid "The file could not be saved in \"{path}\": {error}" msgstr "" -#: kosmorro/__main__.py:156 +#: kosmorro/__main__.py:195 msgid "Please provide a file path to export in this format (--output)." msgstr "" -#: kosmorro/__main__.py:187 +#: kosmorro/__main__.py:226 msgid "Moon phase can only be computed between {min_date} and {max_date}" msgstr "" -#: kosmorro/__main__.py:238 +#: kosmorro/__main__.py:316 msgid "Running on Python {python_version} with Kosmorrolib v{kosmorrolib_version}" msgstr "" -#: kosmorro/__main__.py:251 +#: kosmorro/__main__.py:329 msgid "" "Compute the ephemerides and the events for a given date and a given " "position on Earth." msgstr "" -#: kosmorro/__main__.py:254 +#: kosmorro/__main__.py:332 msgid "" "By default, only the events will be computed for today.\n" "To compute also the ephemerides, latitude and longitude arguments are " "needed." msgstr "" -#: kosmorro/__main__.py:267 +#: kosmorro/__main__.py:345 msgid "Show the program version" msgstr "" -#: kosmorro/__main__.py:275 +#: kosmorro/__main__.py:353 msgid "" "The format to output the information to. If not provided, the output " "format will be inferred from the file extension of the output file." msgstr "" -#: kosmorro/__main__.py:285 +#: kosmorro/__main__.py:363 msgid "" "The observer's position on Earth, in the \"{latitude},{longitude}\" " "format. Can also be set in the KOSMORRO_POSITION environment variable." msgstr "" -#: kosmorro/__main__.py:295 +#: kosmorro/__main__.py:373 msgid "" "The date for which the ephemerides must be calculated. Can be in the " "YYYY-MM-DD format or an interval in the \"[+-]YyMmDd\" format (with Y, M," " and D numbers). Defaults to current date." msgstr "" -#: kosmorro/__main__.py:306 +#: kosmorro/__main__.py:384 msgid "" "The timezone to display the hours in (e.g. 2 for UTC+2 or -3 for UTC-3). " "Can also be set in the KOSMORRO_TIMEZONE environment variable." msgstr "" -#: kosmorro/__main__.py:315 +#: kosmorro/__main__.py:395 +msgid "Search for specific event types by date." +msgstr "" + +#: kosmorro/__main__.py:402 +msgid "The date to begin searching for events. Default is today." +msgstr "" + +#: kosmorro/__main__.py:408 +msgid "The date to end searching for events." +msgstr "" + +#: kosmorro/__main__.py:414 msgid "Disable the colors in the console." msgstr "" -#: kosmorro/__main__.py:322 +#: kosmorro/__main__.py:421 msgid "" "A file to export the output to. If not given, the standard output is " "used. This argument is needed for PDF format." msgstr "" -#: kosmorro/__main__.py:331 +#: kosmorro/__main__.py:430 msgid "" "Do not generate a graph to represent the rise and set times in the PDF " "format." msgstr "" -#: kosmorro/__main__.py:339 +#: kosmorro/__main__.py:438 msgid "Show debugging messages" msgstr "" @@ -118,76 +130,76 @@ msgid "" "offset format." msgstr "" -#: kosmorro/dumper.py:137 +#: kosmorro/dumper.py:139 msgid "Expected events:" msgstr "" -#: kosmorro/dumper.py:144 +#: kosmorro/dumper.py:146 msgid "Note: All the hours are given in UTC." msgstr "" -#: kosmorro/dumper.py:151 +#: kosmorro/dumper.py:153 msgid "Note: All the hours are given in the UTC{offset} timezone." msgstr "" -#: kosmorro/dumper.py:205 kosmorro/dumper.py:339 +#: kosmorro/dumper.py:207 kosmorro/dumper.py:342 msgid "Object" msgstr "" -#: kosmorro/dumper.py:206 kosmorro/dumper.py:340 +#: kosmorro/dumper.py:208 kosmorro/dumper.py:343 msgid "Rise time" msgstr "" -#: kosmorro/dumper.py:207 kosmorro/dumper.py:342 +#: kosmorro/dumper.py:209 kosmorro/dumper.py:345 msgid "Culmination time" msgstr "" -#: kosmorro/dumper.py:208 kosmorro/dumper.py:344 +#: kosmorro/dumper.py:210 kosmorro/dumper.py:347 msgid "Set time" msgstr "" -#: kosmorro/dumper.py:234 +#: kosmorro/dumper.py:237 msgid "Moon phase is unavailable for this date." msgstr "" -#: kosmorro/dumper.py:238 kosmorro/dumper.py:348 +#: kosmorro/dumper.py:241 kosmorro/dumper.py:351 msgid "Moon phase:" msgstr "" -#: kosmorro/dumper.py:242 +#: kosmorro/dumper.py:245 msgid "{next_moon_phase} on {next_moon_phase_date} at {next_moon_phase_time}" msgstr "" -#: kosmorro/dumper.py:312 +#: kosmorro/dumper.py:315 msgid "Overview of your sky" msgstr "" -#: kosmorro/dumper.py:320 +#: kosmorro/dumper.py:323 msgid "" "This document summarizes the ephemerides and the events of {date}. It " "aims to help you to prepare your observation session. All the hours are " "given in {timezone}." msgstr "" -#: kosmorro/dumper.py:330 +#: kosmorro/dumper.py:333 msgid "" "Don't forget to check the weather forecast before you go out with your " "equipment." msgstr "" -#: kosmorro/dumper.py:337 +#: kosmorro/dumper.py:340 msgid "Ephemerides of the day" msgstr "" -#: kosmorro/dumper.py:346 +#: kosmorro/dumper.py:349 msgid "hours" msgstr "" -#: kosmorro/dumper.py:353 +#: kosmorro/dumper.py:356 msgid "Expected events" msgstr "" -#: kosmorro/dumper.py:493 +#: kosmorro/dumper.py:496 msgid "" "Building PDF was not possible, because some dependencies are not " "installed.\n" @@ -195,7 +207,7 @@ msgid "" "pdf/ for more information." msgstr "" -#: kosmorro/dumper.py:542 +#: kosmorro/dumper.py:545 #, python-format msgid "" "An error occurred during the compilation of the PDF.\n" @@ -203,16 +215,26 @@ msgid "" "share the content of the log file at /tmp/kosmorro-%s.log" msgstr "" -#: kosmorro/exceptions.py:35 +#: kosmorro/exceptions.py:36 msgid "The date must be between {minimum_date} and {maximum_date}" msgstr "" -#: kosmorro/exceptions.py:48 +#: kosmorro/exceptions.py:49 msgid "" "Invalid output format: {output_format}. Output file must end with: " "{accepted_extensions}" msgstr "" +#: kosmorro/exceptions.py:60 +msgid "Search end date (--until) is required when searching events." +msgstr "" + +#: kosmorro/exceptions.py:68 +msgid "" +"Invalid event type {event}.\n" +"Supported events are {events}." +msgstr "" + #: kosmorro/geolocation.py:14 #, python-format msgid "The given position (%s) is not valid."