Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-skyfield for openSUSE:Factory 
checked in at 2023-01-21 19:12:31
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-skyfield (Old)
 and      /work/SRC/openSUSE:Factory/.python-skyfield.new.32243 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-skyfield"

Sat Jan 21 19:12:31 2023 rev:17 rq:1060131 version:1.45

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-skyfield/python-skyfield.changes  
2022-08-11 18:33:13.374206585 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-skyfield.new.32243/python-skyfield.changes   
    2023-01-21 19:13:23.261924587 +0100
@@ -1,0 +2,19 @@
+Sat Jan 21 11:25:21 UTC 2023 - Ben Greiner <[email protected]>
+
+- Update to v1.45
+  * Bugfix: minor planets and comets in Skyfield 1.44 would raise
+    an exception if asked for a position in the half of their orbit
+    where they are inbound towards their perihelion.
+- Changelog v1.44
+  * Skyfield’s internal table for the ∆T Earth orientation
+    parameter has been updated, so that instead of including
+    measurements only through December 2021 it now knows Earth
+    orientation through September 2022.
+  * Distance and velocity objects can now be created by calling
+    their unit names as constructors, like d = Distance.km(5.0) and
+    v = Velocity.km_per_s(0.343).
+  * Updated the URL from which the Hipparcos database hip_main.dat
+    is downloaded, following a change in the domain for the
+    University of Strasbourg from u-strasbg.fr to unistra.fr.
+
+-------------------------------------------------------------------

Old:
----
  skyfield-1.43.1.tar.gz

New:
----
  skyfield-1.45.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-skyfield.spec ++++++
--- /var/tmp/diff_new_pack.GdgeE0/_old  2023-01-21 19:13:24.433931425 +0100
+++ /var/tmp/diff_new_pack.GdgeE0/_new  2023-01-21 19:13:24.437931449 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-skyfield
 #
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2023 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -21,7 +21,7 @@
 %define assayver    264.bb62d1f
 %define skip_python2 1
 Name:           python-skyfield
-Version:        1.43.1
+Version:        1.45
 Release:        0
 Summary:        Elegant astronomy for Python
 License:        MIT



++++++ finals2000A.all ++++++
++++ 1777 lines (skipped)
++++ between /work/SRC/openSUSE:Factory/python-skyfield/finals2000A.all
++++ and /work/SRC/openSUSE:Factory/.python-skyfield.new.32243/finals2000A.all

++++++ generate-hipparcos.sh ++++++
--- /var/tmp/diff_new_pack.GdgeE0/_old  2023-01-21 19:13:24.581932289 +0100
+++ /var/tmp/diff_new_pack.GdgeE0/_new  2023-01-21 19:13:24.585932312 +0100
@@ -4,6 +4,6 @@
 # corresponds to last line of
 # https://github.com/skyfielders/python-skyfield/blob/master/builders/Makefile 
 # but with an SSL secured URL for the source (boo#1182424)
-URL="https://cdsarc.u-strasbg.fr/ftp/I/239/hip_main.dat";
+URL="https://cdsarc.cds.unistra.fr/ftp/I/239/hip_main.dat";
 curl "$URL" | awk -F\| '$6 <= 6.6 || $2 == 87937' | gzip -c -9 > 
hip_main.dat.gz
 



++++++ skyfield-1.43.1.tar.gz -> skyfield-1.45.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/skyfield-1.43.1/PKG-INFO new/skyfield-1.45/PKG-INFO
--- old/skyfield-1.43.1/PKG-INFO        2022-07-06 18:12:44.000000000 +0200
+++ new/skyfield-1.45/PKG-INFO  2022-09-15 15:03:21.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: skyfield
-Version: 1.43.1
+Version: 1.45
 Summary: Elegant astronomy for Python
 Home-page: http://github.com/brandon-rhodes/python-skyfield/
 Author: Brandon Rhodes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/skyfield-1.43.1/skyfield/__init__.py 
new/skyfield-1.45/skyfield/__init__.py
--- old/skyfield-1.43.1/skyfield/__init__.py    2022-07-06 18:08:17.000000000 
+0200
+++ new/skyfield-1.45/skyfield/__init__.py      2022-09-15 15:02:57.000000000 
+0200
@@ -5,5 +5,5 @@
 the source code, as well as the http://rhodesmill.org/skyfield/ site!
 
 """
-VERSION = 1, 43, 1
+VERSION = 1, 45
 __version__ = '.'.join(map(str, VERSION))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/skyfield-1.43.1/skyfield/data/hipparcos.py 
new/skyfield-1.45/skyfield/data/hipparcos.py
--- old/skyfield-1.43.1/skyfield/data/hipparcos.py      2021-12-26 
12:05:22.000000000 +0100
+++ new/skyfield-1.45/skyfield/data/hipparcos.py        2022-09-11 
11:31:26.000000000 +0200
@@ -1,11 +1,17 @@
 # This URL worked until September 2020:
-
-#URL = 'http://cdsarc.u-strasbg.fr/ftp/cats/I/239/hip_main.dat.gz'
-
+#
+# URL = 'http://cdsarc.u-strasbg.fr/ftp/cats/I/239/hip_main.dat.gz'
+#
 # Then someone at VizieR apparently ran `gunzip` on the file, breaking
 # the existing URL.  The fastest fix is for us to switch to:
+#
+# URL = 'https://cdsarc.u-strasbg.fr/ftp/cats/I/239/hip_main.dat'
+#
+# Then in September 2022 the site's certificate broke, and an engineer
+# at unistra.fr confirmed that 'the domain "astro.unistra.fr" as well as
+# the domain "u-strasbg.fr" are obsoleted by "cds.unistra.fr".'  Thus:
 
-URL = 'https://cdsarc.u-strasbg.fr/ftp/cats/I/239/hip_main.dat'
+URL = 'https://cdsarc.cds.unistra.fr/ftp/cats/I/239/hip_main.dat'
 
 # But what if someone runs `gzip` on the file again?  Then the new URL
 # will break like the old one did.  It appears that VizieR makes no
Binary files old/skyfield-1.43.1/skyfield/data/iers.npz and 
new/skyfield-1.45/skyfield/data/iers.npz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/skyfield-1.43.1/skyfield/documentation/examples.rst 
new/skyfield-1.45/skyfield/documentation/examples.rst
--- old/skyfield-1.43.1/skyfield/documentation/examples.rst     2022-05-11 
22:55:23.000000000 +0200
+++ new/skyfield-1.45/skyfield/documentation/examples.rst       2022-09-12 
22:08:06.000000000 +0200
@@ -377,6 +377,139 @@
     Sun 20 05:47 MST rises
     Sun 20 14:23 MST sets
 
+At what rate is a target moving across the sky?
+===============================================
+
+Automatically-driven telescopes and antennas
+often need to know the rate at which an object is moving across the sky.
+Specifically,
+an instrument with a simple altazimuth mount
+will need to know the rates at which altitude and azimuth are changing,
+whereas a fancier equatorial mount
+will need the rates for right ascension and declination.
+
+The solution is the same in both cases:
+to call Skyfield’s
+:meth:`~skyfield.positionlib.ICRF.frame_latlon_and_rates()` position method
+and pass it the frame of reference
+in which you want the rates computed.
+In either case,
+you will want to start by asking Skyfield to compute an apparent position:
+
+.. testcode::
+
+    from skyfield.api import load, wgs84, N, E
+
+    ts = load.timescale()
+    t = ts.utc(2021, 2, 3, 0, 0)
+    planets = load('de421.bsp')
+    earth, mars = planets['earth'], planets['mars']
+    top = wgs84.latlon(35.1844866 * N, 248.347300 * E, elevation_m=2106.9128)
+
+    a = (earth + top).at(t).observe(mars).apparent()
+
+Since every topocentric location in Skyfield
+is itself a reference frame representing the location’s horizon,
+we can simply pass ``top`` to the
+:meth:`~skyfield.positionlib.ICRF.frame_latlon_and_rates()` method
+to learn the rates at which the altitude and azimuth are changing:
+
+.. testcode::
+
+    alt, az, distance, alt_rate, az_rate, range_rate = (
+        a.frame_latlon_and_rates(top)
+    )
+
+    print('Alt: {:+.2f} asec/min'.format(alt_rate.arcseconds.per_minute))
+    print('Az:  {:+.2f} asec/min'.format(az_rate.arcseconds.per_minute))
+
+.. testoutput::
+
+    Alt: +548.66 asec/min
+    Az:  +1586.48 asec/min
+
+But if our instrument is on an equatorial mount,
+it will need to know how fast
+the right ascension and declination are changing.
+In that case we import Skyfield’s reference frame
+that represents the Earth’s true orientation in space,
+and pass that object to the
+:meth:`~skyfield.positionlib.ICRF.frame_latlon_and_rates()` method:
+
+.. testcode::
+
+    from skyfield import framelib
+
+    eeod = framelib.true_equator_and_equinox_of_date
+    dec, ra, distance, dec_rate, ra_rate, range_rate = (
+        a.frame_latlon_and_rates(eeod)
+    )
+
+    print(f'RA:  {ra_rate.arcseconds.per_hour:+.2f} asec/hr')
+    print(f'Dec: {dec_rate.arcseconds.per_hour:+.2f} asec/hr')
+
+.. testoutput::
+
+    RA:  +78.66 asec/hr
+    Dec: +25.61 asec/hr
+
+Note that, contrary to Skyfield’s usual custom,
+declination is returned first.
+That’s why the
+:meth:`~skyfield.positionlib.ICRF.frame_latlon_and_rates()` method
+has ``latlon`` in its name:
+it always returns the latitude-like coordinate
+(angle above or below the plane) first,
+then the longitude-like coordinate
+(angle around the plane) second.
+
+Finally, in case you need it,
+you will notice that both of the calls above return a ``range_rate``
+that is positive if the body is moving away from you
+and its range is increasing,
+or is negative if the target is moving closer and the range is falling.
+At the specific date and time we asked about above,
+Mars is moving away:
+
+.. testcode::
+
+    print('Range rate: {:+.2f} km/s'.format(range_rate.km_per_s))
+
+.. testoutput::
+
+    Range rate: +16.79 km/s
+
+Finally,
+there’s the slight complication
+that some data sources and instruments
+want the rate of motion around-the-sky
+to be multiplied by the cosine of the body’s angle
+above or below the reference plane.
+By simply performing the math—and
+remembering that ``sin()`` and ``cos()`` in Python take radian arguments—you
+can produce these alternative measurements yourself:
+
+.. testcode::
+
+    from numpy import cos
+
+    rcos = az_rate.arcseconds.per_minute * cos(alt.radians)
+    print(
+        'Azimuth rate × cos(altitude): {:.2f} arcseconds / minute'
+        .format(rcos)
+    )
+
+    rcos = ra_rate.arcseconds.per_hour * cos(dec.radians)
+    print(
+        'RA rate × cos(declination): {:.2f} arcseconds / hour'
+        .format(rcos)
+    )
+
+.. testoutput::
+
+    Azimuth rate × cos(altitude): 663.55 arcseconds / minute
+    RA rate × cos(declination): 75.16 arcseconds / hour
+
 What is the right ascension and declination of a point in the sky?
 ==================================================================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/skyfield-1.43.1/skyfield/functions.py 
new/skyfield-1.45/skyfield/functions.py
--- old/skyfield-1.43.1/skyfield/functions.py   2021-12-26 12:05:22.000000000 
+0100
+++ new/skyfield-1.45/skyfield/functions.py     2022-09-11 11:31:29.000000000 
+0200
@@ -153,9 +153,10 @@
 def _to_array(value):
     """Convert plain Python sequences into NumPy arrays.
 
-    This helps Skyfield endpoints convert caller-provided tuples and
-    lists into NumPy arrays.  If the ``value`` is not a sequence, then
-    it is coerced to a Numpy float object, but not an actual array.
+    This lets users pass plain old Python lists and tuples to Skyfield,
+    instead of always having to remember to build NumPy arrays.  We pass
+    any kind of generic sequence to the NumPy ``array()`` constructor
+    and wrap any other kind of value in a NumPy ``float64`` object.
 
     """
     if hasattr(value, 'shape'):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/skyfield-1.43.1/skyfield/keplerlib.py 
new/skyfield-1.45/skyfield/keplerlib.py
--- old/skyfield-1.43.1/skyfield/keplerlib.py   2021-01-31 01:43:01.000000000 
+0100
+++ new/skyfield-1.45/skyfield/keplerlib.py     2022-09-14 18:18:49.000000000 
+0200
@@ -2,11 +2,12 @@
 
 import sys
 import math
-from numpy import(abs, amax, amin, arange, arccos, arctan, array, atleast_1d,
-                  clip, copy, copyto, cos, cosh, exp, full_like, log, ndarray,
-                  newaxis, pi, power, repeat, sin, sinh, squeeze, sqrt, sum,
-                  tan, tanh, zeros_like)
-
+from numpy import (
+    abs, amax, amin, arange, arccos, arctan, array, atleast_1d,
+    clip, copy, copyto, cos, cosh, exp, full_like, log, ndarray, newaxis,
+    pi, power, repeat, sign, sin, sinh, squeeze, sqrt, sum,
+    tan, tanh, zeros_like,
+)
 from skyfield.constants import AU_KM, DAY_S, DEG2RAD
 from skyfield.functions import dots, length_of, mxv
 from skyfield.descriptorlib import reify
@@ -267,27 +268,30 @@
     def __repr__(self):
         return '<{0}>'.format(str(self))
 
+_ten_iterations = tuple([None] * 10)
 
 def eccentric_anomaly(e, M):
-    """ Iterates to solve Kepler's equation to find eccentric anomaly
+    """Iterate to solve Kepler's equation to find the eccentric anomaly.
+
+    See arXiv:2108.03215.
 
-    Based on the algorithm in section 8.10.2 of the Explanatory Supplement
-    to the Astronomical Almanac, 3rd ed.
     """
     M = normpi(M)
-    E = M + e*sin(M)
-
-    max_iters = 100
-    iters = 0
-    while iters < max_iters:
-        dM = M - (E - e*sin(E))
-        dE = dM/(1 - e*cos(E))
-        E = E + dE
-        if abs(dE) < 1e-14: return E
-        iters += 1
-    else:
-        raise ValueError('Failed to converge')
+    sign_M = sign(M)
+    M *= sign_M
+    ebar = 0.25 * pi/e - 1.0
+    E = 0.5 * pi * ebar * (sign(ebar) * sqrt(1 + M/(e*ebar*ebar)) - 1.0)
+
+    for _ in _ten_iterations:
+        f1 = 1.0 - e*cos(E)
+        f2 = e*sin(E)
+        f = E - f2 - M
+        dE = f*f1 / (f1*f1 - 0.5*f*f2)
+        E -= dE
+        if abs(dE) < 1e-14:
+            return E * sign_M
 
+    raise ValueError('eccentric anomaly failed to converge')
 
 def true_anomaly_hyperbolic(e, E):
     """Calculates true anomaly from eccentricity and eccentric anomaly.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/skyfield-1.43.1/skyfield/tests/test_keplerlib.py 
new/skyfield-1.45/skyfield/tests/test_keplerlib.py
--- old/skyfield-1.43.1/skyfield/tests/test_keplerlib.py        2020-09-10 
03:19:36.000000000 +0200
+++ new/skyfield-1.45/skyfield/tests/test_keplerlib.py  2022-09-14 
18:24:55.000000000 +0200
@@ -52,7 +52,7 @@
     epsilon = Distance(m=0.001).au
     assert abs(r + sun_au - horizons_au).max() < epsilon
 
-def test_minor_planet():
+def test_minor_planet_with_positive_M():
     text = (b'00001    3.4   0.15 K205V 162.68631   73.73161   80.28698'
             b'   10.58862  0.0775571  0.21406009   2.7676569  0 MPO492748'
             b'  6751 115 1801-2019 0.60 M-v 30h Williams   0000      '
@@ -74,6 +74,30 @@
     assert abs(ra.hours - 23.1437) < 0.00005
     assert abs(dec.degrees - -17.323) < 0.0005
 
+def test_minor_planet_with_negative_M():
+    text = (b'00002    4.11  0.15 K221L 272.47992  310.69724  172.91658'
+            b'   34.92531  0.2299930  0.21366046   2.7711069  0 MPO681823'
+            b'  8875 119 1804-2022 0.58 M-c 28k Pan        0000      '
+            b'(2) Pallas             20220105')
+
+    ts = load.timescale()
+    t = ts.utc(2022, 9, 14)
+    eph = load('de421.bsp')
+    df = mpc.load_mpcorb_dataframe(BytesIO(text))
+    row = df.iloc[0]
+
+    assert row.designation_packed == '00002'
+    assert row.designation == '(2) Pallas'
+
+    ceres = mpc.mpcorb_orbit(row, ts, GM_SUN)
+    ra, dec, distance = eph['earth'].at(t).observe(eph['sun'] + ceres).radec()
+
+    # We can't expect close agreement, since the HORIZONS orbital
+    # elements are different than MPC's.
+    assert ceres.target == '(2) Pallas'
+    assert abs(ra._degrees - 92.750) < 0.006
+    assert abs(dec.degrees - -10.561) < 0.002
+
 def test_comet():
     text = (b'    CJ95O010  1997 03 29.6333  0.916241  0.994928  130.6448'
             b'  283.3593   88.9908  20200224  -2.0  4.0  C/1995 O1 (Hale-Bopp)'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/skyfield-1.43.1/skyfield/tests/test_units.py 
new/skyfield-1.45/skyfield/tests/test_units.py
--- old/skyfield-1.43.1/skyfield/tests/test_units.py    2021-05-11 
13:56:07.000000000 +0200
+++ new/skyfield-1.45/skyfield/tests/test_units.py      2022-09-11 
12:21:53.000000000 +0200
@@ -93,11 +93,27 @@
     assert angle.arcseconds() == 60 * 60
     assert angle.mas() == 60 * 60 * 1000
 
+def test_distance_input_units():
+    for d in (
+        Distance(1.0),
+        Distance(au=1.0),       # deprecated
+        Distance(m=149597870700),
+        Distance(km=149597870.700),
+        Distance.au(1.0),       # modern
+        Distance.m(149597870700),
+        Distance.km(149597870.700),
+    ):
+        assert abs(d.au - 1.0) <= 0
+
 def test_velocity_input_units():
     v1 = Velocity(au_per_d=2.0)
     v2 = Velocity(km_per_s=3462.9137)
     assert abs(v1.au_per_d - v2.au_per_d) < 1e-7
 
+    v1 = Velocity.au_per_d(2.0)
+    v2 = Velocity.km_per_s(3462.9137)
+    assert abs(v1.au_per_d - v2.au_per_d) < 1e-7
+
 def test_stringifying_vector_distance():
     a = array([1.23, 4.56])
     s = str(Distance(au=a))
@@ -172,6 +188,10 @@
     distance = Distance(m=1234.0)
     assert abs(distance.km - 1.234) < 1e-15
 
+def test_deprecated_method_from_au():
+    distance = Distance.from_au(1.25)
+    assert distance.au == 1.25
+
 @needs_astropy
 def test_converting_distance_with_astropy():
     distance = Distance(au=1.234)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/skyfield-1.43.1/skyfield/timelib.py 
new/skyfield-1.45/skyfield/timelib.py
--- old/skyfield-1.43.1/skyfield/timelib.py     2022-02-05 04:04:33.000000000 
+0100
+++ new/skyfield-1.45/skyfield/timelib.py       2022-09-11 11:31:26.000000000 
+0200
@@ -1061,6 +1061,15 @@
     [1820.0, 1920.0, 0.0, 32.0, 0.0, -20.0])
 
 def build_delta_t(delta_t_recent):
+    """Return a function t→∆T, given recent real-world observations of 
∆T.
+
+    When asked for ∆T outside the range of the `delta_t_recent` table,
+    Skyfield uses the splines for 720 BC – AD 2015 computed by Morrison,
+    Stephenson, Hohenkerk, and Zawilski.  For dates that fall outside of
+    the spines, we use the long-term parabola of Stephenson, Morrison,
+    and Hohenkerk.
+
+    """
     parabola = delta_t_parabola_stephenson_morrison_hohenkerk_2016
     s15_table = load_bundled_npy('delta_t.npz')['Table-S15.2020.txt']
     table_tt, table_delta_t = delta_t_recent
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/skyfield-1.43.1/skyfield/units.py 
new/skyfield-1.45/skyfield/units.py
--- old/skyfield-1.43.1/skyfield/units.py       2022-02-05 04:04:33.000000000 
+0100
+++ new/skyfield-1.45/skyfield/units.py 2022-09-11 12:07:48.000000000 +0200
@@ -19,16 +19,55 @@
     """A measurement that can be expressed in several choices of unit."""
 
     def __getitem__(self, *args):
+        """Tell users to ask for a specific unit before indexing or slicing."""
         cls = self.__class__
         name = cls.__name__
         s = 'to use this {0}, ask for its value in a particular unit:\n\n{1}'
         attrs = sorted(k for k, v in cls.__dict__.items()
-                       if k[0].islower() and isinstance(v, reify))
+                       if k[0].islower() and isinstance(v, (getset, reify)))
         examples = ['    {0}.{1}'.format(name.lower(), attr) for attr in attrs]
         raise UnpackingError(s.format(name, '\n'.join(examples)))
 
     __iter__ = __getitem__   # give advice about both foo[i] and "x,y,z = foo"
 
+class getset(object):
+    """Unit name that serves as both a class constructor and instance 
attribute.
+
+    This supports two use cases:
+
+    * When called as a class method like ``Distance.km(5.0)``, we build
+      and return an instance of ``Distance`` whose ``km`` has been set
+      to 5.0 and whose base unit ``m``, using the appropriate conversion
+      factor, has been set to 5000.0.
+
+    * When invoked like ``d.km`` on a particular ``Distance`` that
+      doesn't yet have a ``km`` attribute (which otherwise Python itself
+      would have returned), we apply the conversion factor to ``d.m``
+      and return the result.
+
+    """
+    def __init__(self, name, docstring, conversion_factor=None, 
core_unit=None):
+        self.name = name
+        self.__doc__ = docstring
+        self.conversion_factor = conversion_factor
+        self.core_unit = core_unit
+
+    def __get__(self, instance, objtype=None):
+        if instance is None:  # the class itself has been asked for this name
+            def constructor(value):
+                value = _to_array(value)
+                obj = objtype.__new__(objtype)
+                setattr(obj, self.name, value)
+                conversion_factor = self.conversion_factor
+                if conversion_factor is not None:
+                    setattr(obj, self.core_unit, value / conversion_factor)
+                return obj
+            constructor.__doc__ = self.__doc__
+            return constructor
+        value = getattr(instance, self.core_unit) * self.conversion_factor
+        instance.__dict__[self.name] = value
+        return value
+
 class Distance(Unit):
     """A distance, stored internally as au and available in other units.
 
@@ -64,24 +103,13 @@
             raise ValueError('to construct a Distance provide au, km, or m')
 
     @classmethod
-    def from_au(cls, au):
-        self = cls.__new__(cls)
-        self.au = _to_array(au)
-        return self
-
-    @reify
-    def au(self):  # Empty property to provide Sphinx docstring.
-        """Astronomical units (the Earth-Sun distance of 149,597,870,700 
m)."""
+    def from_au(cls, au):  # deprecated and no longer used internally
+        return cls.au(au)
 
-    @reify
-    def km(self):
-        """Kilometers (1,000 meters)."""
-        return self.au * AU_KM
-
-    @reify
-    def m(self):
-        """Meters."""
-        return self.au * AU_M
+    au = getset('au', 'Astronomical units'
+                ' (the Earth-Sun distance of 149,597,870,700 m).')
+    km = getset('km', 'Kilometers (1,000 meters).', AU_KM, 'au')
+    m = getset('m', 'Meters.', AU_M, 'au')
 
     def __str__(self):
         n = self.au
@@ -134,19 +162,11 @@
             raise ValueError('to construct a Velocity provide'
                              ' au_per_d or km_per_s')
 
-    @reify
-    def au_per_d(self):  # Empty property to provide Sphinx docstring.
-        """Astronomical units per day."""
-
-    @reify
-    def km_per_s(self):
-        """Kilometers per second."""
-        return self.au_per_d * AU_KM / DAY_S
-
-    @reify
-    def m_per_s(self):
-        """Meters per second."""
-        return self.au_per_d * AU_M / DAY_S
+    au_per_d = getset('au_per_d', 'Astronomical units per day.')
+    km_per_s = getset('km_per_s', 'Kilometers per second.',
+                      AU_KM / DAY_S, 'au_per_d')
+    m_per_s = getset('m_per_s', 'Meters per second.',
+                     AU_M / DAY_S, 'au_per_d')
 
     def __str__(self):
         n = self.au_per_d
@@ -275,9 +295,7 @@
         self.signed = signed
         return self
 
-    @reify
-    def radians(self):  # Empty property to provide Sphinx docstring.
-        """Radians (𝜏 = 2𝜋 in a circle)."""
+    radians = getset('radians', 'Radians (𝜏 = 2𝜋 in a circle).')
 
     @reify
     def _hours(self):

Reply via email to