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-few-public-methods,
protected-access,
unnecessary-comprehension
unnecessary-comprehension,
too-many-arguments

# 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


+ 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 --latitude=50.5876 --longitude=3.0624"
assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624 -d 27 -m 1 -y 2020"
assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624 -d 27 -m 1 -y 2020 --timezone=1"
assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624 -d 27 -m 1 -y 2020 --timezone=-1"
assertSuccess "kosmorro --latitude=50.5876 --longitude=3.0624 -d 27 -m 1 -y 2020 --format=json"
assertFailure "kosmorro --latitude=50.5876 --longitude=3.0624 -d 27 -m 1 -y 2020 --format=pdf"
# 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]
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):


+ 7
- 6
kosmorrolib/data.py View File

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

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

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

from .i18n import _

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


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():
raise ValueError('identifier parameter must be one of %s (got %s)' % (', '.join(MOON_PHASES.keys()),
identifier))
@@ -87,9 +87,9 @@ class Position:

class AsterEphemerides:
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.culmination_time = culmination_time
self.set_time = set_time
@@ -141,7 +141,8 @@ class Satellite(Object):


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():
raise ValueError('event_type parameter must be one of the following: %s (got %s)' % (
', '.join(EVENTS.keys()),


+ 76
- 18
kosmorrolib/dumper.py View File

@@ -21,7 +21,6 @@ import datetime
import json
import os
from tabulate import tabulate
from skyfield.timelib import Time
from numpy import int64
from termcolor import colored
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',
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')


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):
self.ephemeris = ephemeris
self.events = events
self.date = date
self.timezone = timezone
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:
date = self.date.strftime(FULL_DATE_FORMAT)

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

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

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:
planet_rise = '-'

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:
planet_culmination = '-'

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:
planet_set = '-'

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

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()])

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()])
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_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])
@@ -214,8 +260,11 @@ class _LatexDumper(Dumper):
.replace('+++INTRODUCTION+++',
'\n\n'.join([
_("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.")
])) \
.replace('+++SECTION-EPHEMERIDES+++', _('Ephemerides of the day')) \
@@ -237,17 +286,21 @@ class _LatexDumper(Dumper):

for aster in self.ephemeris['details']:
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:
aster_rise = '-'

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:
aster_culmination = '-'

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:
aster_set = '-'

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

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()))

return ''.join(latex)
@@ -288,9 +341,14 @@ class _LatexDumper(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):
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())
except RuntimeError:
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

# 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)
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)

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

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

return events

@@ -98,4 +98,4 @@ def search_events(date: date_type) -> [Event]:
return sorted(flatten_list([
_search_oppositions(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 ""
"Project-Id-Version: kosmorro 0.5.2\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"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -99,71 +99,80 @@ msgstr ""
msgid "%s and %s are in conjunction"
msgstr ""

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

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

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

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

#: kosmorrolib/dumper.py:116
#: kosmorrolib/dumper.py:151
msgid "Note: All the hours are given in UTC."
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"
msgstr ""

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

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

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

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

#: kosmorrolib/dumper.py:174
#: kosmorrolib/dumper.py:220
msgid "{next_moon_phase} on {next_moon_phase_date} at {next_moon_phase_time}"
msgstr ""

#: kosmorrolib/dumper.py:212
#: kosmorrolib/dumper.py:258
msgid "A Summary of your Sky"
msgstr ""

#: kosmorrolib/dumper.py:216
#: kosmorrolib/dumper.py:262
msgid ""
"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 ""

#: kosmorrolib/dumper.py:219
#: kosmorrolib/dumper.py:268
msgid ""
"Don't forget to check the weather forecast before you go out with your "
"material."
msgstr ""

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

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

#: kosmorrolib/dumper.py:296
#: kosmorrolib/dumper.py:354
msgid ""
"Building PDFs was not possible, because some dependencies are not "
"installed.\n"
@@ -184,83 +193,87 @@ msgid ""
"the observation coordinate."
msgstr ""

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#: kosmorrolib/main.py:150
#: kosmorrolib/main.py:152
msgid ""
"The year you want to compute the ephemerides for. Defaults to "
"{default_year} (the current year)."
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."
msgstr ""

#: kosmorrolib/main.py:155
#: kosmorrolib/main.py:159
msgid ""
"A file to export the output to. If not given, the standard output is "
"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)

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()
except UnavailableFeatureError as error:
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,
help=_('The year you want to compute the ephemerides for.'
' Defaults to {default_year} (the current year).').format(default_year=today.year))
parser.add_argument('--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',
help=_('Disable the colors in the console.'))
parser.add_argument('--output', '-o', type=str, default=None,


+ 45
- 24
test/dumper.py View File

@@ -1,9 +1,8 @@
import unittest
from datetime import date
from datetime import date, datetime

from kosmorrolib.data import AsterEphemerides, Planet, MoonPhase, Event
from kosmorrolib.dumper import JsonDumper, TextDumper, _LatexDumper
from kosmorrolib.core import get_timescale


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

def test_json_dumper_returns_correct_json(self):
data = self._get_data()
self.assertEqual('{\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'
' "date": "2019-10-14T00:00:00Z"\n'
' "date": "2019-10-14T00:00:00"\n'
' },\n'
' "events": [\n'
' {\n'
@@ -24,7 +22,7 @@ class DumperTestCase(unittest.TestCase):
' "objects": [\n'
' "Mars"\n'
' ],\n'
' "start_time": "2018-07-27T05:12:00Z",\n'
' "start_time": "2019-10-14T23:00:00",\n'
' "end_time": null\n'
' }\n'
' ],\n'
@@ -38,16 +36,14 @@ class DumperTestCase(unittest.TestCase):
' }\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)
self.assertEqual('{\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'
' "date": "2019-10-14T00:00:00Z"\n'
' "date": "2019-10-14T00:00:00"\n'
' },\n'
' "events": [\n'
' {\n'
@@ -55,7 +51,7 @@ class DumperTestCase(unittest.TestCase):
' "objects": [\n'
' "Mars"\n'
' ],\n'
' "start_time": "2018-07-27T05:12:00Z",\n'
' "start_time": "2019-10-14T23:00:00",\n'
' "end_time": null\n'
' }\n'
' ],\n'
@@ -63,9 +59,9 @@ class DumperTestCase(unittest.TestCase):
' {\n'
' "object": "Mars",\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'
@@ -103,7 +99,7 @@ class DumperTestCase(unittest.TestCase):
'Moon phase: Full Moon\n'
'Last Quarter on Monday October 21, 2019 at 00:00\n\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.',
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'
'Last Quarter on Monday October 21, 2019 at 00:00\n\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.',
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):
latex = _LatexDumper(self._get_data(), self._get_events(), date=date(2019, 10, 14)).to_string()
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 Ephemerides of the day}')
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),
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, 'Full Moon')
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'\\section{\\sffamily Ephemerides of the day}')
@@ -151,12 +172,12 @@ class DumperTestCase(unittest.TestCase):

@staticmethod
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 {
'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',
AsterEphemerides(rise_time, culmination_time, set_time))] if has_ephemerides else []
}
@@ -165,7 +186,7 @@ class DumperTestCase(unittest.TestCase):
def _get_events():
return [Event('OPPOSITION',
[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),
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 ###
@@ -25,61 +25,61 @@ class EphemeridesComputerTestCase(unittest.TestCase):
phase = EphemeridesComputer.get_moon_phase(2019, 11, 25)
self.assertEqual('WANING_CRESCENT', phase.identifier)
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)
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)
self.assertEqual('WAXING_CRESCENT', phase.identifier)
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):
phase = EphemeridesComputer.get_moon_phase(2019, 11, 3)
self.assertEqual('WAXING_CRESCENT', phase.identifier)
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)
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)
self.assertEqual('WAXING_GIBBOUS', phase.identifier)
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):
phase = EphemeridesComputer.get_moon_phase(2019, 11, 11)
self.assertEqual('WAXING_GIBBOUS', phase.identifier)
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)
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)
self.assertEqual('WANING_GIBBOUS', phase.identifier)
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):
phase = EphemeridesComputer.get_moon_phase(2019, 11, 18)
self.assertEqual('WANING_GIBBOUS', phase.identifier)
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)
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)
self.assertEqual('WANING_CRESCENT', phase.identifier)
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):
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('OPPOSITION', o[0].event_type)
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.assertEqual('Mars is in opposition', o[0].get_description())

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

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


Loading…
Cancel
Save