From f0dc7e8b1b5a3665e86f220c1c4f44ba21353f4f Mon Sep 17 00:00:00 2001 From: Remco Steineke Date: Mon, 29 Dec 2025 12:43:58 +0100 Subject: [PATCH 1/3] Add stubs for ephem --- pyrightconfig.stricter.json | 1 + stubs/ephem/@tests/stubtest_allowlist.txt | 3 + stubs/ephem/METADATA.toml | 2 + stubs/ephem/ephem/__init__.pyi | 288 +++++++++++++++++ stubs/ephem/ephem/_libastro.pyi | 356 ++++++++++++++++++++++ stubs/ephem/ephem/cities.pyi | 5 + stubs/ephem/ephem/stars.pyi | 15 + 7 files changed, 670 insertions(+) create mode 100644 stubs/ephem/@tests/stubtest_allowlist.txt create mode 100644 stubs/ephem/METADATA.toml create mode 100644 stubs/ephem/ephem/__init__.pyi create mode 100644 stubs/ephem/ephem/_libastro.pyi create mode 100644 stubs/ephem/ephem/cities.pyi create mode 100644 stubs/ephem/ephem/stars.pyi diff --git a/pyrightconfig.stricter.json b/pyrightconfig.stricter.json index c1513a3016ea..4c6f0718cecc 100644 --- a/pyrightconfig.stricter.json +++ b/pyrightconfig.stricter.json @@ -34,6 +34,7 @@ "stubs/defusedxml", "stubs/docker", "stubs/docutils", + "stubs/ephem", "stubs/Flask-SocketIO", "stubs/fpdf2", "stubs/gdb", diff --git a/stubs/ephem/@tests/stubtest_allowlist.txt b/stubs/ephem/@tests/stubtest_allowlist.txt new file mode 100644 index 000000000000..c4dd07dbf42e --- /dev/null +++ b/stubs/ephem/@tests/stubtest_allowlist.txt @@ -0,0 +1,3 @@ +ephem.tests.* +ephem.stars.k +ephem.stars.v diff --git a/stubs/ephem/METADATA.toml b/stubs/ephem/METADATA.toml new file mode 100644 index 000000000000..ea821e2fee21 --- /dev/null +++ b/stubs/ephem/METADATA.toml @@ -0,0 +1,2 @@ +version = "4.2.*" +upstream_repository = "https://github.com/brandon-rhodes/pyephem" diff --git a/stubs/ephem/ephem/__init__.pyi b/stubs/ephem/ephem/__init__.pyi new file mode 100644 index 000000000000..c00a7f1bc63e --- /dev/null +++ b/stubs/ephem/ephem/__init__.pyi @@ -0,0 +1,288 @@ +from collections.abc import Callable +from datetime import datetime as _datetime, timedelta as _timedelta, tzinfo as _tzinfo +from typing import overload +from typing_extensions import Never + +from . import _libastro + +__version__: str + +# Mathematical constants +tau: float +twopi: float +halfpi: float +quarterpi: float +eighthpi: float +degree: float +arcminute: float +arcsecond: float +half_arcsecond: float +tiny: float + +# Physical constants +c: float +meters_per_au: float +earth_radius: float +moon_radius: float +sun_radius: float + +# Epoch constants +B1900: float +B1950: float +J2000: float + +# Type imports from _libastro +Angle = _libastro.Angle +degrees = _libastro.degrees +hours = _libastro.hours +Date = _libastro.Date + +# Time constants +hour: float +minute: float +second: float + +# Precision constants +default_newton_precision: float +rise_set_iterations: tuple[int, int, int, int, int, int, int] + +# Function imports from _libastro +delta_t = _libastro.delta_t +julian_date = _libastro.julian_date + +# Body type imports from _libastro +Body = _libastro.Body +Planet = _libastro.Planet +PlanetMoon = _libastro.PlanetMoon +FixedBody = _libastro.FixedBody +EllipticalBody = _libastro.EllipticalBody +ParabolicBody = _libastro.ParabolicBody +HyperbolicBody = _libastro.HyperbolicBody +EarthSatellite = _libastro.EarthSatellite + +# Database and coordinate functions from _libastro +readdb = _libastro.readdb +readtle = _libastro.readtle +constellation = _libastro.constellation +separation = _libastro.separation +unrefract = _libastro.unrefract +now = _libastro.now + +# Star atlas functions from _libastro +millennium_atlas = _libastro.millennium_atlas +uranometria = _libastro.uranometria +uranometria2000 = _libastro.uranometria2000 + +# Special planet classes from _libastro +Jupiter = _libastro.Jupiter +Saturn = _libastro.Saturn +Moon = _libastro.Moon + +# Dynamically created planet classes +class Mercury(Planet): + __planet__: int + +class Venus(Planet): + __planet__: int + +class Mars(Planet): + __planet__: int + +class Uranus(Planet): + __planet__: int + +class Neptune(Planet): + __planet__: int + +class Pluto(Planet): + __planet__: int + +class Sun(Planet): + __planet__: int + +# Planet moon classes +class Phobos(PlanetMoon): + __planet__: int + +class Deimos(PlanetMoon): + __planet__: int + +class Io(PlanetMoon): + __planet__: int + +class Europa(PlanetMoon): + __planet__: int + +class Ganymede(PlanetMoon): + __planet__: int + +class Callisto(PlanetMoon): + __planet__: int + +class Mimas(PlanetMoon): + __planet__: int + +class Enceladus(PlanetMoon): + __planet__: int + +class Tethys(PlanetMoon): + __planet__: int + +class Dione(PlanetMoon): + __planet__: int + +class Rhea(PlanetMoon): + __planet__: int + +class Titan(PlanetMoon): + __planet__: int + +class Hyperion(PlanetMoon): + __planet__: int + +class Iapetus(PlanetMoon): + __planet__: int + +class Ariel(PlanetMoon): + __planet__: int + +class Umbriel(PlanetMoon): + __planet__: int + +class Titania(PlanetMoon): + __planet__: int + +class Oberon(PlanetMoon): + __planet__: int + +class Miranda(PlanetMoon): + __planet__: int + +# Newton's method +def newton(f: Callable[[float], float], x0: float, x1: float, precision: float = ...) -> float: ... + +# Equinox and solstice functions +def holiday(d0: Date | float, motion: float, offset: float) -> Date: ... +def previous_vernal_equinox(date: Date | float) -> Date: ... +def next_vernal_equinox(date: Date | float) -> Date: ... +def previous_summer_solstice(date: Date | float) -> Date: ... +def next_summer_solstice(date: Date | float) -> Date: ... +def previous_autumnal_equinox(date: Date | float) -> Date: ... +def next_autumnal_equinox(date: Date | float) -> Date: ... +def previous_winter_solstice(date: Date | float) -> Date: ... +def next_winter_solstice(date: Date | float) -> Date: ... + +# Synonyms +next_spring_equinox = next_vernal_equinox +previous_spring_equinox = previous_vernal_equinox +next_fall_equinox = next_autumnal_equinox +next_autumn_equinox = next_autumnal_equinox +previous_fall_equinox = previous_autumnal_equinox +previous_autumn_equinox = previous_autumnal_equinox + +# More general equinox/solstice functions +def previous_equinox(date: Date | float) -> Date: ... +def next_equinox(date: Date | float) -> Date: ... +def previous_solstice(date: Date | float) -> Date: ... +def next_solstice(date: Date | float) -> Date: ... +def previous_new_moon(date: Date | float) -> Date: ... +def next_new_moon(date: Date | float) -> Date: ... +def previous_first_quarter_moon(date: Date | float) -> Date: ... +def next_first_quarter_moon(date: Date | float) -> Date: ... +def previous_full_moon(date: Date | float) -> Date: ... +def next_full_moon(date: Date | float) -> Date: ... +def previous_last_quarter_moon(date: Date | float) -> Date: ... +def next_last_quarter_moon(date: Date | float) -> Date: ... + +# Exceptions +class CircumpolarError(ValueError): ... +class NeverUpError(CircumpolarError): ... +class AlwaysUpError(CircumpolarError): ... + +# Observer class +class Observer(_libastro.Observer): + __slots__: list[str] = ["name"] + + name: object + + def __init__(self, /, *args: object, **kwargs: object) -> None: ... + def copy(self) -> Observer: ... + __copy__ = copy + def compute_pressure(self) -> None: ... + def previous_transit(self, body: Body, start: Date | float | None = None) -> Date: ... + def next_transit(self, body: Body, start: Date | float | None = None) -> Date: ... + def previous_antitransit(self, body: Body, start: Date | float | None = None) -> Date: ... + def next_antitransit(self, body: Body, start: Date | float | None = None) -> Date: ... + def disallow_circumpolar(self, declination: float) -> None: ... + def previous_rising(self, body: Body, start: Date | float | None = None, use_center: bool = False) -> Date: ... + def previous_setting(self, body: Body, start: Date | float | None = None, use_center: bool = False) -> Date: ... + def next_rising(self, body: Body, start: Date | float | None = None, use_center: bool = False) -> Date: ... + def next_setting(self, body: Body, start: Date | float | None = None, use_center: bool = False) -> Date: ... + def next_pass( + self, body: EarthSatellite, singlepass: bool = True + ) -> tuple[Date | None, Date | None, Date | None, Date | None, Date | None, Date | None]: ... + +# Time conversion functions +def localtime(date: Date | float) -> _datetime: ... + +class _UTC(_tzinfo): + ZERO: _timedelta + def tzname(self, dt: _datetime | None, /) -> Never: ... + def utcoffset(self, dt: _datetime | None) -> _timedelta: ... + def dst(self, dt: _datetime | None) -> _timedelta: ... + +UTC: _UTC + +def to_timezone(date: Date | float, tzinfo: _tzinfo) -> _datetime: ... + +# Coordinate classes +class Coordinate: + epoch: Date + + @overload + def __init__(self, body: Body, *, epoch: Date | float | None = None) -> None: ... + @overload + def __init__(self, coord1: float | str, coord2: float | str, *, epoch: Date | float | None = None) -> None: ... + @overload + def __init__(self, coord: Coordinate, *, epoch: Date | float | None = None) -> None: ... + +class Equatorial(Coordinate): + ra: Angle + dec: Angle + + def get(self) -> tuple[Angle, Angle]: ... + def set(self, ra: float | str, dec: float | str) -> None: ... + + to_radec = get + from_radec = set + +class LonLatCoordinate(Coordinate): + lon: Angle + lat: Angle + + def set(self, lon: float | str, lat: float | str) -> None: ... + def get(self) -> tuple[Angle, Angle]: ... + @property + def long(self) -> Angle: ... + @long.setter + def long(self, value: Angle) -> None: ... + +class Ecliptic(LonLatCoordinate): + def to_radec(self) -> tuple[Angle, Angle]: ... + def from_radec(self, ra: float | str, dec: float | str) -> None: ... + +class Galactic(LonLatCoordinate): + def to_radec(self) -> tuple[Angle, Angle]: ... + def from_radec(self, ra: float | str, dec: float | str) -> None: ... + +# Backwards compatibility aliases +date = Date +angle = Angle +LongLatCoordinate = LonLatCoordinate + +# Catalog functions +@overload +def star(name: str, observer: Observer, /) -> FixedBody: ... +@overload +def star(name: str, when: _libastro._DateInitType, epoch: _libastro._DateInitType) -> FixedBody: ... +def city(name: str) -> Observer: ... diff --git a/stubs/ephem/ephem/_libastro.pyi b/stubs/ephem/ephem/_libastro.pyi new file mode 100644 index 000000000000..f4c4941b676e --- /dev/null +++ b/stubs/ephem/ephem/_libastro.pyi @@ -0,0 +1,356 @@ +from datetime import datetime as _datetime +from typing import overload +from typing_extensions import Never, Self, TypeAlias, deprecated + +_DateInitType: TypeAlias = ( + Date + | float + | str + | tuple[int] + | tuple[int, int] + | tuple[int, int, float] + | tuple[int, int, float, float] + | tuple[int, int, float, float, float] + | tuple[int, int, float, float, float, float] + | _datetime +) + +class _DateDescriptor: + @overload + def __get__(self, obj: None, objtype: type | None = None) -> Self: ... + @overload + def __get__(self, obj: object, objtype: type | None = None) -> Date: ... + def __set__(self, obj: object, value: _DateInitType) -> None: ... + +# Descriptor classes for angle attributes that accept float or string input +# These descriptors don't actually exist at runtime but help type checkers +# distinguish between the different angle storage formats used in the C extension + +class _AngleDescriptorRadiansHours: + @overload + def __get__(self, obj: None, objtype: type | None = None) -> Self: ... + @overload + def __get__(self, obj: object, objtype: type | None = None) -> Angle: ... + def __set__(self, obj: object, value: float | str) -> None: ... + +class _AngleDescriptorRadiansDegrees: + @overload + def __get__(self, obj: None, objtype: type | None = None) -> Self: ... + @overload + def __get__(self, obj: object, objtype: type | None = None) -> Angle: ... + def __set__(self, obj: object, value: float | str) -> None: ... + +class _AngleDescriptorDegreesRadians: + @overload + def __get__(self, obj: None, objtype: type | None = None) -> Self: ... + @overload + def __get__(self, obj: object, objtype: type | None = None) -> Angle: ... + @overload + @deprecated("Do not pass Angle objects! The radian value will be incorrectly interpreted as degrees.") + def __set__(self, obj: object, value: Angle) -> None: ... + @overload + def __set__(self, obj: object, value: float | str) -> None: ... + +J2000: float +MJD0: float +earth_radius: float +meters_per_au: float +moon_radius: float +sun_radius: float + +class Angle(float): + def __new__(cls, *args: object, **kwargs: object) -> Never: ... + @property + def norm(self) -> Angle: ... + @property + def znorm(self) -> Angle: ... + +class Date(float): + @overload + def __new__(cls) -> Date: ... + @overload + def __new__(cls, date: _DateInitType, /) -> Date: ... + def triple(self) -> tuple[int, int, float]: ... + def tuple(self) -> tuple[int, int, int, int, int, float]: ... + def datetime(self) -> _datetime: ... + +class Observer: + lat: _AngleDescriptorRadiansDegrees + lon: _AngleDescriptorRadiansDegrees + long: _AngleDescriptorRadiansDegrees + elevation: float + elev: float + temp: float + temperature: float + pressure: float + horizon: _AngleDescriptorRadiansDegrees + epoch: _DateDescriptor + date: _DateDescriptor + + def __init__(self, /, *args: object, **kwargs: object) -> None: ... + def sidereal_time(self) -> Angle: ... + def radec_of(self, az: float | str, alt: float | str) -> tuple[Angle, Angle]: ... + +class Body: + @property + def name(self) -> str | None: ... + @property + def a_ra(self) -> Angle: ... + @property + def a_dec(self) -> Angle: ... + @property + def a_epoch(self) -> Date: ... + @property + def ra(self) -> Angle: ... + @property + def dec(self) -> Angle: ... + @property + def g_ra(self) -> Angle: ... + @property + def g_dec(self) -> Angle: ... + @property + def elong(self) -> Angle: ... + @property + def mag(self) -> float: ... + @property + def size(self) -> float: ... + @property + def radius(self) -> Angle: ... + @property + def alt(self) -> Angle: ... + @property + def az(self) -> Angle: ... + @property + def ha(self) -> Angle: ... + @property + def rise_time(self) -> Date | None: ... + @property + def rise_az(self) -> Angle | None: ... + @property + def transit_time(self) -> Date | None: ... + @property + def transit_alt(self) -> Angle | None: ... + @property + def set_time(self) -> Date | None: ... + @property + def set_az(self) -> Angle | None: ... + @property + def circumpolar(self) -> bool: ... + @property + def neverup(self) -> bool: ... + def __init__(self, *args: object, **kwargs: object) -> Never: ... + def __copy__(self) -> Self: ... + @overload + def compute(self, observer: Observer, /) -> None: ... + @overload + def compute(self, when: _DateInitType = ..., epoch: _DateInitType = ...) -> None: ... + def copy(self) -> Self: ... + def writedb(self) -> str: ... + def parallactic_angle(self) -> Angle: ... + +class Planet(Body): + @property + def hlon(self) -> Angle: ... + @property + def hlat(self) -> Angle: ... + @property + def sun_distance(self) -> float: ... + @property + def earth_distance(self) -> float: ... + @property + def phase(self) -> float: ... + @property + def hlong(self) -> Angle: ... + def __init__(self, /, *args: object, **kwargs: object) -> Never: ... + +class Moon(Planet): + @property + def libration_lat(self) -> Angle: ... + @property + def libration_long(self) -> Angle: ... + @property + def colong(self) -> Angle: ... + @property + def moon_phase(self) -> float: ... + @property + def subsolar_lat(self) -> Angle: ... + def __init__(self, /, *args: object, **kwargs: object) -> None: ... + +class Jupiter(Planet): + @property + def cmlI(self) -> Angle: ... + @property + def cmlII(self) -> Angle: ... + def __init__(self, /, *args: object, **kwargs: object) -> None: ... + +class Saturn(Planet): + @property + def earth_tilt(self) -> Angle: ... + @property + def sun_tilt(self) -> Angle: ... + def __init__(self, /, *args: object, **kwargs: object) -> None: ... + +class PlanetMoon: + @property + def name(self) -> str: ... + @property + def a_ra(self) -> Angle: ... + @property + def a_dec(self) -> Angle: ... + @property + def ra(self) -> Angle: ... + @property + def dec(self) -> Angle: ... + @property + def g_ra(self) -> Angle: ... + @property + def g_dec(self) -> Angle: ... + @property + def alt(self) -> Angle: ... + @property + def az(self) -> Angle: ... + @property + def x(self) -> float: ... + @property + def y(self) -> float: ... + @property + def z(self) -> float: ... + @property + def earth_visible(self) -> float: ... + @property + def sun_visible(self) -> float: ... + def __init__(self, /, *args: object, **kwargs: object) -> Never: ... + def __copy__(self) -> Self: ... + @overload + def compute(self, observer: Observer, /) -> None: ... + @overload + def compute(self, when: _DateInitType = ..., epoch: _DateInitType = ...) -> None: ... + def copy(self) -> Self: ... + def writedb(self) -> str: ... + def parallactic_angle(self) -> Angle: ... + +class FixedBody(Body): + name: str | None + mag: float + _spect: str + _ratio: float + _pa: _AngleDescriptorRadiansDegrees + _epoch: _DateDescriptor + _ra: _AngleDescriptorRadiansHours + _dec: _AngleDescriptorRadiansDegrees + _pmra: float + _pmdec: float + _class: str + + def __init__(self, /, *args: object, **kwargs: object) -> None: ... + +class EllipticalBody(Planet): + name: str | None + _inc: _AngleDescriptorDegreesRadians + _Om: _AngleDescriptorDegreesRadians + _om: _AngleDescriptorDegreesRadians + _M: _AngleDescriptorDegreesRadians + _epoch_M: _DateDescriptor + _epoch: _DateDescriptor + _H: float + _G: float + _g: float + _k: float + _a: float + _size: float + _e: float + + def __init__(self, /, *args: object, **kwargs: object) -> None: ... + +class ParabolicBody(Planet): + name: str | None + _epoch: _DateDescriptor + _epoch_p: _DateDescriptor + _inc: _AngleDescriptorDegreesRadians + _om: _AngleDescriptorDegreesRadians + _Om: _AngleDescriptorDegreesRadians + _q: float + _g: float + _k: float + _size: float + + def __init__(self, /, *args: object, **kwargs: object) -> None: ... + +class HyperbolicBody(Planet): + name: str | None + _epoch: _DateDescriptor + _epoch_p: _DateDescriptor + _inc: _AngleDescriptorDegreesRadians + _Om: _AngleDescriptorDegreesRadians + _om: _AngleDescriptorDegreesRadians + _e: float + _q: float + _g: float + _k: float + _size: float + + def __init__(self, /, *args: object, **kwargs: object) -> None: ... + +class EarthSatellite(Body): + name: str | None + epoch: _DateDescriptor + _epoch: _DateDescriptor + _inc: _AngleDescriptorDegreesRadians + _raan: _AngleDescriptorDegreesRadians + _ap: _AngleDescriptorDegreesRadians + _M: _AngleDescriptorDegreesRadians + n: float + inc: float + raan: float + e: float + ap: float + M: float + decay: float + drag: float + orbit: float + _n: float + _e: float + _decay: float + _drag: float + _orbit: int + catalog_number: str | None + + @property + def sublat(self) -> Angle: ... + @property + def sublong(self) -> Angle: ... + @property + def elevation(self) -> float: ... + @property + def range(self) -> float: ... + @property + def range_velocity(self) -> float: ... + @property + def eclipsed(self) -> bool: ... + def __init__(self, /, *args: object, **kwargs: object) -> None: ... + +def builtin_planets() -> list[tuple[int, str, str]]: ... +def degrees(angle: float | str, /) -> Angle: ... +def hours(angle: float | str, /) -> Angle: ... +def now() -> Date: ... +def separation( + obj1: tuple[float | str, float | str] | Body | Observer, obj2: tuple[float | str, float | str] | Body | Observer, / +) -> Angle: ... +def readdb(db_line: str, /) -> Body: ... +def readtle(name: str, line1: str, line2: str, /) -> EarthSatellite: ... +def unrefract(pressure: float, temperature: float, apparent_alt: float, /) -> Angle: ... +def uranometria(ra: float | str, dec: float | str, epoch: Date | float = ..., /) -> int: ... +def uranometria2000(ra: float | str, dec: float | str, epoch: Date | float = ..., /) -> int: ... +def millennium_atlas(ra: float | str, dec: float | str, epoch: Date | float = ..., /) -> int: ... +def constellation(ra: float | str, dec: float | str, epoch: Date | float = ...) -> tuple[str, str]: ... +def julian_date(date: _DateInitType | Observer = ..., /) -> float: ... +def delta_t(date: _DateInitType | Observer = ..., /) -> float: ... +def moon_phases(date: _DateInitType | Observer = ..., /) -> tuple[Date, Date, Date, Date]: ... +def eq_ecl(epoch: Date | float, ra: Angle | float, dec: Angle | float, /) -> tuple[Angle, Angle]: ... +def ecl_eq(epoch: Date | float, lon: Angle | float, lat: Angle | float, /) -> tuple[Angle, Angle]: ... +def eq_gal(epoch: Date | float, ra: Angle | float, dec: Angle | float, /) -> tuple[Angle, Angle]: ... +def gal_eq(epoch: Date | float, glon: Angle | float, glat: Angle | float, /) -> tuple[Angle, Angle]: ... +def precess(epoch1: Date | float, epoch2: Date | float, ra: Angle | float, dec: Angle | float, /) -> tuple[Angle, Angle]: ... +def _next_pass( + observer: Observer, body: Body, / +) -> tuple[Date | None, Angle | None, Date | None, Angle | None, Date | None, Angle | None]: ... diff --git a/stubs/ephem/ephem/cities.pyi b/stubs/ephem/ephem/cities.pyi new file mode 100644 index 000000000000..fa6959106a6a --- /dev/null +++ b/stubs/ephem/ephem/cities.pyi @@ -0,0 +1,5 @@ +from . import Observer + +def city(name: str) -> Observer: ... +def lookup(address: str) -> None: ... +def lookup_with_geonames(q: str, username: str) -> Observer: ... diff --git a/stubs/ephem/ephem/stars.pyi b/stubs/ephem/ephem/stars.pyi new file mode 100644 index 000000000000..a6b03f4a38c6 --- /dev/null +++ b/stubs/ephem/ephem/stars.pyi @@ -0,0 +1,15 @@ +from typing import overload + +from . import FixedBody, Observer +from ._libastro import _DateInitType + +db: str +stars: dict[str, FixedBody] + +@overload +def star(name: str, observer: Observer, /) -> FixedBody: ... +@overload +def star(name: str, when: _DateInitType = ..., epoch: _DateInitType = ...) -> FixedBody: ... + +STAR_NUMBER_NAME: dict[int, str] +STAR_NAME_NUMBER: dict[str, int] From e4604ef4680a39cc623fe48b1d65b20d92ca2705 Mon Sep 17 00:00:00 2001 From: Remco Steineke Date: Mon, 29 Dec 2025 13:42:30 +0100 Subject: [PATCH 2/3] fixed type hints --- stubs/ephem/ephem/__init__.pyi | 64 ++++++++++++++++----------------- stubs/ephem/ephem/_libastro.pyi | 19 ++++++---- 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/stubs/ephem/ephem/__init__.pyi b/stubs/ephem/ephem/__init__.pyi index c00a7f1bc63e..b85cf8523123 100644 --- a/stubs/ephem/ephem/__init__.pyi +++ b/stubs/ephem/ephem/__init__.pyi @@ -162,15 +162,15 @@ class Miranda(PlanetMoon): def newton(f: Callable[[float], float], x0: float, x1: float, precision: float = ...) -> float: ... # Equinox and solstice functions -def holiday(d0: Date | float, motion: float, offset: float) -> Date: ... -def previous_vernal_equinox(date: Date | float) -> Date: ... -def next_vernal_equinox(date: Date | float) -> Date: ... -def previous_summer_solstice(date: Date | float) -> Date: ... -def next_summer_solstice(date: Date | float) -> Date: ... -def previous_autumnal_equinox(date: Date | float) -> Date: ... -def next_autumnal_equinox(date: Date | float) -> Date: ... -def previous_winter_solstice(date: Date | float) -> Date: ... -def next_winter_solstice(date: Date | float) -> Date: ... +def holiday(d0: _libastro._DateInitType, motion: float, offset: float) -> Date: ... +def previous_vernal_equinox(date: _libastro._DateInitType) -> Date: ... +def next_vernal_equinox(date: _libastro._DateInitType) -> Date: ... +def previous_summer_solstice(date: _libastro._DateInitType) -> Date: ... +def next_summer_solstice(date: _libastro._DateInitType) -> Date: ... +def previous_autumnal_equinox(date: _libastro._DateInitType) -> Date: ... +def next_autumnal_equinox(date: _libastro._DateInitType) -> Date: ... +def previous_winter_solstice(date: _libastro._DateInitType) -> Date: ... +def next_winter_solstice(date: _libastro._DateInitType) -> Date: ... # Synonyms next_spring_equinox = next_vernal_equinox @@ -181,18 +181,18 @@ previous_fall_equinox = previous_autumnal_equinox previous_autumn_equinox = previous_autumnal_equinox # More general equinox/solstice functions -def previous_equinox(date: Date | float) -> Date: ... -def next_equinox(date: Date | float) -> Date: ... -def previous_solstice(date: Date | float) -> Date: ... -def next_solstice(date: Date | float) -> Date: ... -def previous_new_moon(date: Date | float) -> Date: ... -def next_new_moon(date: Date | float) -> Date: ... -def previous_first_quarter_moon(date: Date | float) -> Date: ... -def next_first_quarter_moon(date: Date | float) -> Date: ... -def previous_full_moon(date: Date | float) -> Date: ... -def next_full_moon(date: Date | float) -> Date: ... -def previous_last_quarter_moon(date: Date | float) -> Date: ... -def next_last_quarter_moon(date: Date | float) -> Date: ... +def previous_equinox(date: _libastro._DateInitType) -> Date: ... +def next_equinox(date: _libastro._DateInitType) -> Date: ... +def previous_solstice(date: _libastro._DateInitType) -> Date: ... +def next_solstice(date: _libastro._DateInitType) -> Date: ... +def previous_new_moon(date: _libastro._DateInitType) -> Date: ... +def next_new_moon(date: _libastro._DateInitType) -> Date: ... +def previous_first_quarter_moon(date: _libastro._DateInitType) -> Date: ... +def next_first_quarter_moon(date: _libastro._DateInitType) -> Date: ... +def previous_full_moon(date: _libastro._DateInitType) -> Date: ... +def next_full_moon(date: _libastro._DateInitType) -> Date: ... +def previous_last_quarter_moon(date: _libastro._DateInitType) -> Date: ... +def next_last_quarter_moon(date: _libastro._DateInitType) -> Date: ... # Exceptions class CircumpolarError(ValueError): ... @@ -209,15 +209,15 @@ class Observer(_libastro.Observer): def copy(self) -> Observer: ... __copy__ = copy def compute_pressure(self) -> None: ... - def previous_transit(self, body: Body, start: Date | float | None = None) -> Date: ... - def next_transit(self, body: Body, start: Date | float | None = None) -> Date: ... - def previous_antitransit(self, body: Body, start: Date | float | None = None) -> Date: ... - def next_antitransit(self, body: Body, start: Date | float | None = None) -> Date: ... + def previous_transit(self, body: Body, start: _libastro._DateInitType | None = None) -> Date: ... + def next_transit(self, body: Body, start: _libastro._DateInitType | None = None) -> Date: ... + def previous_antitransit(self, body: Body, start: _libastro._DateInitType | None = None) -> Date: ... + def next_antitransit(self, body: Body, start: _libastro._DateInitType | None = None) -> Date: ... def disallow_circumpolar(self, declination: float) -> None: ... - def previous_rising(self, body: Body, start: Date | float | None = None, use_center: bool = False) -> Date: ... - def previous_setting(self, body: Body, start: Date | float | None = None, use_center: bool = False) -> Date: ... - def next_rising(self, body: Body, start: Date | float | None = None, use_center: bool = False) -> Date: ... - def next_setting(self, body: Body, start: Date | float | None = None, use_center: bool = False) -> Date: ... + def previous_rising(self, body: Body, start: _libastro._DateInitType | None = None, use_center: bool = False) -> Date: ... + def previous_setting(self, body: Body, start: _libastro._DateInitType | None = None, use_center: bool = False) -> Date: ... + def next_rising(self, body: Body, start: _libastro._DateInitType | None = None, use_center: bool = False) -> Date: ... + def next_setting(self, body: Body, start: _libastro._DateInitType | None = None, use_center: bool = False) -> Date: ... def next_pass( self, body: EarthSatellite, singlepass: bool = True ) -> tuple[Date | None, Date | None, Date | None, Date | None, Date | None, Date | None]: ... @@ -240,11 +240,11 @@ class Coordinate: epoch: Date @overload - def __init__(self, body: Body, *, epoch: Date | float | None = None) -> None: ... + def __init__(self, body: Body, *, epoch: _libastro._DateInitType | None = None) -> None: ... @overload - def __init__(self, coord1: float | str, coord2: float | str, *, epoch: Date | float | None = None) -> None: ... + def __init__(self, coord1: float | str, coord2: float | str, *, epoch: _libastro._DateInitType | None = None) -> None: ... @overload - def __init__(self, coord: Coordinate, *, epoch: Date | float | None = None) -> None: ... + def __init__(self, coord: Coordinate, *, epoch: _libastro._DateInitType | None = None) -> None: ... class Equatorial(Coordinate): ra: Angle diff --git a/stubs/ephem/ephem/_libastro.pyi b/stubs/ephem/ephem/_libastro.pyi index f4c4941b676e..92e6910b9d03 100644 --- a/stubs/ephem/ephem/_libastro.pyi +++ b/stubs/ephem/ephem/_libastro.pyi @@ -1,5 +1,5 @@ from datetime import datetime as _datetime -from typing import overload +from typing import TypedDict, overload from typing_extensions import Never, Self, TypeAlias, deprecated _DateInitType: TypeAlias = ( @@ -329,6 +329,10 @@ class EarthSatellite(Body): def eclipsed(self) -> bool: ... def __init__(self, /, *args: object, **kwargs: object) -> None: ... +class _MoonPhases(TypedDict): + new: Date + full: Date + def builtin_planets() -> list[tuple[int, str, str]]: ... def degrees(angle: float | str, /) -> Angle: ... def hours(angle: float | str, /) -> Angle: ... @@ -339,13 +343,16 @@ def separation( def readdb(db_line: str, /) -> Body: ... def readtle(name: str, line1: str, line2: str, /) -> EarthSatellite: ... def unrefract(pressure: float, temperature: float, apparent_alt: float, /) -> Angle: ... -def uranometria(ra: float | str, dec: float | str, epoch: Date | float = ..., /) -> int: ... -def uranometria2000(ra: float | str, dec: float | str, epoch: Date | float = ..., /) -> int: ... -def millennium_atlas(ra: float | str, dec: float | str, epoch: Date | float = ..., /) -> int: ... -def constellation(ra: float | str, dec: float | str, epoch: Date | float = ...) -> tuple[str, str]: ... +def uranometria(ra: float | str, dec: float | str, /) -> int: ... +def uranometria2000(ra: float | str, dec: float | str, /) -> int: ... +def millennium_atlas(ra: float | str, dec: float | str, /) -> int: ... +@overload +def constellation(position: Body) -> tuple[str, str]: ... +@overload +def constellation(position: tuple[Angle | float, Angle | float], epoch: Date | float = ...) -> tuple[str, str]: ... def julian_date(date: _DateInitType | Observer = ..., /) -> float: ... def delta_t(date: _DateInitType | Observer = ..., /) -> float: ... -def moon_phases(date: _DateInitType | Observer = ..., /) -> tuple[Date, Date, Date, Date]: ... +def moon_phases(date: _DateInitType | Observer = ...) -> _MoonPhases: ... def eq_ecl(epoch: Date | float, ra: Angle | float, dec: Angle | float, /) -> tuple[Angle, Angle]: ... def ecl_eq(epoch: Date | float, lon: Angle | float, lat: Angle | float, /) -> tuple[Angle, Angle]: ... def eq_gal(epoch: Date | float, ra: Angle | float, dec: Angle | float, /) -> tuple[Angle, Angle]: ... From a8ea4a1508bec910be702fb13576255d408e349d Mon Sep 17 00:00:00 2001 From: Remco Steineke Date: Mon, 5 Jan 2026 16:46:28 +0100 Subject: [PATCH 3/3] Added @disjoint_base, improved __init__ signatures --- stubs/ephem/@tests/stubtest_allowlist.txt | 3 ++ stubs/ephem/ephem/__init__.pyi | 61 +++++++++++----------- stubs/ephem/ephem/_libastro.pyi | 62 ++++++++++++++--------- 3 files changed, 72 insertions(+), 54 deletions(-) diff --git a/stubs/ephem/@tests/stubtest_allowlist.txt b/stubs/ephem/@tests/stubtest_allowlist.txt index c4dd07dbf42e..345c072a9b17 100644 --- a/stubs/ephem/@tests/stubtest_allowlist.txt +++ b/stubs/ephem/@tests/stubtest_allowlist.txt @@ -1,3 +1,6 @@ ephem.tests.* ephem.stars.k ephem.stars.v +ephem._libastro.Observer.__init__ +ephem.FixedBody.__init__ +ephem._libastro.FixedBody.__init__ diff --git a/stubs/ephem/ephem/__init__.pyi b/stubs/ephem/ephem/__init__.pyi index b85cf8523123..1c18ce2d6faf 100644 --- a/stubs/ephem/ephem/__init__.pyi +++ b/stubs/ephem/ephem/__init__.pyi @@ -1,7 +1,7 @@ from collections.abc import Callable from datetime import datetime as _datetime, timedelta as _timedelta, tzinfo as _tzinfo -from typing import overload -from typing_extensions import Never +from typing import Final, NoReturn, overload +from typing_extensions import Self from . import _libastro @@ -80,83 +80,83 @@ Moon = _libastro.Moon # Dynamically created planet classes class Mercury(Planet): - __planet__: int + __planet__: Final = 0 class Venus(Planet): - __planet__: int + __planet__: Final = 1 class Mars(Planet): - __planet__: int + __planet__: Final = 2 class Uranus(Planet): - __planet__: int + __planet__: Final = 5 class Neptune(Planet): - __planet__: int + __planet__: Final = 6 class Pluto(Planet): - __planet__: int + __planet__: Final = 7 class Sun(Planet): - __planet__: int + __planet__: Final = 8 # Planet moon classes class Phobos(PlanetMoon): - __planet__: int + __planet__: Final = 10 class Deimos(PlanetMoon): - __planet__: int + __planet__: Final = 11 class Io(PlanetMoon): - __planet__: int + __planet__: Final = 12 class Europa(PlanetMoon): - __planet__: int + __planet__: Final = 13 class Ganymede(PlanetMoon): - __planet__: int + __planet__: Final = 14 class Callisto(PlanetMoon): - __planet__: int + __planet__: Final = 15 class Mimas(PlanetMoon): - __planet__: int + __planet__: Final = 16 class Enceladus(PlanetMoon): - __planet__: int + __planet__: Final = 17 class Tethys(PlanetMoon): - __planet__: int + __planet__: Final = 18 class Dione(PlanetMoon): - __planet__: int + __planet__: Final = 19 class Rhea(PlanetMoon): - __planet__: int + __planet__: Final = 20 class Titan(PlanetMoon): - __planet__: int + __planet__: Final = 21 class Hyperion(PlanetMoon): - __planet__: int + __planet__: Final = 22 class Iapetus(PlanetMoon): - __planet__: int + __planet__: Final = 23 class Ariel(PlanetMoon): - __planet__: int + __planet__: Final = 24 class Umbriel(PlanetMoon): - __planet__: int + __planet__: Final = 25 class Titania(PlanetMoon): - __planet__: int + __planet__: Final = 26 class Oberon(PlanetMoon): - __planet__: int + __planet__: Final = 27 class Miranda(PlanetMoon): - __planet__: int + __planet__: Final = 28 # Newton's method def newton(f: Callable[[float], float], x0: float, x1: float, precision: float = ...) -> float: ... @@ -205,8 +205,7 @@ class Observer(_libastro.Observer): name: object - def __init__(self, /, *args: object, **kwargs: object) -> None: ... - def copy(self) -> Observer: ... + def copy(self) -> Self: ... __copy__ = copy def compute_pressure(self) -> None: ... def previous_transit(self, body: Body, start: _libastro._DateInitType | None = None) -> Date: ... @@ -227,7 +226,7 @@ def localtime(date: Date | float) -> _datetime: ... class _UTC(_tzinfo): ZERO: _timedelta - def tzname(self, dt: _datetime | None, /) -> Never: ... + def tzname(self, dt: _datetime | None, /) -> NoReturn: ... def utcoffset(self, dt: _datetime | None) -> _timedelta: ... def dst(self, dt: _datetime | None) -> _timedelta: ... diff --git a/stubs/ephem/ephem/_libastro.pyi b/stubs/ephem/ephem/_libastro.pyi index 92e6910b9d03..62732b4acc12 100644 --- a/stubs/ephem/ephem/_libastro.pyi +++ b/stubs/ephem/ephem/_libastro.pyi @@ -1,6 +1,7 @@ +from _typeshed import Unused from datetime import datetime as _datetime -from typing import TypedDict, overload -from typing_extensions import Never, Self, TypeAlias, deprecated +from typing import NoReturn, Protocol, TypedDict, overload, type_check_only +from typing_extensions import Self, TypeAlias, deprecated, disjoint_base _DateInitType: TypeAlias = ( Date @@ -15,6 +16,7 @@ _DateInitType: TypeAlias = ( | _datetime ) +@type_check_only class _DateDescriptor: @overload def __get__(self, obj: None, objtype: type | None = None) -> Self: ... @@ -22,10 +24,7 @@ class _DateDescriptor: def __get__(self, obj: object, objtype: type | None = None) -> Date: ... def __set__(self, obj: object, value: _DateInitType) -> None: ... -# Descriptor classes for angle attributes that accept float or string input -# These descriptors don't actually exist at runtime but help type checkers -# distinguish between the different angle storage formats used in the C extension - +@type_check_only class _AngleDescriptorRadiansHours: @overload def __get__(self, obj: None, objtype: type | None = None) -> Self: ... @@ -33,6 +32,7 @@ class _AngleDescriptorRadiansHours: def __get__(self, obj: object, objtype: type | None = None) -> Angle: ... def __set__(self, obj: object, value: float | str) -> None: ... +@type_check_only class _AngleDescriptorRadiansDegrees: @overload def __get__(self, obj: None, objtype: type | None = None) -> Self: ... @@ -40,6 +40,7 @@ class _AngleDescriptorRadiansDegrees: def __get__(self, obj: object, objtype: type | None = None) -> Angle: ... def __set__(self, obj: object, value: float | str) -> None: ... +@type_check_only class _AngleDescriptorDegreesRadians: @overload def __get__(self, obj: None, objtype: type | None = None) -> Self: ... @@ -58,8 +59,9 @@ meters_per_au: float moon_radius: float sun_radius: float -class Angle(float): - def __new__(cls, *args: object, **kwargs: object) -> Never: ... +@disjoint_base +class Angle(float): # type: ignore[type-var] + def __new__(cls, *args: Unused, **kwargs: Unused) -> NoReturn: ... @property def norm(self) -> Angle: ... @property @@ -74,6 +76,7 @@ class Date(float): def tuple(self) -> tuple[int, int, int, int, int, float]: ... def datetime(self) -> _datetime: ... +@disjoint_base class Observer: lat: _AngleDescriptorRadiansDegrees lon: _AngleDescriptorRadiansDegrees @@ -87,11 +90,12 @@ class Observer: epoch: _DateDescriptor date: _DateDescriptor - def __init__(self, /, *args: object, **kwargs: object) -> None: ... + def __init__(self) -> None: ... def sidereal_time(self) -> Angle: ... def radec_of(self, az: float | str, alt: float | str) -> tuple[Angle, Angle]: ... -class Body: +@disjoint_base +class Body(Protocol): @property def name(self) -> str | None: ... @property @@ -138,7 +142,7 @@ class Body: def circumpolar(self) -> bool: ... @property def neverup(self) -> bool: ... - def __init__(self, *args: object, **kwargs: object) -> Never: ... + def __init__(self, *args: Unused, **kwargs: Unused) -> None: ... def __copy__(self) -> Self: ... @overload def compute(self, observer: Observer, /) -> None: ... @@ -148,7 +152,7 @@ class Body: def writedb(self) -> str: ... def parallactic_angle(self) -> Angle: ... -class Planet(Body): +class Planet(Body, Protocol): @property def hlon(self) -> Angle: ... @property @@ -161,8 +165,14 @@ class Planet(Body): def phase(self) -> float: ... @property def hlong(self) -> Angle: ... - def __init__(self, /, *args: object, **kwargs: object) -> Never: ... + @overload + def __init__(self, observer: Observer, /) -> None: ... + @overload + def __init__(self, when: _DateInitType, /, epoch: _DateInitType = ...) -> None: ... + @overload + def __init__(self, *args: Unused, **kwargs: Unused) -> None: ... +@disjoint_base class Moon(Planet): @property def libration_lat(self) -> Angle: ... @@ -174,23 +184,23 @@ class Moon(Planet): def moon_phase(self) -> float: ... @property def subsolar_lat(self) -> Angle: ... - def __init__(self, /, *args: object, **kwargs: object) -> None: ... +@disjoint_base class Jupiter(Planet): @property def cmlI(self) -> Angle: ... @property def cmlII(self) -> Angle: ... - def __init__(self, /, *args: object, **kwargs: object) -> None: ... +@disjoint_base class Saturn(Planet): @property def earth_tilt(self) -> Angle: ... @property def sun_tilt(self) -> Angle: ... - def __init__(self, /, *args: object, **kwargs: object) -> None: ... -class PlanetMoon: +@disjoint_base +class PlanetMoon(Protocol): @property def name(self) -> str: ... @property @@ -219,7 +229,12 @@ class PlanetMoon: def earth_visible(self) -> float: ... @property def sun_visible(self) -> float: ... - def __init__(self, /, *args: object, **kwargs: object) -> Never: ... + @overload + def __init__(self, observer: Observer, /) -> None: ... + @overload + def __init__(self, when: _DateInitType, /, epoch: _DateInitType = ...) -> None: ... + @overload + def __init__(self, **kwargs: Unused) -> None: ... def __copy__(self) -> Self: ... @overload def compute(self, observer: Observer, /) -> None: ... @@ -242,7 +257,7 @@ class FixedBody(Body): _pmdec: float _class: str - def __init__(self, /, *args: object, **kwargs: object) -> None: ... + def __init__(self) -> None: ... class EllipticalBody(Planet): name: str | None @@ -260,7 +275,7 @@ class EllipticalBody(Planet): _size: float _e: float - def __init__(self, /, *args: object, **kwargs: object) -> None: ... + def __init__(self, *args: Unused, **kwargs: Unused) -> None: ... class ParabolicBody(Planet): name: str | None @@ -274,7 +289,7 @@ class ParabolicBody(Planet): _k: float _size: float - def __init__(self, /, *args: object, **kwargs: object) -> None: ... + def __init__(self, *args: Unused, **kwargs: Unused) -> None: ... class HyperbolicBody(Planet): name: str | None @@ -289,8 +304,9 @@ class HyperbolicBody(Planet): _k: float _size: float - def __init__(self, /, *args: object, **kwargs: object) -> None: ... + def __init__(self, *args: Unused, **kwargs: Unused) -> None: ... +@disjoint_base class EarthSatellite(Body): name: str | None epoch: _DateDescriptor @@ -327,8 +343,8 @@ class EarthSatellite(Body): def range_velocity(self) -> float: ... @property def eclipsed(self) -> bool: ... - def __init__(self, /, *args: object, **kwargs: object) -> None: ... +@type_check_only class _MoonPhases(TypedDict): new: Date full: Date