diff --git a/.scripts/tests-e2e.sh b/.scripts/tests-e2e.sh index 2595e86..3c59ef2 100644 --- a/.scripts/tests-e2e.sh +++ b/.scripts/tests-e2e.sh @@ -77,20 +77,24 @@ assertSuccess "$PYTHON_BIN setup.py sdist" assertSuccess "$PIP_BIN install dist/kosmorro-$VERSION.tar.gz" "CI" assertSuccess kosmorro +assertSuccess "kosmorro -h" +assertSuccess "kosmorro -d 2020-01-27" +assertFailure "kosmorro -d yolo-yo-lo" +assertFailure "kosmorro -d 2020-13-32" assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624" -assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624 -d 27 -m 1 -y 2020" -assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624 -d 27 -m 1 -y 2020 --timezone=1" -assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624 -d 27 -m 1 -y 2020 --timezone=-1" -assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624 -d 27 -m 1 -y 2020 --format=json" -assertFailure "kosmorro --latitude=50.5876 --longitude=3.0624 -d 27 -m 1 -y 2020 --format=pdf" +assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624 -d 2020-01-27" +assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624 -d 2020-01-27 --timezone=1" +assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624 -d 2020-01-27 --timezone=-1" +assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624 -d 2020-01-27 --format=json" +assertFailure "kosmorro --latitude=50.5876 --longitude=3.0624 -d 2020-01-27 --format=pdf" # Missing dependencies, should fail -assertFailure "kosmorro --latitude=50.5876 --longitude=3.0624 -d 27 -m 1 -y 2020 --format=pdf -o /tmp/document.pdf" +assertFailure "kosmorro --latitude=50.5876 --longitude=3.0624 -d 2020-01-27 --format=pdf -o /tmp/document.pdf" assertSuccess "sudo apt-get install -y texlive" "CI" assertSuccess "$PIP_BIN install latex" "CI" # Dependencies installed, should not fail -assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624 -d 27 -m 1 -y 2020 --format=pdf -o /tmp/document.pdf" +assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624 -d 2020-01-27 --format=pdf -o /tmp/document.pdf" # man page assertSuccess "man --pager=cat kosmorro" diff --git a/kosmorrolib/ephemerides.py b/kosmorrolib/ephemerides.py index 8052944..1c98309 100644 --- a/kosmorrolib/ephemerides.py +++ b/kosmorrolib/ephemerides.py @@ -24,7 +24,7 @@ from skyfield.searchlib import find_discrete, find_maxima from skyfield.timelib import Time from skyfield.constants import tau -from .data import Object, Position, AsterEphemerides, MoonPhase, ASTERS, MONTHS, skyfield_to_moon_phase +from .data import Object, Position, AsterEphemerides, MoonPhase, ASTERS, skyfield_to_moon_phase from .core import get_skf_objects, get_timescale, get_iau2000b RISEN_ANGLE = -0.8333 @@ -47,7 +47,7 @@ class EphemeridesComputer: return {'rise': sunrise, 'set': sunset} @staticmethod - def get_moon_phase(year, month, day) -> MoonPhase: + def get_moon_phase(compute_date: datetime.date) -> MoonPhase: earth = get_skf_objects()['earth'] moon = get_skf_objects()['moon'] sun = get_skf_objects()['sun'] @@ -61,9 +61,9 @@ class EphemeridesComputer: moon_phase_at.rough_period = 7.0 # one lunar phase per week - today = get_timescale().utc(year, month, day) - time1 = get_timescale().utc(year, month, day - 10) - time2 = get_timescale().utc(year, month, day + 10) + today = get_timescale().utc(compute_date.year, compute_date.month, compute_date.day) + time1 = get_timescale().utc(compute_date.year, compute_date.month, compute_date.day - 10) + time2 = get_timescale().utc(compute_date.year, compute_date.month, compute_date.day + 10) times, phase = find_discrete(time1, time2, moon_phase_at) @@ -116,34 +116,11 @@ class EphemeridesComputer: def is_leap_year(year: int) -> bool: return (year % 4 == 0 and year % 100 > 0) or (year % 400 == 0) - def compute_ephemerides_for_day(self, year: int, month: int, day: int) -> dict: - return {'moon_phase': self.get_moon_phase(year, month, day), - 'details': [self.get_asters_ephemerides_for_aster(aster, datetime.date(year, month, day), self.position) + def compute_ephemerides(self, compute_date: datetime.date) -> dict: + return {'moon_phase': self.get_moon_phase(compute_date), + 'details': [self.get_asters_ephemerides_for_aster(aster, compute_date, self.position) for aster in ASTERS] if self.position is not None else []} - def compute_ephemerides_for_month(self, year: int, month: int) -> [dict]: - if month == 2: - max_day = 29 if self.is_leap_year(year) else 28 - elif month < 8: - max_day = 30 if month % 2 == 0 else 31 - else: - max_day = 31 if month % 2 == 0 else 30 - - ephemerides = [] - - for day in range(1, max_day + 1): - ephemerides.append(self.compute_ephemerides_for_day(year, month, day)) - - return ephemerides - - def compute_ephemerides_for_year(self, year: int) -> [dict]: - ephemerides = {'seasons': self.get_seasons(year)} - - for month in range(0, 12): - ephemerides[MONTHS[month]] = self.compute_ephemerides_for_month(year, month + 1) - - return ephemerides - @staticmethod def get_seasons(year: int) -> dict: start_time = get_timescale().utc(year, 1, 1) @@ -166,12 +143,3 @@ class EphemeridesComputer: seasons[season] = time.utc_iso() return seasons - - def compute_ephemerides(self, year: int, month: int, day: int): - if day is not None: - return self.compute_ephemerides_for_day(year, month, day) - - if month is not None: - return self.compute_ephemerides_for_month(year, month) - - return self.compute_ephemerides_for_year(year) diff --git a/kosmorrolib/locales/messages.pot b/kosmorrolib/locales/messages.pot index 92ceb15..c01684b 100644 --- a/kosmorrolib/locales/messages.pot +++ b/kosmorrolib/locales/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: kosmorro 0.6.0\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-03-01 14:20+0100\n" +"POT-Creation-Date: 2020-03-04 08:05+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -185,100 +185,95 @@ msgid "" "information." msgstr "" -#: kosmorrolib/main.py:58 +#: kosmorrolib/main.py:55 msgid "" "Save the planet and paper!\n" "Consider printing you PDF document only if really necessary, and use the " "other side of the sheet." msgstr "" -#: kosmorrolib/main.py:62 +#: kosmorrolib/main.py:59 msgid "" "PDF output will not contain the ephemerides, because you didn't provide " "the observation coordinate." msgstr "" -#: kosmorrolib/main.py:84 +#: kosmorrolib/main.py:81 msgid "Could not save the output in \"{path}\": {error}" msgstr "" -#: kosmorrolib/main.py:89 +#: kosmorrolib/main.py:86 msgid "Selected output format needs an output file (--output)." msgstr "" -#: kosmorrolib/main.py:106 +#: kosmorrolib/main.py:94 +msgid "The date {date} does not match the required YYYY-MM-DD format." +msgstr "" + +#: kosmorrolib/main.py:99 +msgid "The date {date} is not valid: {error}" +msgstr "" + +#: kosmorrolib/main.py:113 msgid "Running on Python {python_version}" msgstr "" -#: kosmorrolib/main.py:112 +#: kosmorrolib/main.py:119 msgid "Do you really want to clear Kosmorro's cache? [yN] " msgstr "" -#: kosmorrolib/main.py:119 +#: kosmorrolib/main.py:126 msgid "Answer did not match expected options, cache not cleared." msgstr "" -#: kosmorrolib/main.py:128 +#: kosmorrolib/main.py:135 msgid "" "Compute the ephemerides and the events for a given date, at a given " "position on Earth." msgstr "" -#: kosmorrolib/main.py:130 +#: kosmorrolib/main.py:137 msgid "" "By default, only the events will be computed for today ({date}).\n" "To compute also the ephemerides, latitude and longitude arguments are " "needed." msgstr "" -#: kosmorrolib/main.py:135 +#: kosmorrolib/main.py:142 msgid "Show the program version" msgstr "" -#: kosmorrolib/main.py:137 +#: kosmorrolib/main.py:144 msgid "Delete all the files Kosmorro stored in the cache." msgstr "" -#: kosmorrolib/main.py:139 +#: kosmorrolib/main.py:146 msgid "The format under which the information have to be output" msgstr "" -#: kosmorrolib/main.py:141 +#: kosmorrolib/main.py:148 msgid "The observer's latitude on Earth" msgstr "" -#: kosmorrolib/main.py:143 +#: kosmorrolib/main.py:150 msgid "The observer's longitude on Earth" msgstr "" -#: kosmorrolib/main.py:145 -msgid "" -"A number between 1 and 28, 29, 30 or 31 (depending on the month). The day" -" you want to compute the ephemerides for. Defaults to {default_day} (the" -" current day)." -msgstr "" - -#: kosmorrolib/main.py:149 -msgid "" -"A number between 1 and 12. The month you want to compute the ephemerides " -"for. Defaults to {default_month} (the current month)." -msgstr "" - #: kosmorrolib/main.py:152 msgid "" -"The year you want to compute the ephemerides for. Defaults to " -"{default_year} (the current year)." +"The date for which the ephemerides must be computed (in the YYYY-MM-DD " +"format). Defaults to the current date ({default_date})" msgstr "" -#: kosmorrolib/main.py:155 +#: kosmorrolib/main.py:156 msgid "The timezone to display the hours in (e.g. 2 for UTC+2 or -3 for UTC-3)." msgstr "" -#: kosmorrolib/main.py:157 +#: kosmorrolib/main.py:158 msgid "Disable the colors in the console." msgstr "" -#: kosmorrolib/main.py:159 +#: kosmorrolib/main.py:160 msgid "" "A file to export the output to. If not given, the standard output is " "used. This argument is needed for PDF format." diff --git a/kosmorrolib/main.py b/kosmorrolib/main.py index 88b2b34..0b2fb1b 100644 --- a/kosmorrolib/main.py +++ b/kosmorrolib/main.py @@ -40,14 +40,11 @@ def main(): if args.special_action is not None: return 0 if args.special_action() else 1 - year = args.year - month = args.month - day = args.day - - compute_date = date(year, month, day) - - if day is not None and month is None: - month = date.today().month + try: + compute_date = get_date(args.date) + except ValueError as error: + print(colored(error.args[0], color='red', attrs=['bold'])) + return -1 if args.latitude is None or args.longitude is None: position = None @@ -64,7 +61,7 @@ def main(): try: ephemeris = EphemeridesComputer(position) - ephemerides = ephemeris.compute_ephemerides(year, month, day) + ephemerides = ephemeris.compute_ephemerides(compute_date) events_list = events.search_events(compute_date) @@ -92,6 +89,16 @@ def main(): return 0 +def get_date(yyyymmdd: str) -> date: + if not re.match(r'^\d{4}-\d{2}-\d{2}$', yyyymmdd): + raise ValueError(_('The date {date} does not match the required YYYY-MM-DD format.').format(date=yyyymmdd)) + + try: + return date.fromisoformat(yyyymmdd) + except ValueError as error: + raise ValueError(_('The date {date} is not valid: {error}').format(date=yyyymmdd, error=error.args[0])) + + def get_dumpers() -> {str: dumper.Dumper}: return { 'text': dumper.TextDumper, @@ -141,16 +148,10 @@ def get_args(output_formats: [str]): help=_("The observer's latitude on Earth")) parser.add_argument('--longitude', '-lon', type=float, default=None, help=_("The observer's longitude on Earth")) - parser.add_argument('--day', '-d', type=int, default=today.day, - help=_('A number between 1 and 28, 29, 30 or 31 (depending on the month). The day you want to ' - ' compute the ephemerides for. Defaults to {default_day} (the current day).').format( - default_day=today.day)) - parser.add_argument('--month', '-m', type=int, default=today.month, - help=_('A number between 1 and 12. The month you want to compute the ephemerides for.' - ' Defaults to {default_month} (the current month).').format(default_month=today.month)) - parser.add_argument('--year', '-y', type=int, default=today.year, - help=_('The year you want to compute the ephemerides for.' - ' Defaults to {default_year} (the current year).').format(default_year=today.year)) + parser.add_argument('--date', '-d', type=str, default=today.strftime('%Y-%m-%d'), + help=_('The date for which the ephemerides must be computed (in the YYYY-MM-DD format). ' + 'Defaults to the current date ({default_date})').format( + default_date=today.strftime('%Y-%m-%d'))) parser.add_argument('--timezone', '-t', type=int, default=0, help=_('The timezone to display the hours in (e.g. 2 for UTC+2 or -3 for UTC-3).')) parser.add_argument('--no-colors', dest='colors', action='store_false', diff --git a/manpage/kosmorro.1.md b/manpage/kosmorro.1.md index e784524..3d7a11d 100644 --- a/manpage/kosmorro.1.md +++ b/manpage/kosmorro.1.md @@ -22,14 +22,8 @@ `--longitude=`_LONGITUDE_, `-lon` _LONGITUDE_ the observer's longitude on Earth -`--day=`_DAY_, `-d` _DAY_ - a number between 1 and 28, 29, 30 or 31 (depending on the month); the day you want to compute the ephemerides for, defaults to the current day - -`--month=`_MONTH_, `-m` _MONTH_ - a number between 1 and 12; the month you want to compute the ephemerides for, defaults to the current month - -`--year=`_YEAR_, `-y` _YEAR_ - the year you want to compute the ephemerides for; defaults to the current year +`--date=`_DATE_, `-d` _DATE_ + The date for which the ephemerides must be computed (in the YYYY-MM-DD format); defaults to the current date `--timezone=`_TIMEZONE_, `-t` _TIMEZONE_ the timezone to display the hours in; e.g. 2 for UTC+2 or -3 for UTC-3 @@ -43,18 +37,24 @@ `--format=`_FORMAT_, `-f` _FORMAT_ the format under which the information have to be output; one of the following: text, json, pdf -## EXAMPLE +## EXAMPLES + +Compute the events only for the current date: + +``` +kosmorro +``` Compute the ephemerides for Lille, France, on April 1st, 2022: ``` -kosmorro --latitude=50.5876 --longitude=3.0624 -d 1 -m 4 -y 2022 +kosmorro --latitude=50.5876 --longitude=3.0624 --date=2022-04-01 ``` Compute the ephemerides for Lille, France, on April 1st, 2022, and export them in a PDF document: ``` -kosmorro --latitude=50.5876 --longitude=3.0624 -d 1 -m 4 -y 2022 --format=pdf --output=file.pdf +kosmorro --latitude=50.5876 --longitude=3.0624 -date=2022-04-01 --format=pdf --output=file.pdf ``` ## AUTHOR diff --git a/test/ephemerides.py b/test/ephemerides.py index 1866beb..6d318f8 100644 --- a/test/ephemerides.py +++ b/test/ephemerides.py @@ -22,61 +22,61 @@ class EphemeridesComputerTestCase(unittest.TestCase): ################################################################################################################### def test_moon_phase_new_moon(self): - phase = EphemeridesComputer.get_moon_phase(2019, 11, 25) + phase = EphemeridesComputer.get_moon_phase(date(2019, 11, 25)) self.assertEqual('WANING_CRESCENT', phase.identifier) self.assertIsNone(phase.time) self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-26T') - phase = EphemeridesComputer.get_moon_phase(2019, 11, 26) + phase = EphemeridesComputer.get_moon_phase(date(2019, 11, 26)) self.assertEqual('NEW_MOON', phase.identifier) self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-12-04T') - phase = EphemeridesComputer.get_moon_phase(2019, 11, 27) + phase = EphemeridesComputer.get_moon_phase(date(2019, 11, 27)) self.assertEqual('WAXING_CRESCENT', phase.identifier) self.assertIsNone(phase.time) self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-12-04T') def test_moon_phase_first_crescent(self): - phase = EphemeridesComputer.get_moon_phase(2019, 11, 3) + phase = EphemeridesComputer.get_moon_phase(date(2019, 11, 3)) self.assertEqual('WAXING_CRESCENT', phase.identifier) self.assertIsNone(phase.time) self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-04T') - phase = EphemeridesComputer.get_moon_phase(2019, 11, 4) + phase = EphemeridesComputer.get_moon_phase(date(2019, 11, 4)) self.assertEqual('FIRST_QUARTER', phase.identifier) self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-12T') - phase = EphemeridesComputer.get_moon_phase(2019, 11, 5) + phase = EphemeridesComputer.get_moon_phase(date(2019, 11, 5)) self.assertEqual('WAXING_GIBBOUS', phase.identifier) self.assertIsNone(phase.time) self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-12T') def test_moon_phase_full_moon(self): - phase = EphemeridesComputer.get_moon_phase(2019, 11, 11) + phase = EphemeridesComputer.get_moon_phase(date(2019, 11, 11)) self.assertEqual('WAXING_GIBBOUS', phase.identifier) self.assertIsNone(phase.time) self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-12T') - phase = EphemeridesComputer.get_moon_phase(2019, 11, 12) + phase = EphemeridesComputer.get_moon_phase(date(2019, 11, 12)) self.assertEqual('FULL_MOON', phase.identifier) self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-19T') - phase = EphemeridesComputer.get_moon_phase(2019, 11, 13) + phase = EphemeridesComputer.get_moon_phase(date(2019, 11, 13)) self.assertEqual('WANING_GIBBOUS', phase.identifier) self.assertIsNone(phase.time) self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-19T') def test_moon_phase_last_quarter(self): - phase = EphemeridesComputer.get_moon_phase(2019, 11, 18) + phase = EphemeridesComputer.get_moon_phase(date(2019, 11, 18)) self.assertEqual('WANING_GIBBOUS', phase.identifier) self.assertIsNone(phase.time) self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-19T') - phase = EphemeridesComputer.get_moon_phase(2019, 11, 19) + phase = EphemeridesComputer.get_moon_phase(date(2019, 11, 19)) self.assertEqual('LAST_QUARTER', phase.identifier) self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-26T') - phase = EphemeridesComputer.get_moon_phase(2019, 11, 20) + phase = EphemeridesComputer.get_moon_phase(date(2019, 11, 20)) self.assertEqual('WANING_CRESCENT', phase.identifier) self.assertIsNone(phase.time) self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-26T')