Browse Source

feat: add support for timezones

tags/v0.6.0
Jérôme Deuchnord 4 years ago
parent
commit
d7730bd2ad
No known key found for this signature in database GPG Key ID: BC6F3C345B7D33B0
12 changed files with 213 additions and 106 deletions
  1. +2
    -1
      .pylintrc
  2. +2
    -0
      .scripts/tests-e2e.sh
  3. +3
    -1
      kosmorrolib/core.py
  4. +7
    -6
      kosmorrolib/data.py
  5. +76
    -18
      kosmorrolib/dumper.py
  6. +5
    -0
      kosmorrolib/ephemerides.py
  7. +3
    -3
      kosmorrolib/events.py
  8. +48
    -35
      kosmorrolib/locales/messages.pot
  9. +5
    -1
      kosmorrolib/main.py
  10. +45
    -24
      test/dumper.py
  11. +15
    -15
      test/ephemerides.py
  12. +2
    -2
      test/events.py

+ 2
- 1
.pylintrc View File

@@ -146,7 +146,8 @@ disable=print-statement,
too-many-branches, too-many-branches,
too-few-public-methods, too-few-public-methods,
protected-access, protected-access,
unnecessary-comprehension
unnecessary-comprehension,
too-many-arguments


# Enable the message, report, category or checker with the given id(s). You can # Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option # either give multiple identifier separated by comma (,) or put this option


+ 2
- 0
.scripts/tests-e2e.sh View File

@@ -79,6 +79,8 @@ assertSuccess "$PIP_BIN install dist/kosmorro-$VERSION.tar.gz" "CI"
assertSuccess kosmorro assertSuccess kosmorro
assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624" 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"
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" 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" assertFailure "kosmorro --latitude=50.5876 --longitude=3.0624 -d 27 -m 1 -y 2020 --format=pdf"
# Missing dependencies, should fail # Missing dependencies, should fail


+ 3
- 1
kosmorrolib/core.py View File

@@ -95,7 +95,9 @@ def skyfield_to_moon_phase(times: [Time], vals: [int], now: Time) -> Union[MoonP
next_phase_time = times[j] next_phase_time = times[j]
break break


return MoonPhase(current_phase, current_phase_time, next_phase_time)
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): def flatten_list(the_list: list):


+ 7
- 6
kosmorrolib/data.py View File

@@ -18,9 +18,9 @@


from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Union from typing import Union
from datetime import datetime


from skyfield.api import Topos from skyfield.api import Topos
from skyfield.timelib import Time


from .i18n import _ from .i18n import _


@@ -42,7 +42,7 @@ EVENTS = {




class MoonPhase: class MoonPhase:
def __init__(self, identifier: str, time: Union[Time, None], next_phase_date: Union[Time, None]):
def __init__(self, identifier: str, time: Union[datetime, None], next_phase_date: Union[datetime, None]):
if identifier not in MOON_PHASES.keys(): if identifier not in MOON_PHASES.keys():
raise ValueError('identifier parameter must be one of %s (got %s)' % (', '.join(MOON_PHASES.keys()), raise ValueError('identifier parameter must be one of %s (got %s)' % (', '.join(MOON_PHASES.keys()),
identifier)) identifier))
@@ -87,9 +87,9 @@ class Position:


class AsterEphemerides: class AsterEphemerides:
def __init__(self, def __init__(self,
rise_time: Union[Time, None],
culmination_time: Union[Time, None],
set_time: Union[Time, None]):
rise_time: Union[datetime, None],
culmination_time: Union[datetime, None],
set_time: Union[datetime, None]):
self.rise_time = rise_time self.rise_time = rise_time
self.culmination_time = culmination_time self.culmination_time = culmination_time
self.set_time = set_time self.set_time = set_time
@@ -141,7 +141,8 @@ class Satellite(Object):




class Event: class Event:
def __init__(self, event_type: str, objects: [Object], start_time: Time, end_time: Union[Time, None] = None):
def __init__(self, event_type: str, objects: [Object], start_time: datetime,
end_time: Union[datetime, None] = None):
if event_type not in EVENTS.keys(): if event_type not in EVENTS.keys():
raise ValueError('event_type parameter must be one of the following: %s (got %s)' % ( raise ValueError('event_type parameter must be one of the following: %s (got %s)' % (
', '.join(EVENTS.keys()), ', '.join(EVENTS.keys()),


+ 76
- 18
kosmorrolib/dumper.py View File

@@ -21,7 +21,6 @@ import datetime
import json import json
import os import os
from tabulate import tabulate from tabulate import tabulate
from skyfield.timelib import Time
from numpy import int64 from numpy import int64
from termcolor import colored from termcolor import colored
from .data import Object, AsterEphemerides, MoonPhase, Event from .data import Object, AsterEphemerides, MoonPhase, Event
@@ -35,17 +34,52 @@ except ImportError:


FULL_DATE_FORMAT = _('{day_of_week} {month} {day_number}, {year}').format(day_of_week='%A', month='%B', FULL_DATE_FORMAT = _('{day_of_week} {month} {day_number}, {year}').format(day_of_week='%A', month='%B',
day_number='%d', year='%Y') day_number='%d', year='%Y')
SHORT_DATETIME_FORMAT = _('{month} {day_number}, {hours}:{minutes}').format(month='%b', day_number='%d',
hours='%H', minutes='%M')
TIME_FORMAT = _('{hours}:{minutes}').format(hours='%H', minutes='%M') TIME_FORMAT = _('{hours}:{minutes}').format(hours='%H', minutes='%M')




class Dumper(ABC): class Dumper(ABC):
def __init__(self, ephemeris: dict, events: [Event], date: datetime.date = datetime.date.today(),
def __init__(self, ephemeris: dict, events: [Event], date: datetime.date = datetime.date.today(), timezone: int = 0,
with_colors: bool = True): with_colors: bool = True):
self.ephemeris = ephemeris self.ephemeris = ephemeris
self.events = events self.events = events
self.date = date self.date = date
self.timezone = timezone
self.with_colors = with_colors self.with_colors = with_colors


if self.timezone != 0:
self._convert_dates_to_timezones()

def _convert_dates_to_timezones(self):
if self.ephemeris['moon_phase'].time is not None:
self.ephemeris['moon_phase'].time = self._datetime_to_timezone(self.ephemeris['moon_phase'].time)
if self.ephemeris['moon_phase'].next_phase_date is not None:
self.ephemeris['moon_phase'].next_phase_date = self._datetime_to_timezone(
self.ephemeris['moon_phase'].next_phase_date)

for aster in self.ephemeris['details']:
if aster.ephemerides.rise_time is not None:
aster.ephemerides.rise_time = self._datetime_to_timezone(aster.ephemerides.rise_time)
if aster.ephemerides.culmination_time is not None:
aster.ephemerides.culmination_time = self._datetime_to_timezone(aster.ephemerides.culmination_time)
if aster.ephemerides.set_time is not None:
aster.ephemerides.set_time = self._datetime_to_timezone(aster.ephemerides.set_time)

for event in self.events:
event.start_time = self._datetime_to_timezone(event.start_time)
if event.end_time is not None:
event.end_time = self._datetime_to_timezone(event.end_time)

def _datetime_to_timezone(self, time: datetime.datetime):
return time.replace(tzinfo=datetime.timezone.utc).astimezone(
tz=datetime.timezone(
datetime.timedelta(
hours=self.timezone
)
)
)

def get_date_as_string(self, capitalized: bool = False) -> str: def get_date_as_string(self, capitalized: bool = False) -> str:
date = self.date.strftime(FULL_DATE_FORMAT) date = self.date.strftime(FULL_DATE_FORMAT)


@@ -77,8 +111,8 @@ class JsonDumper(Dumper):
# See https://stackoverflow.com/a/50577730 # See https://stackoverflow.com/a/50577730
if isinstance(obj, int64): if isinstance(obj, int64):
return int(obj) return int(obj)
if isinstance(obj, Time):
return obj.utc_iso()
if isinstance(obj, datetime.datetime):
return obj.isoformat()
if isinstance(obj, Object): if isinstance(obj, Object):
obj = obj.__dict__ obj = obj.__dict__
obj.pop('skyfield_name') obj.pop('skyfield_name')
@@ -113,7 +147,14 @@ class TextDumper(Dumper):
text.append('\n'.join([self.style(_('Expected events:'), 'h2'), text.append('\n'.join([self.style(_('Expected events:'), 'h2'),
self.get_events(self.events)])) self.get_events(self.events)]))


text.append(self.style(_('Note: All the hours are given in UTC.'), 'em'))
if self.timezone == 0:
text.append(self.style(_('Note: All the hours are given in UTC.'), 'em'))
else:
tz_offset = str(self.timezone)
if self.timezone > 0:
tz_offset = ''.join(['+', tz_offset])
text.append(self.style(_('Note: All the hours are given in the UTC{offset} timezone.').format(
offset=tz_offset), 'em'))


return '\n\n'.join(text) return '\n\n'.join(text)


@@ -138,17 +179,21 @@ class TextDumper(Dumper):
name = self.style(aster.name, 'th') name = self.style(aster.name, 'th')


if aster.ephemerides.rise_time is not None: if aster.ephemerides.rise_time is not None:
planet_rise = aster.ephemerides.rise_time.utc_strftime(TIME_FORMAT)
time_fmt = TIME_FORMAT if aster.ephemerides.rise_time.day == self.date.day else SHORT_DATETIME_FORMAT
planet_rise = aster.ephemerides.rise_time.strftime(time_fmt)
else: else:
planet_rise = '-' planet_rise = '-'


if aster.ephemerides.culmination_time is not None: if aster.ephemerides.culmination_time is not None:
planet_culmination = aster.ephemerides.culmination_time.utc_strftime(TIME_FORMAT)
time_fmt = TIME_FORMAT if aster.ephemerides.culmination_time.day == self.date.day \
else SHORT_DATETIME_FORMAT
planet_culmination = aster.ephemerides.culmination_time.strftime(time_fmt)
else: else:
planet_culmination = '-' planet_culmination = '-'


if aster.ephemerides.set_time is not None: if aster.ephemerides.set_time is not None:
planet_set = aster.ephemerides.set_time.utc_strftime(TIME_FORMAT)
time_fmt = TIME_FORMAT if aster.ephemerides.set_time.day == self.date.day else SHORT_DATETIME_FORMAT
planet_set = aster.ephemerides.set_time.strftime(time_fmt)
else: else:
planet_set = '-' planet_set = '-'


@@ -164,7 +209,8 @@ class TextDumper(Dumper):
data = [] data = []


for event in events: for event in events:
data.append([self.style(event.start_time.utc_strftime(TIME_FORMAT), 'th'),
time_fmt = TIME_FORMAT if event.start_time.day == self.date.day else SHORT_DATETIME_FORMAT
data.append([self.style(event.start_time.strftime(time_fmt), 'th'),
event.get_description()]) event.get_description()])


return tabulate(data, tablefmt='plain', stralign='left') return tabulate(data, tablefmt='plain', stralign='left')
@@ -173,8 +219,8 @@ class TextDumper(Dumper):
current_moon_phase = ' '.join([self.style(_('Moon phase:'), 'strong'), moon_phase.get_phase()]) current_moon_phase = ' '.join([self.style(_('Moon phase:'), 'strong'), moon_phase.get_phase()])
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(), next_moon_phase=moon_phase.get_next_phase(),
next_moon_phase_date=moon_phase.next_phase_date.utc_strftime(FULL_DATE_FORMAT),
next_moon_phase_time=moon_phase.next_phase_date.utc_strftime(TIME_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)
) )


return '\n'.join([current_moon_phase, new_moon_phase]) return '\n'.join([current_moon_phase, new_moon_phase])
@@ -214,8 +260,11 @@ class _LatexDumper(Dumper):
.replace('+++INTRODUCTION+++', .replace('+++INTRODUCTION+++',
'\n\n'.join([ '\n\n'.join([
_("This document summarizes the ephemerides and the events of {date}. " _("This document summarizes the ephemerides and the events of {date}. "
"It aims to help you to prepare your observation session.").format(
date=self.get_date_as_string()),
"It aims to help you to prepare your observation session. "
"All the hours are given in {timezone}.").format(
date=self.get_date_as_string(),
timezone='UTC+%d timezone' % self.timezone if self.timezone != 0 else 'UTC'
),
_("Don't forget to check the weather forecast before you go out with your material.") _("Don't forget to check the weather forecast before you go out with your material.")
])) \ ])) \
.replace('+++SECTION-EPHEMERIDES+++', _('Ephemerides of the day')) \ .replace('+++SECTION-EPHEMERIDES+++', _('Ephemerides of the day')) \
@@ -237,17 +286,21 @@ class _LatexDumper(Dumper):


for aster in self.ephemeris['details']: for aster in self.ephemeris['details']:
if aster.ephemerides.rise_time is not None: if aster.ephemerides.rise_time is not None:
aster_rise = aster.ephemerides.rise_time.utc_strftime(TIME_FORMAT)
time_fmt = TIME_FORMAT if aster.ephemerides.rise_time.day == self.date.day else SHORT_DATETIME_FORMAT
aster_rise = aster.ephemerides.rise_time.strftime(time_fmt)
else: else:
aster_rise = '-' aster_rise = '-'


if aster.ephemerides.culmination_time is not None: if aster.ephemerides.culmination_time is not None:
aster_culmination = aster.ephemerides.culmination_time.utc_strftime(TIME_FORMAT)
time_fmt = TIME_FORMAT if aster.ephemerides.culmination_time.day == self.date.day\
else SHORT_DATETIME_FORMAT
aster_culmination = aster.ephemerides.culmination_time.strftime(time_fmt)
else: else:
aster_culmination = '-' aster_culmination = '-'


if aster.ephemerides.set_time is not None: if aster.ephemerides.set_time is not None:
aster_set = aster.ephemerides.set_time.utc_strftime(TIME_FORMAT)
time_fmt = TIME_FORMAT if aster.ephemerides.set_time.day == self.date.day else SHORT_DATETIME_FORMAT
aster_set = aster.ephemerides.set_time.strftime(time_fmt)
else: else:
aster_set = '-' aster_set = '-'


@@ -262,7 +315,7 @@ class _LatexDumper(Dumper):
latex = [] latex = []


for event in self.events: for event in self.events:
latex.append(r'\event{%s}{%s}' % (event.start_time.utc_strftime(TIME_FORMAT),
latex.append(r'\event{%s}{%s}' % (event.start_time.strftime(TIME_FORMAT),
event.get_description())) event.get_description()))


return ''.join(latex) return ''.join(latex)
@@ -288,9 +341,14 @@ class _LatexDumper(Dumper):




class PdfDumper(Dumper): class PdfDumper(Dumper):
def __init__(self, ephemerides, events, date=datetime.datetime.now(), timezone=0, with_colors=True):
super(PdfDumper, self).__init__(ephemerides, events, date=date, timezone=0, with_colors=with_colors)
self.timezone = timezone

def to_string(self): def to_string(self):
try: try:
latex_dumper = _LatexDumper(self.ephemeris, self.events, self.date, self.with_colors)
latex_dumper = _LatexDumper(self.ephemeris, self.events,
date=self.date, timezone=self.timezone, with_colors=self.with_colors)
return self._compile(latex_dumper.to_string()) return self._compile(latex_dumper.to_string())
except RuntimeError: except RuntimeError:
raise UnavailableFeatureError(_("Building PDFs was not possible, because some dependencies are not" raise UnavailableFeatureError(_("Building PDFs was not possible, because some dependencies are not"


+ 5
- 0
kosmorrolib/ephemerides.py View File

@@ -100,6 +100,11 @@ class EphemeridesComputer:


culmination_time = culmination_time[0] if culmination_time is not None 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)

aster.ephemerides = AsterEphemerides(rise_time, culmination_time, set_time) aster.ephemerides = AsterEphemerides(rise_time, culmination_time, set_time)
return aster return aster




+ 3
- 3
kosmorrolib/events.py View File

@@ -57,7 +57,7 @@ def _search_conjunction(start_time: Time, end_time: Time) -> [Event]:
times, _ = find_discrete(start_time, end_time, is_in_conjunction) times, _ = find_discrete(start_time, end_time, is_in_conjunction)


for time in times: for time in times:
conjunctions.append(Event('CONJUNCTION', [aster1, aster2], time))
conjunctions.append(Event('CONJUNCTION', [aster1, aster2], time.utc_datetime()))


computed.append(aster1) computed.append(aster1)


@@ -86,7 +86,7 @@ def _search_oppositions(start_time: Time, end_time: Time) -> [Event]:


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], time))
events.append(Event('OPPOSITION', [aster], time.utc_datetime()))


return events return events


@@ -98,4 +98,4 @@ def search_events(date: date_type) -> [Event]:
return sorted(flatten_list([ return sorted(flatten_list([
_search_oppositions(start_time, end_time), _search_oppositions(start_time, end_time),
_search_conjunction(start_time, end_time) _search_conjunction(start_time, end_time)
]), key=lambda event: event.start_time.utc_datetime())
]), key=lambda event: event.start_time)

+ 48
- 35
kosmorrolib/locales/messages.pot View File

@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: kosmorro 0.5.2\n" "Project-Id-Version: kosmorro 0.5.2\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2020-02-04 20:45+0100\n"
"POT-Creation-Date: 2020-02-17 20:58+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"
@@ -99,71 +99,80 @@ msgstr ""
msgid "%s and %s are in conjunction" msgid "%s and %s are in conjunction"
msgstr "" msgstr ""


#: kosmorrolib/dumper.py:36
#: kosmorrolib/dumper.py:35
msgid "{day_of_week} {month} {day_number}, {year}" msgid "{day_of_week} {month} {day_number}, {year}"
msgstr "" msgstr ""


#: kosmorrolib/dumper.py:38
#: kosmorrolib/dumper.py:37
msgid "{month} {day_number}, {hours}:{minutes}"
msgstr ""

#: kosmorrolib/dumper.py:39
msgid "{hours}:{minutes}" msgid "{hours}:{minutes}"
msgstr "" msgstr ""


#: kosmorrolib/dumper.py:113
#: kosmorrolib/dumper.py:147
msgid "Expected events:" msgid "Expected events:"
msgstr "" msgstr ""


#: kosmorrolib/dumper.py:116
#: kosmorrolib/dumper.py:151
msgid "Note: All the hours are given in UTC." msgid "Note: All the hours are given in UTC."
msgstr "" msgstr ""


#: kosmorrolib/dumper.py:157 kosmorrolib/dumper.py:222
#: kosmorrolib/dumper.py:156
msgid "Note: All the hours are given in the UTC{offset} timezone."
msgstr ""

#: kosmorrolib/dumper.py:202 kosmorrolib/dumper.py:271
msgid "Object" msgid "Object"
msgstr "" msgstr ""


#: kosmorrolib/dumper.py:158 kosmorrolib/dumper.py:223
#: kosmorrolib/dumper.py:203 kosmorrolib/dumper.py:272
msgid "Rise time" msgid "Rise time"
msgstr "" msgstr ""


#: kosmorrolib/dumper.py:159 kosmorrolib/dumper.py:224
#: kosmorrolib/dumper.py:204 kosmorrolib/dumper.py:273
msgid "Culmination time" msgid "Culmination time"
msgstr "" msgstr ""


#: kosmorrolib/dumper.py:160 kosmorrolib/dumper.py:225
#: kosmorrolib/dumper.py:205 kosmorrolib/dumper.py:274
msgid "Set time" msgid "Set time"
msgstr "" msgstr ""


#: kosmorrolib/dumper.py:173 kosmorrolib/dumper.py:228
#: kosmorrolib/dumper.py:219 kosmorrolib/dumper.py:277
msgid "Moon phase:" msgid "Moon phase:"
msgstr "" msgstr ""


#: kosmorrolib/dumper.py:174
#: kosmorrolib/dumper.py:220
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:212
#: kosmorrolib/dumper.py:258
msgid "A Summary of your Sky" msgid "A Summary of your Sky"
msgstr "" msgstr ""


#: kosmorrolib/dumper.py:216
#: kosmorrolib/dumper.py:262
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."
"aims to help you to prepare your observation session. All the hours are "
"given in {timezone}."
msgstr "" msgstr ""


#: kosmorrolib/dumper.py:219
#: kosmorrolib/dumper.py:268
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 "
"material." "material."
msgstr "" msgstr ""


#: kosmorrolib/dumper.py:221
#: kosmorrolib/dumper.py:270
msgid "Ephemerides of the day" msgid "Ephemerides of the day"
msgstr "" msgstr ""


#: kosmorrolib/dumper.py:230
#: kosmorrolib/dumper.py:279
msgid "Expected events" msgid "Expected events"
msgstr "" msgstr ""


#: kosmorrolib/dumper.py:296
#: kosmorrolib/dumper.py:354
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"
@@ -184,83 +193,87 @@ msgid ""
"the observation coordinate." "the observation coordinate."
msgstr "" msgstr ""


#: kosmorrolib/main.py:82
#: kosmorrolib/main.py:84
msgid "Could not save the output in \"{path}\": {error}" msgid "Could not save the output in \"{path}\": {error}"
msgstr "" msgstr ""


#: kosmorrolib/main.py:87
#: kosmorrolib/main.py:89
msgid "Selected output format needs an output file (--output)." msgid "Selected output format needs an output file (--output)."
msgstr "" msgstr ""


#: kosmorrolib/main.py:104
#: kosmorrolib/main.py:106
msgid "Running on Python {python_version}" msgid "Running on Python {python_version}"
msgstr "" msgstr ""


#: kosmorrolib/main.py:110
#: kosmorrolib/main.py:112
msgid "Do you really want to clear Kosmorro's cache? [yN] " msgid "Do you really want to clear Kosmorro's cache? [yN] "
msgstr "" msgstr ""


#: kosmorrolib/main.py:117
#: kosmorrolib/main.py:119
msgid "Answer did not match expected options, cache not cleared." msgid "Answer did not match expected options, cache not cleared."
msgstr "" msgstr ""


#: kosmorrolib/main.py:126
#: kosmorrolib/main.py:128
msgid "" msgid ""
"Compute the ephemerides and the events for a given date, at a given " "Compute the ephemerides and the events for a given date, at a given "
"position on Earth." "position on Earth."
msgstr "" msgstr ""


#: kosmorrolib/main.py:128
#: kosmorrolib/main.py:130
msgid "" msgid ""
"By default, only the events will be computed for today ({date}).\n" "By default, only the events will be computed for today ({date}).\n"
"To compute also the ephemerides, latitude and longitude arguments are " "To compute also the ephemerides, latitude and longitude arguments are "
"needed." "needed."
msgstr "" msgstr ""


#: kosmorrolib/main.py:133
#: kosmorrolib/main.py:135
msgid "Show the program version" msgid "Show the program version"
msgstr "" msgstr ""


#: kosmorrolib/main.py:135
#: kosmorrolib/main.py:137
msgid "Delete all the files Kosmorro stored in the cache." msgid "Delete all the files Kosmorro stored in the cache."
msgstr "" msgstr ""


#: kosmorrolib/main.py:137
#: kosmorrolib/main.py:139
msgid "The format under which the information have to be output" msgid "The format under which the information have to be output"
msgstr "" msgstr ""


#: kosmorrolib/main.py:139
#: kosmorrolib/main.py:141
msgid "The observer's latitude on Earth" msgid "The observer's latitude on Earth"
msgstr "" msgstr ""


#: kosmorrolib/main.py:141
#: kosmorrolib/main.py:143
msgid "The observer's longitude on Earth" msgid "The observer's longitude on Earth"
msgstr "" msgstr ""


#: kosmorrolib/main.py:143
#: kosmorrolib/main.py:145
msgid "" msgid ""
"A number between 1 and 28, 29, 30 or 31 (depending on the month). The 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 {default_day} (the" " you want to compute the ephemerides for. Defaults to {default_day} (the"
" current day)." " current day)."
msgstr "" msgstr ""


#: kosmorrolib/main.py:147
#: kosmorrolib/main.py:149
msgid "" msgid ""
"A number between 1 and 12. The month you want to compute the ephemerides " "A number between 1 and 12. The month you want to compute the ephemerides "
"for. Defaults to {default_month} (the current month)." "for. Defaults to {default_month} (the current month)."
msgstr "" msgstr ""


#: kosmorrolib/main.py:150
#: kosmorrolib/main.py:152
msgid "" msgid ""
"The year you want to compute the ephemerides for. Defaults to " "The year you want to compute the ephemerides for. Defaults to "
"{default_year} (the current year)." "{default_year} (the current year)."
msgstr "" msgstr ""


#: kosmorrolib/main.py:153
#: kosmorrolib/main.py:155
msgid "The timezone to display the hours in (e.g. 2 for UTC+2 or -3 for UTC-3)."
msgstr ""

#: kosmorrolib/main.py:157
msgid "Disable the colors in the console." msgid "Disable the colors in the console."
msgstr "" msgstr ""


#: kosmorrolib/main.py:155
#: kosmorrolib/main.py:159
msgid "" msgid ""
"A file to export the output to. If not given, the standard output is " "A file to export the output to. If not given, the standard output is "
"used. This argument is needed for PDF format." "used. This argument is needed for PDF format."


+ 5
- 1
kosmorrolib/main.py View File

@@ -68,7 +68,9 @@ def main():


events_list = events.search_events(compute_date) events_list = events.search_events(compute_date)


selected_dumper = output_formats[args.format](ephemerides, events_list, compute_date, args.colors)
selected_dumper = output_formats[args.format](ephemerides, events_list,
date=compute_date, timezone=args.timezone,
with_colors=args.colors)
output = selected_dumper.to_string() output = selected_dumper.to_string()
except UnavailableFeatureError as error: except UnavailableFeatureError as error:
print(colored(error.msg, 'red')) print(colored(error.msg, 'red'))
@@ -149,6 +151,8 @@ def get_args(output_formats: [str]):
parser.add_argument('--year', '-y', type=int, default=today.year, parser.add_argument('--year', '-y', type=int, default=today.year,
help=_('The year you want to compute the ephemerides for.' help=_('The year you want to compute the ephemerides for.'
' Defaults to {default_year} (the current year).').format(default_year=today.year)) ' Defaults to {default_year} (the current year).').format(default_year=today.year))
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', parser.add_argument('--no-colors', dest='colors', action='store_false',
help=_('Disable the colors in the console.')) help=_('Disable the colors in the console.'))
parser.add_argument('--output', '-o', type=str, default=None, parser.add_argument('--output', '-o', type=str, default=None,


+ 45
- 24
test/dumper.py View File

@@ -1,9 +1,8 @@
import unittest import unittest
from datetime import date
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.core import get_timescale




class DumperTestCase(unittest.TestCase): class DumperTestCase(unittest.TestCase):
@@ -11,12 +10,11 @@ class DumperTestCase(unittest.TestCase):
self.maxDiff = None self.maxDiff = None


def test_json_dumper_returns_correct_json(self): def test_json_dumper_returns_correct_json(self):
data = self._get_data()
self.assertEqual('{\n' self.assertEqual('{\n'
' "moon_phase": {\n' ' "moon_phase": {\n'
' "next_phase_date": "2019-10-21T00:00:00Z",\n'
' "next_phase_date": "2019-10-21T00:00:00",\n'
' "phase": "FULL_MOON",\n' ' "phase": "FULL_MOON",\n'
' "date": "2019-10-14T00:00:00Z"\n'
' "date": "2019-10-14T00:00:00"\n'
' },\n' ' },\n'
' "events": [\n' ' "events": [\n'
' {\n' ' {\n'
@@ -24,7 +22,7 @@ class DumperTestCase(unittest.TestCase):
' "objects": [\n' ' "objects": [\n'
' "Mars"\n' ' "Mars"\n'
' ],\n' ' ],\n'
' "start_time": "2018-07-27T05:12:00Z",\n'
' "start_time": "2019-10-14T23:00:00",\n'
' "end_time": null\n' ' "end_time": null\n'
' }\n' ' }\n'
' ],\n' ' ],\n'
@@ -38,16 +36,14 @@ class DumperTestCase(unittest.TestCase):
' }\n' ' }\n'
' }\n' ' }\n'
' ]\n' ' ]\n'
'}', JsonDumper(data,
self._get_events()
).to_string())
'}', JsonDumper(self._get_data(), self._get_events()).to_string())


data = self._get_data(aster_rise_set=True) data = self._get_data(aster_rise_set=True)
self.assertEqual('{\n' self.assertEqual('{\n'
' "moon_phase": {\n' ' "moon_phase": {\n'
' "next_phase_date": "2019-10-21T00:00:00Z",\n'
' "next_phase_date": "2019-10-21T00:00:00",\n'
' "phase": "FULL_MOON",\n' ' "phase": "FULL_MOON",\n'
' "date": "2019-10-14T00:00:00Z"\n'
' "date": "2019-10-14T00:00:00"\n'
' },\n' ' },\n'
' "events": [\n' ' "events": [\n'
' {\n' ' {\n'
@@ -55,7 +51,7 @@ class DumperTestCase(unittest.TestCase):
' "objects": [\n' ' "objects": [\n'
' "Mars"\n' ' "Mars"\n'
' ],\n' ' ],\n'
' "start_time": "2018-07-27T05:12:00Z",\n'
' "start_time": "2019-10-14T23:00:00",\n'
' "end_time": null\n' ' "end_time": null\n'
' }\n' ' }\n'
' ],\n' ' ],\n'
@@ -63,9 +59,9 @@ class DumperTestCase(unittest.TestCase):
' {\n' ' {\n'
' "object": "Mars",\n' ' "object": "Mars",\n'
' "details": {\n' ' "details": {\n'
' "rise_time": "2019-10-14T08:00:00Z",\n'
' "culmination_time": "2019-10-14T13:00:00Z",\n'
' "set_time": "2019-10-14T23:00:00Z"\n'
' "rise_time": "2019-10-14T08:00:00",\n'
' "culmination_time": "2019-10-14T13:00:00",\n'
' "set_time": "2019-10-14T23:00:00"\n'
' }\n' ' }\n'
' }\n' ' }\n'
' ]\n' ' ]\n'
@@ -103,7 +99,7 @@ class DumperTestCase(unittest.TestCase):
'Moon phase: Full Moon\n' 'Moon phase: Full Moon\n'
'Last Quarter on Monday October 21, 2019 at 00:00\n\n' 'Last Quarter on Monday October 21, 2019 at 00:00\n\n'
'Expected events:\n' 'Expected events:\n'
'05:12 Mars is in opposition\n\n'
'23:00 Mars is in opposition\n\n'
'Note: All the hours are given in UTC.', 'Note: All the hours are given in UTC.',
TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string()) TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string())


@@ -113,10 +109,35 @@ class DumperTestCase(unittest.TestCase):
'Moon phase: Full Moon\n' 'Moon phase: Full Moon\n'
'Last Quarter on Monday October 21, 2019 at 00:00\n\n' 'Last Quarter on Monday October 21, 2019 at 00:00\n\n'
'Expected events:\n' 'Expected events:\n'
'05:12 Mars is in opposition\n\n'
'23:00 Mars is in opposition\n\n'
'Note: All the hours are given in UTC.', 'Note: All the hours are given in UTC.',
TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string()) TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string())


def test_timezone_is_taken_in_account(self):
ephemerides = self._get_data(aster_rise_set=True)
self.assertEqual('Monday October 14, 2019\n\n'
'Object Rise time Culmination time Set time\n'
'-------- ----------- ------------------ -------------\n'
'Mars 09:00 14:00 Oct 15, 00:00\n\n'
'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'
'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())

ephemerides = self._get_data(aster_rise_set=True)
self.assertEqual('Monday October 14, 2019\n\n'
'Object Rise time Culmination time Set time\n'
'-------- ----------- ------------------ ----------\n'
'Mars 07:00 12:00 22:00\n\n'
'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'
'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())

def test_latex_dumper(self): def test_latex_dumper(self):
latex = _LatexDumper(self._get_data(), self._get_events(), date=date(2019, 10, 14)).to_string() latex = _LatexDumper(self._get_data(), self._get_events(), date=date(2019, 10, 14)).to_string()
self.assertRegex(latex, 'Monday October 14, 2019') self.assertRegex(latex, 'Monday October 14, 2019')
@@ -124,7 +145,7 @@ class DumperTestCase(unittest.TestCase):
self.assertRegex(latex, r'\\section{\\sffamily Expected events}') self.assertRegex(latex, r'\\section{\\sffamily Expected events}')
self.assertRegex(latex, r'\\section{\\sffamily Ephemerides of the day}') self.assertRegex(latex, r'\\section{\\sffamily Ephemerides of the day}')
self.assertRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}') self.assertRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}')
self.assertRegex(latex, r'\\event\{05:12\}\{Mars is in opposition\}')
self.assertRegex(latex, r'\\event\{23:00\}\{Mars is in opposition\}')


latex = _LatexDumper(self._get_data(aster_rise_set=True), latex = _LatexDumper(self._get_data(aster_rise_set=True),
self._get_events(), date=date(2019, 10, 14)).to_string() self._get_events(), date=date(2019, 10, 14)).to_string()
@@ -135,7 +156,7 @@ class DumperTestCase(unittest.TestCase):
self.assertRegex(latex, 'Monday October 14, 2019') self.assertRegex(latex, 'Monday October 14, 2019')
self.assertRegex(latex, 'Full Moon') self.assertRegex(latex, 'Full Moon')
self.assertRegex(latex, r'\\section{\\sffamily Expected events}') self.assertRegex(latex, r'\\section{\\sffamily Expected events}')
self.assertRegex(latex, r'\\event\{05:12\}\{Mars is in opposition\}')
self.assertRegex(latex, r'\\event\{23:00\}\{Mars is in opposition\}')


self.assertNotRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}') self.assertNotRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}')
self.assertNotRegex(latex, r'\\section{\\sffamily Ephemerides of the day}') self.assertNotRegex(latex, r'\\section{\\sffamily Ephemerides of the day}')
@@ -151,12 +172,12 @@ class DumperTestCase(unittest.TestCase):


@staticmethod @staticmethod
def _get_data(has_ephemerides: bool = True, aster_rise_set=False): def _get_data(has_ephemerides: bool = True, aster_rise_set=False):
rise_time = get_timescale().utc(2019, 10, 14, 8) if aster_rise_set else None
culmination_time = get_timescale().utc(2019, 10, 14, 13) if aster_rise_set else None
set_time = get_timescale().utc(2019, 10, 14, 23) if aster_rise_set else None
rise_time = datetime(2019, 10, 14, 8) if aster_rise_set else None
culmination_time = datetime(2019, 10, 14, 13) if aster_rise_set else None
set_time = datetime(2019, 10, 14, 23) if aster_rise_set else None


return { return {
'moon_phase': MoonPhase('FULL_MOON', get_timescale().utc(2019, 10, 14), get_timescale().utc(2019, 10, 21)),
'moon_phase': MoonPhase('FULL_MOON', datetime(2019, 10, 14), datetime(2019, 10, 21)),
'details': [Planet('Mars', 'MARS', 'details': [Planet('Mars', 'MARS',
AsterEphemerides(rise_time, culmination_time, set_time))] if has_ephemerides else [] AsterEphemerides(rise_time, culmination_time, set_time))] if has_ephemerides else []
} }
@@ -165,7 +186,7 @@ class DumperTestCase(unittest.TestCase):
def _get_events(): def _get_events():
return [Event('OPPOSITION', return [Event('OPPOSITION',
[Planet('Mars', 'MARS')], [Planet('Mars', 'MARS')],
get_timescale().utc(2018, 7, 27, 5, 12))
datetime(2019, 10, 14, 23, 00))
] ]






+ 15
- 15
test/ephemerides.py View File

@@ -13,9 +13,9 @@ class EphemeridesComputerTestCase(unittest.TestCase):
date=date(2019, 11, 18), date=date(2019, 11, 18),
position=position) position=position)


self.assertEqual('2019-11-18T05:41:31Z', star.ephemerides.rise_time.utc_iso())
self.assertEqual('2019-11-18T11:45:02Z', star.ephemerides.culmination_time.utc_iso())
self.assertEqual('2019-11-18T17:48:39Z', star.ephemerides.set_time.utc_iso())
self.assertEqual('2019-11-18T05:41:30+00:00', star.ephemerides.rise_time.isoformat())
self.assertEqual('2019-11-18T11:45:02+00:00', star.ephemerides.culmination_time.isoformat())
self.assertEqual('2019-11-18T17:48:39+00:00', star.ephemerides.set_time.isoformat())


################################################################################################################### ###################################################################################################################
### MOON PHASE TESTS ### ### MOON PHASE TESTS ###
@@ -25,61 +25,61 @@ class EphemeridesComputerTestCase(unittest.TestCase):
phase = EphemeridesComputer.get_moon_phase(2019, 11, 25) phase = EphemeridesComputer.get_moon_phase(2019, 11, 25)
self.assertEqual('WANING_CRESCENT', phase.identifier) self.assertEqual('WANING_CRESCENT', phase.identifier)
self.assertIsNone(phase.time) self.assertIsNone(phase.time)
self.assertRegexpMatches(phase.next_phase_date.utc_iso(), '^2019-11-26T')
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-26T')


phase = EphemeridesComputer.get_moon_phase(2019, 11, 26) phase = EphemeridesComputer.get_moon_phase(2019, 11, 26)
self.assertEqual('NEW_MOON', phase.identifier) self.assertEqual('NEW_MOON', phase.identifier)
self.assertRegexpMatches(phase.next_phase_date.utc_iso(), '^2019-12-04T')
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-12-04T')


phase = EphemeridesComputer.get_moon_phase(2019, 11, 27) phase = EphemeridesComputer.get_moon_phase(2019, 11, 27)
self.assertEqual('WAXING_CRESCENT', phase.identifier) self.assertEqual('WAXING_CRESCENT', phase.identifier)
self.assertIsNone(phase.time) self.assertIsNone(phase.time)
self.assertRegexpMatches(phase.next_phase_date.utc_iso(), '^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 = EphemeridesComputer.get_moon_phase(2019, 11, 3) phase = EphemeridesComputer.get_moon_phase(2019, 11, 3)
self.assertEqual('WAXING_CRESCENT', phase.identifier) self.assertEqual('WAXING_CRESCENT', phase.identifier)
self.assertIsNone(phase.time) self.assertIsNone(phase.time)
self.assertRegexpMatches(phase.next_phase_date.utc_iso(), '^2019-11-04T')
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-04T')


phase = EphemeridesComputer.get_moon_phase(2019, 11, 4) phase = EphemeridesComputer.get_moon_phase(2019, 11, 4)
self.assertEqual('FIRST_QUARTER', phase.identifier) self.assertEqual('FIRST_QUARTER', phase.identifier)
self.assertRegexpMatches(phase.next_phase_date.utc_iso(), '^2019-11-12T')
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-12T')


phase = EphemeridesComputer.get_moon_phase(2019, 11, 5) phase = EphemeridesComputer.get_moon_phase(2019, 11, 5)
self.assertEqual('WAXING_GIBBOUS', phase.identifier) self.assertEqual('WAXING_GIBBOUS', phase.identifier)
self.assertIsNone(phase.time) self.assertIsNone(phase.time)
self.assertRegexpMatches(phase.next_phase_date.utc_iso(), '^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 = EphemeridesComputer.get_moon_phase(2019, 11, 11) phase = EphemeridesComputer.get_moon_phase(2019, 11, 11)
self.assertEqual('WAXING_GIBBOUS', phase.identifier) self.assertEqual('WAXING_GIBBOUS', phase.identifier)
self.assertIsNone(phase.time) self.assertIsNone(phase.time)
self.assertRegexpMatches(phase.next_phase_date.utc_iso(), '^2019-11-12T')
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-12T')


phase = EphemeridesComputer.get_moon_phase(2019, 11, 12) phase = EphemeridesComputer.get_moon_phase(2019, 11, 12)
self.assertEqual('FULL_MOON', phase.identifier) self.assertEqual('FULL_MOON', phase.identifier)
self.assertRegexpMatches(phase.next_phase_date.utc_iso(), '^2019-11-19T')
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-19T')


phase = EphemeridesComputer.get_moon_phase(2019, 11, 13) phase = EphemeridesComputer.get_moon_phase(2019, 11, 13)
self.assertEqual('WANING_GIBBOUS', phase.identifier) self.assertEqual('WANING_GIBBOUS', phase.identifier)
self.assertIsNone(phase.time) self.assertIsNone(phase.time)
self.assertRegexpMatches(phase.next_phase_date.utc_iso(), '^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 = EphemeridesComputer.get_moon_phase(2019, 11, 18) phase = EphemeridesComputer.get_moon_phase(2019, 11, 18)
self.assertEqual('WANING_GIBBOUS', phase.identifier) self.assertEqual('WANING_GIBBOUS', phase.identifier)
self.assertIsNone(phase.time) self.assertIsNone(phase.time)
self.assertRegexpMatches(phase.next_phase_date.utc_iso(), '^2019-11-19T')
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-19T')


phase = EphemeridesComputer.get_moon_phase(2019, 11, 19) phase = EphemeridesComputer.get_moon_phase(2019, 11, 19)
self.assertEqual('LAST_QUARTER', phase.identifier) self.assertEqual('LAST_QUARTER', phase.identifier)
self.assertRegexpMatches(phase.next_phase_date.utc_iso(), '^2019-11-26T')
self.assertRegexpMatches(phase.next_phase_date.isoformat(), '^2019-11-26T')


phase = EphemeridesComputer.get_moon_phase(2019, 11, 20) phase = EphemeridesComputer.get_moon_phase(2019, 11, 20)
self.assertEqual('WANING_CRESCENT', phase.identifier) self.assertEqual('WANING_CRESCENT', phase.identifier)
self.assertIsNone(phase.time) self.assertIsNone(phase.time)
self.assertRegexpMatches(phase.next_phase_date.utc_iso(), '^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) phase = MoonPhase('NEW_MOON', None, None)


+ 2
- 2
test/events.py View File

@@ -24,7 +24,7 @@ class MyTestCase(unittest.TestCase):
self.assertEqual(1, len(o), 'Expected 1 event for %s, got %d' % (expected_date, len(o))) self.assertEqual(1, len(o), 'Expected 1 event for %s, got %d' % (expected_date, len(o)))
self.assertEqual('OPPOSITION', o[0].event_type) self.assertEqual('OPPOSITION', o[0].event_type)
self.assertEqual('MARS', o[0].objects[0].skyfield_name) self.assertEqual('MARS', o[0].objects[0].skyfield_name)
self.assertRegex(o[0].start_time.utc_iso(), expected_date)
self.assertRegex(o[0].start_time.isoformat(), expected_date)
self.assertIsNone(o[0].end_time) self.assertIsNone(o[0].end_time)
self.assertEqual('Mars is in opposition', o[0].get_description()) self.assertEqual('Mars is in opposition', o[0].get_description())


@@ -45,7 +45,7 @@ class MyTestCase(unittest.TestCase):
objects, expected_date = expected_dates[i] objects, expected_date = expected_dates[i]


j = 0 j = 0
self.assertRegex(conjunction.start_time.utc_iso(), expected_date)
self.assertRegex(conjunction.start_time.isoformat(), expected_date)
for object in objects: for object in objects:
self.assertEqual(object, conjunction.objects[j].skyfield_name) self.assertEqual(object, conjunction.objects[j].skyfield_name)
j += 1 j += 1


Loading…
Cancel
Save