From 6c24d529aac5ff5b77eeb6e4fffc93dbd0908aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Thu, 15 Apr 2021 13:06:23 +0200 Subject: [PATCH] feat: replace object name with enum identifier BREAKING CHANGE: name of objects of type `kosmorrolib.model.Object` has been replaced with an enum typed identifier. --- kosmorrolib/__init__.py | 1 + kosmorrolib/data.py | 59 +++++++++++++++++++++----------------- kosmorrolib/dateutil.py | 18 ++++++++++++ kosmorrolib/enum.py | 25 ++++++++++++++++ kosmorrolib/ephemerides.py | 26 ++++++++++------- kosmorrolib/events.py | 6 ++-- tests/data.py | 5 ++-- tests/ephemerides.py | 4 +-- 8 files changed, 100 insertions(+), 44 deletions(-) diff --git a/kosmorrolib/__init__.py b/kosmorrolib/__init__.py index 74a65dc..02d46e3 100644 --- a/kosmorrolib/__init__.py +++ b/kosmorrolib/__init__.py @@ -3,3 +3,4 @@ from .data import Position from .ephemerides import get_ephemerides, get_moon_phase from .events import get_events +from .enum import * diff --git a/kosmorrolib/data.py b/kosmorrolib/data.py index 45ab90e..42db7a9 100644 --- a/kosmorrolib/data.py +++ b/kosmorrolib/data.py @@ -10,7 +10,7 @@ from skyfield.api import Topos, Time from skyfield.vectorlib import VectorSum as SkfPlanet from .core import get_skf_objects -from .enum import MoonPhaseType, EventType +from .enum import MoonPhaseType, EventType, ObjectIdentifier, ObjectType class Serializable(ABC): @@ -66,27 +66,32 @@ class Object(Serializable): An astronomical object. """ - def __init__(self, name: str, skyfield_name: str, radius: float = None): + def __init__( + self, identifier: ObjectIdentifier, skyfield_name: str, radius: float = None + ): """ Initialize an astronomical object - :param str name: the official name of the object (may be internationalized) + :param ObjectIdentifier identifier: the official name of the object (may be internationalized) :param str skyfield_name: the internal name of the object in Skyfield library :param float radius: the radius (in km) of the object :param AsterEphemerides ephemerides: the ephemerides associated to the object """ - self.name = name + self.identifier = identifier self.skyfield_name = skyfield_name self.radius = radius def __repr__(self): - return "" % (self.get_type(), self.name) + return "" % ( + self.get_type().name, + self.identifier.name, + ) def get_skyfield_object(self) -> SkfPlanet: return get_skf_objects()[self.skyfield_name] @abstractmethod - def get_type(self) -> str: + def get_type(self) -> ObjectType: pass def get_apparent_radius(self, time: Time, from_place) -> float: @@ -97,7 +102,7 @@ class Object(Serializable): :return: """ if self.radius is None: - raise ValueError("Missing radius for %s object" % self.name) + raise ValueError("Missing radius for %s" % self.identifier.name) return ( 360 @@ -110,30 +115,30 @@ class Object(Serializable): def serialize(self) -> dict: return { - "name": self.name, + "identifier": self.identifier.name, "type": self.get_type(), "radius": self.radius, } class Star(Object): - def get_type(self) -> str: - return "star" + def get_type(self) -> ObjectType: + return ObjectType.STAR class Planet(Object): - def get_type(self) -> str: - return "planet" + def get_type(self) -> ObjectType: + return ObjectType.PLANET class DwarfPlanet(Planet): - def get_type(self) -> str: - return "dwarf_planet" + def get_type(self) -> ObjectType: + return ObjectType.DWARF_PLANET class Satellite(Object): - def get_type(self) -> str: - return "satellite" + def get_type(self) -> ObjectType: + return ObjectType.SATELLITE class Event(Serializable): @@ -216,19 +221,19 @@ class AsterEphemerides(Serializable): } -EARTH = Planet("Earth", "EARTH") +EARTH = Planet(ObjectIdentifier.EARTH, "EARTH") ASTERS = [ - Star("Sun", "SUN", radius=696342), - Satellite("Moon", "MOON", radius=1737.4), - Planet("Mercury", "MERCURY", radius=2439.7), - Planet("Venus", "VENUS", radius=6051.8), - Planet("Mars", "MARS", radius=3396.2), - Planet("Jupiter", "JUPITER BARYCENTER", radius=71492), - Planet("Saturn", "SATURN BARYCENTER", radius=60268), - Planet("Uranus", "URANUS BARYCENTER", radius=25559), - Planet("Neptune", "NEPTUNE BARYCENTER", radius=24764), - Planet("Pluto", "PLUTO BARYCENTER", radius=1185), + Star(ObjectIdentifier.SUN, "SUN", radius=696342), + Satellite(ObjectIdentifier.MOON, "MOON", radius=1737.4), + Planet(ObjectIdentifier.MERCURY, "MERCURY", radius=2439.7), + Planet(ObjectIdentifier.VENUS, "VENUS", radius=6051.8), + Planet(ObjectIdentifier.MARS, "MARS", radius=3396.2), + Planet(ObjectIdentifier.JUPITER, "JUPITER BARYCENTER", radius=71492), + Planet(ObjectIdentifier.SATURN, "SATURN BARYCENTER", radius=60268), + Planet(ObjectIdentifier.URANUS, "URANUS BARYCENTER", radius=25559), + Planet(ObjectIdentifier.NEPTUNE, "NEPTUNE BARYCENTER", radius=24764), + Planet(ObjectIdentifier.PLUTO, "PLUTO BARYCENTER", radius=1185), ] diff --git a/kosmorrolib/dateutil.py b/kosmorrolib/dateutil.py index b5a8fda..472b733 100644 --- a/kosmorrolib/dateutil.py +++ b/kosmorrolib/dateutil.py @@ -12,3 +12,21 @@ def translate_to_timezone(date: datetime, to_tz: int, from_tz: int = None): return date.replace(tzinfo=source_tz).astimezone( tz=timezone(timedelta(hours=to_tz)) ) + + +def normalize_datetime(date: datetime) -> datetime: + """Round the seconds in the given datetime + + >>> normalize_datetime(datetime(2021, 6, 9, 2, 30, 29)) + datetime.datetime(2021, 6, 9, 2, 30) + + >>> normalize_datetime(datetime(2021, 6, 9, 2, 30, 30)) + datetime.datetime(2021, 6, 9, 2, 31) + """ + return datetime( + date.year, + date.month, + date.day, + date.hour, + date.minute if date.second < 30 else date.minute + 1, + ) diff --git a/kosmorrolib/enum.py b/kosmorrolib/enum.py index 03676ec..e9420cd 100644 --- a/kosmorrolib/enum.py +++ b/kosmorrolib/enum.py @@ -25,3 +25,28 @@ class EventType(Enum): MAXIMAL_ELONGATION = 4 MOON_PERIGEE = 5 MOON_APOGEE = 6 + + +class ObjectType(Enum): + """An enumeration of object types""" + + STAR = 0 + PLANET = 1 + DWARF_PLANET = 11 + SATELLITE = 2 + + +class ObjectIdentifier(Enum): + """An enumeration of identifiers for objects""" + + SUN = 0 + EARTH = 1 + MOON = 11 + MERCURY = 2 + VENUS = 3 + MARS = 4 + JUPITER = 5 + SATURN = 6 + URANUS = 7 + NEPTUNE = 8 + PLUTO = 9 diff --git a/kosmorrolib/ephemerides.py b/kosmorrolib/ephemerides.py index 33b25e6..007d202 100644 --- a/kosmorrolib/ephemerides.py +++ b/kosmorrolib/ephemerides.py @@ -9,7 +9,7 @@ from skyfield.constants import tau from skyfield.errors import EphemerisRangeError from .data import Position, AsterEphemerides, MoonPhase, Object, ASTERS -from .dateutil import translate_to_timezone +from .dateutil import translate_to_timezone, normalize_datetime from .core import get_skf_objects, get_timescale, get_iau2000b from .enum import MoonPhaseType from .exceptions import OutOfRangeDateError @@ -121,12 +121,12 @@ def get_ephemerides( >>> pos = Position(50.5824, 3.0624) >>> get_ephemerides(pos, datetime.date(2021, 6, 9)) - [>, >, >, >, >, >, >, >, >, >] + [>, >, >, >, >, >, >, >, >, >] Compute the ephemerides for June 9th, 2021: >>> get_ephemerides(pos, datetime.date(2021, 6, 9), timezone=2) - [>, >, >, >, >, >, >, >, >, >] + [>, >, >, >, >, >, >, >, >, >] """ ephemerides = [] @@ -182,19 +182,25 @@ def get_ephemerides( # Convert the Time instances to Python datetime objects if rise_time is not None: - rise_time = translate_to_timezone( - rise_time.utc_datetime().replace(microsecond=0), to_tz=timezone + rise_time = normalize_datetime( + translate_to_timezone( + rise_time.utc_datetime().replace(microsecond=0), to_tz=timezone + ) ) if culmination_time is not None: - culmination_time = translate_to_timezone( - culmination_time.utc_datetime().replace(microsecond=0), - to_tz=timezone, + culmination_time = normalize_datetime( + translate_to_timezone( + culmination_time.utc_datetime().replace(microsecond=0), + to_tz=timezone, + ) ) if set_time is not None: - set_time = translate_to_timezone( - set_time.utc_datetime().replace(microsecond=0), to_tz=timezone + set_time = normalize_datetime( + translate_to_timezone( + set_time.utc_datetime().replace(microsecond=0), to_tz=timezone + ) ) ephemerides.append( diff --git a/kosmorrolib/events.py b/kosmorrolib/events.py index 86c70c6..ded7425 100644 --- a/kosmorrolib/events.py +++ b/kosmorrolib/events.py @@ -219,17 +219,17 @@ def get_events(date: date_type = date_type.today(), timezone: int = 0) -> [Event Find events that happen on April 4th, 2020 (show hours in UTC): >>> get_events(date_type(2020, 4, 4)) - [, ] start=2020-04-04 01:14:39.063308+00:00 end=None details=None />] + [, ] start=2020-04-04 01:14:39.063308+00:00 end=None details=None />] Find events that happen on April 4th, 2020 (show timezones in UTC+2): >>> get_events(date_type(2020, 4, 4), 2) - [, ] start=2020-04-04 03:14:39.063267+02:00 end=None details=None />] + [, ] start=2020-04-04 03:14:39.063267+02:00 end=None details=None />] Find events that happen on April 3rd, 2020 (show timezones in UTC-2): >>> get_events(date_type(2020, 4, 3), -2) - [, ] start=2020-04-03 23:14:39.063388-02:00 end=None details=None />] + [, ] start=2020-04-03 23:14:39.063388-02:00 end=None details=None />] :param date: the date for which the events must be calculated :param timezone: the timezone to adapt the results to. If not given, defaults to 0. diff --git a/tests/data.py b/tests/data.py index 0b68fb0..f545b88 100644 --- a/tests/data.py +++ b/tests/data.py @@ -1,18 +1,19 @@ import unittest from kosmorrolib import data, core +from kosmorrolib.enum import ObjectIdentifier class DataTestCase(unittest.TestCase): def test_object_radius_must_be_set_to_get_apparent_radius(self): - o = data.Planet("Saturn", "SATURN") + o = data.Planet(ObjectIdentifier.SATURN, "SATURN") with self.assertRaises(ValueError) as context: o.get_apparent_radius( core.get_timescale().now(), core.get_skf_objects()["earth"] ) - self.assertEqual(("Missing radius for Saturn object",), context.exception.args) + self.assertEqual(("Missing radius for SATURN",), context.exception.args) if __name__ == "__main__": diff --git a/tests/ephemerides.py b/tests/ephemerides.py index 90a6003..d6c6bb4 100644 --- a/tests/ephemerides.py +++ b/tests/ephemerides.py @@ -18,11 +18,11 @@ class EphemeridesTestCase(unittest.TestCase): def do_assertions(assert_regex): for ephemeris in eph: if ephemeris.object.skyfield_name == "SUN": - assert_regex(ephemeris.rise_time.isoformat(), "^2019-11-18T05:41:") + assert_regex(ephemeris.rise_time.isoformat(), "^2019-11-18T05:42:") assert_regex( ephemeris.culmination_time.isoformat(), "^2019-11-18T11:45:" ) - assert_regex(ephemeris.set_time.isoformat(), "^2019-11-18T17:48:") + assert_regex(ephemeris.set_time.isoformat(), "^2019-11-18T17:49:") break do_assertions()