Add support for maximal elongations of Mercury and Venustags/v0.6.0
| @@ -6,8 +6,9 @@ | |||
| \usepackage{graphicx} | |||
| \usepackage{hyperref} | |||
| % Fix non-break spaces issues | |||
| % Fix Unicode issues | |||
| \DeclareUnicodeCharacter{202F}{~} | |||
| \DeclareUnicodeCharacter{00B0}{$^\circ$} | |||
| \hypersetup{pdfinfo={ | |||
| Title={+++DOCUMENT-TITLE+++}, | |||
| @@ -18,30 +18,13 @@ | |||
| from shutil import rmtree | |||
| from pathlib import Path | |||
| from typing import Union | |||
| from skyfield.api import Loader | |||
| from skyfield.timelib import Time | |||
| from skyfield.nutationlib import iau2000b | |||
| from .data import Star, Planet, Satellite, MOON_PHASES, MoonPhase | |||
| from .i18n import _ | |||
| CACHE_FOLDER = str(Path.home()) + '/.kosmorro-cache' | |||
| MONTHS = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'] | |||
| ASTERS = [Star(_('Sun'), 'SUN'), | |||
| Satellite(_('Moon'), 'MOON'), | |||
| Planet(_('Mercury'), 'MERCURY'), | |||
| Planet(_('Venus'), 'VENUS'), | |||
| Planet(_('Mars'), 'MARS'), | |||
| Planet(_('Jupiter'), 'JUPITER BARYCENTER'), | |||
| Planet(_('Saturn'), 'SATURN BARYCENTER'), | |||
| Planet(_('Uranus'), 'URANUS BARYCENTER'), | |||
| Planet(_('Neptune'), 'NEPTUNE BARYCENTER'), | |||
| Planet(_('Pluto'), 'PLUTO BARYCENTER')] | |||
| def get_loader(): | |||
| return Loader(CACHE_FOLDER) | |||
| @@ -63,43 +46,6 @@ def clear_cache(): | |||
| rmtree(CACHE_FOLDER) | |||
| def skyfield_to_moon_phase(times: [Time], vals: [int], now: Time) -> Union[MoonPhase, None]: | |||
| tomorrow = get_timescale().utc(now.utc_datetime().year, now.utc_datetime().month, now.utc_datetime().day + 1) | |||
| phases = list(MOON_PHASES.keys()) | |||
| current_phase = None | |||
| current_phase_time = None | |||
| next_phase_time = None | |||
| i = 0 | |||
| if len(times) == 0: | |||
| return None | |||
| for i, time in enumerate(times): | |||
| if now.utc_iso() <= time.utc_iso(): | |||
| if vals[i] in [0, 2, 4, 6]: | |||
| if time.utc_datetime() < tomorrow.utc_datetime(): | |||
| current_phase_time = time | |||
| current_phase = phases[vals[i]] | |||
| else: | |||
| i -= 1 | |||
| current_phase_time = None | |||
| current_phase = phases[vals[i]] | |||
| else: | |||
| current_phase = phases[vals[i]] | |||
| break | |||
| for j in range(i + 1, len(times)): | |||
| if vals[j] in [0, 2, 4, 6]: | |||
| next_phase_time = times[j] | |||
| break | |||
| return MoonPhase(current_phase, | |||
| current_phase_time.utc_datetime() if current_phase_time is not None else None, | |||
| next_phase_time.utc_datetime() if next_phase_time is not None else None) | |||
| def flatten_list(the_list: list): | |||
| new_list = [] | |||
| for item in the_list: | |||
| @@ -20,8 +20,10 @@ from abc import ABC, abstractmethod | |||
| from typing import Union | |||
| from datetime import datetime | |||
| from skyfield.api import Topos | |||
| from skyfield.api import Topos, Time | |||
| from skyfield.vectorlib import VectorSum as SkfPlanet | |||
| from .core import get_skf_objects, get_timescale | |||
| from .i18n import _ | |||
| MOON_PHASES = { | |||
| @@ -37,7 +39,8 @@ MOON_PHASES = { | |||
| EVENTS = { | |||
| 'OPPOSITION': {'message': _('%s is in opposition')}, | |||
| 'CONJUNCTION': {'message': _('%s and %s are in conjunction')} | |||
| 'CONJUNCTION': {'message': _('%s and %s are in conjunction')}, | |||
| 'MAXIMAL_ELONGATION': {'message': _("%s's largest elongation")} | |||
| } | |||
| @@ -115,6 +118,9 @@ class Object(ABC): | |||
| self.skyfield_name = skyfield_name | |||
| self.ephemerides = ephemerides | |||
| def get_skyfield_object(self) -> SkfPlanet: | |||
| return get_skf_objects()[self.skyfield_name] | |||
| @abstractmethod | |||
| def get_type(self) -> str: | |||
| pass | |||
| @@ -142,23 +148,77 @@ class Satellite(Object): | |||
| class Event: | |||
| def __init__(self, event_type: str, objects: [Object], start_time: datetime, | |||
| end_time: Union[datetime, None] = None): | |||
| end_time: Union[datetime, None] = None, details: str = None): | |||
| if event_type not in EVENTS.keys(): | |||
| raise ValueError('event_type parameter must be one of the following: %s (got %s)' % ( | |||
| ', '.join(EVENTS.keys()), | |||
| event_type) | |||
| ) | |||
| accepted_types = ', '.join(EVENTS.keys()) | |||
| raise ValueError('event_type parameter must be one of the following: %s (got %s)' % (accepted_types, | |||
| event_type)) | |||
| self.event_type = event_type | |||
| self.objects = objects | |||
| self.start_time = start_time | |||
| self.end_time = end_time | |||
| self.details = details | |||
| def get_description(self) -> str: | |||
| return EVENTS[self.event_type]['message'] % self._get_objects_name() | |||
| def get_description(self, show_details: bool = True) -> str: | |||
| description = EVENTS[self.event_type]['message'] % self._get_objects_name() | |||
| if show_details and self.details is not None: | |||
| description += ' ({:s})'.format(self.details) | |||
| return description | |||
| def _get_objects_name(self): | |||
| if len(self.objects) == 1: | |||
| return self.objects[0].name | |||
| return tuple(object.name for object in self.objects) | |||
| def skyfield_to_moon_phase(times: [Time], vals: [int], now: Time) -> Union[MoonPhase, None]: | |||
| tomorrow = get_timescale().utc(now.utc_datetime().year, now.utc_datetime().month, now.utc_datetime().day + 1) | |||
| phases = list(MOON_PHASES.keys()) | |||
| current_phase = None | |||
| current_phase_time = None | |||
| next_phase_time = None | |||
| i = 0 | |||
| if len(times) == 0: | |||
| return None | |||
| for i, time in enumerate(times): | |||
| if now.utc_iso() <= time.utc_iso(): | |||
| if vals[i] in [0, 2, 4, 6]: | |||
| if time.utc_datetime() < tomorrow.utc_datetime(): | |||
| current_phase_time = time | |||
| current_phase = phases[vals[i]] | |||
| else: | |||
| i -= 1 | |||
| current_phase_time = None | |||
| current_phase = phases[vals[i]] | |||
| else: | |||
| current_phase = phases[vals[i]] | |||
| break | |||
| for j in range(i + 1, len(times)): | |||
| if vals[j] in [0, 2, 4, 6]: | |||
| next_phase_time = times[j] | |||
| break | |||
| return MoonPhase(current_phase, | |||
| current_phase_time.utc_datetime() if current_phase_time is not None else None, | |||
| next_phase_time.utc_datetime() if next_phase_time is not None else None) | |||
| MONTHS = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'] | |||
| ASTERS = [Star(_('Sun'), 'SUN'), | |||
| Satellite(_('Moon'), 'MOON'), | |||
| Planet(_('Mercury'), 'MERCURY'), | |||
| Planet(_('Venus'), 'VENUS'), | |||
| Planet(_('Mars'), 'MARS'), | |||
| Planet(_('Jupiter'), 'JUPITER BARYCENTER'), | |||
| Planet(_('Saturn'), 'SATURN BARYCENTER'), | |||
| Planet(_('Uranus'), 'URANUS BARYCENTER'), | |||
| Planet(_('Neptune'), 'NEPTUNE BARYCENTER'), | |||
| Planet(_('Pluto'), 'PLUTO BARYCENTER')] | |||
| @@ -24,8 +24,8 @@ 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 | |||
| from .core import get_skf_objects, get_timescale, get_iau2000b, ASTERS, MONTHS, skyfield_to_moon_phase | |||
| from .data import Object, Position, AsterEphemerides, MoonPhase, ASTERS, MONTHS, skyfield_to_moon_phase | |||
| from .core import get_skf_objects, get_timescale, get_iau2000b | |||
| RISEN_ANGLE = -0.8333 | |||
| @@ -88,6 +88,7 @@ class EphemeridesComputer: | |||
| rise_times, arr = find_discrete(start_time, end_time, is_risen) | |||
| try: | |||
| culmination_time, _ = find_maxima(start_time, end_time, f=get_angle, epsilon=1./3600/24, num=12) | |||
| culmination_time = culmination_time[0] if len(culmination_time) > 0 else None | |||
| except ValueError: | |||
| culmination_time = None | |||
| @@ -98,12 +99,15 @@ class EphemeridesComputer: | |||
| rise_time = rise_times[0] if arr[0] else None | |||
| set_time = rise_times[0] if not arr[0] else None | |||
| culmination_time = culmination_time[0] if culmination_time is not None else None | |||
| # Convert the Time instances to Python datetime objects | |||
| rise_time = rise_time.utc_datetime().replace(microsecond=0) | |||
| culmination_time = culmination_time.utc_datetime().replace(microsecond=0) | |||
| set_time = set_time.utc_datetime().replace(microsecond=0) | |||
| if rise_time is not None: | |||
| rise_time = rise_time.utc_datetime().replace(microsecond=0) | |||
| if culmination_time is not None: | |||
| culmination_time = culmination_time.utc_datetime().replace(microsecond=0) | |||
| if set_time is not None: | |||
| set_time = set_time.utc_datetime().replace(microsecond=0) if set_time is not None else None | |||
| aster.ephemerides = AsterEphemerides(rise_time, culmination_time, set_time) | |||
| return aster | |||
| @@ -19,10 +19,10 @@ | |||
| from datetime import date as date_type | |||
| from skyfield.timelib import Time | |||
| from skyfield.almanac import find_discrete | |||
| from skyfield.searchlib import find_discrete, find_maxima | |||
| from .data import Event, Planet | |||
| from .core import get_timescale, get_skf_objects, ASTERS, flatten_list | |||
| from .data import Event, Planet, ASTERS | |||
| from .core import get_timescale, get_skf_objects, flatten_list | |||
| def _search_conjunction(start_time: Time, end_time: Time) -> [Event]: | |||
| @@ -91,11 +91,41 @@ def _search_oppositions(start_time: Time, end_time: Time) -> [Event]: | |||
| return events | |||
| def _search_maximal_elongations(start_time: Time, end_time: Time) -> [Event]: | |||
| earth = get_skf_objects()['earth'] | |||
| sun = get_skf_objects()['sun'] | |||
| aster = None | |||
| def get_elongation(time: Time): | |||
| sun_pos = (sun - earth).at(time) | |||
| aster_pos = (aster.get_skyfield_object() - earth).at(time) | |||
| separation = sun_pos.separation_from(aster_pos) | |||
| return separation.degrees | |||
| get_elongation.rough_period = 1.0 | |||
| events = [] | |||
| for aster in ASTERS: | |||
| if aster.skyfield_name not in ['MERCURY', 'VENUS']: | |||
| continue | |||
| times, elongations = find_maxima(start_time, end_time, f=get_elongation, epsilon=1./24/3600, num=12) | |||
| for i, time in enumerate(times): | |||
| elongation = elongations[i] | |||
| events.append(Event('MAXIMAL_ELONGATION', [aster], time.utc_datetime(), | |||
| details='{:.3n}°'.format(elongation))) | |||
| return events | |||
| def search_events(date: date_type) -> [Event]: | |||
| start_time = get_timescale().utc(date.year, date.month, date.day) | |||
| end_time = get_timescale().utc(date.year, date.month, date.day + 1) | |||
| return sorted(flatten_list([ | |||
| _search_oppositions(start_time, end_time), | |||
| _search_conjunction(start_time, end_time) | |||
| _search_conjunction(start_time, end_time), | |||
| _search_maximal_elongations(start_time, end_time) | |||
| ]), key=lambda event: event.start_time) | |||
| @@ -8,7 +8,7 @@ msgid "" | |||
| msgstr "" | |||
| "Project-Id-Version: kosmorro 0.5.2\n" | |||
| "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | |||
| "POT-Creation-Date: 2020-02-17 20:58+0100\n" | |||
| "POT-Creation-Date: 2020-02-21 20:14+0100\n" | |||
| "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | |||
| "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | |||
| "Language-Team: LANGUAGE <LL@li.org>\n" | |||
| @@ -17,86 +17,91 @@ msgstr "" | |||
| "Content-Transfer-Encoding: 8bit\n" | |||
| "Generated-By: Babel 2.8.0\n" | |||
| #: kosmorrolib/core.py:34 | |||
| msgid "Sun" | |||
| #: kosmorrolib/data.py:30 | |||
| msgid "New Moon" | |||
| msgstr "" | |||
| #: kosmorrolib/core.py:35 | |||
| msgid "Moon" | |||
| #: kosmorrolib/data.py:31 | |||
| msgid "Waxing crescent" | |||
| msgstr "" | |||
| #: kosmorrolib/core.py:36 | |||
| msgid "Mercury" | |||
| #: kosmorrolib/data.py:32 | |||
| msgid "First Quarter" | |||
| msgstr "" | |||
| #: kosmorrolib/core.py:37 | |||
| msgid "Venus" | |||
| #: kosmorrolib/data.py:33 | |||
| msgid "Waxing gibbous" | |||
| msgstr "" | |||
| #: kosmorrolib/core.py:38 | |||
| msgid "Mars" | |||
| #: kosmorrolib/data.py:34 | |||
| msgid "Full Moon" | |||
| msgstr "" | |||
| #: kosmorrolib/core.py:39 | |||
| msgid "Jupiter" | |||
| #: kosmorrolib/data.py:35 | |||
| msgid "Waning gibbous" | |||
| msgstr "" | |||
| #: kosmorrolib/core.py:40 | |||
| msgid "Saturn" | |||
| #: kosmorrolib/data.py:36 | |||
| msgid "Last Quarter" | |||
| msgstr "" | |||
| #: kosmorrolib/core.py:41 | |||
| msgid "Uranus" | |||
| #: kosmorrolib/data.py:37 | |||
| msgid "Waning crescent" | |||
| msgstr "" | |||
| #: kosmorrolib/core.py:42 | |||
| msgid "Neptune" | |||
| #: kosmorrolib/data.py:41 | |||
| #, python-format | |||
| msgid "%s is in opposition" | |||
| msgstr "" | |||
| #: kosmorrolib/core.py:43 | |||
| msgid "Pluto" | |||
| #: kosmorrolib/data.py:42 | |||
| #, python-format | |||
| msgid "%s and %s are in conjunction" | |||
| msgstr "" | |||
| #: kosmorrolib/data.py:28 | |||
| msgid "New Moon" | |||
| #: kosmorrolib/data.py:43 | |||
| #, python-format | |||
| msgid "%s's largest elongation" | |||
| msgstr "" | |||
| #: kosmorrolib/data.py:29 | |||
| msgid "Waxing crescent" | |||
| #: kosmorrolib/data.py:215 | |||
| msgid "Sun" | |||
| msgstr "" | |||
| #: kosmorrolib/data.py:30 | |||
| msgid "First Quarter" | |||
| #: kosmorrolib/data.py:216 | |||
| msgid "Moon" | |||
| msgstr "" | |||
| #: kosmorrolib/data.py:31 | |||
| msgid "Waxing gibbous" | |||
| #: kosmorrolib/data.py:217 | |||
| msgid "Mercury" | |||
| msgstr "" | |||
| #: kosmorrolib/data.py:32 | |||
| msgid "Full Moon" | |||
| #: kosmorrolib/data.py:218 | |||
| msgid "Venus" | |||
| msgstr "" | |||
| #: kosmorrolib/data.py:33 | |||
| msgid "Waning gibbous" | |||
| #: kosmorrolib/data.py:219 | |||
| msgid "Mars" | |||
| msgstr "" | |||
| #: kosmorrolib/data.py:34 | |||
| msgid "Last Quarter" | |||
| #: kosmorrolib/data.py:220 | |||
| msgid "Jupiter" | |||
| msgstr "" | |||
| #: kosmorrolib/data.py:35 | |||
| msgid "Waning crescent" | |||
| #: kosmorrolib/data.py:221 | |||
| msgid "Saturn" | |||
| msgstr "" | |||
| #: kosmorrolib/data.py:39 | |||
| #, python-format | |||
| msgid "%s is in opposition" | |||
| #: kosmorrolib/data.py:222 | |||
| msgid "Uranus" | |||
| msgstr "" | |||
| #: kosmorrolib/data.py:40 | |||
| #, python-format | |||
| msgid "%s and %s are in conjunction" | |||
| #: kosmorrolib/data.py:223 | |||
| msgid "Neptune" | |||
| msgstr "" | |||
| #: kosmorrolib/data.py:224 | |||
| msgid "Pluto" | |||
| msgstr "" | |||
| #: kosmorrolib/dumper.py:35 | |||
| @@ -23,7 +23,17 @@ class DumperTestCase(unittest.TestCase): | |||
| ' "Mars"\n' | |||
| ' ],\n' | |||
| ' "start_time": "2019-10-14T23:00:00",\n' | |||
| ' "end_time": null\n' | |||
| ' "end_time": null,\n' | |||
| ' "details": null\n' | |||
| ' },\n' | |||
| ' {\n' | |||
| ' "event_type": "MAXIMAL_ELONGATION",\n' | |||
| ' "objects": [\n' | |||
| ' "Venus"\n' | |||
| ' ],\n' | |||
| ' "start_time": "2019-10-14T12:00:00",\n' | |||
| ' "end_time": null,\n' | |||
| ' "details": "42.0\\u00b0"\n' | |||
| ' }\n' | |||
| ' ],\n' | |||
| ' "ephemerides": [\n' | |||
| @@ -52,7 +62,17 @@ class DumperTestCase(unittest.TestCase): | |||
| ' "Mars"\n' | |||
| ' ],\n' | |||
| ' "start_time": "2019-10-14T23:00:00",\n' | |||
| ' "end_time": null\n' | |||
| ' "end_time": null,\n' | |||
| ' "details": null\n' | |||
| ' },\n' | |||
| ' {\n' | |||
| ' "event_type": "MAXIMAL_ELONGATION",\n' | |||
| ' "objects": [\n' | |||
| ' "Venus"\n' | |||
| ' ],\n' | |||
| ' "start_time": "2019-10-14T12:00:00",\n' | |||
| ' "end_time": null,\n' | |||
| ' "details": "42.0\\u00b0"\n' | |||
| ' }\n' | |||
| ' ],\n' | |||
| ' "ephemerides": [\n' | |||
| @@ -92,15 +112,16 @@ class DumperTestCase(unittest.TestCase): | |||
| def test_text_dumper_with_events(self): | |||
| ephemerides = self._get_data() | |||
| self.assertEqual('Monday October 14, 2019\n\n' | |||
| 'Object Rise time Culmination time Set time\n' | |||
| '-------- ----------- ------------------ ----------\n' | |||
| 'Mars - - -\n\n' | |||
| 'Moon phase: Full Moon\n' | |||
| 'Last Quarter on Monday October 21, 2019 at 00:00\n\n' | |||
| 'Expected events:\n' | |||
| '23:00 Mars is in opposition\n\n' | |||
| 'Note: All the hours are given in UTC.', | |||
| self.assertEqual("Monday October 14, 2019\n\n" | |||
| "Object Rise time Culmination time Set time\n" | |||
| "-------- ----------- ------------------ ----------\n" | |||
| "Mars - - -\n\n" | |||
| "Moon phase: Full Moon\n" | |||
| "Last Quarter on Monday October 21, 2019 at 00:00\n\n" | |||
| "Expected events:\n" | |||
| "23:00 Mars is in opposition\n" | |||
| "12:00 Venus's largest elongation (42.0°)\n\n" | |||
| "Note: All the hours are given in UTC.", | |||
| TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string()) | |||
| def test_text_dumper_without_ephemerides_and_with_events(self): | |||
| @@ -109,7 +130,8 @@ class DumperTestCase(unittest.TestCase): | |||
| 'Moon phase: Full Moon\n' | |||
| 'Last Quarter on Monday October 21, 2019 at 00:00\n\n' | |||
| 'Expected events:\n' | |||
| '23:00 Mars is in opposition\n\n' | |||
| '23:00 Mars is in opposition\n' | |||
| "12:00 Venus's largest elongation (42.0°)\n\n" | |||
| 'Note: All the hours are given in UTC.', | |||
| TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string()) | |||
| @@ -122,7 +144,8 @@ class DumperTestCase(unittest.TestCase): | |||
| 'Moon phase: Full Moon\n' | |||
| 'Last Quarter on Monday October 21, 2019 at 01:00\n\n' | |||
| 'Expected events:\n' | |||
| 'Oct 15, 00:00 Mars is in opposition\n\n' | |||
| 'Oct 15, 00:00 Mars is in opposition\n' | |||
| "13:00 Venus's largest elongation (42.0°)\n\n" | |||
| 'Note: All the hours are given in the UTC+1 timezone.', | |||
| TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False, timezone=1).to_string()) | |||
| @@ -134,7 +157,8 @@ class DumperTestCase(unittest.TestCase): | |||
| 'Moon phase: Full Moon\n' | |||
| 'Last Quarter on Sunday October 20, 2019 at 23:00\n\n' | |||
| 'Expected events:\n' | |||
| '22:00 Mars is in opposition\n\n' | |||
| '22:00 Mars is in opposition\n' | |||
| "11:00 Venus's largest elongation (42.0°)\n\n" | |||
| 'Note: All the hours are given in the UTC-1 timezone.', | |||
| TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False, timezone=-1).to_string()) | |||
| @@ -146,6 +170,7 @@ class DumperTestCase(unittest.TestCase): | |||
| self.assertRegex(latex, r'\\section{\\sffamily Ephemerides of the day}') | |||
| self.assertRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}') | |||
| self.assertRegex(latex, r'\\event\{23:00\}\{Mars is in opposition\}') | |||
| self.assertRegex(latex, r"\\event\{12:00\}\{Venus's largest elongation \(42.0°\)\}") | |||
| latex = _LatexDumper(self._get_data(aster_rise_set=True), | |||
| self._get_events(), date=date(2019, 10, 14)).to_string() | |||
| @@ -157,6 +182,7 @@ class DumperTestCase(unittest.TestCase): | |||
| self.assertRegex(latex, 'Full Moon') | |||
| self.assertRegex(latex, r'\\section{\\sffamily Expected events}') | |||
| self.assertRegex(latex, r'\\event\{23:00\}\{Mars is in opposition\}') | |||
| self.assertRegex(latex, r"\\event\{12:00\}\{Venus's largest elongation \(42.0°\)\}") | |||
| self.assertNotRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}') | |||
| self.assertNotRegex(latex, r'\\section{\\sffamily Ephemerides of the day}') | |||
| @@ -186,7 +212,10 @@ class DumperTestCase(unittest.TestCase): | |||
| def _get_events(): | |||
| return [Event('OPPOSITION', | |||
| [Planet('Mars', 'MARS')], | |||
| datetime(2019, 10, 14, 23, 00)) | |||
| datetime(2019, 10, 14, 23, 00)), | |||
| Event('MAXIMAL_ELONGATION', | |||
| [Planet('Venus', 'VENUS')], | |||
| datetime(2019, 10, 14, 12, 00), details='42.0°'), | |||
| ] | |||
| @@ -55,6 +55,33 @@ class MyTestCase(unittest.TestCase): | |||
| i += 1 | |||
| def test_find_maximal_elongation(self): | |||
| e = events.search_events(date(2020, 2, 10)) | |||
| self.assertEquals(1, len(e), 'Expected 1 events, got %d.' % len(e)) | |||
| e = e[0] | |||
| self.assertEquals('MAXIMAL_ELONGATION', e.event_type) | |||
| self.assertEquals(1, len(e.objects)) | |||
| self.assertEquals('MERCURY', e.objects[0].skyfield_name) | |||
| self.assertEqual('18.2°', e.details) | |||
| self.assertEquals((2020, 2, 10, 13, 46), (e.start_time.year, e.start_time.month, e.start_time.day, | |||
| e.start_time.hour, e.start_time.minute)) | |||
| e = events.search_events(date(2020, 3, 24)) | |||
| self.assertEquals(2, len(e), 'Expected 2 events, got %d.' % len(e)) | |||
| self.assertEquals('MAXIMAL_ELONGATION', e[0].event_type) | |||
| self.assertEquals(1, len(e[0].objects)) | |||
| self.assertEquals('MERCURY', e[0].objects[0].skyfield_name) | |||
| self.assertEqual('27.8°', e[0].details) | |||
| self.assertEquals((2020, 3, 24, 1, 56), (e[0].start_time.year, e[0].start_time.month, e[0].start_time.day, | |||
| e[0].start_time.hour, e[0].start_time.minute)) | |||
| self.assertEquals('MAXIMAL_ELONGATION', e[1].event_type) | |||
| self.assertEquals(1, len(e[1].objects)) | |||
| self.assertEquals('VENUS', e[1].objects[0].skyfield_name) | |||
| self.assertEqual('46.1°', e[1].details) | |||
| self.assertEquals((2020, 3, 24, 21, 58), (e[1].start_time.year, e[1].start_time.month, e[1].start_time.day, | |||
| e[1].start_time.hour, e[1].start_time.minute)) | |||
| if __name__ == '__main__': | |||
| unittest.main() | |||