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 .ephemerides import get_ephemerides, get_moon_phase
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 .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 "<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:
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),
]




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

+ 16
- 10
kosmorrolib/ephemerides.py View File

@@ -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))
[<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:

>>> 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 = []

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


+ 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):

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

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

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

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__":


+ 2
- 2
tests/ephemerides.py View File

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


Loading…
Cancel
Save