Browse Source

feat: replace object name with enum identifier (#15)

BREAKING CHANGE: name of objects of type `kosmorrolib.model.Object` has
been replaced with an enum typed identifier.
tags/v0.11.0
Jérôme Deuchnord 3 years ago
committed by GitHub
parent
commit
69206585d2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 100 additions and 44 deletions
  1. +1
    -0
      kosmorrolib/__init__.py
  2. +32
    -27
      kosmorrolib/data.py
  3. +18
    -0
      kosmorrolib/dateutil.py
  4. +25
    -0
      kosmorrolib/enum.py
  5. +16
    -10
      kosmorrolib/ephemerides.py
  6. +3
    -3
      kosmorrolib/events.py
  7. +3
    -2
      tests/data.py
  8. +2
    -2
      tests/ephemerides.py

+ 1
- 0
kosmorrolib/__init__.py View File

@@ -3,3 +3,4 @@
from .data import Position from .data import Position
from .ephemerides import get_ephemerides, get_moon_phase from .ephemerides import get_ephemerides, get_moon_phase
from .events import get_events from .events import get_events
from .enum import *

+ 32
- 27
kosmorrolib/data.py View File

@@ -10,7 +10,7 @@ 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 from .core import get_skf_objects
from .enum import MoonPhaseType, EventType
from .enum import MoonPhaseType, EventType, ObjectIdentifier, ObjectType




class Serializable(ABC): class Serializable(ABC):
@@ -66,27 +66,32 @@ class Object(Serializable):
An astronomical object. 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 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 str skyfield_name: the internal name of the object in Skyfield library
:param float radius: the radius (in km) of the object :param float radius: the radius (in km) of the object
:param AsterEphemerides ephemerides: the ephemerides associated to the object :param AsterEphemerides ephemerides: the ephemerides associated to the object
""" """
self.name = name
self.identifier = identifier
self.skyfield_name = skyfield_name self.skyfield_name = skyfield_name
self.radius = radius self.radius = radius


def __repr__(self): def __repr__(self):
return "<Object type=%s name=%s />" % (self.get_type(), self.name)
return "<Object type=%s name=%s />" % (
self.get_type().name,
self.identifier.name,
)


def get_skyfield_object(self) -> SkfPlanet: def get_skyfield_object(self) -> SkfPlanet:
return get_skf_objects()[self.skyfield_name] return get_skf_objects()[self.skyfield_name]


@abstractmethod @abstractmethod
def get_type(self) -> str:
def get_type(self) -> ObjectType:
pass pass


def get_apparent_radius(self, time: Time, from_place) -> float: def get_apparent_radius(self, time: Time, from_place) -> float:
@@ -97,7 +102,7 @@ class Object(Serializable):
:return: :return:
""" """
if self.radius is None: if self.radius is None:
raise ValueError("Missing radius for %s object" % self.name)
raise ValueError("Missing radius for %s" % self.identifier.name)


return ( return (
360 360
@@ -110,30 +115,30 @@ class Object(Serializable):


def serialize(self) -> dict: def serialize(self) -> dict:
return { return {
"name": self.name,
"identifier": self.identifier.name,
"type": self.get_type(), "type": self.get_type(),
"radius": self.radius, "radius": self.radius,
} }




class Star(Object): class Star(Object):
def get_type(self) -> str:
return "star"
def get_type(self) -> ObjectType:
return ObjectType.STAR




class Planet(Object): class Planet(Object):
def get_type(self) -> str:
return "planet"
def get_type(self) -> ObjectType:
return ObjectType.PLANET




class DwarfPlanet(Planet): class DwarfPlanet(Planet):
def get_type(self) -> str:
return "dwarf_planet"
def get_type(self) -> ObjectType:
return ObjectType.DWARF_PLANET




class Satellite(Object): class Satellite(Object):
def get_type(self) -> str:
return "satellite"
def get_type(self) -> ObjectType:
return ObjectType.SATELLITE




class Event(Serializable): class Event(Serializable):
@@ -216,19 +221,19 @@ class AsterEphemerides(Serializable):
} }




EARTH = Planet("Earth", "EARTH")
EARTH = Planet(ObjectIdentifier.EARTH, "EARTH")


ASTERS = [ 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),
] ]






+ 18
- 0
kosmorrolib/dateutil.py View File

@@ -12,3 +12,21 @@ def translate_to_timezone(date: datetime, to_tz: int, from_tz: int = None):
return date.replace(tzinfo=source_tz).astimezone( return date.replace(tzinfo=source_tz).astimezone(
tz=timezone(timedelta(hours=to_tz)) 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,
)

+ 25
- 0
kosmorrolib/enum.py View File

@@ -25,3 +25,28 @@ class EventType(Enum):
MAXIMAL_ELONGATION = 4 MAXIMAL_ELONGATION = 4
MOON_PERIGEE = 5 MOON_PERIGEE = 5
MOON_APOGEE = 6 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

+ 16
- 10
kosmorrolib/ephemerides.py View File

@@ -9,7 +9,7 @@ from skyfield.constants import tau
from skyfield.errors import EphemerisRangeError from skyfield.errors import EphemerisRangeError


from .data import Position, AsterEphemerides, MoonPhase, Object, ASTERS 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 .core import get_skf_objects, get_timescale, get_iau2000b
from .enum import MoonPhaseType from .enum import MoonPhaseType
from .exceptions import OutOfRangeDateError from .exceptions import OutOfRangeDateError
@@ -121,12 +121,12 @@ def get_ephemerides(


>>> pos = Position(50.5824, 3.0624) >>> pos = Position(50.5824, 3.0624)
>>> get_ephemerides(pos, datetime.date(2021, 6, 9)) >>> get_ephemerides(pos, datetime.date(2021, 6, 9))
[<AsterEphemerides rise_time=2021-06-09 03:36:18+00:00 culmination_time=2021-06-09 11:47:05+00:00 set_time=2021-06-09 19:58:10+00:00 aster=<Object type=star name=Sun />>, <AsterEphemerides rise_time=2021-06-09 02:58:49+00:00 culmination_time=2021-06-09 11:02:18+00:00 set_time=2021-06-09 19:15:58+00:00 aster=<Object type=satellite name=Moon />>, <AsterEphemerides rise_time=2021-06-09 04:05:32+00:00 culmination_time=2021-06-09 11:57:51+00:00 set_time=2021-06-09 19:49:16+00:00 aster=<Object type=planet name=Mercury />>, <AsterEphemerides rise_time=2021-06-09 04:51:39+00:00 culmination_time=2021-06-09 13:12:45+00:00 set_time=2021-06-09 21:33:38+00:00 aster=<Object type=planet name=Venus />>, <AsterEphemerides rise_time=2021-06-09 06:37:42+00:00 culmination_time=2021-06-09 14:39:49+00:00 set_time=2021-06-09 22:41:29+00:00 aster=<Object type=planet name=Mars />>, <AsterEphemerides rise_time=2021-06-09 23:43:15+00:00 culmination_time=2021-06-09 04:53:50+00:00 set_time=2021-06-09 10:00:35+00:00 aster=<Object type=planet name=Jupiter />>, <AsterEphemerides rise_time=2021-06-09 23:01:34+00:00 culmination_time=2021-06-09 03:40:38+00:00 set_time=2021-06-09 08:15:43+00:00 aster=<Object type=planet name=Saturn />>, <AsterEphemerides rise_time=2021-06-09 01:55:34+00:00 culmination_time=2021-06-09 09:18:00+00:00 set_time=2021-06-09 16:40:29+00:00 aster=<Object type=planet name=Uranus />>, <AsterEphemerides rise_time=2021-06-09 00:26:53+00:00 culmination_time=2021-06-09 06:12:55+00:00 set_time=2021-06-09 11:58:57+00:00 aster=<Object type=planet name=Neptune />>, <AsterEphemerides rise_time=2021-06-09 22:22:10+00:00 culmination_time=2021-06-09 02:31:56+00:00 set_time=2021-06-09 06:37:43+00:00 aster=<Object type=planet name=Pluto />>]
[<AsterEphemerides rise_time=2021-06-09 03:36:00 culmination_time=2021-06-09 11:47:00 set_time=2021-06-09 19:58:00 aster=<Object type=STAR name=SUN />>, <AsterEphemerides rise_time=2021-06-09 02:59:00 culmination_time=2021-06-09 11:02:00 set_time=2021-06-09 19:16:00 aster=<Object type=SATELLITE name=MOON />>, <AsterEphemerides rise_time=2021-06-09 04:06:00 culmination_time=2021-06-09 11:58:00 set_time=2021-06-09 19:49:00 aster=<Object type=PLANET name=MERCURY />>, <AsterEphemerides rise_time=2021-06-09 04:52:00 culmination_time=2021-06-09 13:13:00 set_time=2021-06-09 21:34:00 aster=<Object type=PLANET name=VENUS />>, <AsterEphemerides rise_time=2021-06-09 06:38:00 culmination_time=2021-06-09 14:40:00 set_time=2021-06-09 22:41:00 aster=<Object type=PLANET name=MARS />>, <AsterEphemerides rise_time=2021-06-09 23:43:00 culmination_time=2021-06-09 04:54:00 set_time=2021-06-09 10:01:00 aster=<Object type=PLANET name=JUPITER />>, <AsterEphemerides rise_time=2021-06-09 23:02:00 culmination_time=2021-06-09 03:41:00 set_time=2021-06-09 08:16:00 aster=<Object type=PLANET name=SATURN />>, <AsterEphemerides rise_time=2021-06-09 01:56:00 culmination_time=2021-06-09 09:18:00 set_time=2021-06-09 16:40:00 aster=<Object type=PLANET name=URANUS />>, <AsterEphemerides rise_time=2021-06-09 00:27:00 culmination_time=2021-06-09 06:13:00 set_time=2021-06-09 11:59:00 aster=<Object type=PLANET name=NEPTUNE />>, <AsterEphemerides rise_time=2021-06-09 22:22:00 culmination_time=2021-06-09 02:32:00 set_time=2021-06-09 06:38:00 aster=<Object type=PLANET name=PLUTO />>]


Compute the ephemerides for June 9th, 2021: Compute the ephemerides for June 9th, 2021:


>>> get_ephemerides(pos, datetime.date(2021, 6, 9), timezone=2) >>> get_ephemerides(pos, datetime.date(2021, 6, 9), timezone=2)
[<AsterEphemerides rise_time=2021-06-09 05:36:18+02:00 culmination_time=2021-06-09 13:47:05+02:00 set_time=2021-06-09 21:58:10+02:00 aster=<Object type=star name=Sun />>, <AsterEphemerides rise_time=2021-06-09 04:58:49+02:00 culmination_time=2021-06-09 13:02:19+02:00 set_time=2021-06-09 21:15:58+02:00 aster=<Object type=satellite name=Moon />>, <AsterEphemerides rise_time=2021-06-09 06:05:32+02:00 culmination_time=2021-06-09 13:57:51+02:00 set_time=2021-06-09 21:49:16+02:00 aster=<Object type=planet name=Mercury />>, <AsterEphemerides rise_time=2021-06-09 06:51:39+02:00 culmination_time=2021-06-09 15:12:45+02:00 set_time=2021-06-09 23:33:38+02:00 aster=<Object type=planet name=Venus />>, <AsterEphemerides rise_time=2021-06-09 08:37:42+02:00 culmination_time=2021-06-09 16:39:49+02:00 set_time=2021-06-09 00:43:41+02:00 aster=<Object type=planet name=Mars />>, <AsterEphemerides rise_time=2021-06-09 01:47:05+02:00 culmination_time=2021-06-09 06:53:50+02:00 set_time=2021-06-09 12:00:35+02:00 aster=<Object type=planet name=Jupiter />>, <AsterEphemerides rise_time=2021-06-09 01:05:33+02:00 culmination_time=2021-06-09 05:40:38+02:00 set_time=2021-06-09 10:15:43+02:00 aster=<Object type=planet name=Saturn />>, <AsterEphemerides rise_time=2021-06-09 03:55:34+02:00 culmination_time=2021-06-09 11:18:01+02:00 set_time=2021-06-09 18:40:29+02:00 aster=<Object type=planet name=Uranus />>, <AsterEphemerides rise_time=2021-06-09 02:26:53+02:00 culmination_time=2021-06-09 08:12:55+02:00 set_time=2021-06-09 13:58:57+02:00 aster=<Object type=planet name=Neptune />>, <AsterEphemerides rise_time=2021-06-09 00:26:08+02:00 culmination_time=2021-06-09 04:31:56+02:00 set_time=2021-06-09 08:37:43+02:00 aster=<Object type=planet name=Pluto />>]
[<AsterEphemerides rise_time=2021-06-09 05:36:00 culmination_time=2021-06-09 13:47:00 set_time=2021-06-09 21:58:00 aster=<Object type=STAR name=SUN />>, <AsterEphemerides rise_time=2021-06-09 04:59:00 culmination_time=2021-06-09 13:02:00 set_time=2021-06-09 21:16:00 aster=<Object type=SATELLITE name=MOON />>, <AsterEphemerides rise_time=2021-06-09 06:06:00 culmination_time=2021-06-09 13:58:00 set_time=2021-06-09 21:49:00 aster=<Object type=PLANET name=MERCURY />>, <AsterEphemerides rise_time=2021-06-09 06:52:00 culmination_time=2021-06-09 15:13:00 set_time=2021-06-09 23:34:00 aster=<Object type=PLANET name=VENUS />>, <AsterEphemerides rise_time=2021-06-09 08:38:00 culmination_time=2021-06-09 16:40:00 set_time=2021-06-09 00:44:00 aster=<Object type=PLANET name=MARS />>, <AsterEphemerides rise_time=2021-06-09 01:47:00 culmination_time=2021-06-09 06:54:00 set_time=2021-06-09 12:01:00 aster=<Object type=PLANET name=JUPITER />>, <AsterEphemerides rise_time=2021-06-09 01:06:00 culmination_time=2021-06-09 05:41:00 set_time=2021-06-09 10:16:00 aster=<Object type=PLANET name=SATURN />>, <AsterEphemerides rise_time=2021-06-09 03:56:00 culmination_time=2021-06-09 11:18:00 set_time=2021-06-09 18:40:00 aster=<Object type=PLANET name=URANUS />>, <AsterEphemerides rise_time=2021-06-09 02:27:00 culmination_time=2021-06-09 08:13:00 set_time=2021-06-09 13:59:00 aster=<Object type=PLANET name=NEPTUNE />>, <AsterEphemerides rise_time=2021-06-09 00:26:00 culmination_time=2021-06-09 04:32:00 set_time=2021-06-09 08:38:00 aster=<Object type=PLANET name=PLUTO />>]
""" """
ephemerides = [] ephemerides = []


@@ -182,19 +182,25 @@ def get_ephemerides(


# Convert the Time instances to Python datetime objects # Convert the Time instances to Python datetime objects
if rise_time is not None: 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: 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: 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( ephemerides.append(


+ 3
- 3
kosmorrolib/events.py View File

@@ -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): Find events that happen on April 4th, 2020 (show hours in UTC):


>>> get_events(date_type(2020, 4, 4)) >>> get_events(date_type(2020, 4, 4))
[<Event type=CONJUNCTION objects=[<Object type=planet name=Mercury />, <Object type=planet name=Neptune />] start=2020-04-04 01:14:39.063308+00:00 end=None details=None />]
[<Event type=CONJUNCTION objects=[<Object type=PLANET name=MERCURY />, <Object type=PLANET name=NEPTUNE />] 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): Find events that happen on April 4th, 2020 (show timezones in UTC+2):


>>> get_events(date_type(2020, 4, 4), 2) >>> get_events(date_type(2020, 4, 4), 2)
[<Event type=CONJUNCTION objects=[<Object type=planet name=Mercury />, <Object type=planet name=Neptune />] start=2020-04-04 03:14:39.063267+02:00 end=None details=None />]
[<Event type=CONJUNCTION objects=[<Object type=PLANET name=MERCURY />, <Object type=PLANET name=NEPTUNE />] 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): Find events that happen on April 3rd, 2020 (show timezones in UTC-2):


>>> get_events(date_type(2020, 4, 3), -2) >>> get_events(date_type(2020, 4, 3), -2)
[<Event type=CONJUNCTION objects=[<Object type=planet name=Mercury />, <Object type=planet name=Neptune />] start=2020-04-03 23:14:39.063388-02:00 end=None details=None />]
[<Event type=CONJUNCTION objects=[<Object type=PLANET name=MERCURY />, <Object type=PLANET name=NEPTUNE />] 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 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. :param timezone: the timezone to adapt the results to. If not given, defaults to 0.


+ 3
- 2
tests/data.py View File

@@ -1,18 +1,19 @@
import unittest import unittest


from kosmorrolib import data, core from kosmorrolib import data, core
from kosmorrolib.enum import ObjectIdentifier




class DataTestCase(unittest.TestCase): class DataTestCase(unittest.TestCase):
def test_object_radius_must_be_set_to_get_apparent_radius(self): 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: with self.assertRaises(ValueError) as context:
o.get_apparent_radius( o.get_apparent_radius(
core.get_timescale().now(), core.get_skf_objects()["earth"] 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__": if __name__ == "__main__":


+ 2
- 2
tests/ephemerides.py View File

@@ -18,11 +18,11 @@ class EphemeridesTestCase(unittest.TestCase):
def do_assertions(assert_regex): def do_assertions(assert_regex):
for ephemeris in eph: for ephemeris in eph:
if ephemeris.object.skyfield_name == "SUN": 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( assert_regex(
ephemeris.culmination_time.isoformat(), "^2019-11-18T11:45:" 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 break


do_assertions() do_assertions()


Loading…
Cancel
Save