BREAKING CHANGE: some methodes in Event and MoonPhase have been dropped in favor of `enum.Enum`'s `name` and `value` properties.tags/v0.9.0
@@ -19,13 +19,26 @@ jobs: | |||||
- name: Check i18n | - name: Check i18n | ||||
run: | | run: | | ||||
pipenv run python setup.py extract_messages --output-file=/tmp/kosmorro-messages.pot > /dev/null | pipenv run python setup.py extract_messages --output-file=/tmp/kosmorro-messages.pot > /dev/null | ||||
n=$(diff -y --suppress-common-lines kosmorrolib/locales/messages.pot /tmp/kosmorro-messages.pot | grep -v -E '^"POT-Creation-Date: ' | wc -l) | |||||
diff=$(diff kosmorrolib/locales/messages.pot /tmp/kosmorro-messages.pot | grep '^>') | |||||
n=$(echo "$diff" | grep -v '> "POT-Creation-Date: ' | wc -l) | |||||
if [ "$(echo "$diff" | grep -E '^"Generated-By: Babel' | wc -l)" -eq "1" ]; then | |||||
echo "❌ You dependencies may be out of date!" | |||||
echo " Please run the following command to fix this:" | |||||
echo | |||||
echo " pipenv sync --dev" | |||||
echo | |||||
echo " Then update the messages file:" | |||||
echo | |||||
echo " make messages" | |||||
exit 2 | |||||
fi | |||||
if [ "$n" -ne "0" ]; then | if [ "$n" -ne "0" ]; then | ||||
echo "❌ The messages file is not up-to-date!" | echo "❌ The messages file is not up-to-date!" | ||||
echo " Please run the following command to fix this:" | echo " Please run the following command to fix this:" | ||||
echo | echo | ||||
echo " pipenv run python setup.py extract_messages --output-file=kosmorrolib/locales/messages.pot" | |||||
echo " make messages" | |||||
exit 1 | exit 1 | ||||
fi | fi | ||||
@@ -6,13 +6,17 @@ test: | |||||
unset KOSMORRO_TIMEZONE; \ | unset KOSMORRO_TIMEZONE; \ | ||||
LANG=C pipenv run python3 -m coverage run -m unittest test | LANG=C pipenv run python3 -m coverage run -m unittest test | ||||
build: i18n | |||||
build: i18n manpages | |||||
python3 setup.py sdist bdist_wheel | python3 setup.py sdist bdist_wheel | ||||
i18n: | |||||
messages: | |||||
pipenv run python setup.py extract_messages --output-file=kosmorrolib/locales/messages.pot | |||||
manpages: | |||||
ronn --roff manpage/kosmorro.1.md | ronn --roff manpage/kosmorro.1.md | ||||
ronn --roff manpage/kosmorro.7.md | ronn --roff manpage/kosmorro.7.md | ||||
i18n: | |||||
if [ "$$POEDITOR_API_ACCESS" != "" ]; then \ | if [ "$$POEDITOR_API_ACCESS" != "" ]; then \ | ||||
python3 .scripts/build/getlangs.py; \ | python3 .scripts/build/getlangs.py; \ | ||||
python3 setup.py compile_catalog; \ | python3 setup.py compile_catalog; \ | ||||
@@ -25,30 +25,10 @@ from numpy import pi, arcsin | |||||
from skyfield.api import Topos, Time | from skyfield.api import Topos, Time | ||||
from skyfield.vectorlib import VectorSum as SkfPlanet | from skyfield.vectorlib import VectorSum as SkfPlanet | ||||
from .core import get_skf_objects, get_timescale | |||||
from .core import get_skf_objects | |||||
from .enum import MoonPhaseType, EventType | |||||
from .i18n import _ | from .i18n import _ | ||||
MOON_PHASES = { | |||||
'NEW_MOON': _('New Moon'), | |||||
'WAXING_CRESCENT': _('Waxing crescent'), | |||||
'FIRST_QUARTER': _('First Quarter'), | |||||
'WAXING_GIBBOUS': _('Waxing gibbous'), | |||||
'FULL_MOON': _('Full Moon'), | |||||
'WANING_GIBBOUS': _('Waning gibbous'), | |||||
'LAST_QUARTER': _('Last Quarter'), | |||||
'WANING_CRESCENT': _('Waning crescent'), | |||||
'UNKNOWN': _('Unavailable') | |||||
} | |||||
EVENTS = { | |||||
'OPPOSITION': {'message': _('%s is in opposition')}, | |||||
'CONJUNCTION': {'message': _('%s and %s are in conjunction')}, | |||||
'OCCULTATION': {'message': _('%s occults %s')}, | |||||
'MAXIMAL_ELONGATION': {'message': _("%s's largest elongation")}, | |||||
'MOON_PERIGEE': {'message': _("%s is at its perigee")}, | |||||
'MOON_APOGEE': {'message': _("%s is at its apogee")}, | |||||
} | |||||
class Serializable(ABC): | class Serializable(ABC): | ||||
@abstractmethod | @abstractmethod | ||||
@@ -57,40 +37,27 @@ class Serializable(ABC): | |||||
class MoonPhase(Serializable): | class MoonPhase(Serializable): | ||||
def __init__(self, identifier: str, time: datetime = None, next_phase_date: datetime = None): | |||||
if identifier not in MOON_PHASES.keys(): | |||||
raise ValueError('identifier parameter must be one of %s (got %s)' % (', '.join(MOON_PHASES.keys()), | |||||
identifier)) | |||||
self.identifier = identifier | |||||
def __init__(self, phase_type: MoonPhaseType, time: datetime = None, next_phase_date: datetime = None): | |||||
self.phase_type = phase_type | |||||
self.time = time | self.time = time | ||||
self.next_phase_date = next_phase_date | self.next_phase_date = next_phase_date | ||||
def get_phase(self): | |||||
return MOON_PHASES[self.identifier] | |||||
def get_next_phase_name(self): | |||||
next_identifier = self.get_next_phase() | |||||
return MOON_PHASES[next_identifier] | |||||
def get_next_phase(self): | def get_next_phase(self): | ||||
if self.identifier == 'NEW_MOON' or self.identifier == 'WAXING_CRESCENT': | |||||
next_identifier = 'FIRST_QUARTER' | |||||
elif self.identifier == 'FIRST_QUARTER' or self.identifier == 'WAXING_GIBBOUS': | |||||
next_identifier = 'FULL_MOON' | |||||
elif self.identifier == 'FULL_MOON' or self.identifier == 'WANING_GIBBOUS': | |||||
next_identifier = 'LAST_QUARTER' | |||||
else: | |||||
next_identifier = 'NEW_MOON' | |||||
return next_identifier | |||||
if self.phase_type in [MoonPhaseType.NEW_MOON, MoonPhaseType.WAXING_CRESCENT]: | |||||
return MoonPhaseType.FIRST_QUARTER | |||||
if self.phase_type in [MoonPhaseType.FIRST_QUARTER, MoonPhaseType.WAXING_GIBBOUS]: | |||||
return MoonPhaseType.FULL_MOON | |||||
if self.phase_type in [MoonPhaseType.FULL_MOON, MoonPhaseType.WANING_GIBBOUS]: | |||||
return MoonPhaseType.LAST_QUARTER | |||||
return MoonPhaseType.NEW_MOON | |||||
def serialize(self) -> dict: | def serialize(self) -> dict: | ||||
return { | return { | ||||
'phase': self.identifier, | |||||
'phase': self.phase_type.name, | |||||
'time': self.time.isoformat() if self.time is not None else None, | 'time': self.time.isoformat() if self.time is not None else None, | ||||
'next': { | 'next': { | ||||
'phase': self.get_next_phase(), | |||||
'phase': self.get_next_phase().name, | |||||
'time': self.next_phase_date.isoformat() | 'time': self.next_phase_date.isoformat() | ||||
} | } | ||||
} | } | ||||
@@ -168,13 +135,8 @@ class Satellite(Object): | |||||
class Event(Serializable): | class Event(Serializable): | ||||
def __init__(self, event_type: str, objects: [Object], start_time: datetime, | |||||
def __init__(self, event_type: EventType, objects: [Object], start_time: datetime, | |||||
end_time: Union[datetime, None] = None, details: str = None): | end_time: Union[datetime, None] = None, details: str = None): | ||||
if event_type not in EVENTS.keys(): | |||||
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.event_type = event_type | ||||
self.objects = objects | self.objects = objects | ||||
self.start_time = start_time | self.start_time = start_time | ||||
@@ -189,7 +151,7 @@ class Event(Serializable): | |||||
self.details) | self.details) | ||||
def get_description(self, show_details: bool = True) -> str: | def get_description(self, show_details: bool = True) -> str: | ||||
description = EVENTS[self.event_type]['message'] % self._get_objects_name() | |||||
description = self.event_type.value % self._get_objects_name() | |||||
if show_details and self.details is not None: | if show_details and self.details is not None: | ||||
description += ' ({:s})'.format(self.details) | description += ' ({:s})'.format(self.details) | ||||
return description | return description | ||||
@@ -203,50 +165,13 @@ class Event(Serializable): | |||||
def serialize(self) -> dict: | def serialize(self) -> dict: | ||||
return { | return { | ||||
'objects': [object.serialize() for object in self.objects], | 'objects': [object.serialize() for object in self.objects], | ||||
'event': self.event_type, | |||||
'event': self.event_type.name, | |||||
'starts_at': self.start_time.isoformat(), | 'starts_at': self.start_time.isoformat(), | ||||
'ends_at': self.end_time.isoformat() if self.end_time is not None else None, | 'ends_at': self.end_time.isoformat() if self.end_time is not None else None, | ||||
'details': self.details | 'details': self.details | ||||
} | } | ||||
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) | |||||
class AsterEphemerides(Serializable): | class AsterEphemerides(Serializable): | ||||
def __init__(self, | def __init__(self, | ||||
rise_time: Union[datetime, None], | rise_time: Union[datetime, None], | ||||
@@ -267,8 +192,6 @@ class AsterEphemerides(Serializable): | |||||
} | } | ||||
MONTHS = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'] | |||||
EARTH = Planet('Earth', 'EARTH') | EARTH = Planet('Earth', 'EARTH') | ||||
ASTERS = [Star(_('Sun'), 'SUN', radius=696342), | ASTERS = [Star(_('Sun'), 'SUN', radius=696342), | ||||
@@ -23,6 +23,7 @@ import os | |||||
from pathlib import Path | from pathlib import Path | ||||
from tabulate import tabulate | from tabulate import tabulate | ||||
from termcolor import colored | from termcolor import colored | ||||
from .data import ASTERS, AsterEphemerides, MoonPhase, Event | from .data import ASTERS, AsterEphemerides, MoonPhase, Event | ||||
from .i18n import _, FULL_DATE_FORMAT, SHORT_DATETIME_FORMAT, TIME_FORMAT | from .i18n import _, FULL_DATE_FORMAT, SHORT_DATETIME_FORMAT, TIME_FORMAT | ||||
from .version import VERSION | from .version import VERSION | ||||
@@ -159,9 +160,9 @@ class TextDumper(Dumper): | |||||
if moon_phase is None: | if moon_phase is None: | ||||
return _('Moon phase is unavailable for this date.') | return _('Moon phase is unavailable for this date.') | ||||
current_moon_phase = ' '.join([self.style(_('Moon phase:'), 'strong'), moon_phase.get_phase()]) | |||||
current_moon_phase = ' '.join([self.style(_('Moon phase:'), 'strong'), moon_phase.phase_type.value]) | |||||
new_moon_phase = _('{next_moon_phase} on {next_moon_phase_date} at {next_moon_phase_time}').format( | new_moon_phase = _('{next_moon_phase} on {next_moon_phase_date} at {next_moon_phase_time}').format( | ||||
next_moon_phase=moon_phase.get_next_phase_name(), | |||||
next_moon_phase=moon_phase.get_next_phase().value, | |||||
next_moon_phase_date=moon_phase.next_phase_date.strftime(FULL_DATE_FORMAT), | next_moon_phase_date=moon_phase.next_phase_date.strftime(FULL_DATE_FORMAT), | ||||
next_moon_phase_time=moon_phase.next_phase_date.strftime(TIME_FORMAT) | next_moon_phase_time=moon_phase.next_phase_date.strftime(TIME_FORMAT) | ||||
) | ) | ||||
@@ -183,12 +184,9 @@ class _LatexDumper(Dumper): | |||||
kosmorro_logo_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), | kosmorro_logo_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), | ||||
'assets', 'png', 'kosmorro-logo.png') | 'assets', 'png', 'kosmorro-logo.png') | ||||
if self.moon_phase is None: | |||||
self.moon_phase = MoonPhase('UNKNOWN') | |||||
moon_phase_graphics = os.path.join(os.path.abspath(os.path.dirname(__file__)), | moon_phase_graphics = os.path.join(os.path.abspath(os.path.dirname(__file__)), | ||||
'assets', 'moonphases', 'png', | 'assets', 'moonphases', 'png', | ||||
'.'.join([self.moon_phase.identifier.lower().replace('_', '-'), | |||||
'.'.join([self.moon_phase.phase_type.name.lower().replace('_', '-'), | |||||
'png'])) | 'png'])) | ||||
document = template | document = template | ||||
@@ -234,7 +232,7 @@ class _LatexDumper(Dumper): | |||||
.replace('+++GRAPH_LABEL_HOURS+++', _('hours')) \ | .replace('+++GRAPH_LABEL_HOURS+++', _('hours')) \ | ||||
.replace('+++MOON-PHASE-GRAPHICS+++', moon_phase_graphics) \ | .replace('+++MOON-PHASE-GRAPHICS+++', moon_phase_graphics) \ | ||||
.replace('+++CURRENT-MOON-PHASE-TITLE+++', _('Moon phase:')) \ | .replace('+++CURRENT-MOON-PHASE-TITLE+++', _('Moon phase:')) \ | ||||
.replace('+++CURRENT-MOON-PHASE+++', self.moon_phase.get_phase()) \ | |||||
.replace('+++CURRENT-MOON-PHASE+++', self.moon_phase.phase_type.value) \ | |||||
.replace('+++SECTION-EVENTS+++', _('Expected events')) \ | .replace('+++SECTION-EVENTS+++', _('Expected events')) \ | ||||
.replace('+++EVENTS+++', self._make_events()) | .replace('+++EVENTS+++', self._make_events()) | ||||
@@ -0,0 +1,40 @@ | |||||
#!/usr/bin/env python3 | |||||
# Kosmorro - Compute The Next Ephemerides | |||||
# Copyright (C) 2019 Jérôme Deuchnord <jerome@deuchnord.fr> | |||||
# | |||||
# This program is free software: you can redistribute it and/or modify | |||||
# it under the terms of the GNU Affero General Public License as | |||||
# published by the Free Software Foundation, either version 3 of the | |||||
# License, or (at your option) any later version. | |||||
# | |||||
# This program is distributed in the hope that it will be useful, | |||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
# GNU Affero General Public License for more details. | |||||
# | |||||
# You should have received a copy of the GNU Affero General Public License | |||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. | |||||
from enum import Enum | |||||
from .i18n import _ | |||||
class MoonPhaseType(Enum): | |||||
NEW_MOON = _('New Moon') | |||||
WAXING_CRESCENT = _('Waxing crescent') | |||||
FIRST_QUARTER = _('First Quarter') | |||||
WAXING_GIBBOUS = _('Waxing gibbous') | |||||
FULL_MOON = _('Full Moon') | |||||
WANING_GIBBOUS = _('Waning gibbous') | |||||
LAST_QUARTER = _('Last Quarter') | |||||
WANING_CRESCENT = _('Waning crescent') | |||||
class EventType(Enum): | |||||
OPPOSITION = _('%s is in opposition') | |||||
CONJUNCTION = _('%s and %s are in conjunction') | |||||
OCCULTATION = _('%s occults %s') | |||||
MAXIMAL_ELONGATION = _("%s's largest elongation") | |||||
MOON_PERIGEE = _("%s is at its perigee") | |||||
MOON_APOGEE = _("%s is at its apogee") |
@@ -17,20 +17,59 @@ | |||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. | # along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
import datetime | import datetime | ||||
from typing import Union | |||||
from skyfield.searchlib import find_discrete, find_maxima | from skyfield.searchlib import find_discrete, find_maxima | ||||
from skyfield.timelib import Time | from skyfield.timelib import Time | ||||
from skyfield.constants import tau | from skyfield.constants import tau | ||||
from skyfield.errors import EphemerisRangeError | from skyfield.errors import EphemerisRangeError | ||||
from .data import Position, AsterEphemerides, MoonPhase, Object, ASTERS, skyfield_to_moon_phase | |||||
from .data import Position, AsterEphemerides, MoonPhase, Object, ASTERS | |||||
from .dateutil import translate_to_timezone | from .dateutil import translate_to_timezone | ||||
from .core import get_skf_objects, get_timescale, get_iau2000b | from .core import get_skf_objects, get_timescale, get_iau2000b | ||||
from .enum import MoonPhaseType | |||||
from .exceptions import OutOfRangeDateError | from .exceptions import OutOfRangeDateError | ||||
RISEN_ANGLE = -0.8333 | RISEN_ANGLE = -0.8333 | ||||
def _get_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(MoonPhaseType) | |||||
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 get_moon_phase(compute_date: datetime.date, timezone: int = 0) -> MoonPhase: | def get_moon_phase(compute_date: datetime.date, timezone: int = 0) -> MoonPhase: | ||||
earth = get_skf_objects()['earth'] | earth = get_skf_objects()['earth'] | ||||
moon = get_skf_objects()['moon'] | moon = get_skf_objects()['moon'] | ||||
@@ -60,7 +99,7 @@ def get_moon_phase(compute_date: datetime.date, timezone: int = 0) -> MoonPhase: | |||||
raise OutOfRangeDateError(start, end) | raise OutOfRangeDateError(start, end) | ||||
return skyfield_to_moon_phase(times, phase, today) | |||||
return _get_skyfield_to_moon_phase(times, phase, today) | |||||
def get_ephemerides(date: datetime.date, position: Position, timezone: int = 0) -> [AsterEphemerides]: | def get_ephemerides(date: datetime.date, position: Position, timezone: int = 0) -> [AsterEphemerides]: | ||||
@@ -25,6 +25,7 @@ from numpy import pi | |||||
from .data import Event, Star, Planet, ASTERS | from .data import Event, Star, Planet, ASTERS | ||||
from .dateutil import translate_to_timezone | from .dateutil import translate_to_timezone | ||||
from .enum import EventType | |||||
from .exceptions import OutOfRangeDateError | from .exceptions import OutOfRangeDateError | ||||
from .core import get_timescale, get_skf_objects, flatten_list | from .core import get_timescale, get_skf_objects, flatten_list | ||||
@@ -68,10 +69,10 @@ def _search_conjunction(start_time: Time, end_time: Time, timezone: int) -> [Eve | |||||
aster2] if aster1_pos.distance().km < aster2_pos.distance().km else [aster2, | aster2] if aster1_pos.distance().km < aster2_pos.distance().km else [aster2, | ||||
aster1] | aster1] | ||||
conjunctions.append(Event('OCCULTATION', occulting_aster, | |||||
conjunctions.append(Event(EventType.OCCULTATION, occulting_aster, | |||||
translate_to_timezone(time.utc_datetime(), timezone))) | translate_to_timezone(time.utc_datetime(), timezone))) | ||||
else: | else: | ||||
conjunctions.append(Event('CONJUNCTION', [aster1, aster2], | |||||
conjunctions.append(Event(EventType.CONJUNCTION, [aster1, aster2], | |||||
translate_to_timezone(time.utc_datetime(), timezone))) | translate_to_timezone(time.utc_datetime(), timezone))) | ||||
computed.append(aster1) | computed.append(aster1) | ||||
@@ -101,7 +102,7 @@ def _search_oppositions(start_time: Time, end_time: Time, timezone: int) -> [Eve | |||||
times, _ = find_discrete(start_time, end_time, is_oppositing) | times, _ = find_discrete(start_time, end_time, is_oppositing) | ||||
for time in times: | for time in times: | ||||
events.append(Event('OPPOSITION', [aster], translate_to_timezone(time.utc_datetime(), timezone))) | |||||
events.append(Event(EventType.OPPOSITION, [aster], translate_to_timezone(time.utc_datetime(), timezone))) | |||||
return events | return events | ||||
@@ -129,7 +130,9 @@ def _search_maximal_elongations(start_time: Time, end_time: Time, timezone: int) | |||||
for i, time in enumerate(times): | for i, time in enumerate(times): | ||||
elongation = elongations[i] | elongation = elongations[i] | ||||
events.append(Event('MAXIMAL_ELONGATION', [aster], translate_to_timezone(time.utc_datetime(), timezone), | |||||
events.append(Event(EventType.MAXIMAL_ELONGATION, | |||||
[aster], | |||||
translate_to_timezone(time.utc_datetime(), timezone), | |||||
details='{:.3n}°'.format(elongation))) | details='{:.3n}°'.format(elongation))) | ||||
return events | return events | ||||
@@ -157,7 +160,7 @@ def _search_moon_apogee(start_time: Time, end_time: Time, timezone: int) -> [Eve | |||||
times, _ = find_maxima(start_time, end_time, f=_get_moon_distance(), epsilon=1./24/60) | times, _ = find_maxima(start_time, end_time, f=_get_moon_distance(), epsilon=1./24/60) | ||||
for time in times: | for time in times: | ||||
events.append(Event('MOON_APOGEE', [moon], translate_to_timezone(time.utc_datetime(), timezone))) | |||||
events.append(Event(EventType.MOON_APOGEE, [moon], translate_to_timezone(time.utc_datetime(), timezone))) | |||||
return events | return events | ||||
@@ -169,7 +172,7 @@ def _search_moon_perigee(start_time: Time, end_time: Time, timezone: int) -> [Ev | |||||
times, _ = find_minima(start_time, end_time, f=_get_moon_distance(), epsilon=1./24/60) | times, _ = find_minima(start_time, end_time, f=_get_moon_distance(), epsilon=1./24/60) | ||||
for time in times: | for time in times: | ||||
events.append(Event('MOON_PERIGEE', [moon], translate_to_timezone(time.utc_datetime(), timezone))) | |||||
events.append(Event(EventType.MOON_PERIGEE, [moon], translate_to_timezone(time.utc_datetime(), timezone))) | |||||
return events | return events | ||||
@@ -8,7 +8,7 @@ msgid "" | |||||
msgstr "" | msgstr "" | ||||
"Project-Id-Version: kosmorro 0.8.1\n" | "Project-Id-Version: kosmorro 0.8.1\n" | ||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | ||||
"POT-Creation-Date: 2020-12-01 12:01+0100\n" | |||||
"POT-Creation-Date: 2020-12-02 10:22+0100\n" | |||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||
"Language-Team: LANGUAGE <LL@li.org>\n" | "Language-Team: LANGUAGE <LL@li.org>\n" | ||||
@@ -27,182 +27,116 @@ msgid "" | |||||
"offset format." | "offset format." | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:32 | |||||
msgid "New Moon" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:33 | |||||
msgid "Waxing crescent" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:34 | |||||
msgid "First Quarter" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:35 | |||||
msgid "Waxing gibbous" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:36 | |||||
msgid "Full Moon" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:37 | |||||
msgid "Waning gibbous" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:38 | |||||
msgid "Last Quarter" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:39 | |||||
msgid "Waning crescent" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:40 | |||||
msgid "Unavailable" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:44 | |||||
#, python-format | |||||
msgid "%s is in opposition" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:45 | |||||
#, python-format | |||||
msgid "%s and %s are in conjunction" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:46 | |||||
#, python-format | |||||
msgid "%s occults %s" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:47 | |||||
#, python-format | |||||
msgid "%s's largest elongation" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:48 | |||||
#, python-format | |||||
msgid "%s is at its perigee" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:49 | |||||
#, python-format | |||||
msgid "%s is at its apogee" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:274 | |||||
#: kosmorrolib/data.py:197 | |||||
msgid "Sun" | msgid "Sun" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:275 | |||||
#: kosmorrolib/data.py:198 | |||||
msgid "Moon" | msgid "Moon" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:276 | |||||
#: kosmorrolib/data.py:199 | |||||
msgid "Mercury" | msgid "Mercury" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:277 | |||||
#: kosmorrolib/data.py:200 | |||||
msgid "Venus" | msgid "Venus" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:278 | |||||
#: kosmorrolib/data.py:201 | |||||
msgid "Mars" | msgid "Mars" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:279 | |||||
#: kosmorrolib/data.py:202 | |||||
msgid "Jupiter" | msgid "Jupiter" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:280 | |||||
#: kosmorrolib/data.py:203 | |||||
msgid "Saturn" | msgid "Saturn" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:281 | |||||
#: kosmorrolib/data.py:204 | |||||
msgid "Uranus" | msgid "Uranus" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:282 | |||||
#: kosmorrolib/data.py:205 | |||||
msgid "Neptune" | msgid "Neptune" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:283 | |||||
#: kosmorrolib/data.py:206 | |||||
msgid "Pluto" | msgid "Pluto" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:87 | |||||
#: kosmorrolib/dumper.py:88 | |||||
msgid "Expected events:" | msgid "Expected events:" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:91 | |||||
#: kosmorrolib/dumper.py:92 | |||||
msgid "Note: All the hours are given in UTC." | msgid "Note: All the hours are given in UTC." | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:96 | |||||
#: kosmorrolib/dumper.py:97 | |||||
msgid "Note: All the hours are given in the UTC{offset} timezone." | msgid "Note: All the hours are given in the UTC{offset} timezone." | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:142 kosmorrolib/dumper.py:229 | |||||
#: kosmorrolib/dumper.py:143 kosmorrolib/dumper.py:227 | |||||
msgid "Object" | msgid "Object" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:143 kosmorrolib/dumper.py:230 | |||||
#: kosmorrolib/dumper.py:144 kosmorrolib/dumper.py:228 | |||||
msgid "Rise time" | msgid "Rise time" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:144 kosmorrolib/dumper.py:231 | |||||
#: kosmorrolib/dumper.py:145 kosmorrolib/dumper.py:229 | |||||
msgid "Culmination time" | msgid "Culmination time" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:145 kosmorrolib/dumper.py:232 | |||||
#: kosmorrolib/dumper.py:146 kosmorrolib/dumper.py:230 | |||||
msgid "Set time" | msgid "Set time" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:160 | |||||
#: kosmorrolib/dumper.py:161 | |||||
msgid "Moon phase is unavailable for this date." | msgid "Moon phase is unavailable for this date." | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:162 kosmorrolib/dumper.py:236 | |||||
#: kosmorrolib/dumper.py:163 kosmorrolib/dumper.py:234 | |||||
msgid "Moon phase:" | msgid "Moon phase:" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:163 | |||||
#: kosmorrolib/dumper.py:164 | |||||
msgid "{next_moon_phase} on {next_moon_phase_date} at {next_moon_phase_time}" | msgid "{next_moon_phase} on {next_moon_phase_date} at {next_moon_phase_time}" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:216 | |||||
#: kosmorrolib/dumper.py:214 | |||||
msgid "A Summary of your Sky" | msgid "A Summary of your Sky" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:220 | |||||
#: kosmorrolib/dumper.py:218 | |||||
msgid "" | msgid "" | ||||
"This document summarizes the ephemerides and the events of {date}. It " | "This document summarizes the ephemerides and the events of {date}. It " | ||||
"aims to help you to prepare your observation session. All the hours are " | "aims to help you to prepare your observation session. All the hours are " | ||||
"given in {timezone}." | "given in {timezone}." | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:226 | |||||
#: kosmorrolib/dumper.py:224 | |||||
msgid "" | msgid "" | ||||
"Don't forget to check the weather forecast before you go out with your " | "Don't forget to check the weather forecast before you go out with your " | ||||
"equipment." | "equipment." | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:228 | |||||
#: kosmorrolib/dumper.py:226 | |||||
msgid "Ephemerides of the day" | msgid "Ephemerides of the day" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:234 | |||||
#: kosmorrolib/dumper.py:232 | |||||
msgid "hours" | msgid "hours" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:238 | |||||
#: kosmorrolib/dumper.py:236 | |||||
msgid "Expected events" | msgid "Expected events" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:352 | |||||
#: kosmorrolib/dumper.py:350 | |||||
msgid "" | msgid "" | ||||
"Building PDFs was not possible, because some dependencies are not " | "Building PDFs was not possible, because some dependencies are not " | ||||
"installed.\n" | "installed.\n" | ||||
@@ -210,6 +144,68 @@ msgid "" | |||||
"information." | "information." | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/enum.py:24 | |||||
msgid "New Moon" | |||||
msgstr "" | |||||
#: kosmorrolib/enum.py:25 | |||||
msgid "Waxing crescent" | |||||
msgstr "" | |||||
#: kosmorrolib/enum.py:26 | |||||
msgid "First Quarter" | |||||
msgstr "" | |||||
#: kosmorrolib/enum.py:27 | |||||
msgid "Waxing gibbous" | |||||
msgstr "" | |||||
#: kosmorrolib/enum.py:28 | |||||
msgid "Full Moon" | |||||
msgstr "" | |||||
#: kosmorrolib/enum.py:29 | |||||
msgid "Waning gibbous" | |||||
msgstr "" | |||||
#: kosmorrolib/enum.py:30 | |||||
msgid "Last Quarter" | |||||
msgstr "" | |||||
#: kosmorrolib/enum.py:31 | |||||
msgid "Waning crescent" | |||||
msgstr "" | |||||
#: kosmorrolib/enum.py:35 | |||||
#, python-format | |||||
msgid "%s is in opposition" | |||||
msgstr "" | |||||
#: kosmorrolib/enum.py:36 | |||||
#, python-format | |||||
msgid "%s and %s are in conjunction" | |||||
msgstr "" | |||||
#: kosmorrolib/enum.py:37 | |||||
#, python-format | |||||
msgid "%s occults %s" | |||||
msgstr "" | |||||
#: kosmorrolib/enum.py:38 | |||||
#, python-format | |||||
msgid "%s's largest elongation" | |||||
msgstr "" | |||||
#: kosmorrolib/enum.py:39 | |||||
#, python-format | |||||
msgid "%s is at its perigee" | |||||
msgstr "" | |||||
#: kosmorrolib/enum.py:40 | |||||
#, python-format | |||||
msgid "%s is at its apogee" | |||||
msgstr "" | |||||
#: kosmorrolib/exceptions.py:34 | #: kosmorrolib/exceptions.py:34 | ||||
msgid "The date must be between {minimum_date} and {maximum_date}" | msgid "The date must be between {minimum_date} and {maximum_date}" | ||||
msgstr "" | msgstr "" | ||||
@@ -3,6 +3,7 @@ from datetime import date, datetime | |||||
from kosmorrolib.data import AsterEphemerides, Planet, MoonPhase, Event | from kosmorrolib.data import AsterEphemerides, Planet, MoonPhase, Event | ||||
from kosmorrolib.dumper import JsonDumper, TextDumper, _LatexDumper | from kosmorrolib.dumper import JsonDumper, TextDumper, _LatexDumper | ||||
from kosmorrolib.enum import MoonPhaseType, EventType | |||||
class DumperTestCase(unittest.TestCase): | class DumperTestCase(unittest.TestCase): | ||||
@@ -283,14 +284,14 @@ class DumperTestCase(unittest.TestCase): | |||||
@staticmethod | @staticmethod | ||||
def _get_moon_phase(): | def _get_moon_phase(): | ||||
return MoonPhase('FULL_MOON', datetime(2019, 10, 14), datetime(2019, 10, 21)) | |||||
return MoonPhase(MoonPhaseType.FULL_MOON, datetime(2019, 10, 14), datetime(2019, 10, 21)) | |||||
@staticmethod | @staticmethod | ||||
def _get_events(): | def _get_events(): | ||||
return [Event('OPPOSITION', | |||||
return [Event(EventType.OPPOSITION, | |||||
[Planet('Mars', 'MARS')], | [Planet('Mars', 'MARS')], | ||||
datetime(2019, 10, 14, 23, 00)), | datetime(2019, 10, 14, 23, 00)), | ||||
Event('MAXIMAL_ELONGATION', | |||||
Event(EventType.MAXIMAL_ELONGATION, | |||||
[Planet('Venus', 'VENUS')], | [Planet('Venus', 'VENUS')], | ||||
datetime(2019, 10, 14, 12, 00), details='42.0°'), | datetime(2019, 10, 14, 12, 00), details='42.0°'), | ||||
] | ] | ||||
@@ -1,7 +1,10 @@ | |||||
import unittest | import unittest | ||||
from .testutils import expect_assertions | from .testutils import expect_assertions | ||||
from kosmorrolib import ephemerides | from kosmorrolib import ephemerides | ||||
from kosmorrolib.data import EARTH, Position, MoonPhase | from kosmorrolib.data import EARTH, Position, MoonPhase | ||||
from kosmorrolib.enum import MoonPhaseType | |||||
from datetime import date | from datetime import date | ||||
from kosmorrolib.exceptions import OutOfRangeDateError | from kosmorrolib.exceptions import OutOfRangeDateError | ||||
@@ -29,84 +32,84 @@ class EphemeridesTestCase(unittest.TestCase): | |||||
def test_moon_phase_new_moon(self): | def test_moon_phase_new_moon(self): | ||||
phase = ephemerides.get_moon_phase(date(2019, 11, 25)) | phase = ephemerides.get_moon_phase(date(2019, 11, 25)) | ||||
self.assertEqual('WANING_CRESCENT', phase.identifier) | |||||
self.assertEqual(MoonPhaseType.WANING_CRESCENT, phase.phase_type) | |||||
self.assertIsNone(phase.time) | self.assertIsNone(phase.time) | ||||
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-26T') | self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-26T') | ||||
phase = ephemerides.get_moon_phase(date(2019, 11, 26)) | phase = ephemerides.get_moon_phase(date(2019, 11, 26)) | ||||
self.assertEqual('NEW_MOON', phase.identifier) | |||||
self.assertEqual(MoonPhaseType.NEW_MOON, phase.phase_type) | |||||
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-12-04T') | self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-12-04T') | ||||
phase = ephemerides.get_moon_phase(date(2019, 11, 27)) | phase = ephemerides.get_moon_phase(date(2019, 11, 27)) | ||||
self.assertEqual('WAXING_CRESCENT', phase.identifier) | |||||
self.assertEqual(MoonPhaseType.WAXING_CRESCENT, phase.phase_type) | |||||
self.assertIsNone(phase.time) | self.assertIsNone(phase.time) | ||||
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-12-04T') | self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-12-04T') | ||||
def test_moon_phase_first_crescent(self): | def test_moon_phase_first_crescent(self): | ||||
phase = ephemerides.get_moon_phase(date(2019, 11, 3)) | phase = ephemerides.get_moon_phase(date(2019, 11, 3)) | ||||
self.assertEqual('WAXING_CRESCENT', phase.identifier) | |||||
self.assertEqual(MoonPhaseType.WAXING_CRESCENT, phase.phase_type) | |||||
self.assertIsNone(phase.time) | self.assertIsNone(phase.time) | ||||
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-04T') | self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-04T') | ||||
phase = ephemerides.get_moon_phase(date(2019, 11, 4)) | phase = ephemerides.get_moon_phase(date(2019, 11, 4)) | ||||
self.assertEqual('FIRST_QUARTER', phase.identifier) | |||||
self.assertEqual(MoonPhaseType.FIRST_QUARTER, phase.phase_type) | |||||
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-12T') | self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-12T') | ||||
phase = ephemerides.get_moon_phase(date(2019, 11, 5)) | phase = ephemerides.get_moon_phase(date(2019, 11, 5)) | ||||
self.assertEqual('WAXING_GIBBOUS', phase.identifier) | |||||
self.assertEqual(MoonPhaseType.WAXING_GIBBOUS, phase.phase_type) | |||||
self.assertIsNone(phase.time) | self.assertIsNone(phase.time) | ||||
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-12T') | self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-12T') | ||||
def test_moon_phase_full_moon(self): | def test_moon_phase_full_moon(self): | ||||
phase = ephemerides.get_moon_phase(date(2019, 11, 11)) | phase = ephemerides.get_moon_phase(date(2019, 11, 11)) | ||||
self.assertEqual('WAXING_GIBBOUS', phase.identifier) | |||||
self.assertEqual(MoonPhaseType.WAXING_GIBBOUS, phase.phase_type) | |||||
self.assertIsNone(phase.time) | self.assertIsNone(phase.time) | ||||
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-12T') | self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-12T') | ||||
phase = ephemerides.get_moon_phase(date(2019, 11, 12)) | phase = ephemerides.get_moon_phase(date(2019, 11, 12)) | ||||
self.assertEqual('FULL_MOON', phase.identifier) | |||||
self.assertEqual(MoonPhaseType.FULL_MOON, phase.phase_type) | |||||
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-19T') | self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-19T') | ||||
phase = ephemerides.get_moon_phase(date(2019, 11, 13)) | phase = ephemerides.get_moon_phase(date(2019, 11, 13)) | ||||
self.assertEqual('WANING_GIBBOUS', phase.identifier) | |||||
self.assertEqual(MoonPhaseType.WANING_GIBBOUS, phase.phase_type) | |||||
self.assertIsNone(phase.time) | self.assertIsNone(phase.time) | ||||
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-19T') | self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-19T') | ||||
def test_moon_phase_last_quarter(self): | def test_moon_phase_last_quarter(self): | ||||
phase = ephemerides.get_moon_phase(date(2019, 11, 18)) | phase = ephemerides.get_moon_phase(date(2019, 11, 18)) | ||||
self.assertEqual('WANING_GIBBOUS', phase.identifier) | |||||
self.assertEqual(MoonPhaseType.WANING_GIBBOUS, phase.phase_type) | |||||
self.assertIsNone(phase.time) | self.assertIsNone(phase.time) | ||||
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-19T') | self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-19T') | ||||
phase = ephemerides.get_moon_phase(date(2019, 11, 19)) | phase = ephemerides.get_moon_phase(date(2019, 11, 19)) | ||||
self.assertEqual('LAST_QUARTER', phase.identifier) | |||||
self.assertEqual(MoonPhaseType.LAST_QUARTER, phase.phase_type) | |||||
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-26T') | self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-26T') | ||||
phase = ephemerides.get_moon_phase(date(2019, 11, 20)) | phase = ephemerides.get_moon_phase(date(2019, 11, 20)) | ||||
self.assertEqual('WANING_CRESCENT', phase.identifier) | |||||
self.assertEqual(MoonPhaseType.WANING_CRESCENT, phase.phase_type) | |||||
self.assertIsNone(phase.time) | self.assertIsNone(phase.time) | ||||
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-26T') | self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-26T') | ||||
def test_moon_phase_prediction(self): | def test_moon_phase_prediction(self): | ||||
phase = MoonPhase('NEW_MOON', None, None) | |||||
self.assertEqual('First Quarter', phase.get_next_phase_name()) | |||||
phase = MoonPhase('WAXING_CRESCENT', None, None) | |||||
self.assertEqual('First Quarter', phase.get_next_phase_name()) | |||||
phase = MoonPhase('FIRST_QUARTER', None, None) | |||||
self.assertEqual('Full Moon', phase.get_next_phase_name()) | |||||
phase = MoonPhase('WAXING_GIBBOUS', None, None) | |||||
self.assertEqual('Full Moon', phase.get_next_phase_name()) | |||||
phase = MoonPhase('FULL_MOON', None, None) | |||||
self.assertEqual('Last Quarter', phase.get_next_phase_name()) | |||||
phase = MoonPhase('WANING_GIBBOUS', None, None) | |||||
self.assertEqual('Last Quarter', phase.get_next_phase_name()) | |||||
phase = MoonPhase('LAST_QUARTER', None, None) | |||||
self.assertEqual('New Moon', phase.get_next_phase_name()) | |||||
phase = MoonPhase('WANING_CRESCENT', None, None) | |||||
self.assertEqual('New Moon', phase.get_next_phase_name()) | |||||
phase = MoonPhase(MoonPhaseType.NEW_MOON, None, None) | |||||
self.assertEqual(MoonPhaseType.FIRST_QUARTER, phase.get_next_phase()) | |||||
phase = MoonPhase(MoonPhaseType.WAXING_CRESCENT, None, None) | |||||
self.assertEqual(MoonPhaseType.FIRST_QUARTER, phase.get_next_phase()) | |||||
phase = MoonPhase(MoonPhaseType.FIRST_QUARTER, None, None) | |||||
self.assertEqual(MoonPhaseType.FULL_MOON, phase.get_next_phase()) | |||||
phase = MoonPhase(MoonPhaseType.WAXING_GIBBOUS, None, None) | |||||
self.assertEqual(MoonPhaseType.FULL_MOON, phase.get_next_phase()) | |||||
phase = MoonPhase(MoonPhaseType.FULL_MOON, None, None) | |||||
self.assertEqual(MoonPhaseType.LAST_QUARTER, phase.get_next_phase()) | |||||
phase = MoonPhase(MoonPhaseType.WANING_GIBBOUS, None, None) | |||||
self.assertEqual(MoonPhaseType.LAST_QUARTER, phase.get_next_phase()) | |||||
phase = MoonPhase(MoonPhaseType.LAST_QUARTER, None, None) | |||||
self.assertEqual(MoonPhaseType.NEW_MOON, phase.get_next_phase()) | |||||
phase = MoonPhase(MoonPhaseType.WANING_CRESCENT, None, None) | |||||
self.assertEqual(MoonPhaseType.NEW_MOON, phase.get_next_phase()) | |||||
def test_get_ephemerides_raises_exception_on_out_of_date_range(self): | def test_get_ephemerides_raises_exception_on_out_of_date_range(self): | ||||
with self.assertRaises(OutOfRangeDateError): | with self.assertRaises(OutOfRangeDateError): | ||||
@@ -1,12 +1,11 @@ | |||||
import unittest | import unittest | ||||
from datetime import date, datetime | from datetime import date, datetime | ||||
from json import dumps | |||||
from unittest_data_provider import data_provider | |||||
from kosmorrolib import events | from kosmorrolib import events | ||||
from kosmorrolib.data import Event, ASTERS | from kosmorrolib.data import Event, ASTERS | ||||
from kosmorrolib.core import get_timescale | |||||
from unittest_data_provider import data_provider | |||||
from kosmorrolib.enum import EventType | |||||
from kosmorrolib.exceptions import OutOfRangeDateError | from kosmorrolib.exceptions import OutOfRangeDateError | ||||
@@ -14,42 +13,38 @@ class EventTestCase(unittest.TestCase): | |||||
def setUp(self) -> None: | def setUp(self) -> None: | ||||
self.maxDiff = None | self.maxDiff = None | ||||
def test_event_only_accepts_valid_values(self): | |||||
with self.assertRaises(ValueError): | |||||
Event('SUPERNOVA', None, get_timescale().now()) | |||||
expected_events_provider = lambda: ( | expected_events_provider = lambda: ( | ||||
(date(2020, 2, 7), []), | (date(2020, 2, 7), []), | ||||
(date(2020, 10, 13), [Event('OPPOSITION', [ASTERS[4]], datetime(2020, 10, 13, 23, 25))]), | |||||
(date(2020, 10, 13), [Event(EventType.OPPOSITION, [ASTERS[4]], datetime(2020, 10, 13, 23, 25))]), | |||||
(date(2022, 12, 8), [Event('CONJUNCTION', [ASTERS[1], ASTERS[4]], datetime(2022, 12, 8, 4, 18)), | |||||
Event('OPPOSITION', [ASTERS[4]], datetime(2022, 12, 8, 5, 41))]), | |||||
(date(2022, 12, 8), [Event(EventType.CONJUNCTION, [ASTERS[1], ASTERS[4]], datetime(2022, 12, 8, 4, 18)), | |||||
Event(EventType.OPPOSITION, [ASTERS[4]], datetime(2022, 12, 8, 5, 41))]), | |||||
(date(2025, 1, 16), [Event('OPPOSITION', [ASTERS[4]], datetime(2025, 1, 16, 2, 38))]), | |||||
(date(2025, 1, 16), [Event(EventType.OPPOSITION, [ASTERS[4]], datetime(2025, 1, 16, 2, 38))]), | |||||
(date(2027, 2, 19), [Event('MOON_PERIGEE', [ASTERS[1]], datetime(2027, 2, 19, 7, 38)), | |||||
Event('OPPOSITION', [ASTERS[4]], datetime(2027, 2, 19, 15, 50))]), | |||||
(date(2027, 2, 19), [Event(EventType.MOON_PERIGEE, [ASTERS[1]], datetime(2027, 2, 19, 7, 38)), | |||||
Event(EventType.OPPOSITION, [ASTERS[4]], datetime(2027, 2, 19, 15, 50))]), | |||||
(date(2020, 1, 2), [Event('MOON_APOGEE', [ASTERS[1]], datetime(2020, 1, 2, 1, 32)), | |||||
Event('CONJUNCTION', [ASTERS[2], ASTERS[5]], datetime(2020, 1, 2, 16, 41))]), | |||||
(date(2020, 1, 2), [Event(EventType.MOON_APOGEE, [ASTERS[1]], datetime(2020, 1, 2, 1, 32)), | |||||
Event(EventType.CONJUNCTION, [ASTERS[2], ASTERS[5]], datetime(2020, 1, 2, 16, 41))]), | |||||
(date(2020, 1, 12), [Event('CONJUNCTION', [ASTERS[2], ASTERS[6]], datetime(2020, 1, 12, 9, 51)), | |||||
Event('CONJUNCTION', [ASTERS[2], ASTERS[9]], datetime(2020, 1, 12, 10, 13)), | |||||
Event('CONJUNCTION', [ASTERS[6], ASTERS[9]], datetime(2020, 1, 12, 16, 57))]), | |||||
(date(2020, 1, 12), [Event(EventType.CONJUNCTION, [ASTERS[2], ASTERS[6]], datetime(2020, 1, 12, 9, 51)), | |||||
Event(EventType.CONJUNCTION, [ASTERS[2], ASTERS[9]], datetime(2020, 1, 12, 10, 13)), | |||||
Event(EventType.CONJUNCTION, [ASTERS[6], ASTERS[9]], datetime(2020, 1, 12, 16, 57))]), | |||||
(date(2020, 2, 10), [Event('MAXIMAL_ELONGATION', [ASTERS[2]], datetime(2020, 2, 10, 13, 46), details='18.2°'), | |||||
Event('MOON_PERIGEE', [ASTERS[1]], datetime(2020, 2, 10, 20, 34))]), | |||||
(date(2020, 2, 10), [Event(EventType.MAXIMAL_ELONGATION, [ASTERS[2]], datetime(2020, 2, 10, 13, 46), details='18.2°'), | |||||
Event(EventType.MOON_PERIGEE, [ASTERS[1]], datetime(2020, 2, 10, 20, 34))]), | |||||
(date(2020, 3, 24), [Event('MAXIMAL_ELONGATION', [ASTERS[2]], datetime(2020, 3, 24, 1, 56), details='27.8°'), | |||||
Event('MOON_APOGEE', [ASTERS[1]], datetime(2020, 3, 24, 15, 39)), | |||||
Event('MAXIMAL_ELONGATION', [ASTERS[3]], datetime(2020, 3, 24, 21, 58), details='46.1°')]), | |||||
(date(2020, 3, 24), [Event(EventType.MAXIMAL_ELONGATION, [ASTERS[2]], datetime(2020, 3, 24, 1, 56), details='27.8°'), | |||||
Event(EventType.MOON_APOGEE, [ASTERS[1]], datetime(2020, 3, 24, 15, 39)), | |||||
Event(EventType.MAXIMAL_ELONGATION, [ASTERS[3]], datetime(2020, 3, 24, 21, 58), details='46.1°')]), | |||||
(date(2005, 6, 16), [Event('OCCULTATION', [ASTERS[1], ASTERS[5]], datetime(2005, 6, 16, 6, 31))]), | |||||
(date(2005, 6, 16), [Event(EventType.OCCULTATION, [ASTERS[1], ASTERS[5]], datetime(2005, 6, 16, 6, 31))]), | |||||
(date(2020, 4, 7), [Event('MOON_PERIGEE', [ASTERS[1]], datetime(2020, 4, 7, 18, 14))]), | |||||
(date(2020, 4, 7), [Event(EventType.MOON_PERIGEE, [ASTERS[1]], datetime(2020, 4, 7, 18, 14))]), | |||||
(date(2020, 1, 29), [Event('MOON_APOGEE', [ASTERS[1]], datetime(2020, 1, 29, 21, 32))]) | |||||
(date(2020, 1, 29), [Event(EventType.MOON_APOGEE, [ASTERS[1]], datetime(2020, 1, 29, 21, 32))]) | |||||
) | ) | ||||
@data_provider(expected_events_provider) | @data_provider(expected_events_provider) | ||||