BREAKING CHANGE: name of objects of type `kosmorrolib.model.Object` has been replaced with an enum typed identifier.tags/v0.11.0
| @@ -3,3 +3,4 @@ | |||
| from .data import Position | |||
| from .ephemerides import get_ephemerides, get_moon_phase | |||
| from .events import get_events | |||
| from .enum import * | |||
| @@ -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), | |||
| ] | |||
| @@ -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,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 | |||
| @@ -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( | |||
| @@ -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. | |||
| @@ -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__": | |||
| @@ -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() | |||