BREAKING CHANGE: name of objects of type `kosmorrolib.model.Object` has been replaced with an enum typed identifier.pull/15/head
@@ -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 * |
@@ -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), | |||||
] | ] | ||||
@@ -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,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 |
@@ -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( | ||||
@@ -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. | ||||
@@ -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__": | ||||
@@ -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() | ||||