Repository: cosinekitty/astronomy (language: python)

Issue:
Python: Few typehints for initial review
Hi! I've written a few type hints for the first couple of classes/methods in reference to #276. I'd like to see if you're fine with them and I'll proceed then.

<img width="351" alt="image" src="https://user-images.githubusercontent.com/25360214/218395749-0db3c4b1-89b8-4346-8981-d75ef5bf1e81.png">


Comments:
- The reason there are some type hints written within quotations is because they're referencing a class that's defined before they are being referenced, which allows delayed annotations.

Issues: 
- I'm not exactly sure what's happening within the `__init__.py` file but it causes an issue with Mypy where it says the astronomy module doesn't exist. Any clarification on the init file would be great!
- I tried `from typing import Union` to allow a variable to have 2 different types. For example, the constructor of the `Time` class has a small segment where it checks if the`tt` variable is a string and does something else (lines 732-735). I ran into issues with `pydown.py`:
```
Generating Python documentation.
FATAL(pydown): Undocumented symbol: Union
ERROR(./makedoc): Error generating Markdown from Python source.
```
Am I supposed to declare a new import somewhere in the documentation?

Thanks!
Consider adding Python type hints
Evaluate adding [Python type hints](https://docs.python.org/3/library/typing.html) to the Python version of Astronomy Engine.

Questions:

* Does it add value to end users by helping them avoid errors calling Astronomy Engine functions?
* Does the existing pylint step in the unit tests benefit the project by detecting a wider range of mistakes in the code?



Discussion / hints:
This looks like a great start. I'm stoked!

About the `__init__.py`, I'm not sure what to do. The thing is, I don't know nearly as much as I want about creating Python packages. I basically Googled stuff and groped around blindly until I got something that worked to upload the package [astronomy-engine](https://pypi.org/project/astronomy-engine/) on PyPI. If you look at the contents of the package init file, you will see it is very simple. Astronomy Engine itself has a simple structure: one source file and no external third-party dependencies. So please feel free to tinker with that file to get things working.

Regarding the issues with pydown, I'm not surprised. Pydown is my own creation, because I needed something that generated GitHub flavored Markdown documentation. It was faster and easier to write my own generator than to fight with existing tools that are overly opinionated about how things should be formatted. That said, pydown is very primitive and brittle. So I will fix this issue in Pydown.

Which brings me to the next item. I think it will work better for both of us to develop iteratively if I create a topic branch, merge the above changes into it, then fix pydown. I also need to merge in a change I made over the weekend: I added a new function `HourAngle`. Then you could proceed from that point to make more progress.

The idea is, instead of working directly in the `master` branch, I will create a new branch called `python_type_hints`, and that will be the target for your pull requests going forward. That way we can experiment and freely make messes without affecting the live code and documentation that people use for reference.

That means I need to leave this PR here until I get your existing work integrated into the new branch. I believe after that, you would create a new PR referencing the new branch `python_type_hints`.

Does this sound like a good plan to you? Please let me know if there is a better way to do this...
Oh, I just tried using mypy's `-m` option, and it might help resolve the issue with `__init__.py`:

```
don@spearmint:~/github/astronomy/source/python/astronomy $ mypy -m astronomy
Success: no issues found in 1 source file
```

Apparently you have to tell mypy that you are analyzing a module file, not a normal Python program?
Update: I went ahead and created the new branch [python_type_hints](https://github.com/cosinekitty/astronomy/tree/python_type_hints) that includes your work so far. I added 3 more commits to it:

* 740ef86d31c488daa284bcfd1da24eacddf0313d runs mypy as part of the build process, both on the contributor's local system and in GitHub Actions.
* d73d271a4fdd163a564772ff5fa31198c2a6ab08 includes the use of Union to fix the typing problem in the Time constructor, and fixes the resulting problems in pydown.
* f87b600955fb1fa1e39a256abb43ccb9558cd152 documents that contributors need to install pylint and mypy.

I still want to support Python 3.7, so I was not able to use the vertical bar syntax `float | str` for the type signature in the Time constructor. That syntax requires 3.10+. That's why I had to express it this way:

```python
    def __init__(self, ut : Union[float, str], tt = None):
```

I believe you can now resume work from the current state of python_type_hints. I'm not sure the best way to do that with GitHub. If you need to delete your current fork and re-create it, it will delete this PR and discussion with it, but at least your work and your status as a contributor are already part of my python_type_hints branch. Or maybe you can find a way to update your fork and switch to the new branch to submit another PR from it?
I don't think there are any downsides to adding this. I would like to help towards this if it's still up for doing!
Hi @ris-tlp! This would be super helpful and most welcome if you wish to take this on.

The workflow for Astronomy Engine developers/contributors is to edit "template" source files, then execute the script [generate/run](https://github.com/cosinekitty/astronomy/blob/master/generate/run). This script feeds the source templates through a code generator, mostly to insert numeric lookup tables. Then it executes all the unit tests. I mention this because sometimes people don't know this and work for hours editing the generated code, which then gets overwritten by the `run` script! (Painful.)

If you are using Linux or Mac OS for your development platform, please take a look at the [contributor tool setup instructions](https://github.com/cosinekitty/astronomy/tree/master/generate#linux-and-macos). Windows is also possible for contributors, although the unit tests are not as complete; then you can take a look at [these instructions](https://github.com/cosinekitty/astronomy/tree/master/generate#windows) instead.

You can also take a look at the GitHub Actions [yml script](https://github.com/cosinekitty/astronomy/blob/master/.github/workflows/astronomy-engine-tests.yml) to get an idea of how it installs tools and runs that same `run` script.

Before beginning any code changes, it is strongly recommended that  you run the following to successful completion:

```
cd generate
./run
```

It will probably take a few iterations to resolve missing dependencies. Once you get that to succeed, then you can start making changes in `generate/template/astronomy.py`. When you have changes you like, execute `run` again like above, which will also update the generated versions of `astronomy.py`. You need to do this every time before committing to git and pushing, or GitHub Actions will fail the commit.

So let me know what you think. If you are still interested in moving forward, I will be happy to help with any issues you run into getting your development environment set up.
Hi! I had no issues with getting the dependencies setup and executing the `run` script. I did however run into 1 test failing from 3 different languages that prevented the `run` script from executing till completion. 

Kotlin: Convert EQJ to ECT (line 289 in `source/kotlin/src/test/kotlin/io/github/cosinekitty/astronomy/Tests.kt`
- `<failure message="org.opentest4j.AssertionFailedError: excessive sphere_diff = 3.471167061223179E-18 AU." type="org.opentest4j.AssertionFailedError">org.opentest4j.AssertionFailedError: excessive sphere_diff = 3.471167061223179E-18 AU.`

Python: Ecliptic (line 1239 in `generate/test.py`)
- `PY Ecliptic FAIL: EXCESSIVE ANGLE DIFF = 3.006602e-18 au.`

C#: ﻿EclipticTest (line 2165 in `generate/dotnet/csharp_test/csharp_test.cs`
- `C# EclipticTest: EXCESSIVE ANGLE DIFF = 3.00659E-18 AU.
ERROR(./unit_test_csharp): Error running csharp unit test`

Commenting these tests out allowed me to run the script to completion. I'm not exactly sure what could be causing the issue. I'm assuming they're all the same test but I don't know too much about the codebase yet. Is this to be expected? Please let me know how I can proceed, thanks!
Hi Omar, that's great progress! I'm not at all worried about the test failures. This sort of thing has happened before. These are very tiny floating point errors, just larger than existing builds have encountered. I suspect you are using a different compiler and/or different hardware than I and GitHub Actions use. I will update the tests in the master branch. I will post here again in about an hour or so... stay tuned!

By the way, what operating system and processor are you using?
Ah I see, that makes sense! I'm using MacOS Monterey (12.6) and a M1. 
OK, I was guessing you would say M1! It must be the first time anyone has run the tests on that processor.

I just now pushed fixes to the unit tests to the master branch. If you discard your changes where you commented out the failing tests, and pull again, this time all the tests should pass.
Yup that seemed to work! Although I just ran into this towards the final test check which I guess stemmed from relaxing the test ranges, sorry about the hassle!

```
First  file: temp/c_check.txt
Second file: temp/py_check.txt
Tolerance = 3.100e-15

            lnum                 a_value                 b_value     factor       diff  name
FAIL      201528  3.4491354552834508e+01  3.4491354552832789e+01    0.00275  4.722e-15  sky_hor_az
 
Score = 4.722e-15
ctest(Diff): EXCEEDED ERROR TOLERANCE.
```
No hassle at all! I will fix this one too. This is helpful because I want the development tools to work on the M1, and I haven't had access to one before now.
OK, I just pushed 73f9cb4b0d3be75698fea9a20b811bb33e33b57b which should resolve that test failure.
Awesome! All tests pass now, thanks for being super fast with the responses! I'll get started with adding the type hints and checking them with mypy locally. I'll make a smaller PR to get your feedback on it first and then proceed with doing larger batches. 
Oh cool, I didn't know about mypy. I'm reading about it now. Currently I use pylint in the build process, and it has been helpful for finding mistakes in the code. I didn't know if pylint would analyze type hints also. If mypy is the best way to find type errors, I would like to add that to the generate/run script, and make sure it can work in GitHub Actions. But first things first... I like your approach, and I'm so glad someone is willing and able to help with this!

Fix patch:
diff --git a/demo/python/astronomy.py b/demo/python/astronomy.py
index fbd1003d..30f5e1ea 100644
--- a/demo/python/astronomy.py
+++ b/demo/python/astronomy.py
@@ -36,7 +36,7 @@
 import enum
 import re
 import abc
-from typing import Union
+from typing import List, Optional, Union, Callable
 
 def _cbrt(x):
     if x < 0.0:
@@ -374,7 +374,7 @@ def _UserDefinedStar(body):
         return star
     return None
 
-def DefineStar(body, ra, dec, distanceLightYears):
+def DefineStar(body: Body, ra: float, dec: float, distanceLightYears: float) -> None:
     """Assign equatorial coordinates to a user-defined star.
 
     Some Astronomy Engine functions allow their `body` parameter to
@@ -413,7 +413,7 @@ def DefineStar(body, ra, dec, distanceLightYears):
     star.dec = dec
     star.dist = distanceLightYears * AU_PER_LY
 
-def BodyCode(name):
+def BodyCode(name: str) -> Body:
     """Finds the Body enumeration value, given the name of a body.
 
     Parameters
@@ -439,7 +439,7 @@ def BodyCode(name):
         return Body.Invalid
     return Body[name]
 
-def _IsSuperiorPlanet(body):
+def _IsSuperiorPlanet(body: Body) -> bool:
     return body in [Body.Mars, Body.Jupiter, Body.Saturn, Body.Uranus, Body.Neptune, Body.Pluto]
 
 _PlanetOrbitalPeriod = [
@@ -456,27 +456,27 @@ def _IsSuperiorPlanet(body):
 
 class Error(Exception):
     """Indicates an error in an astronomical calculation."""
-    def __init__(self, message):
+    def __init__(self, message: str) -> None:
         Exception.__init__(self, message)
 
 class DateTimeFormatError(Error):
     """The syntax of a UTC date/time string was not valid, or it contains invalid values."""
-    def __init__(self, text):
+    def __init__(self, text: str) -> None:
         Error.__init__(self, 'The date/time string is not valid: "{}"'.format(text))
 
 class EarthNotAllowedError(Error):
     """The Earth is not allowed as the celestial body in this calculation."""
-    def __init__(self):
+    def __init__(self) -> None:
         Error.__init__(self, 'The Earth is not allowed as the body.')
 
 class InvalidBodyError(Error):
     """The celestial body is not allowed for this calculation."""
-    def __init__(self, body):
+    def __init__(self, body: Body) -> None:
         Error.__init__(self, 'This body is not valid, or is not supported for this calculation: {}'.format(body))
 
 class BadVectorError(Error):
     """A vector magnitude is too small to have a direction in space."""
-    def __init__(self):
+    def __init__(self) -> None:
         Error.__init__(self, 'Vector is too small to have a direction.')
 
 class InternalError(Error):
@@ -489,7 +489,7 @@ class InternalError(Error):
     of how to reproduce the error. This will help improve the quality of
     Astronomy Engine for everyone! (Thank you in advance from the author.)
     """
-    def __init__(self):
+    def __init__(self) -> None:
         Error.__init__(self, 'Internal error - please report issue, including stack trace, at https://github.com/cosinekitty/astronomy/issues')
 
 class NoConvergeError(Error):
@@ -502,10 +502,10 @@ class NoConvergeError(Error):
     of how to reproduce the error. This will help improve the quality of
     Astronomy Engine for everyone! (Thank you in advance from the author.)
     """
-    def __init__(self):
+    def __init__(self) -> None:
         Error.__init__(self, 'Numeric solver did not converge - please report issue at https://github.com/cosinekitty/astronomy/issues')
 
-def PlanetOrbitalPeriod(body):
+def PlanetOrbitalPeriod(body: Body) -> float:
     """Returns the average number of days it takes for a planet to orbit the Sun.
 
     Parameters
@@ -522,7 +522,7 @@ def PlanetOrbitalPeriod(body):
         return _PlanetOrbitalPeriod[body.value]
     raise InvalidBodyError(body)
 
-def _SynodicPeriod(body):
+def _SynodicPeriod(body: Body) -> float:
     if body == Body.Earth:
         raise EarthNotAllowedError()
     if body.value < 0 or body.value >= len(_PlanetOrbitalPeriod):
@@ -531,7 +531,7 @@ def _SynodicPeriod(body):
         return _MEAN_SYNODIC_MONTH
     return abs(_EARTH_ORBITAL_PERIOD / (_EARTH_ORBITAL_PERIOD/_PlanetOrbitalPeriod[body.value] - 1.0))
 
-def AngleBetween(a, b):
+def AngleBetween(a: Vector, b: Vector) -> float:
     """Calculates the angle in degrees between two vectors.
 
     Given a pair of vectors, this function returns the angle in degrees
@@ -551,10 +551,10 @@ def AngleBetween(a, b):
         The angle between the two vectors expressed in degrees.
         The value is in the range [0, 180].
     """
-    r = a.Length() * b.Length()
+    r: float = a.Length() * b.Length()
     if r < 1.0e-8:
-        return BadVectorError()
-    dot = (a.x*b.x + a.y*b.y + a.z*b.z) / r
+        raise BadVectorError()
+    dot: float = (a.x*b.x + a.y*b.y + a.z*b.z) / r
     if dot <= -1.0:
         return 180.0
     if dot >= +1.0:
@@ -562,7 +562,7 @@ def AngleBetween(a, b):
     return math.degrees(math.acos(dot))
 
 
-def DeltaT_EspenakMeeus(ut):
+def DeltaT_EspenakMeeus(ut: float) -> float:
     """The default Delta T function used by Astronomy Engine.
 
     Espenak and Meeus use a series of piecewise polynomials to
@@ -666,10 +666,10 @@ def DeltaT_EspenakMeeus(ut):
 _DeltaT = DeltaT_EspenakMeeus
 
 
-def _TerrestrialTime(ut):
+def _TerrestrialTime(ut: float) -> float:
     return ut + _DeltaT(ut) / 86400.0
 
-def _UniversalTime(tt):
+def _UniversalTime(tt: float) -> float:
     # This is the inverse function of _TerrestrialTime.
     # This is an iterative numerical solver, but because
     # the relationship between UT and TT is almost perfectly linear,
@@ -729,23 +729,23 @@ class Time:
         such as the orbits of planets around the Sun, or the Moon around the Earth.
         Historically, Terrestrial Time has also been known by the term *Ephemeris Time* (ET).
     """
-    def __init__(self, ut : Union[float, str], tt = None):
+    def __init__(self, ut : Union[float, str], tt: Optional[float] = None):
         if isinstance(ut, str):
             # Undocumented hack, to make repr(time) reversible.
             other = Time.Parse(ut)
-            self.ut = other.ut
-            self.tt = other.tt
+            self.ut: float = other.ut
+            self.tt: float = other.tt
         else:
             self.ut = ut
             if tt is None:
                 self.tt = _TerrestrialTime(ut)
             else:
                 self.tt = tt
-        self._et = None     # lazy-cache for earth tilt
-        self._st = None     # lazy-cache for sidereal time
+        self._et: Optional[float] = None     # lazy-cache for earth tilt
+        self._st: Optional[float] = None     # lazy-cache for sidereal time
 
     @staticmethod
-    def FromTerrestrialTime(tt):
+    def FromTerrestrialTime(tt: float) -> "Time":
         """Creates a #Time object from a Terrestrial Time day value.
 
         Parameters
@@ -760,7 +760,7 @@ def FromTerrestrialTime(tt):
         return Time(_UniversalTime(tt), tt)
 
     @staticmethod
-    def Parse(text):
+    def Parse(text: str) -> "Time":
         """Creates a #Time object from a string of the form 'yyyy-mm-ddThh:mm:ss.sssZ'
 
         Parses a UTC date and time from a string and returns a #Time object.
@@ -805,7 +805,7 @@ def Parse(text):
         return Time.Make(year, month, day, hour, minute, second)
 
     @staticmethod
-    def Make(year, month, day, hour, minute, second):
+    def Make(year: int, month: int, day: int, hour: int, minute: int, second: float) -> "Time":
         """Creates a #Time object from a UTC calendar date and time.
 
         Parameters
@@ -841,7 +841,7 @@ def Make(year, month, day, hour, minute, second):
         return Time(ut)
 
     @staticmethod
-    def Now():
+    def Now() -> "Time":
         """Returns the computer's current date and time in the form of a #Time object.
 
         Uses the computer's system clock to find the current UTC date and time.
@@ -856,7 +856,7 @@ def Now():
         ut = (datetime.datetime.utcnow() - _EPOCH).total_seconds() / 86400.0
         return Time(ut)
 
-    def AddDays(self, days):
+    def AddDays(self, days: float) -> "Time":
         """Calculates the sum or difference of a #Time with a specified real-valued number of days.
 
         Sometimes we need to adjust a given #Time value by a certain amount of time.
@@ -883,10 +883,10 @@ def AddDays(self, days):
         """
         return Time(self.ut + days)
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'Time(\'' + str(self) + '\')'
 
-    def __str__(self):
+    def __str__(self) -> str:
         # Adapted from the NOVAS C 3.1 function cal_date().
         djd = self.ut + 2451545.5
         jd = int(djd)
@@ -924,7 +924,7 @@ def __str__(self):
         text += '-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}.{:03d}Z'.format(month, day, hour, minute, millis // 1000, millis % 1000)
         return text
 
-    def Utc(self):
+    def Utc(self) -> datetime.datetime:
         """Returns the UTC date and time as a `datetime` object.
 
         Uses the standard [`datetime`](https://docs.python.org/3/library/datetime.html) class
@@ -944,22 +944,26 @@ def _etilt(self):
             self._et = _e_tilt(self)
         return self._et
 
-    def __lt__(self, other):
+    def __lt__(self, other: "Time") -> bool:
         return self.tt < other.tt
 
-    def __eq__(self, other):
+    def __eq__(self, other: object) -> bool:
+        if not isinstance(other, Time):
+            return NotImplemented
         return self.tt == other.tt
 
-    def __le__(self, other):
+    def __le__(self, other: "Time") -> bool:
         return self.tt <= other.tt
 
-    def __ne__(self, other):
+    def __ne__(self, other: object) -> bool:
+        if not isinstance(other, Time):
+            return NotImplemented
         return self.tt != other.tt
 
-    def __gt__(self, other):
+    def __gt__(self, other: "Time") -> bool:
         return self.tt > other.tt
 
-    def __ge__(self, other):
+    def __ge__(self, other: "Time") -> bool:
         return self.tt >= other.tt
 
 
@@ -975,15 +979,15 @@ class Observer:
     height : float
         Elevation above sea level in meters.
     """
-    def __init__(self, latitude, longitude, height=0.0):
+    def __init__(self, latitude: float, longitude: float, height: float = 0.0) -> None:
         self.latitude = latitude
         self.longitude = longitude
         self.height = height
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'Observer(latitude={}, longitude={}, height={})'.format(self.latitude, self.longitude, self.height)
 
-    def __str__(self):
+    def __str__(self) -> str:
         text = '('
         text += 'S' if (self.latitude < 0) else 'N'
         text += '{:0.8f}, '.format(abs(self.latitude))
@@ -1002,10 +1006,10 @@ class RotationMatrix:
     rot : float[3][3]
         A normalized 3x3 rotation matrix.
     """
-    def __init__(self, rot):
+    def __init__(self, rot: List[List[float]]) -> None:
         self.rot = rot
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'RotationMatrix({})'.format(self.rot)
 
 class Spherical:
@@ -1020,16 +1024,16 @@ class Spherical:
     dist : float
         Distance in AU.
     """
-    def __init__(self, lat, lon, dist):
+    def __init__(self, lat: float, lon: float, dist: float) -> None:
         self.lat = lat
         self.lon = lon
         self.dist = dist
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'Spherical(lat={}, lon={}, dist={})'.format(self.lat, self.lon, self.dist)
 
 class _iau2000b:
-    def __init__(self, time):
+    def __init__(self, time: Time) -> None:
         t = time.tt / 36525.0
         elp = math.fmod((1287104.79305 + t*129596581.0481),  _ASEC360) * _ASEC2RAD
         f   = math.fmod((335779.526232 + t*1739527262.8478), _ASEC360) * _ASEC2RAD
@@ -1067,7 +1071,7 @@ def __init__(self, time):
         self.dpsi = -0.000135 + (dp * 1.0e-7)
         self.deps = +0.000388 + (de * 1.0e-7)
 
-def _mean_obliq(tt):
+def _mean_obliq(tt: float) -> float:
     t = tt / 36525
     asec = (
         (((( -  0.0000000434   * t
@@ -1079,7 +1083,7 @@ def _mean_obliq(tt):
     return asec / 3600.0
 
 class _e_tilt:
-    def __init__(self, time):
+    def __init__(self, time: Time) -> None:
         e = _iau2000b(time)
         self.dpsi = e.dpsi
         self.deps = e.deps
@@ -1201,17 +1205,17 @@ class Equatorial:
         y = direction of the June solstice,
         z = north.
     """
-    def __init__(self, ra, dec, dist, vec):
+    def __init__(self, ra: float, dec: float, dist: float, vec: Vector) -> None:
         self.ra = ra
         self.dec = dec
         self.dist = dist
         self.vec = vec
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'Equatorial(ra={}, dec={}, dist={}, vec={})'.format(self.ra, self.dec, self.dist, repr(self.vec))
 
 
-def _vector2radec(pos, time):
+def _vector2radec(pos, time: Time) -> Equatorial:
     xyproj = pos[0]*pos[0] + pos[1]*pos[1]
     dist = math.sqrt(xyproj + pos[2]*pos[2])
     if xyproj == 0.0:
@@ -1232,7 +1236,7 @@ def _vector2radec(pos, time):
     return Equatorial(ra, dec, dist, vec)
 
 
-def _nutation_rot(time, direction):
+def _nutation_rot(time: Time, direction) -> RotationMatrix:
     tilt = time._etilt()
     oblm = math.radians(tilt.mobl)
     oblt = math.radians(tilt.tobl)
@@ -1288,7 +1292,7 @@ def _era(time):        # Earth Rotation Angle
         theta += 360.0
     return theta
 
-def SiderealTime(time):
+def SiderealTime(time: Time) -> float:
     """Calculates Greenwich Apparent Sidereal Time (GAST).
 
     Given a date and time, this function calculates the rotation of the
@@ -2235,7 +2239,7 @@ def ADDN(coeffn, p, q, r, s):
         (_ARC * _EARTH_EQUATORIAL_RADIUS_AU) / (0.999953253 * SINPI)
     )
 
-def GeoMoon(time):
+def GeoMoon(time: Time) -> Vector:
     """Calculates equatorial geocentric position of the Moon at a given time.
 
     Given a time of observation, calculates the Moon's position as a vector.
@@ -2278,7 +2282,7 @@ def GeoMoon(time):
     return Vector(mpos2[0], mpos2[1], mpos2[2], time)
 
 
-def EclipticGeoMoon(time):
+def EclipticGeoMoon(time: Time) -> Spherical:
     """Calculates spherical ecliptic geocentric position of the Moon.
 
     Given a time of observation, calculates the Moon's geocentric position
@@ -2336,7 +2340,7 @@ def EclipticGeoMoon(time):
     return Spherical(eclip.elat, eclip.elon, moon.distance_au)
 
 
-def GeoMoonState(time):
+def GeoMoonState(time: Time) -> StateVector:
     """Calculates equatorial geocentric position and velocity of the Moon at a given time.
 
     Given a time of observation, calculates the Moon's position and velocity vectors.
@@ -2378,7 +2382,7 @@ def GeoMoonState(time):
     )
 
 
-def GeoEmbState(time):
+def GeoEmbState(time: Time) -> StateVector:
     """Calculates the geocentric position and velocity of the Earth/Moon barycenter.
 
     Given a time of observation, calculates the geocentric position and velocity vectors
@@ -3265,45 +3269,45 @@ def _CalcEarth(time):
 
 
 class _TerseVector:
-    def __init__(self, x, y, z):
+    def __init__(self, x, y, z) -> None:
         self.x = x
         self.y = y
         self.z = z
 
-    def clone(self):
+    def clone(self) -> "_TerseVector":
         '''Create a copy of this vector.'''
         return _TerseVector(self.x, self.y, self.z)
 
     @staticmethod
-    def zero():
+    def zero() -> "_TerseVector":
         '''Return a zero vector.'''
         return _TerseVector(0.0, 0.0, 0.0)
 
-    def ToAstroVector(self, time):
+    def ToAstroVector(self, time: Time) -> Vector:
         '''Convert _TerseVector object to Vector object.'''
         return Vector(self.x, self.y, self.z, time)
 
-    def quadrature(self):
+    def quadrature(self) -> float:
         '''Return magnitude squared of this vector.'''
         return self.x**2 + self.y**2 + self.z**2
 
-    def mean(self, other):
+    def mean(self, other: "_TerseVector") -> "_TerseVector":
         '''Return the average of this vector and another vector.'''
         return _TerseVector((self.x + other.x)/2.0, (self.y + other.y)/2.0, (self.z + other.z)/2.0)
 
-    def __add__(self, other):
+    def __add__(self, other: "_TerseVector") -> "_TerseVector":
         return _TerseVector(self.x + other.x, self.y + other.y, self.z + other.z)
 
-    def __sub__(self, other):
+    def __sub__(self, other: "_TerseVector") -> "_TerseVector":
         return _TerseVector(self.x - other.x, self.y - other.y, self.z - other.z)
 
-    def __mul__(self, scalar):
+    def __mul__(self, scalar: float) -> "_TerseVector":
         return _TerseVector(scalar * self.x, scalar * self.y, scalar * self.z)
 
-    def __rmul__(self, scalar):
+    def __rmul__(self, scalar: float) -> "_TerseVector":
         return _TerseVector(scalar * self.x, scalar * self.y, scalar * self.z)
 
-    def __truediv__(self, scalar):
+    def __truediv__(self, scalar: float) -> "_TerseVector":
         return _TerseVector(self.x / scalar, self.y / scalar, self.z / scalar)
 
 
@@ -3690,13 +3694,13 @@ class JupiterMoonsInfo:
     callisto : StateVector
         The position and velocity of Jupiter's moon Callisto.
     """
-    def __init__(self, moon):
+    def __init__(self, moon: List[StateVector]) -> None:
         self.io = moon[0]
         self.europa = moon[1]
         self.ganymede = moon[2]
         self.callisto = moon[3]
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'JupiterMoonsInfo(io={}, europa={}, ganymede={}, callisto={})'.format(
             repr(self.io),
             repr(self.europa),
@@ -3782,7 +3786,7 @@ def _CalcJupiterMoon(time, mu, al0, al1, a, l, z, zeta):
     return RotateState(_Rotation_JUP_EQJ, state)
 
 
-def JupiterMoons(time):
+def JupiterMoons(time: Time) -> JupiterMoonsInfo:
     """Calculates jovicentric positions and velocities of Jupiter's largest 4 moons.
 
     Calculates position and velocity vectors for Jupiter's moons
@@ -3852,7 +3856,7 @@ def _QuadInterp(tm, dt, fa, fm, fb):
     df_dt = (2*Q*x + R) / dt
     return (t, df_dt)
 
-def Search(func, context, t1, t2, dt_tolerance_seconds):
+def Search(func: Callable[[object, Time], float], context: object, t1: Time, t2: Time, dt_tolerance_seconds: float) -> Optional[Time]:
     """Searches for a time at which a function's value increases through zero.
 
     Certain astronomy calculations involve finding a time when an event occurs.
@@ -4000,7 +4004,7 @@ def Search(func, context, t1, t2, dt_tolerance_seconds):
 #----------------------------------------------------------------------------
 
 
-def HelioVector(body, time):
+def HelioVector(body: Body, time: Time) -> Vector:
     """Calculates heliocentric Cartesian coordinates of a body in the J2000 equatorial system.
 
     This function calculates the position of the given celestial body as a vector,
@@ -4059,7 +4063,7 @@ def HelioVector(body, time):
     raise InvalidBodyError(body)
 
 
-def HelioDistance(body, time):
+def HelioDistance(body: Body, time: Time) -> float:
     """Calculates the distance between a body and the Sun at a given time.
 
     Given a date and time, this function calculates the distance between
@@ -4108,11 +4112,11 @@ class PositionFunction(abc.ABC):
     specified time. It is passed an instance of `PositionFunction`
     that expresses a relative position vector function.
     """
-    def __init__(self):
+    def __init__(self) -> None:
         pass
 
     @abc.abstractmethod
-    def Position(self, time):
+    def Position(self, time: Time) -> Vector:
         """Returns a relative position vector for a given time.
 
         Parameters
@@ -4125,7 +4129,7 @@ def Position(self, time):
         Vector
         """
 
-def CorrectLightTravel(func, time):
+def CorrectLightTravel(func: PositionFunction, time: Time) -> Vector:
     """Solve for light travel time of a vector function.
 
     When observing a distant object, for example Jupiter as seen from Earth,
@@ -4176,14 +4180,14 @@ def CorrectLightTravel(func, time):
 
 
 class _BodyPosition(PositionFunction):
-    def __init__(self, observerBody, targetBody, aberration, observerPos):
+    def __init__(self, observerBody: Body, targetBody: Body, aberration: bool, observerPos) -> None:
         super().__init__()
         self.observerBody = observerBody
         self.targetBody = targetBody
         self.aberration = aberration
         self.observerPos = observerPos
 
-    def Position(self, time):
+    def Position(self, time: Time) -> Vector:
         if self.aberration:
             # The following discussion is worded with the observer body being the Earth,
             # which is often the case. However, the same reasoning applies to any observer body
@@ -4209,7 +4213,7 @@ def Position(self, time):
         return HelioVector(self.targetBody, time) - observerPos
 
 
-def BackdatePosition(time, observerBody, targetBody, aberration):
+def BackdatePosition(time: Time, observerBody: Body, targetBody: Body, aberration: bool) -> Vector:
     """Solve for light travel time correction of apparent position.
 
     When observing a distant object, for example Jupiter as seen from Earth,
@@ -4277,7 +4281,7 @@ def BackdatePosition(time, observerBody, targetBody, aberration):
     return CorrectLightTravel(func, time)
 
 
-def GeoVector(body, time, aberration):
+def GeoVector(body: Body, time: Time, aberration: bool) -> Vector:
     """Calculates geocentric Cartesian coordinates of a body in the J2000 equatorial system.
 
     This function calculates the position of the given celestial body as a vector,
@@ -4324,7 +4328,7 @@ def GeoVector(body, time, aberration):
     return vec
 
 
-def _ExportState(terse, time):
+def _ExportState(terse, time: Time) -> StateVector:
     return StateVector(
         terse.r.x, terse.r.y, terse.r.z,
         terse.v.x, terse.v.y, terse.v.z,
@@ -4332,7 +4336,7 @@ def _ExportState(terse, time):
     )
 
 
-def BaryState(body, time):
+def BaryState(body: Body, time: Time) -> StateVector:
     """Calculates barycentric position and velocity vectors for the given body.
 
     Given a body and a time, calculates the barycentric position and velocity
@@ -4410,7 +4414,7 @@ def BaryState(body, time):
     raise InvalidBodyError(body)
 
 
-def HelioState(body, time):
+def HelioState(body: Body, time: Time) -> StateVector:
     """Calculates heliocentric position and velocity vectors for the given body.
 
     Given a body and a time, calculates the position and velocity
@@ -4484,7 +4488,7 @@ def HelioState(body, time):
     raise InvalidBodyError(body)
 
 
-def Equator(body, time, observer, ofdate, aberration):
+def Equator(body: Body, time: Time, observer: Observer, ofdate: bool, aberration: bool) -> Equatorial:
     """Calculates equatorial coordinates of a celestial body as seen by an observer on the Earth's surface.
 
     Calculates topocentric equatorial coordinates in one of two different systems:
@@ -4537,7 +4541,7 @@ def Equator(body, time, observer, ofdate, aberration):
     return _vector2radec(datevect, time)
 
 
-def ObserverVector(time, observer, ofdate):
+def ObserverVector(time: Time, observer: Observer, ofdate: bool) -> Vector:
     """Calculates geocentric equatorial coordinates of an observer on the surface of the Earth.
 
     This function calculates a vector from the center of the Earth to
@@ -4581,7 +4585,7 @@ def ObserverVector(time, observer, ofdate):
         ovec = _precession(ovec, time, _PrecessDir.Into2000)
     return Vector(ovec[0], ovec[1], ovec[2], time)
 
-def ObserverState(time, observer, ofdate):
+def ObserverState(time: Time, observer: Observer, ofdate: bool) -> StateVector:
     """Calculates geocentric equatorial position and velocity of an observer on the surface of the Earth.
 
     This function calculates position and velocity vectors of an observer
@@ -4628,7 +4632,7 @@ def ObserverState(time, observer, ofdate):
         state = _precession_posvel(state, time, _PrecessDir.Into2000)
     return state
 
-def VectorObserver(vector, ofdate):
+def VectorObserver(vector: Vector, ofdate: bool) -> Observer:
     """Calculates the geographic location corresponding to an equatorial vector.
 
     This is the inverse function of #ObserverVector.
@@ -4661,7 +4665,7 @@ def VectorObserver(vector, ofdate):
         ovec = _nutation(ovec, vector.t, _PrecessDir.From2000)
     return _inverse_terra(ovec, gast)
 
-def ObserverGravity(latitude, height):
+def ObserverGravity(latitude: float, height: float) -> float:
     """Calculates the gravitational acceleration experienced by an observer on the Earth.
 
     This function implements the WGS 84 Ellipsoidal Gravity Formula.
@@ -4731,13 +4735,13 @@ class HorizontalCoordinates:
     dec : float
         The declination in degrees.
     """
-    def __init__(self, azimuth, altitude, ra, dec):
+    def __init__(self, azimuth: float, altitude: float, ra: float, dec: float) -> None:
         self.azimuth = azimuth
         self.altitude = altitude
         self.ra = ra
         self.dec = dec
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'HorizontalCoordinates(azimuth={}, altitude={}, ra={}, dec={})'.format(
             self.azimuth,
             self.altitude,
@@ -4745,7 +4749,7 @@ def __repr__(self):
             self.dec
         )
 
-def Horizon(time, observer, ra, dec, refraction):
+def Horizon(time: Time, observer: Observer, ra: float, dec: float, refraction: Refraction) -> HorizontalCoordinates:
     """Calculates the apparent location of a body relative to the local horizon of an observer on the Earth.
 
     Given a date and time, the geographic location of an observer on the Earth, and
@@ -4908,7 +4912,7 @@ def Horizon(time, observer, ra, dec, refraction):
 
     return HorizontalCoordinates(az, 90.0 - zd, hor_ra, hor_dec)
 
-def RefractionAngle(refraction, altitude):
+def RefractionAngle(refraction: Refraction, altitude: float) -> float:
     """Calculates the amount of "lift" to an altitude angle caused by atmospheric refraction.
 
     Given an altitude angle and a refraction option, calculates
@@ -4964,7 +4968,7 @@ def RefractionAngle(refraction, altitude):
         raise Error('Inalid refraction option')
     return refr
 
-def InverseRefractionAngle(refraction, bent_altitude):
+def InverseRefractionAngle(refraction: Refraction, bent_altitude: float) -> float:
     """Calculates the inverse of an atmospheric refraction angle.
 
     Given an observed altitude angle that includes atmospheric refraction,
@@ -5018,12 +5022,12 @@ class EclipticCoordinates:
     elon : float
         Longitude in degrees around the ecliptic plane prograde from the equinox.
     """
-    def __init__(self, vec, elat, elon):
+    def __init__(self, vec: Vector, elat: float, elon: float) -> None:
         self.vec = vec
         self.elat = elat
         self.elon = elon
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'EclipticCoordinates({}, elat={}, elon={})'.format(repr(self.vec), self.elat, self.elon)
 
 def _RotateEquatorialToEcliptic(pos, obliq_radians, time):
@@ -5043,7 +5047,7 @@ def _RotateEquatorialToEcliptic(pos, obliq_radians, time):
     vec = Vector(ex, ey, ez, time)
     return EclipticCoordinates(vec, elat, elon)
 
-def SunPosition(time):
+def SunPosition(time: Time) -> EclipticCoordinates:
     """Calculates geocentric ecliptic coordinates for the Sun.
 
     This function calculates the position of the Sun as seen from the Earth.
@@ -5085,7 +5089,7 @@ def SunPosition(time):
     true_obliq = math.radians(adjusted_time._etilt().tobl)
     return _RotateEquatorialToEcliptic(sun_ofdate, true_obliq, time)
 
-def Ecliptic(eqj):
+def Ecliptic(eqj: Vector) -> EclipticCoordinates:
     """Converts a J2000 mean equator (EQJ) vector to a true ecliptic of date (ETC) vector and angles.
 
     Given coordinates relative to the Earth's equator at J2000 (the instant of noon UTC
@@ -5094,7 +5098,7 @@ def Ecliptic(eqj):
 
     Parameters
     ----------
-    eqj : Equatorial
+    eqj : Vector
         Equatorial coordinates in the J2000 frame of reference.
         You can call #GeoVector to obtain suitable equatorial coordinates.
 
@@ -5116,7 +5120,7 @@ def Ecliptic(eqj):
     return _RotateEquatorialToEcliptic(eqd_pos, math.radians(et.tobl), eqj.t)
 
 
-def EclipticLongitude(body, time):
+def EclipticLongitude(body: Body, time: Time) -> float:
     """Calculates heliocentric ecliptic longitude of a body.
 
     This function calculates the angle around the plane of the Earth's orbit
@@ -5142,7 +5146,7 @@ def EclipticLongitude(body, time):
     eclip = Ecliptic(hv)
     return eclip.elon
 
-def AngleFromSun(body, time):
+def AngleFromSun(body: Body, time: Time) -> float:
     """Returns the angle between the given body and the Sun, as seen from the Earth.
 
     This function calculates the angular separation between the given body and the Sun,
@@ -5169,7 +5173,7 @@ def AngleFromSun(body, time):
     bv = GeoVector(body, time, True)
     return AngleBetween(sv, bv)
 
-def PairLongitude(body1, body2, time):
+def PairLongitude(body1: Body, body2: Body, time: Time) -> float:
     """Returns one body's ecliptic longitude with respect to another, as seen from the Earth.
 
     This function determines where one body appears around the ecliptic plane
@@ -5228,13 +5232,13 @@ class ElongationEvent:
     ecliptic_separation : float
         The difference between the ecliptic longitudes of the body and the Sun, as seen from the Earth.
     """
-    def __init__(self, time, visibility, elongation, ecliptic_separation):
+    def __init__(self, time: Time, visibility: "Visibility", elongation: float, ecliptic_separation: float) -> None:
         self.time = time
         self.visibility = visibility
         self.elongation = elongation
         self.ecliptic_separation = ecliptic_separation
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'ElongationEvent({}, {}, elongation={}, ecliptic_separation={})'.format(
             repr(self.time),
             self.visibility,
@@ -5254,7 +5258,7 @@ class Visibility(enum.Enum):
     Morning = 0
     Evening = 1
 
-def Elongation(body, time):
+def Elongation(body: Body, time: Time) -> ElongationEvent:
     """Determines visibility of a celestial body relative to the Sun, as seen from the Earth.
 
     This function returns an #ElongationEvent object, which provides the following
@@ -5301,7 +5305,7 @@ def _rlon_offset(body, time, direction, targetRelLon):
     diff = direction * (elon - plon)
     return _LongitudeOffset(diff - targetRelLon)
 
-def SearchRelativeLongitude(body, targetRelLon, startTime):
+def SearchRelativeLongitude(body: Body, targetRelLon:float, startTime: Time) -> Time:
     """Searches for when the Earth and another planet are separated by a certain ecliptic longitude.
 
     Searches for the time when the Earth and another planet are separated by a specified angle
@@ -5393,7 +5397,7 @@ def _neg_elong_slope(body, time):
     e2 = AngleFromSun(body, t2)
     return (e1 - e2)/dt
 
-def SearchMaxElongation(body, startTime):
+def SearchMaxElongation(body: Body, startTime: Time) -> Optional[ElongationEvent]:
     """Finds a date and time when Mercury or Venus reaches its maximum angle from the Sun as seen from the Earth.
 
     Mercury and Venus are are often difficult to observe because they are closer to the Sun than the Earth is.
@@ -5507,7 +5511,7 @@ def _sun_offset(targetLon, time):
     ecl = SunPosition(time)
     return _LongitudeOffset(ecl.elon - targetLon)
 
-def SearchSunLongitude(targetLon, startTime, limitDays):
+def SearchSunLongitude(targetLon: float, startTime: Time, limitDays: float) -> Optional[Time]:
     """Searches for the time when the Sun reaches an apparent ecliptic longitude as seen from the Earth.
 
     This function finds the moment in time, if any exists in the given time window,
@@ -5544,7 +5548,7 @@ def SearchSunLongitude(targetLon, startTime, limitDays):
     t2 = startTime.AddDays(limitDays)
     return Search(_sun_offset, targetLon, startTime, t2, 0.01)
 
-def MoonPhase(time):
+def MoonPhase(time: Time) -> float:
     """Returns the Moon's phase as an angle from 0 to 360 degrees.
 
     This function determines the phase of the Moon using its apparent
@@ -5571,7 +5575,7 @@ def _moon_offset(targetLon, time):
     angle = MoonPhase(time)
     return _LongitudeOffset(angle - targetLon)
 
-def SearchMoonPhase(targetLon, startTime, limitDays):
+def SearchMoonPhase(targetLon: float, startTime: Time, limitDays: float):
     """Searches for the time that the Moon reaches a specified phase.
 
     Lunar phases are conventionally defined in terms of the Moon's geocentric ecliptic
@@ -5662,7 +5666,7 @@ def __init__(self, quarter, time):
     def __repr__(self):
         return 'MoonQuarter({}, {})'.format(self.quarter, repr(self.time))
 
-def SearchMoonQuarter(startTime):
+def SearchMoonQuarter(startTime: Time) -> MoonQuarter:
     """Finds the first lunar quarter after the specified date and time.
 
     A lunar quarter is one of the following four lunar phase events:
@@ -5690,7 +5694,7 @@ def SearchMoonQuarter(startTime):
         raise InternalError()
     return MoonQuarter(quarter, time)
 
-def NextMoonQuarter(mq):
+def NextMoonQuarter(mq: MoonQuarter) -> MoonQuarter:
     """Continues searching for lunar quarters from a previous search.
 
     After calling #SearchMoonQuarter, this function can be called
@@ -5751,7 +5755,7 @@ class IlluminationInfo:
         as seen from observers on the Earth, and are thus very difficult to see.
         For bodies other than Saturn, `ring_tilt` is `None`.
     """
-    def __init__(self, time, mag, phase, helio_dist, geo_dist, hc, gc, ring_tilt):
+    def __init__(self, time: Time, mag: float, phase: float, helio_dist: float, geo_dist: float, hc: Vector, gc: Vector, ring_tilt: Optional[float]) -> None:
         self.time = time
         self.mag = mag
         self.phase_angle = phase
@@ -5762,7 +5766,7 @@ def __init__(self, time, mag, phase, helio_dist, geo_dist, hc, gc, ring_tilt):
         self.gc = gc
         self.ring_tilt = ring_tilt
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'IlluminationInfo({}, mag={}, phase_angle={}, helio_dist={}, geo_dist={}, hc={}, gc={}, ring_tilt={})'.format(
             repr(self.time),
             self.mag,
@@ -5834,7 +5838,7 @@ def _VisualMagnitude(body, phase, helio_dist, geo_dist):
     mag += 5.0 * math.log10(helio_dist * geo_dist)
     return mag
 
-def Illumination(body, time):
+def Illumination(body: Body, time: Time) -> IlluminationInfo:
     """Finds visual magnitude, phase angle, and other illumination information about a celestial body.
 
     This function calculates information about how bright a celestial body appears from the Earth,
@@ -5910,7 +5914,7 @@ def _mag_slope(body, time):
     y2 = Illumination(body, t2)
     return (y2.mag - y1.mag) / dt
 
-def SearchPeakMagnitude(body, startTime):
+def SearchPeakMagnitude(body: Body, startTime: Time) -> IlluminationInfo:
     """Searches for the date and time Venus will next appear brightest as seen from the Earth.
 
     This function searches for the date and time Venus appears brightest as seen from the Earth.
@@ -6028,14 +6032,14 @@ class HourAngleEvent:
     hor : HorizontalCoordinates
         Apparent coordinates of the body at the time it crosses the specified hour angle.
     """
-    def __init__(self, time, hor):
+    def __init__(self, time: Time, hor: HorizontalCoordinates):
         self.time = time
         self.hor = hor
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'HourAngleEvent({}, {})'.format(repr(self.time), repr(self.hor))
 
-def SearchHourAngle(body, observer, hourAngle, startTime, direction = +1):
+def SearchHourAngle(body: Body, observer: Observer, hourAngle: float, startTime: Time, direction: int = +1) -> HourAngleEvent:
     """Searches for the time when the center of a body reaches a specified hour angle as seen by an observer on the Earth.
 
     The *hour angle* of a celestial body indicates its position in the sky with respect
@@ -6129,7 +6133,7 @@ def SearchHourAngle(body, observer, hourAngle, startTime, direction = +1):
         time = time.AddDays(delta_days)
 
 
-def HourAngle(body, time, observer):
+def HourAngle(body: Body, time: Time, observer: Observer) -> float:
     """Finds the hour angle of a body for a given observer and time.
 
     The *hour angle* of a celestial body indicates its position in the sky with respect
@@ -6361,7 +6365,7 @@ def _InternalSearchAltitude(body, observer, direction, startTime, limitDays, bod
             a1 = a2
 
 
-def SearchRiseSet(body, observer, direction, startTime, limitDays):
+def SearchRiseSet(body: Body, observer: Observer, direction: Direction, startTime: Time, limitDays: float) -> Optional[Time]:
     """Searches for the next time a celestial body rises or sets as seen by an observer on the Earth.
 
     This function finds the next rise or set time of the Sun, Moon, or planet other than the Earth.
@@ -6422,7 +6426,7 @@ def SearchRiseSet(body, observer, direction, startTime, limitDays):
     return _InternalSearchAltitude(body, observer, direction, startTime, limitDays, bodyRadiusAu, -_REFRACTION_NEAR_HORIZON)
 
 
-def SearchAltitude(body, observer, direction, startTime, limitDays, altitude):
+def SearchAltitude(body: Body, observer: Observer, direction: Direction, startTime: Time, limitDays: float, altitude: float) -> Optional[Time]:
     """Finds the next time the center of a body passes through a given altitude.
 
     Finds when the center of the given body ascends or descends through a given
@@ -6505,13 +6509,13 @@ class SeasonInfo:
     dec_solstice : Time
         The date and time of the December solstice for the specified year.
     """
-    def __init__(self, mar_equinox, jun_solstice, sep_equinox, dec_solstice):
+    def __init__(self, mar_equinox: Time, jun_solstice: Time, sep_equinox: Time, dec_solstice: Time) -> None:
         self.mar_equinox = mar_equinox
         self.jun_solstice = jun_solstice
         self.sep_equinox = sep_equinox
         self.dec_solstice = dec_solstice
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'SeasonInfo(mar_equinox={}, jun_solstice={}, sep_equinox={}, dec_solstice={})'.format(
             repr(self.mar_equinox),
             repr(self.jun_solstice),
@@ -6527,7 +6531,7 @@ def _FindSeasonChange(targetLon, year, month, day):
         raise InternalError()
     return time
 
-def Seasons(year):
+def Seasons(year: int) -> SeasonInfo:
     """Finds both equinoxes and both solstices for a given calendar year.
 
     The changes of seasons are defined by solstices and equinoxes.
@@ -6632,20 +6636,20 @@ class Apsis:
     dist_km : float
         The distance between the centers of the bodies in kilometers.
     """
-    def __init__(self, time, kind, dist_au):
+    def __init__(self, time: Time, kind: ApsisKind, dist_au: float) -> None:
         self.time = time
         self.kind = kind
         self.dist_au = dist_au
         self.dist_km = dist_au * KM_PER_AU
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'Apsis({}, {}, dist_au={})'.format(
             repr(self.time),
             self.kind,
             self.dist_au
         )
 
-def SearchLunarApsis(startTime):
+def SearchLunarApsis(startTime: Time) -> Apsis:
     """Finds the time of the first lunar apogee or perigee after the given time.
 
     Given a date and time to start the search in `startTime`, this function finds
@@ -6712,7 +6716,7 @@ def SearchLunarApsis(startTime):
     raise InternalError()
 
 
-def NextLunarApsis(apsis):
+def NextLunarApsis(apsis: Apsis) -> Apsis:
     """Finds the next lunar perigee or apogee in a series.
 
     This function requires an #Apsis value obtained from a call to
@@ -6751,7 +6755,7 @@ def _planet_distance_slope(context, time):
     return direction * (dist2 - dist1) / dt
 
 
-def SearchPlanetApsis(body, startTime):
+def SearchPlanetApsis(body: Body, startTime: Time) -> Apsis:
     """Finds the next planet perihelion or aphelion, after a given time.
 
     Given a date and time to start the search in `startTime`, this function finds the
@@ -6818,7 +6822,7 @@ def SearchPlanetApsis(body, startTime):
     raise InternalError()   # should have found planet apsis within 2 planet orbits
 
 
-def NextPlanetApsis(body, apsis):
+def NextPlanetApsis(body: Body, apsis: Apsis) -> Apsis:
     """Finds the next planetary perihelion or aphelion event in a series.
 
     This function requires an #Apsis value obtained from a call
@@ -6925,7 +6929,7 @@ def _BruteSearchPlanetApsis(body, startTime):
     raise InternalError()   # failed to find Neptune apsis
 
 
-def VectorFromSphere(sphere, time):
+def VectorFromSphere(sphere: Spherical, time: Time) -> Vector:
     """Converts spherical coordinates to Cartesian coordinates.
 
     Given spherical coordinates and a time at which they are valid,
@@ -6955,7 +6959,7 @@ def VectorFromSphere(sphere, time):
     )
 
 
-def EquatorFromVector(vec):
+def EquatorFromVector(vec: Vector) -> Equatorial:
     """Given an equatorial vector, calculates equatorial angular coordinates.
 
     Parameters
@@ -6972,7 +6976,7 @@ def EquatorFromVector(vec):
     return Equatorial(sphere.lon / 15.0, sphere.lat, sphere.dist, vec)
 
 
-def SphereFromVector(vector):
+def SphereFromVector(vector: Vector) -> Spherical:
     """Converts Cartesian coordinates to spherical coordinates.
 
     Given a Cartesian vector, returns latitude, longitude, and distance.
@@ -7014,7 +7018,7 @@ def _ToggleAzimuthDirection(az):
     return az
 
 
-def VectorFromHorizon(sphere, time, refraction):
+def VectorFromHorizon(sphere: Spherical, time: Time, refraction: Refraction) -> Vector:
     """Given apparent angular horizontal coordinates in `sphere`, calculate horizontal vector.
 
     Parameters
@@ -7041,7 +7045,7 @@ def VectorFromHorizon(sphere, time, refraction):
     return VectorFromSphere(xsphere, time)
 
 
-def HorizonFromVector(vector, refraction):
+def HorizonFromVector(vector: Vector, refraction: Refraction) -> Spherical:
     """Converts Cartesian coordinates to horizontal coordinates.
 
     Given a horizontal Cartesian vector, returns horizontal azimuth and altitude.
@@ -7075,7 +7079,7 @@ def HorizonFromVector(vector, refraction):
     return sphere
 
 
-def InverseRotation(rotation):
+def InverseRotation(rotation: RotationMatrix) -> RotationMatrix:
     """Calculates the inverse of a rotation matrix.
 
     Given a rotation matrix that performs some coordinate transform,
@@ -7098,7 +7102,7 @@ def InverseRotation(rotation):
     ])
 
 
-def CombineRotation(a, b):
+def CombineRotation(a: RotationMatrix, b: RotationMatrix) -> RotationMatrix:
     """Creates a rotation based on applying one rotation followed by another.
 
     Given two rotation matrices, returns a combined rotation matrix that is
@@ -7141,7 +7145,7 @@ def CombineRotation(a, b):
     ])
 
 
-def IdentityMatrix():
+def IdentityMatrix() -> RotationMatrix:
     """Creates an identity rotation matrix.
 
     Returns a rotation matrix that has no effect on orientation.
@@ -7161,7 +7165,7 @@ def IdentityMatrix():
     ])
 
 
-def Pivot(rotation, axis, angle):
+def Pivot(rotation: RotationMatrix, axis: int, angle: float) -> RotationMatrix:
     """Re-orients a rotation matrix by pivoting it by an angle around one of its axes.
 
     Given a rotation matrix, a selected coordinate axis, and an angle in degrees,
@@ -7209,7 +7213,7 @@ def Pivot(rotation, axis, angle):
     j = (axis + 2) % 3
     k = axis
 
-    rot = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
+    rot: List[List[float]] = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
 
     rot[i][i] = c*rotation.rot[i][i] - s*rotation.rot[i][j]
     rot[i][j] = s*rotation.rot[i][i] + c*rotation.rot[i][j]
@@ -7226,7 +7230,7 @@ def Pivot(rotation, axis, angle):
     return RotationMatrix(rot)
 
 
-def RotateVector(rotation, vector):
+def RotateVector(rotation: RotationMatrix, vector: Vector) -> Vector:
     """Applies a rotation to a vector, yielding a rotated vector.
 
     This function transforms a vector in one orientation to a vector
@@ -7252,7 +7256,7 @@ def RotateVector(rotation, vector):
     )
 
 
-def RotateState(rotation, state):
+def RotateState(rotation: RotationMatrix, state: StateVector) -> StateVector:
     """Applies a rotation to a state vector, yielding a rotated state vector.
 
     This function transforms a state vector in one orientation to a
@@ -7282,7 +7286,7 @@ def RotateState(rotation, state):
     )
 
 
-def Rotation_EQJ_ECL():
+def Rotation_EQJ_ECL() -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean equator (EQJ) to J2000 mean ecliptic (ECL).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7305,7 +7309,7 @@ def Rotation_EQJ_ECL():
     ])
 
 
-def Rotation_ECL_EQJ():
+def Rotation_ECL_EQJ() -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean ecliptic (ECL) to J2000 mean equator (EQJ).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7327,7 +7331,7 @@ def Rotation_ECL_EQJ():
         [ 0, -s, +c]
     ])
 
-def Rotation_EQJ_EQD(time):
+def Rotation_EQJ_EQD(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean equator (EQJ) to equatorial of-date (EQD).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7350,7 +7354,7 @@ def Rotation_EQJ_EQD(time):
     return CombineRotation(prec, nut)
 
 
-def Rotation_EQJ_ECT(time):
+def Rotation_EQJ_ECT(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean equator (EQJ) to true ecliptic of date (ECT).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7373,7 +7377,7 @@ def Rotation_EQJ_ECT(time):
     return CombineRotation(rot, step)
 
 
-def Rotation_ECT_EQJ(time):
+def Rotation_ECT_EQJ(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from true ecliptic of date (ECT) to J2000 mean equator (EQJ).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7396,7 +7400,7 @@ def Rotation_ECT_EQJ(time):
     return CombineRotation(rot, step)
 
 
-def Rotation_EQD_EQJ(time):
+def Rotation_EQD_EQJ(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from equatorial of-date (EQD) to J2000 mean equator (EQJ).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7419,7 +7423,7 @@ def Rotation_EQD_EQJ(time):
     return CombineRotation(nut, prec)
 
 
-def Rotation_EQD_HOR(time, observer):
+def Rotation_EQD_HOR(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from equatorial of-date (EQD) to horizontal (HOR).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7464,7 +7468,7 @@ def Rotation_EQD_HOR(time, observer):
     ])
 
 
-def Rotation_HOR_EQD(time, observer):
+def Rotation_HOR_EQD(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from horizontal (HOR) to equatorial of-date (EQD).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7488,7 +7492,7 @@ def Rotation_HOR_EQD(time, observer):
     return InverseRotation(rot)
 
 
-def Rotation_HOR_EQJ(time, observer):
+def Rotation_HOR_EQJ(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from horizontal (HOR) to J2000 equatorial (EQJ).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7513,7 +7517,7 @@ def Rotation_HOR_EQJ(time, observer):
     return CombineRotation(hor_eqd, eqd_eqj)
 
 
-def Rotation_EQJ_HOR(time, observer):
+def Rotation_EQJ_HOR(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean equator (EQJ) to horizontal (HOR).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7544,7 +7548,7 @@ def Rotation_EQJ_HOR(time, observer):
     return InverseRotation(rot)
 
 
-def Rotation_EQD_ECL(time):
+def Rotation_EQD_ECL(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from equatorial of-date (EQD) to J2000 mean ecliptic (ECL).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7567,7 +7571,7 @@ def Rotation_EQD_ECL(time):
     return CombineRotation(eqd_eqj, eqj_ecl)
 
 
-def Rotation_ECL_EQD(time):
+def Rotation_ECL_EQD(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean ecliptic (ECL) to equatorial of-date (EQD).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7589,7 +7593,7 @@ def Rotation_ECL_EQD(time):
     return InverseRotation(rot)
 
 
-def Rotation_ECL_HOR(time, observer):
+def Rotation_ECL_HOR(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean ecliptic (ECL) to horizontal (HOR).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7621,7 +7625,7 @@ def Rotation_ECL_HOR(time, observer):
     return CombineRotation(ecl_eqd, eqd_hor)
 
 
-def Rotation_HOR_ECL(time, observer):
+def Rotation_HOR_ECL(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from horizontal (HOR) to J2000 mean ecliptic (ECL).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7644,7 +7648,7 @@ def Rotation_HOR_ECL(time, observer):
     rot = Rotation_ECL_HOR(time, observer)
     return InverseRotation(rot)
 
-def Rotation_EQJ_GAL():
+def Rotation_EQJ_GAL() -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean equator (EQJ) to galactic (GAL).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7666,7 +7670,7 @@ def Rotation_EQJ_GAL():
         [-0.4838000529948520, +0.7470034631630423, +0.4559861124470794]
     ])
 
-def Rotation_GAL_EQJ():
+def Rotation_GAL_EQJ() -> RotationMatrix:
     """Calculates a rotation matrix from galactic (GAL) to J2000 mean equator (EQJ).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7688,7 +7692,7 @@ def Rotation_GAL_EQJ():
         [-0.8676668813529025, -0.1980677870294097, +0.4559861124470794]
     ])
 
-def Rotation_ECT_EQD(time):
+def Rotation_ECT_EQD(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from true ecliptic of date (ECT) to equator of date (EQD).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7716,7 +7720,7 @@ def Rotation_ECT_EQD(time):
         [0.0,  -s,  +c]
     ])
 
-def Rotation_EQD_ECT(time):
+def Rotation_EQD_ECT(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from equator of date (EQD) to true ecliptic of date (ECT).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7765,13 +7769,13 @@ class ConstellationInfo:
     dec1875 : float
         Declination expressed in B1875 coordinates.
     """
-    def __init__(self, symbol, name, ra1875, dec1875):
+    def __init__(self, symbol: str, name: str, ra1875: float, dec1875: float) -> None:
         self.symbol = symbol
         self.name = name
         self.ra1875 = ra1875
         self.dec1875 = dec1875
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'ConstellationInfo(symbol={}, name={}, ra1875={}, dec1875={})'.format(
             repr(self.symbol),
             repr(self.name),
@@ -8236,7 +8240,7 @@ def __repr__(self):
 
 
 
-def Constellation(ra, dec):
+def Constellation(ra: float, dec: float) -> ConstellationInfo:
     """Determines the constellation that contains the given point in the sky.
 
     Given J2000 equatorial (EQJ) coordinates of a point in the sky, determines the
@@ -8483,7 +8487,7 @@ class LunarEclipseInfo:
     sd_total : float
          The semi-duration of the penumbral phase in minutes, or 0.0 if none.
     """
-    def __init__(self, kind, obscuration, peak, sd_penum, sd_partial, sd_total):
+    def __init__(self, kind: EclipseKind, obscuration: float, peak: Time, sd_penum: float, sd_partial: float, sd_total: float) -> None:
         self.kind = kind
         self.obscuration = obscuration
         self.peak = peak
@@ -8491,7 +8495,7 @@ def __init__(self, kind, obscuration, peak, sd_penum, sd_partial, sd_total):
         self.sd_partial = sd_partial
         self.sd_total = sd_total
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'LunarEclipseInfo({}, obscuration={}, peak={}, sd_penum={}, sd_partial={}, sd_total={})'.format(
             self.kind,
             self.obscuration,
@@ -8552,7 +8556,7 @@ class GlobalSolarEclipseInfo:
     longitude : float
         The geographic longitude at the center of the peak eclipse shadow.
     """
-    def __init__(self, kind, obscuration, peak, distance, latitude, longitude):
+    def __init__(self, kind: EclipseKind, obscuration: float, peak: Time, distance: float, latitude: float, longitude: float) -> None:
         self.kind = kind
         self.obscuration = obscuration
         self.peak = peak
@@ -8560,7 +8564,7 @@ def __init__(self, kind, obscuration, peak, distance, latitude, longitude):
         self.latitude = latitude
         self.longitude = longitude
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'GlobalSolarEclipseInfo({}, obscuration={}, peak={}, distance={}, latitude={}, longitude={})'.format(
             self.kind,
             self.obscuration,
@@ -8593,11 +8597,11 @@ class EclipseEvent:
         The angular altitude of the center of the Sun above/below the horizon, at `time`,
         corrected for atmospheric refraction and expressed in degrees.
     """
-    def __init__(self, time, altitude):
+    def __init__(self, time: Time, altitude: float) -> None:
         self.time = time
         self.altitude = altitude
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'EclipseEvent({}, altitude={})'.format(
             repr(self.time),
             self.altitude
@@ -8653,7 +8657,7 @@ class LocalSolarEclipseInfo:
     partial_end : EclipseEvent
         The time and Sun altitude at the end of the eclipse.
     """
-    def __init__(self, kind, obscuration, partial_begin, total_begin, peak, total_end, partial_end):
+    def __init__(self, kind: EclipseKind, obscuration: float, partial_begin: EclipseEvent, total_begin: EclipseEvent, peak: EclipseEvent, total_end: EclipseEvent, partial_end: EclipseEvent) -> None:
         self.kind = kind
         self.obscuration = obscuration
         self.partial_begin = partial_begin
@@ -8662,7 +8666,7 @@ def __init__(self, kind, obscuration, partial_begin, total_begin, peak, total_en
         self.total_end = total_end
         self.partial_end = partial_end
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'LocalSolarEclipseInfo({}, obscuration={}, partial_begin={}, total_begin={}, peak={}, total_end={}, partial_end={})'.format(
             self.kind,
             self.obscuration,
@@ -8921,7 +8925,7 @@ def _SolarEclipseObscuration(hm, lo):
     return min(0.9999, obscuration)
 
 
-def SearchLunarEclipse(startTime):
+def SearchLunarEclipse(startTime: Time) -> LunarEclipseInfo:
     """Searches for a lunar eclipse.
 
     This function finds the first lunar eclipse that occurs after `startTime`.
@@ -8986,7 +8990,7 @@ def SearchLunarEclipse(startTime):
     raise Error('Failed to find lunar eclipse within 12 full moons.')
 
 
-def NextLunarEclipse(prevEclipseTime):
+def NextLunarEclipse(prevEclipseTime: Time) -> LunarEclipseInfo:
     """Searches for the next lunar eclipse in a series.
 
      After using #SearchLunarEclipse to find the first lunar eclipse
@@ -9008,7 +9012,7 @@ def NextLunarEclipse(prevEclipseTime):
     return SearchLunarEclipse(startTime)
 
 
-def SearchGlobalSolarEclipse(startTime):
+def SearchGlobalSolarEclipse(startTime: Time) -> GlobalSolarEclipseInfo:
     """Searches for a solar eclipse visible anywhere on the Earth's surface.
 
     This function finds the first solar eclipse that occurs after `startTime`.
@@ -9055,7 +9059,7 @@ def SearchGlobalSolarEclipse(startTime):
     raise Error('Failed to find solar eclipse within 12 full moons.')
 
 
-def NextGlobalSolarEclipse(prevEclipseTime):
+def NextGlobalSolarEclipse(prevEclipseTime: Time) -> GlobalSolarEclipseInfo:
     """Searches for the next global solar eclipse in a series.
 
     After using #SearchGlobalSolarEclipse to find the first solar eclipse
@@ -9077,7 +9081,7 @@ def NextGlobalSolarEclipse(prevEclipseTime):
     return SearchGlobalSolarEclipse(startTime)
 
 
-def SearchLocalSolarEclipse(startTime, observer):
+def SearchLocalSolarEclipse(startTime: Time, observer: Observer) -> LocalSolarEclipseInfo:
     """Searches for a solar eclipse visible at a specific location on the Earth's surface.
     This function finds the first solar eclipse that occurs after `startTime`.
     A solar eclipse may be partial, annular, or total.
@@ -9132,7 +9136,7 @@ def SearchLocalSolarEclipse(startTime, observer):
         nmtime = newmoon.AddDays(10.0)
 
 
-def NextLocalSolarEclipse(prevEclipseTime, observer):
+def NextLocalSolarEclipse(prevEclipseTime: Time, observer: Observer) -> LocalSolarEclipseInfo:
     """Searches for the next local solar eclipse in a series.
 
     After using #SearchLocalSolarEclipse to find the first solar eclipse
@@ -9180,13 +9184,13 @@ class TransitInfo:
         The minimum angular separation, in arcminutes, between the centers of the Sun and the planet.
         This angle pertains to the time stored in `peak`.
     """
-    def __init__(self, start, peak, finish, separation):
+    def __init__(self, start: Time, peak: Time, finish: Time, separation: float) -> None:
         self.start = start
         self.peak = peak
         self.finish = finish
         self.separation = separation
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'TransitInfo(start={}, peak={}, finish={}, separation={})'.format(
             repr(self.start),
             repr(self.peak),
@@ -9210,7 +9214,7 @@ def _PlanetTransitBoundary(body, planet_radius_km, t1, t2, direction):
     return tx
 
 
-def SearchTransit(body, startTime):
+def SearchTransit(body: Body, startTime: Time) -> TransitInfo:
     """Searches for the first transit of Mercury or Venus after a given date.
 
     Finds the first transit of Mercury or Venus after a specified date.
@@ -9270,7 +9274,7 @@ def SearchTransit(body, startTime):
         search_time = conj.AddDays(10.0)
 
 
-def NextTransit(body, prevTransitTime):
+def NextTransit(body: Body, prevTransitTime: Time) -> TransitInfo:
     """Searches for another transit of Mercury or Venus.
 
     After calling #SearchTransit to find a transit of Mercury or Venus,
@@ -9319,11 +9323,11 @@ class NodeEventInfo:
     time : Time
         The time when the body passes through the ecliptic plane.
     """
-    def __init__(self, kind, time):
+    def __init__(self, kind: NodeEventKind, time: Time) -> None:
         self.kind = kind
         self.time = time
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'NodeEventInfo({}, {})'.format(self.kind, repr(self.time))
 
 _MoonNodeStepDays = +10.0   # a safe number of days to step without missing a Moon node
@@ -9331,7 +9335,7 @@ def __repr__(self):
 def _MoonNodeSearchFunc(direction, time):
     return direction * EclipticGeoMoon(time).lat
 
-def SearchMoonNode(startTime):
+def SearchMoonNode(startTime: Time) -> NodeEventInfo:
     """Searches for a time when the Moon's center crosses through the ecliptic plane.
 
     Searches for the first ascending or descending node of the Moon after `startTime`.
@@ -9371,7 +9375,7 @@ def SearchMoonNode(startTime):
         eclip1 = eclip2
 
 
-def NextMoonNode(prevNode):
+def NextMoonNode(prevNode: NodeEventInfo) -> NodeEventInfo:
     """Searches for the next time when the Moon's center crosses through the ecliptic plane.
 
     Call #SearchMoonNode to find the first of a series of nodes.
@@ -9420,7 +9424,7 @@ class LibrationInfo:
     diam_deg : float
         The apparent angular diameter of the Moon as seen from the center of the Earth.
     """
-    def __init__(self, elat, elon, mlat, mlon, dist_km, diam_deg):
+    def __init__(self, elat: float, elon: float, mlat: float, mlon: float, dist_km: float, diam_deg: float) -> None:
         self.elat = elat
         self.elon = elon
         self.mlat = mlat
@@ -9428,7 +9432,7 @@ def __init__(self, elat, elon, mlat, mlon, dist_km, diam_deg):
         self.dist_km = dist_km
         self.diam_deg = diam_deg
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'LibrationInfo(elat={}, elon={}, mlat={}, mlon={}, dist_km={}, diam_deg={})'.format(
             self.elat,
             self.elon,
@@ -9439,7 +9443,7 @@ def __repr__(self):
         )
 
 
-def Libration(time):
+def Libration(time: Time) -> LibrationInfo:
     """Calculates the Moon's libration angles at a given moment in time.
 
     Libration is an observed back-and-forth wobble of the portion of the
@@ -9599,13 +9603,13 @@ class AxisInfo:
     north : Vector
         A J2000 dimensionless unit vector pointing in the direction of the body's north pole.
     """
-    def __init__(self, ra, dec, spin, north):
+    def __init__(self, ra: float, dec: float, spin: float, north: Vector) -> None:
         self.ra = ra
         self.dec = dec
         self.spin = spin
         self.north = north
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'AxisInfo(ra={}, dec={}, spin={}, north={})'.format(
             self.ra,
             self.dec,
@@ -9635,7 +9639,7 @@ def _EarthRotationAxis(time):
     return AxisInfo(equ.ra, equ.dec, spin, north)
 
 
-def RotationAxis(body, time):
+def RotationAxis(body: Body, time: Time) -> AxisInfo:
     """Calculates information about a body's rotation axis at a given time.
 
     Calculates the orientation of a body's rotation axis, along with
@@ -9836,7 +9840,7 @@ def RotationAxis(body, time):
     return AxisInfo(ra/15.0, dec, w, north)
 
 
-def LagrangePoint(point, time, major_body, minor_body):
+def LagrangePoint(point: int, time: Time, major_body: Body, minor_body: Body) -> StateVector:
     """Calculates one of the 5 Lagrange points for a pair of co-orbiting bodies.
 
     Given a more massive "major" body and a much less massive "minor" body,
@@ -9902,7 +9906,7 @@ def LagrangePoint(point, time, major_body, minor_body):
     )
 
 
-def LagrangePointFast(point, major_state, major_mass, minor_state, minor_mass):
+def LagrangePointFast(point: int, major_state: StateVector, major_mass: float, minor_state: StateVector, minor_mass: float) -> StateVector:
     """Calculates one of the 5 Lagrange points from body masses and state vectors.
 
     Given a more massive "major" body and a much less massive "minor" body,
@@ -10090,7 +10094,7 @@ class GravitySimulator:
     time steps.
     """
 
-    def __init__(self, originBody, time, bodyStates):
+    def __init__(self, originBody: Body, time: "Time", bodyStates: List[StateVector]) -> None:
         """Creates a gravity simulation object.
 
         Parameters
@@ -10129,7 +10133,7 @@ def __init__(self, originBody, time, bodyStates):
 
         # Create a stub list of small body states that we will append to later.
         # We just need the stub to put into `self.curr`
-        smallBodyList = []
+        smallBodyList: List = []
 
         # Calculate the states of the Sun and planets at the initial time.
         largeBodyDict = _CalcSolarSystem(time)
@@ -10160,7 +10164,7 @@ def Time(self):
         """
         return self.curr.time
 
-    def OriginBody(self):
+    def OriginBody(self) -> Body:
         """The origin of the reference frame. See constructor for more info.
 
         Returns
@@ -10169,7 +10173,7 @@ def OriginBody(self):
         """
         return self._originBody
 
-    def Update(self, time):
+    def Update(self, time) -> List[StateVector]:
         """Advances the gravity simulation by a small time step.
 
         Updates the simulation of the user-supplied small bodies
@@ -10269,7 +10273,7 @@ def Update(self, time):
         return bodyStates
 
 
-    def Swap(self):
+    def Swap(self) -> None:
         """Exchange the current time step with the previous time step.
 
         Sometimes it is helpful to "explore" various times near a given
@@ -10295,7 +10299,7 @@ def Swap(self):
         """
         (self.curr, self.prev) = (self.prev, self.curr)
 
-    def SolarSystemBodyState(self, body):
+    def SolarSystemBodyState(self, body: Body) -> StateVector:
         """Get the position and velocity of a Solar System body included in the simulation.
 
         In order to simulate the movement of small bodies through the Solar System,
diff --git a/generate/pydown/pydown.py b/generate/pydown/pydown.py
index 89c7a63a..ec537321 100755
--- a/generate/pydown/pydown.py
+++ b/generate/pydown/pydown.py
@@ -365,7 +365,13 @@ def ConstantsMd(inPythonFileName):
             # Consider symbols like Union defined in lines like the following:
             # "from typing import Union"
             tokens = line.split()
+            
             if len(tokens) > 3 and tokens[0] == 'from' and tokens[2] == 'import':
+                # from typing import Optional, Union are currently split as
+                # ["from", "typing", "import", "Optional,", "Union"]
+                # Removing the commas within the strings to properly identify as tokens
+                tokens = [token.replace(",", "") for token in tokens]
+                
                 for name in tokens[3:]:
                     if name != ',':
                         documentedSymbolSet.add(name)
diff --git a/generate/template/astronomy.py b/generate/template/astronomy.py
index 58589156..976719e3 100644
--- a/generate/template/astronomy.py
+++ b/generate/template/astronomy.py
@@ -36,7 +36,7 @@
 import enum
 import re
 import abc
-from typing import Union
+from typing import List, Optional, Union, Callable
 
 def _cbrt(x):
     if x < 0.0:
@@ -374,7 +374,7 @@ def _UserDefinedStar(body):
         return star
     return None
 
-def DefineStar(body, ra, dec, distanceLightYears):
+def DefineStar(body: Body, ra: float, dec: float, distanceLightYears: float) -> None:
     """Assign equatorial coordinates to a user-defined star.
 
     Some Astronomy Engine functions allow their `body` parameter to
@@ -413,7 +413,7 @@ def DefineStar(body, ra, dec, distanceLightYears):
     star.dec = dec
     star.dist = distanceLightYears * AU_PER_LY
 
-def BodyCode(name):
+def BodyCode(name: str) -> Body:
     """Finds the Body enumeration value, given the name of a body.
 
     Parameters
@@ -439,7 +439,7 @@ def BodyCode(name):
         return Body.Invalid
     return Body[name]
 
-def _IsSuperiorPlanet(body):
+def _IsSuperiorPlanet(body: Body) -> bool:
     return body in [Body.Mars, Body.Jupiter, Body.Saturn, Body.Uranus, Body.Neptune, Body.Pluto]
 
 _PlanetOrbitalPeriod = [
@@ -456,27 +456,27 @@ def _IsSuperiorPlanet(body):
 
 class Error(Exception):
     """Indicates an error in an astronomical calculation."""
-    def __init__(self, message):
+    def __init__(self, message: str) -> None:
         Exception.__init__(self, message)
 
 class DateTimeFormatError(Error):
     """The syntax of a UTC date/time string was not valid, or it contains invalid values."""
-    def __init__(self, text):
+    def __init__(self, text: str) -> None:
         Error.__init__(self, 'The date/time string is not valid: "{}"'.format(text))
 
 class EarthNotAllowedError(Error):
     """The Earth is not allowed as the celestial body in this calculation."""
-    def __init__(self):
+    def __init__(self) -> None:
         Error.__init__(self, 'The Earth is not allowed as the body.')
 
 class InvalidBodyError(Error):
     """The celestial body is not allowed for this calculation."""
-    def __init__(self, body):
+    def __init__(self, body: Body) -> None:
         Error.__init__(self, 'This body is not valid, or is not supported for this calculation: {}'.format(body))
 
 class BadVectorError(Error):
     """A vector magnitude is too small to have a direction in space."""
-    def __init__(self):
+    def __init__(self) -> None:
         Error.__init__(self, 'Vector is too small to have a direction.')
 
 class InternalError(Error):
@@ -489,7 +489,7 @@ class InternalError(Error):
     of how to reproduce the error. This will help improve the quality of
     Astronomy Engine for everyone! (Thank you in advance from the author.)
     """
-    def __init__(self):
+    def __init__(self) -> None:
         Error.__init__(self, 'Internal error - please report issue, including stack trace, at https://github.com/cosinekitty/astronomy/issues')
 
 class NoConvergeError(Error):
@@ -502,10 +502,10 @@ class NoConvergeError(Error):
     of how to reproduce the error. This will help improve the quality of
     Astronomy Engine for everyone! (Thank you in advance from the author.)
     """
-    def __init__(self):
+    def __init__(self) -> None:
         Error.__init__(self, 'Numeric solver did not converge - please report issue at https://github.com/cosinekitty/astronomy/issues')
 
-def PlanetOrbitalPeriod(body):
+def PlanetOrbitalPeriod(body: Body) -> float:
     """Returns the average number of days it takes for a planet to orbit the Sun.
 
     Parameters
@@ -522,7 +522,7 @@ def PlanetOrbitalPeriod(body):
         return _PlanetOrbitalPeriod[body.value]
     raise InvalidBodyError(body)
 
-def _SynodicPeriod(body):
+def _SynodicPeriod(body: Body) -> float:
     if body == Body.Earth:
         raise EarthNotAllowedError()
     if body.value < 0 or body.value >= len(_PlanetOrbitalPeriod):
@@ -531,7 +531,7 @@ def _SynodicPeriod(body):
         return _MEAN_SYNODIC_MONTH
     return abs(_EARTH_ORBITAL_PERIOD / (_EARTH_ORBITAL_PERIOD/_PlanetOrbitalPeriod[body.value] - 1.0))
 
-def AngleBetween(a, b):
+def AngleBetween(a: Vector, b: Vector) -> float:
     """Calculates the angle in degrees between two vectors.
 
     Given a pair of vectors, this function returns the angle in degrees
@@ -551,10 +551,10 @@ def AngleBetween(a, b):
         The angle between the two vectors expressed in degrees.
         The value is in the range [0, 180].
     """
-    r = a.Length() * b.Length()
+    r: float = a.Length() * b.Length()
     if r < 1.0e-8:
-        return BadVectorError()
-    dot = (a.x*b.x + a.y*b.y + a.z*b.z) / r
+        raise BadVectorError()
+    dot: float = (a.x*b.x + a.y*b.y + a.z*b.z) / r
     if dot <= -1.0:
         return 180.0
     if dot >= +1.0:
@@ -562,7 +562,7 @@ def AngleBetween(a, b):
     return math.degrees(math.acos(dot))
 
 
-def DeltaT_EspenakMeeus(ut):
+def DeltaT_EspenakMeeus(ut: float) -> float:
     """The default Delta T function used by Astronomy Engine.
 
     Espenak and Meeus use a series of piecewise polynomials to
@@ -666,10 +666,10 @@ def DeltaT_EspenakMeeus(ut):
 _DeltaT = DeltaT_EspenakMeeus
 
 
-def _TerrestrialTime(ut):
+def _TerrestrialTime(ut: float) -> float:
     return ut + _DeltaT(ut) / 86400.0
 
-def _UniversalTime(tt):
+def _UniversalTime(tt: float) -> float:
     # This is the inverse function of _TerrestrialTime.
     # This is an iterative numerical solver, but because
     # the relationship between UT and TT is almost perfectly linear,
@@ -729,23 +729,23 @@ class Time:
         such as the orbits of planets around the Sun, or the Moon around the Earth.
         Historically, Terrestrial Time has also been known by the term *Ephemeris Time* (ET).
     """
-    def __init__(self, ut : Union[float, str], tt = None):
+    def __init__(self, ut : Union[float, str], tt: Optional[float] = None):
         if isinstance(ut, str):
             # Undocumented hack, to make repr(time) reversible.
             other = Time.Parse(ut)
-            self.ut = other.ut
-            self.tt = other.tt
+            self.ut: float = other.ut
+            self.tt: float = other.tt
         else:
             self.ut = ut
             if tt is None:
                 self.tt = _TerrestrialTime(ut)
             else:
                 self.tt = tt
-        self._et = None     # lazy-cache for earth tilt
-        self._st = None     # lazy-cache for sidereal time
+        self._et: Optional[float] = None     # lazy-cache for earth tilt
+        self._st: Optional[float] = None     # lazy-cache for sidereal time
 
     @staticmethod
-    def FromTerrestrialTime(tt):
+    def FromTerrestrialTime(tt: float) -> "Time":
         """Creates a #Time object from a Terrestrial Time day value.
 
         Parameters
@@ -760,7 +760,7 @@ def FromTerrestrialTime(tt):
         return Time(_UniversalTime(tt), tt)
 
     @staticmethod
-    def Parse(text):
+    def Parse(text: str) -> "Time":
         """Creates a #Time object from a string of the form 'yyyy-mm-ddThh:mm:ss.sssZ'
 
         Parses a UTC date and time from a string and returns a #Time object.
@@ -805,7 +805,7 @@ def Parse(text):
         return Time.Make(year, month, day, hour, minute, second)
 
     @staticmethod
-    def Make(year, month, day, hour, minute, second):
+    def Make(year: int, month: int, day: int, hour: int, minute: int, second: float) -> "Time":
         """Creates a #Time object from a UTC calendar date and time.
 
         Parameters
@@ -841,7 +841,7 @@ def Make(year, month, day, hour, minute, second):
         return Time(ut)
 
     @staticmethod
-    def Now():
+    def Now() -> "Time":
         """Returns the computer's current date and time in the form of a #Time object.
 
         Uses the computer's system clock to find the current UTC date and time.
@@ -856,7 +856,7 @@ def Now():
         ut = (datetime.datetime.utcnow() - _EPOCH).total_seconds() / 86400.0
         return Time(ut)
 
-    def AddDays(self, days):
+    def AddDays(self, days: float) -> "Time":
         """Calculates the sum or difference of a #Time with a specified real-valued number of days.
 
         Sometimes we need to adjust a given #Time value by a certain amount of time.
@@ -883,10 +883,10 @@ def AddDays(self, days):
         """
         return Time(self.ut + days)
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'Time(\'' + str(self) + '\')'
 
-    def __str__(self):
+    def __str__(self) -> str:
         # Adapted from the NOVAS C 3.1 function cal_date().
         djd = self.ut + 2451545.5
         jd = int(djd)
@@ -924,7 +924,7 @@ def __str__(self):
         text += '-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}.{:03d}Z'.format(month, day, hour, minute, millis // 1000, millis % 1000)
         return text
 
-    def Utc(self):
+    def Utc(self) -> datetime.datetime:
         """Returns the UTC date and time as a `datetime` object.
 
         Uses the standard [`datetime`](https://docs.python.org/3/library/datetime.html) class
@@ -944,22 +944,26 @@ def _etilt(self):
             self._et = _e_tilt(self)
         return self._et
 
-    def __lt__(self, other):
+    def __lt__(self, other: "Time") -> bool:
         return self.tt < other.tt
 
-    def __eq__(self, other):
+    def __eq__(self, other: object) -> bool:
+        if not isinstance(other, Time):
+            return NotImplemented
         return self.tt == other.tt
 
-    def __le__(self, other):
+    def __le__(self, other: "Time") -> bool:
         return self.tt <= other.tt
 
-    def __ne__(self, other):
+    def __ne__(self, other: object) -> bool:
+        if not isinstance(other, Time):
+            return NotImplemented
         return self.tt != other.tt
 
-    def __gt__(self, other):
+    def __gt__(self, other: "Time") -> bool:
         return self.tt > other.tt
 
-    def __ge__(self, other):
+    def __ge__(self, other: "Time") -> bool:
         return self.tt >= other.tt
 
 
@@ -975,15 +979,15 @@ class Observer:
     height : float
         Elevation above sea level in meters.
     """
-    def __init__(self, latitude, longitude, height=0.0):
+    def __init__(self, latitude: float, longitude: float, height: float = 0.0) -> None:
         self.latitude = latitude
         self.longitude = longitude
         self.height = height
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'Observer(latitude={}, longitude={}, height={})'.format(self.latitude, self.longitude, self.height)
 
-    def __str__(self):
+    def __str__(self) -> str:
         text = '('
         text += 'S' if (self.latitude < 0) else 'N'
         text += '{:0.8f}, '.format(abs(self.latitude))
@@ -1002,10 +1006,10 @@ class RotationMatrix:
     rot : float[3][3]
         A normalized 3x3 rotation matrix.
     """
-    def __init__(self, rot):
+    def __init__(self, rot: List[List[float]]) -> None:
         self.rot = rot
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'RotationMatrix({})'.format(self.rot)
 
 class Spherical:
@@ -1020,16 +1024,16 @@ class Spherical:
     dist : float
         Distance in AU.
     """
-    def __init__(self, lat, lon, dist):
+    def __init__(self, lat: float, lon: float, dist: float) -> None:
         self.lat = lat
         self.lon = lon
         self.dist = dist
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'Spherical(lat={}, lon={}, dist={})'.format(self.lat, self.lon, self.dist)
 
 class _iau2000b:
-    def __init__(self, time):
+    def __init__(self, time: Time) -> None:
         t = time.tt / 36525.0
         elp = math.fmod((1287104.79305 + t*129596581.0481),  _ASEC360) * _ASEC2RAD
         f   = math.fmod((335779.526232 + t*1739527262.8478), _ASEC360) * _ASEC2RAD
@@ -1067,7 +1071,7 @@ def __init__(self, time):
         self.dpsi = -0.000135 + (dp * 1.0e-7)
         self.deps = +0.000388 + (de * 1.0e-7)
 
-def _mean_obliq(tt):
+def _mean_obliq(tt: float) -> float:
     t = tt / 36525
     asec = (
         (((( -  0.0000000434   * t
@@ -1079,7 +1083,7 @@ def _mean_obliq(tt):
     return asec / 3600.0
 
 class _e_tilt:
-    def __init__(self, time):
+    def __init__(self, time: Time) -> None:
         e = _iau2000b(time)
         self.dpsi = e.dpsi
         self.deps = e.deps
@@ -1201,17 +1205,17 @@ class Equatorial:
         y = direction of the June solstice,
         z = north.
     """
-    def __init__(self, ra, dec, dist, vec):
+    def __init__(self, ra: float, dec: float, dist: float, vec: Vector) -> None:
         self.ra = ra
         self.dec = dec
         self.dist = dist
         self.vec = vec
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'Equatorial(ra={}, dec={}, dist={}, vec={})'.format(self.ra, self.dec, self.dist, repr(self.vec))
 
 
-def _vector2radec(pos, time):
+def _vector2radec(pos, time: Time) -> Equatorial:
     xyproj = pos[0]*pos[0] + pos[1]*pos[1]
     dist = math.sqrt(xyproj + pos[2]*pos[2])
     if xyproj == 0.0:
@@ -1232,7 +1236,7 @@ def _vector2radec(pos, time):
     return Equatorial(ra, dec, dist, vec)
 
 
-def _nutation_rot(time, direction):
+def _nutation_rot(time: Time, direction) -> RotationMatrix:
     tilt = time._etilt()
     oblm = math.radians(tilt.mobl)
     oblt = math.radians(tilt.tobl)
@@ -1288,7 +1292,7 @@ def _era(time):        # Earth Rotation Angle
         theta += 360.0
     return theta
 
-def SiderealTime(time):
+def SiderealTime(time: Time) -> float:
     """Calculates Greenwich Apparent Sidereal Time (GAST).
 
     Given a date and time, this function calculates the rotation of the
@@ -1548,7 +1552,7 @@ def ADDN(coeffn, p, q, r, s):
         (_ARC * _EARTH_EQUATORIAL_RADIUS_AU) / (0.999953253 * SINPI)
     )
 
-def GeoMoon(time):
+def GeoMoon(time: Time) -> Vector:
     """Calculates equatorial geocentric position of the Moon at a given time.
 
     Given a time of observation, calculates the Moon's position as a vector.
@@ -1591,7 +1595,7 @@ def GeoMoon(time):
     return Vector(mpos2[0], mpos2[1], mpos2[2], time)
 
 
-def EclipticGeoMoon(time):
+def EclipticGeoMoon(time: Time) -> Spherical:
     """Calculates spherical ecliptic geocentric position of the Moon.
 
     Given a time of observation, calculates the Moon's geocentric position
@@ -1649,7 +1653,7 @@ def EclipticGeoMoon(time):
     return Spherical(eclip.elat, eclip.elon, moon.distance_au)
 
 
-def GeoMoonState(time):
+def GeoMoonState(time: Time) -> StateVector:
     """Calculates equatorial geocentric position and velocity of the Moon at a given time.
 
     Given a time of observation, calculates the Moon's position and velocity vectors.
@@ -1691,7 +1695,7 @@ def GeoMoonState(time):
     )
 
 
-def GeoEmbState(time):
+def GeoEmbState(time: Time) -> StateVector:
     """Calculates the geocentric position and velocity of the Earth/Moon barycenter.
 
     Given a time of observation, calculates the geocentric position and velocity vectors
@@ -1892,45 +1896,45 @@ def _CalcEarth(time):
 $ASTRO_PLUTO_TABLE()
 
 class _TerseVector:
-    def __init__(self, x, y, z):
+    def __init__(self, x, y, z) -> None:
         self.x = x
         self.y = y
         self.z = z
 
-    def clone(self):
+    def clone(self) -> "_TerseVector":
         '''Create a copy of this vector.'''
         return _TerseVector(self.x, self.y, self.z)
 
     @staticmethod
-    def zero():
+    def zero() -> "_TerseVector":
         '''Return a zero vector.'''
         return _TerseVector(0.0, 0.0, 0.0)
 
-    def ToAstroVector(self, time):
+    def ToAstroVector(self, time: Time) -> Vector:
         '''Convert _TerseVector object to Vector object.'''
         return Vector(self.x, self.y, self.z, time)
 
-    def quadrature(self):
+    def quadrature(self) -> float:
         '''Return magnitude squared of this vector.'''
         return self.x**2 + self.y**2 + self.z**2
 
-    def mean(self, other):
+    def mean(self, other: "_TerseVector") -> "_TerseVector":
         '''Return the average of this vector and another vector.'''
         return _TerseVector((self.x + other.x)/2.0, (self.y + other.y)/2.0, (self.z + other.z)/2.0)
 
-    def __add__(self, other):
+    def __add__(self, other: "_TerseVector") -> "_TerseVector":
         return _TerseVector(self.x + other.x, self.y + other.y, self.z + other.z)
 
-    def __sub__(self, other):
+    def __sub__(self, other: "_TerseVector") -> "_TerseVector":
         return _TerseVector(self.x - other.x, self.y - other.y, self.z - other.z)
 
-    def __mul__(self, scalar):
+    def __mul__(self, scalar: float) -> "_TerseVector":
         return _TerseVector(scalar * self.x, scalar * self.y, scalar * self.z)
 
-    def __rmul__(self, scalar):
+    def __rmul__(self, scalar: float) -> "_TerseVector":
         return _TerseVector(scalar * self.x, scalar * self.y, scalar * self.z)
 
-    def __truediv__(self, scalar):
+    def __truediv__(self, scalar: float) -> "_TerseVector":
         return _TerseVector(self.x / scalar, self.y / scalar, self.z / scalar)
 
 
@@ -2184,13 +2188,13 @@ class JupiterMoonsInfo:
     callisto : StateVector
         The position and velocity of Jupiter's moon Callisto.
     """
-    def __init__(self, moon):
+    def __init__(self, moon: List[StateVector]) -> None:
         self.io = moon[0]
         self.europa = moon[1]
         self.ganymede = moon[2]
         self.callisto = moon[3]
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'JupiterMoonsInfo(io={}, europa={}, ganymede={}, callisto={})'.format(
             repr(self.io),
             repr(self.europa),
@@ -2276,7 +2280,7 @@ def _CalcJupiterMoon(time, mu, al0, al1, a, l, z, zeta):
     return RotateState(_Rotation_JUP_EQJ, state)
 
 
-def JupiterMoons(time):
+def JupiterMoons(time: Time) -> JupiterMoonsInfo:
     """Calculates jovicentric positions and velocities of Jupiter's largest 4 moons.
 
     Calculates position and velocity vectors for Jupiter's moons
@@ -2346,7 +2350,7 @@ def _QuadInterp(tm, dt, fa, fm, fb):
     df_dt = (2*Q*x + R) / dt
     return (t, df_dt)
 
-def Search(func, context, t1, t2, dt_tolerance_seconds):
+def Search(func: Callable[[object, Time], float], context: object, t1: Time, t2: Time, dt_tolerance_seconds: float) -> Optional[Time]:
     """Searches for a time at which a function's value increases through zero.
 
     Certain astronomy calculations involve finding a time when an event occurs.
@@ -2494,7 +2498,7 @@ def Search(func, context, t1, t2, dt_tolerance_seconds):
 #----------------------------------------------------------------------------
 
 
-def HelioVector(body, time):
+def HelioVector(body: Body, time: Time) -> Vector:
     """Calculates heliocentric Cartesian coordinates of a body in the J2000 equatorial system.
 
     This function calculates the position of the given celestial body as a vector,
@@ -2553,7 +2557,7 @@ def HelioVector(body, time):
     raise InvalidBodyError(body)
 
 
-def HelioDistance(body, time):
+def HelioDistance(body: Body, time: Time) -> float:
     """Calculates the distance between a body and the Sun at a given time.
 
     Given a date and time, this function calculates the distance between
@@ -2602,11 +2606,11 @@ class PositionFunction(abc.ABC):
     specified time. It is passed an instance of `PositionFunction`
     that expresses a relative position vector function.
     """
-    def __init__(self):
+    def __init__(self) -> None:
         pass
 
     @abc.abstractmethod
-    def Position(self, time):
+    def Position(self, time: Time) -> Vector:
         """Returns a relative position vector for a given time.
 
         Parameters
@@ -2619,7 +2623,7 @@ def Position(self, time):
         Vector
         """
 
-def CorrectLightTravel(func, time):
+def CorrectLightTravel(func: PositionFunction, time: Time) -> Vector:
     """Solve for light travel time of a vector function.
 
     When observing a distant object, for example Jupiter as seen from Earth,
@@ -2670,14 +2674,14 @@ def CorrectLightTravel(func, time):
 
 
 class _BodyPosition(PositionFunction):
-    def __init__(self, observerBody, targetBody, aberration, observerPos):
+    def __init__(self, observerBody: Body, targetBody: Body, aberration: bool, observerPos) -> None:
         super().__init__()
         self.observerBody = observerBody
         self.targetBody = targetBody
         self.aberration = aberration
         self.observerPos = observerPos
 
-    def Position(self, time):
+    def Position(self, time: Time) -> Vector:
         if self.aberration:
             # The following discussion is worded with the observer body being the Earth,
             # which is often the case. However, the same reasoning applies to any observer body
@@ -2703,7 +2707,7 @@ def Position(self, time):
         return HelioVector(self.targetBody, time) - observerPos
 
 
-def BackdatePosition(time, observerBody, targetBody, aberration):
+def BackdatePosition(time: Time, observerBody: Body, targetBody: Body, aberration: bool) -> Vector:
     """Solve for light travel time correction of apparent position.
 
     When observing a distant object, for example Jupiter as seen from Earth,
@@ -2771,7 +2775,7 @@ def BackdatePosition(time, observerBody, targetBody, aberration):
     return CorrectLightTravel(func, time)
 
 
-def GeoVector(body, time, aberration):
+def GeoVector(body: Body, time: Time, aberration: bool) -> Vector:
     """Calculates geocentric Cartesian coordinates of a body in the J2000 equatorial system.
 
     This function calculates the position of the given celestial body as a vector,
@@ -2818,7 +2822,7 @@ def GeoVector(body, time, aberration):
     return vec
 
 
-def _ExportState(terse, time):
+def _ExportState(terse, time: Time) -> StateVector:
     return StateVector(
         terse.r.x, terse.r.y, terse.r.z,
         terse.v.x, terse.v.y, terse.v.z,
@@ -2826,7 +2830,7 @@ def _ExportState(terse, time):
     )
 
 
-def BaryState(body, time):
+def BaryState(body: Body, time: Time) -> StateVector:
     """Calculates barycentric position and velocity vectors for the given body.
 
     Given a body and a time, calculates the barycentric position and velocity
@@ -2904,7 +2908,7 @@ def BaryState(body, time):
     raise InvalidBodyError(body)
 
 
-def HelioState(body, time):
+def HelioState(body: Body, time: Time) -> StateVector:
     """Calculates heliocentric position and velocity vectors for the given body.
 
     Given a body and a time, calculates the position and velocity
@@ -2978,7 +2982,7 @@ def HelioState(body, time):
     raise InvalidBodyError(body)
 
 
-def Equator(body, time, observer, ofdate, aberration):
+def Equator(body: Body, time: Time, observer: Observer, ofdate: bool, aberration: bool) -> Equatorial:
     """Calculates equatorial coordinates of a celestial body as seen by an observer on the Earth's surface.
 
     Calculates topocentric equatorial coordinates in one of two different systems:
@@ -3031,7 +3035,7 @@ def Equator(body, time, observer, ofdate, aberration):
     return _vector2radec(datevect, time)
 
 
-def ObserverVector(time, observer, ofdate):
+def ObserverVector(time: Time, observer: Observer, ofdate: bool) -> Vector:
     """Calculates geocentric equatorial coordinates of an observer on the surface of the Earth.
 
     This function calculates a vector from the center of the Earth to
@@ -3075,7 +3079,7 @@ def ObserverVector(time, observer, ofdate):
         ovec = _precession(ovec, time, _PrecessDir.Into2000)
     return Vector(ovec[0], ovec[1], ovec[2], time)
 
-def ObserverState(time, observer, ofdate):
+def ObserverState(time: Time, observer: Observer, ofdate: bool) -> StateVector:
     """Calculates geocentric equatorial position and velocity of an observer on the surface of the Earth.
 
     This function calculates position and velocity vectors of an observer
@@ -3122,7 +3126,7 @@ def ObserverState(time, observer, ofdate):
         state = _precession_posvel(state, time, _PrecessDir.Into2000)
     return state
 
-def VectorObserver(vector, ofdate):
+def VectorObserver(vector: Vector, ofdate: bool) -> Observer:
     """Calculates the geographic location corresponding to an equatorial vector.
 
     This is the inverse function of #ObserverVector.
@@ -3155,7 +3159,7 @@ def VectorObserver(vector, ofdate):
         ovec = _nutation(ovec, vector.t, _PrecessDir.From2000)
     return _inverse_terra(ovec, gast)
 
-def ObserverGravity(latitude, height):
+def ObserverGravity(latitude: float, height: float) -> float:
     """Calculates the gravitational acceleration experienced by an observer on the Earth.
 
     This function implements the WGS 84 Ellipsoidal Gravity Formula.
@@ -3225,13 +3229,13 @@ class HorizontalCoordinates:
     dec : float
         The declination in degrees.
     """
-    def __init__(self, azimuth, altitude, ra, dec):
+    def __init__(self, azimuth: float, altitude: float, ra: float, dec: float) -> None:
         self.azimuth = azimuth
         self.altitude = altitude
         self.ra = ra
         self.dec = dec
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'HorizontalCoordinates(azimuth={}, altitude={}, ra={}, dec={})'.format(
             self.azimuth,
             self.altitude,
@@ -3239,7 +3243,7 @@ def __repr__(self):
             self.dec
         )
 
-def Horizon(time, observer, ra, dec, refraction):
+def Horizon(time: Time, observer: Observer, ra: float, dec: float, refraction: Refraction) -> HorizontalCoordinates:
     """Calculates the apparent location of a body relative to the local horizon of an observer on the Earth.
 
     Given a date and time, the geographic location of an observer on the Earth, and
@@ -3402,7 +3406,7 @@ def Horizon(time, observer, ra, dec, refraction):
 
     return HorizontalCoordinates(az, 90.0 - zd, hor_ra, hor_dec)
 
-def RefractionAngle(refraction, altitude):
+def RefractionAngle(refraction: Refraction, altitude: float) -> float:
     """Calculates the amount of "lift" to an altitude angle caused by atmospheric refraction.
 
     Given an altitude angle and a refraction option, calculates
@@ -3458,7 +3462,7 @@ def RefractionAngle(refraction, altitude):
         raise Error('Inalid refraction option')
     return refr
 
-def InverseRefractionAngle(refraction, bent_altitude):
+def InverseRefractionAngle(refraction: Refraction, bent_altitude: float) -> float:
     """Calculates the inverse of an atmospheric refraction angle.
 
     Given an observed altitude angle that includes atmospheric refraction,
@@ -3512,12 +3516,12 @@ class EclipticCoordinates:
     elon : float
         Longitude in degrees around the ecliptic plane prograde from the equinox.
     """
-    def __init__(self, vec, elat, elon):
+    def __init__(self, vec: Vector, elat: float, elon: float) -> None:
         self.vec = vec
         self.elat = elat
         self.elon = elon
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'EclipticCoordinates({}, elat={}, elon={})'.format(repr(self.vec), self.elat, self.elon)
 
 def _RotateEquatorialToEcliptic(pos, obliq_radians, time):
@@ -3537,7 +3541,7 @@ def _RotateEquatorialToEcliptic(pos, obliq_radians, time):
     vec = Vector(ex, ey, ez, time)
     return EclipticCoordinates(vec, elat, elon)
 
-def SunPosition(time):
+def SunPosition(time: Time) -> EclipticCoordinates:
     """Calculates geocentric ecliptic coordinates for the Sun.
 
     This function calculates the position of the Sun as seen from the Earth.
@@ -3579,7 +3583,7 @@ def SunPosition(time):
     true_obliq = math.radians(adjusted_time._etilt().tobl)
     return _RotateEquatorialToEcliptic(sun_ofdate, true_obliq, time)
 
-def Ecliptic(eqj):
+def Ecliptic(eqj: Vector) -> EclipticCoordinates:
     """Converts a J2000 mean equator (EQJ) vector to a true ecliptic of date (ETC) vector and angles.
 
     Given coordinates relative to the Earth's equator at J2000 (the instant of noon UTC
@@ -3588,7 +3592,7 @@ def Ecliptic(eqj):
 
     Parameters
     ----------
-    eqj : Equatorial
+    eqj : Vector
         Equatorial coordinates in the J2000 frame of reference.
         You can call #GeoVector to obtain suitable equatorial coordinates.
 
@@ -3610,7 +3614,7 @@ def Ecliptic(eqj):
     return _RotateEquatorialToEcliptic(eqd_pos, math.radians(et.tobl), eqj.t)
 
 
-def EclipticLongitude(body, time):
+def EclipticLongitude(body: Body, time: Time) -> float:
     """Calculates heliocentric ecliptic longitude of a body.
 
     This function calculates the angle around the plane of the Earth's orbit
@@ -3636,7 +3640,7 @@ def EclipticLongitude(body, time):
     eclip = Ecliptic(hv)
     return eclip.elon
 
-def AngleFromSun(body, time):
+def AngleFromSun(body: Body, time: Time) -> float:
     """Returns the angle between the given body and the Sun, as seen from the Earth.
 
     This function calculates the angular separation between the given body and the Sun,
@@ -3663,7 +3667,7 @@ def AngleFromSun(body, time):
     bv = GeoVector(body, time, True)
     return AngleBetween(sv, bv)
 
-def PairLongitude(body1, body2, time):
+def PairLongitude(body1: Body, body2: Body, time: Time) -> float:
     """Returns one body's ecliptic longitude with respect to another, as seen from the Earth.
 
     This function determines where one body appears around the ecliptic plane
@@ -3722,13 +3726,13 @@ class ElongationEvent:
     ecliptic_separation : float
         The difference between the ecliptic longitudes of the body and the Sun, as seen from the Earth.
     """
-    def __init__(self, time, visibility, elongation, ecliptic_separation):
+    def __init__(self, time: Time, visibility: "Visibility", elongation: float, ecliptic_separation: float) -> None:
         self.time = time
         self.visibility = visibility
         self.elongation = elongation
         self.ecliptic_separation = ecliptic_separation
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'ElongationEvent({}, {}, elongation={}, ecliptic_separation={})'.format(
             repr(self.time),
             self.visibility,
@@ -3748,7 +3752,7 @@ class Visibility(enum.Enum):
     Morning = 0
     Evening = 1
 
-def Elongation(body, time):
+def Elongation(body: Body, time: Time) -> ElongationEvent:
     """Determines visibility of a celestial body relative to the Sun, as seen from the Earth.
 
     This function returns an #ElongationEvent object, which provides the following
@@ -3795,7 +3799,7 @@ def _rlon_offset(body, time, direction, targetRelLon):
     diff = direction * (elon - plon)
     return _LongitudeOffset(diff - targetRelLon)
 
-def SearchRelativeLongitude(body, targetRelLon, startTime):
+def SearchRelativeLongitude(body: Body, targetRelLon:float, startTime: Time) -> Time:
     """Searches for when the Earth and another planet are separated by a certain ecliptic longitude.
 
     Searches for the time when the Earth and another planet are separated by a specified angle
@@ -3887,7 +3891,7 @@ def _neg_elong_slope(body, time):
     e2 = AngleFromSun(body, t2)
     return (e1 - e2)/dt
 
-def SearchMaxElongation(body, startTime):
+def SearchMaxElongation(body: Body, startTime: Time) -> Optional[ElongationEvent]:
     """Finds a date and time when Mercury or Venus reaches its maximum angle from the Sun as seen from the Earth.
 
     Mercury and Venus are are often difficult to observe because they are closer to the Sun than the Earth is.
@@ -4001,7 +4005,7 @@ def _sun_offset(targetLon, time):
     ecl = SunPosition(time)
     return _LongitudeOffset(ecl.elon - targetLon)
 
-def SearchSunLongitude(targetLon, startTime, limitDays):
+def SearchSunLongitude(targetLon: float, startTime: Time, limitDays: float) -> Optional[Time]:
     """Searches for the time when the Sun reaches an apparent ecliptic longitude as seen from the Earth.
 
     This function finds the moment in time, if any exists in the given time window,
@@ -4038,7 +4042,7 @@ def SearchSunLongitude(targetLon, startTime, limitDays):
     t2 = startTime.AddDays(limitDays)
     return Search(_sun_offset, targetLon, startTime, t2, 0.01)
 
-def MoonPhase(time):
+def MoonPhase(time: Time) -> float:
     """Returns the Moon's phase as an angle from 0 to 360 degrees.
 
     This function determines the phase of the Moon using its apparent
@@ -4065,7 +4069,7 @@ def _moon_offset(targetLon, time):
     angle = MoonPhase(time)
     return _LongitudeOffset(angle - targetLon)
 
-def SearchMoonPhase(targetLon, startTime, limitDays):
+def SearchMoonPhase(targetLon: float, startTime: Time, limitDays: float):
     """Searches for the time that the Moon reaches a specified phase.
 
     Lunar phases are conventionally defined in terms of the Moon's geocentric ecliptic
@@ -4156,7 +4160,7 @@ def __init__(self, quarter, time):
     def __repr__(self):
         return 'MoonQuarter({}, {})'.format(self.quarter, repr(self.time))
 
-def SearchMoonQuarter(startTime):
+def SearchMoonQuarter(startTime: Time) -> MoonQuarter:
     """Finds the first lunar quarter after the specified date and time.
 
     A lunar quarter is one of the following four lunar phase events:
@@ -4184,7 +4188,7 @@ def SearchMoonQuarter(startTime):
         raise InternalError()
     return MoonQuarter(quarter, time)
 
-def NextMoonQuarter(mq):
+def NextMoonQuarter(mq: MoonQuarter) -> MoonQuarter:
     """Continues searching for lunar quarters from a previous search.
 
     After calling #SearchMoonQuarter, this function can be called
@@ -4245,7 +4249,7 @@ class IlluminationInfo:
         as seen from observers on the Earth, and are thus very difficult to see.
         For bodies other than Saturn, `ring_tilt` is `None`.
     """
-    def __init__(self, time, mag, phase, helio_dist, geo_dist, hc, gc, ring_tilt):
+    def __init__(self, time: Time, mag: float, phase: float, helio_dist: float, geo_dist: float, hc: Vector, gc: Vector, ring_tilt: Optional[float]) -> None:
         self.time = time
         self.mag = mag
         self.phase_angle = phase
@@ -4256,7 +4260,7 @@ def __init__(self, time, mag, phase, helio_dist, geo_dist, hc, gc, ring_tilt):
         self.gc = gc
         self.ring_tilt = ring_tilt
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'IlluminationInfo({}, mag={}, phase_angle={}, helio_dist={}, geo_dist={}, hc={}, gc={}, ring_tilt={})'.format(
             repr(self.time),
             self.mag,
@@ -4328,7 +4332,7 @@ def _VisualMagnitude(body, phase, helio_dist, geo_dist):
     mag += 5.0 * math.log10(helio_dist * geo_dist)
     return mag
 
-def Illumination(body, time):
+def Illumination(body: Body, time: Time) -> IlluminationInfo:
     """Finds visual magnitude, phase angle, and other illumination information about a celestial body.
 
     This function calculates information about how bright a celestial body appears from the Earth,
@@ -4404,7 +4408,7 @@ def _mag_slope(body, time):
     y2 = Illumination(body, t2)
     return (y2.mag - y1.mag) / dt
 
-def SearchPeakMagnitude(body, startTime):
+def SearchPeakMagnitude(body: Body, startTime: Time) -> IlluminationInfo:
     """Searches for the date and time Venus will next appear brightest as seen from the Earth.
 
     This function searches for the date and time Venus appears brightest as seen from the Earth.
@@ -4522,14 +4526,14 @@ class HourAngleEvent:
     hor : HorizontalCoordinates
         Apparent coordinates of the body at the time it crosses the specified hour angle.
     """
-    def __init__(self, time, hor):
+    def __init__(self, time: Time, hor: HorizontalCoordinates):
         self.time = time
         self.hor = hor
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'HourAngleEvent({}, {})'.format(repr(self.time), repr(self.hor))
 
-def SearchHourAngle(body, observer, hourAngle, startTime, direction = +1):
+def SearchHourAngle(body: Body, observer: Observer, hourAngle: float, startTime: Time, direction: int = +1) -> HourAngleEvent:
     """Searches for the time when the center of a body reaches a specified hour angle as seen by an observer on the Earth.
 
     The *hour angle* of a celestial body indicates its position in the sky with respect
@@ -4623,7 +4627,7 @@ def SearchHourAngle(body, observer, hourAngle, startTime, direction = +1):
         time = time.AddDays(delta_days)
 
 
-def HourAngle(body, time, observer):
+def HourAngle(body: Body, time: Time, observer: Observer) -> float:
     """Finds the hour angle of a body for a given observer and time.
 
     The *hour angle* of a celestial body indicates its position in the sky with respect
@@ -4855,7 +4859,7 @@ def _InternalSearchAltitude(body, observer, direction, startTime, limitDays, bod
             a1 = a2
 
 
-def SearchRiseSet(body, observer, direction, startTime, limitDays):
+def SearchRiseSet(body: Body, observer: Observer, direction: Direction, startTime: Time, limitDays: float) -> Optional[Time]:
     """Searches for the next time a celestial body rises or sets as seen by an observer on the Earth.
 
     This function finds the next rise or set time of the Sun, Moon, or planet other than the Earth.
@@ -4916,7 +4920,7 @@ def SearchRiseSet(body, observer, direction, startTime, limitDays):
     return _InternalSearchAltitude(body, observer, direction, startTime, limitDays, bodyRadiusAu, -_REFRACTION_NEAR_HORIZON)
 
 
-def SearchAltitude(body, observer, direction, startTime, limitDays, altitude):
+def SearchAltitude(body: Body, observer: Observer, direction: Direction, startTime: Time, limitDays: float, altitude: float) -> Optional[Time]:
     """Finds the next time the center of a body passes through a given altitude.
 
     Finds when the center of the given body ascends or descends through a given
@@ -4999,13 +5003,13 @@ class SeasonInfo:
     dec_solstice : Time
         The date and time of the December solstice for the specified year.
     """
-    def __init__(self, mar_equinox, jun_solstice, sep_equinox, dec_solstice):
+    def __init__(self, mar_equinox: Time, jun_solstice: Time, sep_equinox: Time, dec_solstice: Time) -> None:
         self.mar_equinox = mar_equinox
         self.jun_solstice = jun_solstice
         self.sep_equinox = sep_equinox
         self.dec_solstice = dec_solstice
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'SeasonInfo(mar_equinox={}, jun_solstice={}, sep_equinox={}, dec_solstice={})'.format(
             repr(self.mar_equinox),
             repr(self.jun_solstice),
@@ -5021,7 +5025,7 @@ def _FindSeasonChange(targetLon, year, month, day):
         raise InternalError()
     return time
 
-def Seasons(year):
+def Seasons(year: int) -> SeasonInfo:
     """Finds both equinoxes and both solstices for a given calendar year.
 
     The changes of seasons are defined by solstices and equinoxes.
@@ -5126,20 +5130,20 @@ class Apsis:
     dist_km : float
         The distance between the centers of the bodies in kilometers.
     """
-    def __init__(self, time, kind, dist_au):
+    def __init__(self, time: Time, kind: ApsisKind, dist_au: float) -> None:
         self.time = time
         self.kind = kind
         self.dist_au = dist_au
         self.dist_km = dist_au * KM_PER_AU
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'Apsis({}, {}, dist_au={})'.format(
             repr(self.time),
             self.kind,
             self.dist_au
         )
 
-def SearchLunarApsis(startTime):
+def SearchLunarApsis(startTime: Time) -> Apsis:
     """Finds the time of the first lunar apogee or perigee after the given time.
 
     Given a date and time to start the search in `startTime`, this function finds
@@ -5206,7 +5210,7 @@ def SearchLunarApsis(startTime):
     raise InternalError()
 
 
-def NextLunarApsis(apsis):
+def NextLunarApsis(apsis: Apsis) -> Apsis:
     """Finds the next lunar perigee or apogee in a series.
 
     This function requires an #Apsis value obtained from a call to
@@ -5245,7 +5249,7 @@ def _planet_distance_slope(context, time):
     return direction * (dist2 - dist1) / dt
 
 
-def SearchPlanetApsis(body, startTime):
+def SearchPlanetApsis(body: Body, startTime: Time) -> Apsis:
     """Finds the next planet perihelion or aphelion, after a given time.
 
     Given a date and time to start the search in `startTime`, this function finds the
@@ -5312,7 +5316,7 @@ def SearchPlanetApsis(body, startTime):
     raise InternalError()   # should have found planet apsis within 2 planet orbits
 
 
-def NextPlanetApsis(body, apsis):
+def NextPlanetApsis(body: Body, apsis: Apsis) -> Apsis:
     """Finds the next planetary perihelion or aphelion event in a series.
 
     This function requires an #Apsis value obtained from a call
@@ -5419,7 +5423,7 @@ def _BruteSearchPlanetApsis(body, startTime):
     raise InternalError()   # failed to find Neptune apsis
 
 
-def VectorFromSphere(sphere, time):
+def VectorFromSphere(sphere: Spherical, time: Time) -> Vector:
     """Converts spherical coordinates to Cartesian coordinates.
 
     Given spherical coordinates and a time at which they are valid,
@@ -5449,7 +5453,7 @@ def VectorFromSphere(sphere, time):
     )
 
 
-def EquatorFromVector(vec):
+def EquatorFromVector(vec: Vector) -> Equatorial:
     """Given an equatorial vector, calculates equatorial angular coordinates.
 
     Parameters
@@ -5466,7 +5470,7 @@ def EquatorFromVector(vec):
     return Equatorial(sphere.lon / 15.0, sphere.lat, sphere.dist, vec)
 
 
-def SphereFromVector(vector):
+def SphereFromVector(vector: Vector) -> Spherical:
     """Converts Cartesian coordinates to spherical coordinates.
 
     Given a Cartesian vector, returns latitude, longitude, and distance.
@@ -5508,7 +5512,7 @@ def _ToggleAzimuthDirection(az):
     return az
 
 
-def VectorFromHorizon(sphere, time, refraction):
+def VectorFromHorizon(sphere: Spherical, time: Time, refraction: Refraction) -> Vector:
     """Given apparent angular horizontal coordinates in `sphere`, calculate horizontal vector.
 
     Parameters
@@ -5535,7 +5539,7 @@ def VectorFromHorizon(sphere, time, refraction):
     return VectorFromSphere(xsphere, time)
 
 
-def HorizonFromVector(vector, refraction):
+def HorizonFromVector(vector: Vector, refraction: Refraction) -> Spherical:
     """Converts Cartesian coordinates to horizontal coordinates.
 
     Given a horizontal Cartesian vector, returns horizontal azimuth and altitude.
@@ -5569,7 +5573,7 @@ def HorizonFromVector(vector, refraction):
     return sphere
 
 
-def InverseRotation(rotation):
+def InverseRotation(rotation: RotationMatrix) -> RotationMatrix:
     """Calculates the inverse of a rotation matrix.
 
     Given a rotation matrix that performs some coordinate transform,
@@ -5592,7 +5596,7 @@ def InverseRotation(rotation):
     ])
 
 
-def CombineRotation(a, b):
+def CombineRotation(a: RotationMatrix, b: RotationMatrix) -> RotationMatrix:
     """Creates a rotation based on applying one rotation followed by another.
 
     Given two rotation matrices, returns a combined rotation matrix that is
@@ -5635,7 +5639,7 @@ def CombineRotation(a, b):
     ])
 
 
-def IdentityMatrix():
+def IdentityMatrix() -> RotationMatrix:
     """Creates an identity rotation matrix.
 
     Returns a rotation matrix that has no effect on orientation.
@@ -5655,7 +5659,7 @@ def IdentityMatrix():
     ])
 
 
-def Pivot(rotation, axis, angle):
+def Pivot(rotation: RotationMatrix, axis: int, angle: float) -> RotationMatrix:
     """Re-orients a rotation matrix by pivoting it by an angle around one of its axes.
 
     Given a rotation matrix, a selected coordinate axis, and an angle in degrees,
@@ -5703,7 +5707,7 @@ def Pivot(rotation, axis, angle):
     j = (axis + 2) % 3
     k = axis
 
-    rot = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
+    rot: List[List[float]] = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
 
     rot[i][i] = c*rotation.rot[i][i] - s*rotation.rot[i][j]
     rot[i][j] = s*rotation.rot[i][i] + c*rotation.rot[i][j]
@@ -5720,7 +5724,7 @@ def Pivot(rotation, axis, angle):
     return RotationMatrix(rot)
 
 
-def RotateVector(rotation, vector):
+def RotateVector(rotation: RotationMatrix, vector: Vector) -> Vector:
     """Applies a rotation to a vector, yielding a rotated vector.
 
     This function transforms a vector in one orientation to a vector
@@ -5746,7 +5750,7 @@ def RotateVector(rotation, vector):
     )
 
 
-def RotateState(rotation, state):
+def RotateState(rotation: RotationMatrix, state: StateVector) -> StateVector:
     """Applies a rotation to a state vector, yielding a rotated state vector.
 
     This function transforms a state vector in one orientation to a
@@ -5776,7 +5780,7 @@ def RotateState(rotation, state):
     )
 
 
-def Rotation_EQJ_ECL():
+def Rotation_EQJ_ECL() -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean equator (EQJ) to J2000 mean ecliptic (ECL).
 
     This is one of the family of functions that returns a rotation matrix
@@ -5799,7 +5803,7 @@ def Rotation_EQJ_ECL():
     ])
 
 
-def Rotation_ECL_EQJ():
+def Rotation_ECL_EQJ() -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean ecliptic (ECL) to J2000 mean equator (EQJ).
 
     This is one of the family of functions that returns a rotation matrix
@@ -5821,7 +5825,7 @@ def Rotation_ECL_EQJ():
         [ 0, -s, +c]
     ])
 
-def Rotation_EQJ_EQD(time):
+def Rotation_EQJ_EQD(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean equator (EQJ) to equatorial of-date (EQD).
 
     This is one of the family of functions that returns a rotation matrix
@@ -5844,7 +5848,7 @@ def Rotation_EQJ_EQD(time):
     return CombineRotation(prec, nut)
 
 
-def Rotation_EQJ_ECT(time):
+def Rotation_EQJ_ECT(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean equator (EQJ) to true ecliptic of date (ECT).
 
     This is one of the family of functions that returns a rotation matrix
@@ -5867,7 +5871,7 @@ def Rotation_EQJ_ECT(time):
     return CombineRotation(rot, step)
 
 
-def Rotation_ECT_EQJ(time):
+def Rotation_ECT_EQJ(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from true ecliptic of date (ECT) to J2000 mean equator (EQJ).
 
     This is one of the family of functions that returns a rotation matrix
@@ -5890,7 +5894,7 @@ def Rotation_ECT_EQJ(time):
     return CombineRotation(rot, step)
 
 
-def Rotation_EQD_EQJ(time):
+def Rotation_EQD_EQJ(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from equatorial of-date (EQD) to J2000 mean equator (EQJ).
 
     This is one of the family of functions that returns a rotation matrix
@@ -5913,7 +5917,7 @@ def Rotation_EQD_EQJ(time):
     return CombineRotation(nut, prec)
 
 
-def Rotation_EQD_HOR(time, observer):
+def Rotation_EQD_HOR(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from equatorial of-date (EQD) to horizontal (HOR).
 
     This is one of the family of functions that returns a rotation matrix
@@ -5958,7 +5962,7 @@ def Rotation_EQD_HOR(time, observer):
     ])
 
 
-def Rotation_HOR_EQD(time, observer):
+def Rotation_HOR_EQD(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from horizontal (HOR) to equatorial of-date (EQD).
 
     This is one of the family of functions that returns a rotation matrix
@@ -5982,7 +5986,7 @@ def Rotation_HOR_EQD(time, observer):
     return InverseRotation(rot)
 
 
-def Rotation_HOR_EQJ(time, observer):
+def Rotation_HOR_EQJ(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from horizontal (HOR) to J2000 equatorial (EQJ).
 
     This is one of the family of functions that returns a rotation matrix
@@ -6007,7 +6011,7 @@ def Rotation_HOR_EQJ(time, observer):
     return CombineRotation(hor_eqd, eqd_eqj)
 
 
-def Rotation_EQJ_HOR(time, observer):
+def Rotation_EQJ_HOR(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean equator (EQJ) to horizontal (HOR).
 
     This is one of the family of functions that returns a rotation matrix
@@ -6038,7 +6042,7 @@ def Rotation_EQJ_HOR(time, observer):
     return InverseRotation(rot)
 
 
-def Rotation_EQD_ECL(time):
+def Rotation_EQD_ECL(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from equatorial of-date (EQD) to J2000 mean ecliptic (ECL).
 
     This is one of the family of functions that returns a rotation matrix
@@ -6061,7 +6065,7 @@ def Rotation_EQD_ECL(time):
     return CombineRotation(eqd_eqj, eqj_ecl)
 
 
-def Rotation_ECL_EQD(time):
+def Rotation_ECL_EQD(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean ecliptic (ECL) to equatorial of-date (EQD).
 
     This is one of the family of functions that returns a rotation matrix
@@ -6083,7 +6087,7 @@ def Rotation_ECL_EQD(time):
     return InverseRotation(rot)
 
 
-def Rotation_ECL_HOR(time, observer):
+def Rotation_ECL_HOR(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean ecliptic (ECL) to horizontal (HOR).
 
     This is one of the family of functions that returns a rotation matrix
@@ -6115,7 +6119,7 @@ def Rotation_ECL_HOR(time, observer):
     return CombineRotation(ecl_eqd, eqd_hor)
 
 
-def Rotation_HOR_ECL(time, observer):
+def Rotation_HOR_ECL(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from horizontal (HOR) to J2000 mean ecliptic (ECL).
 
     This is one of the family of functions that returns a rotation matrix
@@ -6138,7 +6142,7 @@ def Rotation_HOR_ECL(time, observer):
     rot = Rotation_ECL_HOR(time, observer)
     return InverseRotation(rot)
 
-def Rotation_EQJ_GAL():
+def Rotation_EQJ_GAL() -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean equator (EQJ) to galactic (GAL).
 
     This is one of the family of functions that returns a rotation matrix
@@ -6160,7 +6164,7 @@ def Rotation_EQJ_GAL():
         [-0.4838000529948520, +0.7470034631630423, +0.4559861124470794]
     ])
 
-def Rotation_GAL_EQJ():
+def Rotation_GAL_EQJ() -> RotationMatrix:
     """Calculates a rotation matrix from galactic (GAL) to J2000 mean equator (EQJ).
 
     This is one of the family of functions that returns a rotation matrix
@@ -6182,7 +6186,7 @@ def Rotation_GAL_EQJ():
         [-0.8676668813529025, -0.1980677870294097, +0.4559861124470794]
     ])
 
-def Rotation_ECT_EQD(time):
+def Rotation_ECT_EQD(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from true ecliptic of date (ECT) to equator of date (EQD).
 
     This is one of the family of functions that returns a rotation matrix
@@ -6210,7 +6214,7 @@ def Rotation_ECT_EQD(time):
         [0.0,  -s,  +c]
     ])
 
-def Rotation_EQD_ECT(time):
+def Rotation_EQD_ECT(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from equator of date (EQD) to true ecliptic of date (ECT).
 
     This is one of the family of functions that returns a rotation matrix
@@ -6259,13 +6263,13 @@ class ConstellationInfo:
     dec1875 : float
         Declination expressed in B1875 coordinates.
     """
-    def __init__(self, symbol, name, ra1875, dec1875):
+    def __init__(self, symbol: str, name: str, ra1875: float, dec1875: float) -> None:
         self.symbol = symbol
         self.name = name
         self.ra1875 = ra1875
         self.dec1875 = dec1875
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'ConstellationInfo(symbol={}, name={}, ra1875={}, dec1875={})'.format(
             repr(self.symbol),
             repr(self.name),
@@ -6279,7 +6283,7 @@ def __repr__(self):
 $ASTRO_CONSTEL()
 
 
-def Constellation(ra, dec):
+def Constellation(ra: float, dec: float) -> ConstellationInfo:
     """Determines the constellation that contains the given point in the sky.
 
     Given J2000 equatorial (EQJ) coordinates of a point in the sky, determines the
@@ -6526,7 +6530,7 @@ class LunarEclipseInfo:
     sd_total : float
          The semi-duration of the penumbral phase in minutes, or 0.0 if none.
     """
-    def __init__(self, kind, obscuration, peak, sd_penum, sd_partial, sd_total):
+    def __init__(self, kind: EclipseKind, obscuration: float, peak: Time, sd_penum: float, sd_partial: float, sd_total: float) -> None:
         self.kind = kind
         self.obscuration = obscuration
         self.peak = peak
@@ -6534,7 +6538,7 @@ def __init__(self, kind, obscuration, peak, sd_penum, sd_partial, sd_total):
         self.sd_partial = sd_partial
         self.sd_total = sd_total
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'LunarEclipseInfo({}, obscuration={}, peak={}, sd_penum={}, sd_partial={}, sd_total={})'.format(
             self.kind,
             self.obscuration,
@@ -6595,7 +6599,7 @@ class GlobalSolarEclipseInfo:
     longitude : float
         The geographic longitude at the center of the peak eclipse shadow.
     """
-    def __init__(self, kind, obscuration, peak, distance, latitude, longitude):
+    def __init__(self, kind: EclipseKind, obscuration: float, peak: Time, distance: float, latitude: float, longitude: float) -> None:
         self.kind = kind
         self.obscuration = obscuration
         self.peak = peak
@@ -6603,7 +6607,7 @@ def __init__(self, kind, obscuration, peak, distance, latitude, longitude):
         self.latitude = latitude
         self.longitude = longitude
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'GlobalSolarEclipseInfo({}, obscuration={}, peak={}, distance={}, latitude={}, longitude={})'.format(
             self.kind,
             self.obscuration,
@@ -6636,11 +6640,11 @@ class EclipseEvent:
         The angular altitude of the center of the Sun above/below the horizon, at `time`,
         corrected for atmospheric refraction and expressed in degrees.
     """
-    def __init__(self, time, altitude):
+    def __init__(self, time: Time, altitude: float) -> None:
         self.time = time
         self.altitude = altitude
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'EclipseEvent({}, altitude={})'.format(
             repr(self.time),
             self.altitude
@@ -6696,7 +6700,7 @@ class LocalSolarEclipseInfo:
     partial_end : EclipseEvent
         The time and Sun altitude at the end of the eclipse.
     """
-    def __init__(self, kind, obscuration, partial_begin, total_begin, peak, total_end, partial_end):
+    def __init__(self, kind: EclipseKind, obscuration: float, partial_begin: EclipseEvent, total_begin: EclipseEvent, peak: EclipseEvent, total_end: EclipseEvent, partial_end: EclipseEvent) -> None:
         self.kind = kind
         self.obscuration = obscuration
         self.partial_begin = partial_begin
@@ -6705,7 +6709,7 @@ def __init__(self, kind, obscuration, partial_begin, total_begin, peak, total_en
         self.total_end = total_end
         self.partial_end = partial_end
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'LocalSolarEclipseInfo({}, obscuration={}, partial_begin={}, total_begin={}, peak={}, total_end={}, partial_end={})'.format(
             self.kind,
             self.obscuration,
@@ -6964,7 +6968,7 @@ def _SolarEclipseObscuration(hm, lo):
     return min(0.9999, obscuration)
 
 
-def SearchLunarEclipse(startTime):
+def SearchLunarEclipse(startTime: Time) -> LunarEclipseInfo:
     """Searches for a lunar eclipse.
 
     This function finds the first lunar eclipse that occurs after `startTime`.
@@ -7029,7 +7033,7 @@ def SearchLunarEclipse(startTime):
     raise Error('Failed to find lunar eclipse within 12 full moons.')
 
 
-def NextLunarEclipse(prevEclipseTime):
+def NextLunarEclipse(prevEclipseTime: Time) -> LunarEclipseInfo:
     """Searches for the next lunar eclipse in a series.
 
      After using #SearchLunarEclipse to find the first lunar eclipse
@@ -7051,7 +7055,7 @@ def NextLunarEclipse(prevEclipseTime):
     return SearchLunarEclipse(startTime)
 
 
-def SearchGlobalSolarEclipse(startTime):
+def SearchGlobalSolarEclipse(startTime: Time) -> GlobalSolarEclipseInfo:
     """Searches for a solar eclipse visible anywhere on the Earth's surface.
 
     This function finds the first solar eclipse that occurs after `startTime`.
@@ -7098,7 +7102,7 @@ def SearchGlobalSolarEclipse(startTime):
     raise Error('Failed to find solar eclipse within 12 full moons.')
 
 
-def NextGlobalSolarEclipse(prevEclipseTime):
+def NextGlobalSolarEclipse(prevEclipseTime: Time) -> GlobalSolarEclipseInfo:
     """Searches for the next global solar eclipse in a series.
 
     After using #SearchGlobalSolarEclipse to find the first solar eclipse
@@ -7120,7 +7124,7 @@ def NextGlobalSolarEclipse(prevEclipseTime):
     return SearchGlobalSolarEclipse(startTime)
 
 
-def SearchLocalSolarEclipse(startTime, observer):
+def SearchLocalSolarEclipse(startTime: Time, observer: Observer) -> LocalSolarEclipseInfo:
     """Searches for a solar eclipse visible at a specific location on the Earth's surface.
     This function finds the first solar eclipse that occurs after `startTime`.
     A solar eclipse may be partial, annular, or total.
@@ -7175,7 +7179,7 @@ def SearchLocalSolarEclipse(startTime, observer):
         nmtime = newmoon.AddDays(10.0)
 
 
-def NextLocalSolarEclipse(prevEclipseTime, observer):
+def NextLocalSolarEclipse(prevEclipseTime: Time, observer: Observer) -> LocalSolarEclipseInfo:
     """Searches for the next local solar eclipse in a series.
 
     After using #SearchLocalSolarEclipse to find the first solar eclipse
@@ -7223,13 +7227,13 @@ class TransitInfo:
         The minimum angular separation, in arcminutes, between the centers of the Sun and the planet.
         This angle pertains to the time stored in `peak`.
     """
-    def __init__(self, start, peak, finish, separation):
+    def __init__(self, start: Time, peak: Time, finish: Time, separation: float) -> None:
         self.start = start
         self.peak = peak
         self.finish = finish
         self.separation = separation
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'TransitInfo(start={}, peak={}, finish={}, separation={})'.format(
             repr(self.start),
             repr(self.peak),
@@ -7253,7 +7257,7 @@ def _PlanetTransitBoundary(body, planet_radius_km, t1, t2, direction):
     return tx
 
 
-def SearchTransit(body, startTime):
+def SearchTransit(body: Body, startTime: Time) -> TransitInfo:
     """Searches for the first transit of Mercury or Venus after a given date.
 
     Finds the first transit of Mercury or Venus after a specified date.
@@ -7313,7 +7317,7 @@ def SearchTransit(body, startTime):
         search_time = conj.AddDays(10.0)
 
 
-def NextTransit(body, prevTransitTime):
+def NextTransit(body: Body, prevTransitTime: Time) -> TransitInfo:
     """Searches for another transit of Mercury or Venus.
 
     After calling #SearchTransit to find a transit of Mercury or Venus,
@@ -7362,11 +7366,11 @@ class NodeEventInfo:
     time : Time
         The time when the body passes through the ecliptic plane.
     """
-    def __init__(self, kind, time):
+    def __init__(self, kind: NodeEventKind, time: Time) -> None:
         self.kind = kind
         self.time = time
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'NodeEventInfo({}, {})'.format(self.kind, repr(self.time))
 
 _MoonNodeStepDays = +10.0   # a safe number of days to step without missing a Moon node
@@ -7374,7 +7378,7 @@ def __repr__(self):
 def _MoonNodeSearchFunc(direction, time):
     return direction * EclipticGeoMoon(time).lat
 
-def SearchMoonNode(startTime):
+def SearchMoonNode(startTime: Time) -> NodeEventInfo:
     """Searches for a time when the Moon's center crosses through the ecliptic plane.
 
     Searches for the first ascending or descending node of the Moon after `startTime`.
@@ -7414,7 +7418,7 @@ def SearchMoonNode(startTime):
         eclip1 = eclip2
 
 
-def NextMoonNode(prevNode):
+def NextMoonNode(prevNode: NodeEventInfo) -> NodeEventInfo:
     """Searches for the next time when the Moon's center crosses through the ecliptic plane.
 
     Call #SearchMoonNode to find the first of a series of nodes.
@@ -7463,7 +7467,7 @@ class LibrationInfo:
     diam_deg : float
         The apparent angular diameter of the Moon as seen from the center of the Earth.
     """
-    def __init__(self, elat, elon, mlat, mlon, dist_km, diam_deg):
+    def __init__(self, elat: float, elon: float, mlat: float, mlon: float, dist_km: float, diam_deg: float) -> None:
         self.elat = elat
         self.elon = elon
         self.mlat = mlat
@@ -7471,7 +7475,7 @@ def __init__(self, elat, elon, mlat, mlon, dist_km, diam_deg):
         self.dist_km = dist_km
         self.diam_deg = diam_deg
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'LibrationInfo(elat={}, elon={}, mlat={}, mlon={}, dist_km={}, diam_deg={})'.format(
             self.elat,
             self.elon,
@@ -7482,7 +7486,7 @@ def __repr__(self):
         )
 
 
-def Libration(time):
+def Libration(time: Time) -> LibrationInfo:
     """Calculates the Moon's libration angles at a given moment in time.
 
     Libration is an observed back-and-forth wobble of the portion of the
@@ -7642,13 +7646,13 @@ class AxisInfo:
     north : Vector
         A J2000 dimensionless unit vector pointing in the direction of the body's north pole.
     """
-    def __init__(self, ra, dec, spin, north):
+    def __init__(self, ra: float, dec: float, spin: float, north: Vector) -> None:
         self.ra = ra
         self.dec = dec
         self.spin = spin
         self.north = north
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'AxisInfo(ra={}, dec={}, spin={}, north={})'.format(
             self.ra,
             self.dec,
@@ -7678,7 +7682,7 @@ def _EarthRotationAxis(time):
     return AxisInfo(equ.ra, equ.dec, spin, north)
 
 
-def RotationAxis(body, time):
+def RotationAxis(body: Body, time: Time) -> AxisInfo:
     """Calculates information about a body's rotation axis at a given time.
 
     Calculates the orientation of a body's rotation axis, along with
@@ -7879,7 +7883,7 @@ def RotationAxis(body, time):
     return AxisInfo(ra/15.0, dec, w, north)
 
 
-def LagrangePoint(point, time, major_body, minor_body):
+def LagrangePoint(point: int, time: Time, major_body: Body, minor_body: Body) -> StateVector:
     """Calculates one of the 5 Lagrange points for a pair of co-orbiting bodies.
 
     Given a more massive "major" body and a much less massive "minor" body,
@@ -7945,7 +7949,7 @@ def LagrangePoint(point, time, major_body, minor_body):
     )
 
 
-def LagrangePointFast(point, major_state, major_mass, minor_state, minor_mass):
+def LagrangePointFast(point: int, major_state: StateVector, major_mass: float, minor_state: StateVector, minor_mass: float) -> StateVector:
     """Calculates one of the 5 Lagrange points from body masses and state vectors.
 
     Given a more massive "major" body and a much less massive "minor" body,
@@ -8133,7 +8137,7 @@ class GravitySimulator:
     time steps.
     """
 
-    def __init__(self, originBody, time, bodyStates):
+    def __init__(self, originBody: Body, time: "Time", bodyStates: List[StateVector]) -> None:
         """Creates a gravity simulation object.
 
         Parameters
@@ -8172,7 +8176,7 @@ def __init__(self, originBody, time, bodyStates):
 
         # Create a stub list of small body states that we will append to later.
         # We just need the stub to put into `self.curr`
-        smallBodyList = []
+        smallBodyList: List = []
 
         # Calculate the states of the Sun and planets at the initial time.
         largeBodyDict = _CalcSolarSystem(time)
@@ -8203,7 +8207,7 @@ def Time(self):
         """
         return self.curr.time
 
-    def OriginBody(self):
+    def OriginBody(self) -> Body:
         """The origin of the reference frame. See constructor for more info.
 
         Returns
@@ -8212,7 +8216,7 @@ def OriginBody(self):
         """
         return self._originBody
 
-    def Update(self, time):
+    def Update(self, time) -> List[StateVector]:
         """Advances the gravity simulation by a small time step.
 
         Updates the simulation of the user-supplied small bodies
@@ -8312,7 +8316,7 @@ def Update(self, time):
         return bodyStates
 
 
-    def Swap(self):
+    def Swap(self) -> None:
         """Exchange the current time step with the previous time step.
 
         Sometimes it is helpful to "explore" various times near a given
@@ -8338,7 +8342,7 @@ def Swap(self):
         """
         (self.curr, self.prev) = (self.prev, self.curr)
 
-    def SolarSystemBodyState(self, body):
+    def SolarSystemBodyState(self, body: Body) -> StateVector:
         """Get the position and velocity of a Solar System body included in the simulation.
 
         In order to simulate the movement of small bodies through the Solar System,
diff --git a/source/python/README.md b/source/python/README.md
index b10594db..2f2b59f8 100644
--- a/source/python/README.md
+++ b/source/python/README.md
@@ -487,7 +487,7 @@ time steps.
 #### member functions
 
 <a name="GravitySimulator.__init__"></a>
-### GravitySimulator.__init__(self, originBody, time, bodyStates)
+### GravitySimulator.__init__(self, originBody: astronomy.Body, time: 'Time', bodyStates: List[astronomy.StateVector]) -&gt; None
 
 **Creates a gravity simulation object.**
 
@@ -498,14 +498,14 @@ time steps.
 | [`StateVector`](#StateVector)`[]` | `bodyStates` | An array of zero or more initial state vectors (positions and velocities) of the small bodies to be simulated. The caller must know the positions and velocities of the small bodies at an initial moment in time. Their positions and velocities are expressed with respect to `originBody`, using J2000 mean equator orientation (EQJ). Positions are expressed in astronomical units (AU). Velocities are expressed in AU/day. All the times embedded within the state vectors must exactly match `time`, or this constructor will throw an exception. |
 
 <a name="GravitySimulator.OriginBody"></a>
-### GravitySimulator.OriginBody(self)
+### GravitySimulator.OriginBody(self) -&gt; astronomy.Body
 
 **The origin of the reference frame. See constructor for more info.**
 
 **Returns**: [`Body`](#Body)
 
 <a name="GravitySimulator.SolarSystemBodyState"></a>
-### GravitySimulator.SolarSystemBodyState(self, body)
+### GravitySimulator.SolarSystemBodyState(self, body: astronomy.Body) -&gt; astronomy.StateVector
 
 **Get the position and velocity of a Solar System body included in the simulation.**
 
@@ -526,7 +526,7 @@ of the `originBody` parameter that was passed to this object's constructor.
 The state vector of the requested Solar System body.
 
 <a name="GravitySimulator.Swap"></a>
-### GravitySimulator.Swap(self)
+### GravitySimulator.Swap(self) -&gt; None
 
 **Exchange the current time step with the previous time step.**
 
@@ -556,7 +556,7 @@ that has not yet been updated by a call to [`GravitySimulator.Update`](#GravityS
 **Returns**: [`Time`](#Time)
 
 <a name="GravitySimulator.Update"></a>
-### GravitySimulator.Update(self, time)
+### GravitySimulator.Update(self, time) -&gt; List[astronomy.StateVector]
 
 **Advances the gravity simulation by a small time step.**
 
@@ -820,7 +820,7 @@ that expresses a relative position vector function.
 #### member functions
 
 <a name="PositionFunction.Position"></a>
-### PositionFunction.Position(self, time)
+### PositionFunction.Position(self, time: astronomy.Time) -&gt; astronomy.Vector
 
 **Returns a relative position vector for a given time.**
 
@@ -927,7 +927,7 @@ dates and times represented by `Time` objects.
 #### member functions
 
 <a name="Time.AddDays"></a>
-### Time.AddDays(self, days)
+### Time.AddDays(self, days: float) -&gt; 'Time'
 
 **Calculates the sum or difference of a [`Time`](#Time) with a specified real-valued number of days.**
 
@@ -948,7 +948,7 @@ The value of the calling object is not modified. This function creates a brand n
 **Returns**: [`Time`](#Time)
 
 <a name="Time.FromTerrestrialTime"></a>
-### Time.FromTerrestrialTime(tt)
+### Time.FromTerrestrialTime(tt: float) -&gt; 'Time'
 
 **Creates a [`Time`](#Time) object from a Terrestrial Time day value.**
 
@@ -959,7 +959,7 @@ The value of the calling object is not modified. This function creates a brand n
 **Returns**: [`Time`](#Time)
 
 <a name="Time.Make"></a>
-### Time.Make(year, month, day, hour, minute, second)
+### Time.Make(year: int, month: int, day: int, hour: int, minute: int, second: float) -&gt; 'Time'
 
 **Creates a [`Time`](#Time) object from a UTC calendar date and time.**
 
@@ -975,7 +975,7 @@ The value of the calling object is not modified. This function creates a brand n
 **Returns**: [`Time`](#Time)
 
 <a name="Time.Now"></a>
-### Time.Now()
+### Time.Now() -&gt; 'Time'
 
 **Returns the computer's current date and time in the form of a [`Time`](#Time) object.**
 
@@ -987,7 +987,7 @@ calculate current observational conditions.
 **Returns**: [`Time`](#Time)
 
 <a name="Time.Parse"></a>
-### Time.Parse(text)
+### Time.Parse(text: str) -&gt; 'Time'
 
 **Creates a [`Time`](#Time) object from a string of the form 'yyyy-mm-ddThh:mm:ss.sssZ'**
 
@@ -1005,7 +1005,7 @@ and a 'Z' at the end of the time.
 **Returns**: [`Time`](#Time)
 
 <a name="Time.Utc"></a>
-### Time.Utc(self)
+### Time.Utc(self) -&gt; datetime.datetime
 
 **Returns the UTC date and time as a `datetime` object.**
 
@@ -1268,7 +1268,7 @@ Astronomy Engine for everyone! (Thank you in advance from the author.)
 ---
 
 <a name="AngleBetween"></a>
-### AngleBetween(a, b)
+### AngleBetween(a: astronomy.Vector, b: astronomy.Vector) -&gt; float
 
 **Calculates the angle in degrees between two vectors.**
 
@@ -1288,7 +1288,7 @@ The value is in the range [0, 180].
 ---
 
 <a name="AngleFromSun"></a>
-### AngleFromSun(body, time)
+### AngleFromSun(body: astronomy.Body, time: astronomy.Time) -&gt; float
 
 **Returns the angle between the given body and the Sun, as seen from the Earth.**
 
@@ -1308,7 +1308,7 @@ and the specified body as seen from the center of the Earth.
 ---
 
 <a name="BackdatePosition"></a>
-### BackdatePosition(time, observerBody, targetBody, aberration)
+### BackdatePosition(time: astronomy.Time, observerBody: astronomy.Body, targetBody: astronomy.Body, aberration: bool) -&gt; astronomy.Vector
 
 **Solve for light travel time correction of apparent position.**
 
@@ -1340,7 +1340,7 @@ body to arrive at the observer at the observation time.
 ---
 
 <a name="BaryState"></a>
-### BaryState(body, time)
+### BaryState(body: astronomy.Body, time: astronomy.Time) -&gt; astronomy.StateVector
 
 **Calculates barycentric position and velocity vectors for the given body.**
 
@@ -1359,7 +1359,7 @@ An object that contains barycentric position and velocity vectors.
 ---
 
 <a name="BodyCode"></a>
-### BodyCode(name)
+### BodyCode(name: str) -&gt; astronomy.Body
 
 **Finds the Body enumeration value, given the name of a body.**
 
@@ -1380,7 +1380,7 @@ Otherwise, returns `Body.Invalid`.
 ---
 
 <a name="CombineRotation"></a>
-### CombineRotation(a, b)
+### CombineRotation(a: astronomy.RotationMatrix, b: astronomy.RotationMatrix) -&gt; astronomy.RotationMatrix
 
 **Creates a rotation based on applying one rotation followed by another.**
 
@@ -1398,7 +1398,7 @@ The combined rotation matrix.
 ---
 
 <a name="Constellation"></a>
-### Constellation(ra, dec)
+### Constellation(ra: float, dec: float) -&gt; astronomy.ConstellationInfo
 
 **Determines the constellation that contains the given point in the sky.**
 
@@ -1418,7 +1418,7 @@ the converted B1875 (ra,dec) for that point.
 ---
 
 <a name="CorrectLightTravel"></a>
-### CorrectLightTravel(func, time)
+### CorrectLightTravel(func: astronomy.PositionFunction, time: astronomy.Time) -&gt; astronomy.Vector
 
 **Solve for light travel time of a vector function.**
 
@@ -1454,7 +1454,7 @@ body to arrive at the observer at the observation time.
 ---
 
 <a name="DefineStar"></a>
-### DefineStar(body, ra, dec, distanceLightYears)
+### DefineStar(body: astronomy.Body, ra: float, dec: float, distanceLightYears: float) -&gt; None
 
 **Assign equatorial coordinates to a user-defined star.**
 
@@ -1475,7 +1475,7 @@ definition until re-defined by another call to `DefineStar`.
 ---
 
 <a name="DeltaT_EspenakMeeus"></a>
-### DeltaT_EspenakMeeus(ut)
+### DeltaT_EspenakMeeus(ut: float) -&gt; float
 
 **The default Delta T function used by Astronomy Engine.**
 
@@ -1494,7 +1494,7 @@ The estimated difference TT-UT on the given date, expressed in seconds.
 ---
 
 <a name="Ecliptic"></a>
-### Ecliptic(eqj)
+### Ecliptic(eqj: astronomy.Vector) -&gt; astronomy.EclipticCoordinates
 
 **Converts a J2000 mean equator (EQJ) vector to a true ecliptic of date (ETC) vector and angles.**
 
@@ -1504,7 +1504,7 @@ which are relative to the plane of the Earth's orbit around the Sun.
 
 | Type | Parameter | Description |
 | --- | --- | --- |
-| [`Equatorial`](#Equatorial) | `eqj` | Equatorial coordinates in the J2000 frame of reference. You can call [`GeoVector`](#GeoVector) to obtain suitable equatorial coordinates. |
+| [`Vector`](#Vector) | `eqj` | Equatorial coordinates in the J2000 frame of reference. You can call [`GeoVector`](#GeoVector) to obtain suitable equatorial coordinates. |
 
 **Returns**: [`EclipticCoordinates`](#EclipticCoordinates)
 Spherical and vector coordinates expressed in true ecliptic coordinates of date (ECT).
@@ -1512,7 +1512,7 @@ Spherical and vector coordinates expressed in true ecliptic coordinates of date
 ---
 
 <a name="EclipticGeoMoon"></a>
-### EclipticGeoMoon(time)
+### EclipticGeoMoon(time: astronomy.Time) -&gt; astronomy.Spherical
 
 **Calculates spherical ecliptic geocentric position of the Moon.**
 
@@ -1540,7 +1540,7 @@ The Moon's position as a distance, ecliptic latitude, and ecliptic longitude.
 ---
 
 <a name="EclipticLongitude"></a>
-### EclipticLongitude(body, time)
+### EclipticLongitude(body: astronomy.Body, time: astronomy.Time) -&gt; float
 
 **Calculates heliocentric ecliptic longitude of a body.**
 
@@ -1560,7 +1560,7 @@ An angular value in degrees indicating the ecliptic longitude of the body.
 ---
 
 <a name="Elongation"></a>
-### Elongation(body, time)
+### Elongation(body: astronomy.Body, time: astronomy.Time) -&gt; astronomy.ElongationEvent
 
 **Determines visibility of a celestial body relative to the Sun, as seen from the Earth.**
 
@@ -1588,7 +1588,7 @@ information about the given celestial body at the given time:
 ---
 
 <a name="Equator"></a>
-### Equator(body, time, observer, ofdate, aberration)
+### Equator(body: astronomy.Body, time: astronomy.Time, observer: astronomy.Observer, ofdate: bool, aberration: bool) -&gt; astronomy.Equatorial
 
 **Calculates equatorial coordinates of a celestial body as seen by an observer on the Earth's surface.**
 
@@ -1617,7 +1617,7 @@ Equatorial coordinates in the specified frame of reference.
 ---
 
 <a name="EquatorFromVector"></a>
-### EquatorFromVector(vec)
+### EquatorFromVector(vec: astronomy.Vector) -&gt; astronomy.Equatorial
 
 **Given an equatorial vector, calculates equatorial angular coordinates.**
 
@@ -1631,7 +1631,7 @@ Angular coordinates expressed in the same equatorial system as `vec`.
 ---
 
 <a name="GeoEmbState"></a>
-### GeoEmbState(time)
+### GeoEmbState(time: astronomy.Time) -&gt; astronomy.StateVector
 
 **Calculates the geocentric position and velocity of the Earth/Moon barycenter.**
 
@@ -1650,7 +1650,7 @@ The EMB's position and velocity vectors in J2000 equatorial coordinates.
 ---
 
 <a name="GeoMoon"></a>
-### GeoMoon(time)
+### GeoMoon(time: astronomy.Time) -&gt; astronomy.Vector
 
 **Calculates equatorial geocentric position of the Moon at a given time.**
 
@@ -1675,7 +1675,7 @@ The Moon's position as a vector in J2000 Cartesian equatorial coordinates (EQJ).
 ---
 
 <a name="GeoMoonState"></a>
-### GeoMoonState(time)
+### GeoMoonState(time: astronomy.Time) -&gt; astronomy.StateVector
 
 **Calculates equatorial geocentric position and velocity of the Moon at a given time.**
 
@@ -1698,7 +1698,7 @@ The Moon's position and velocity vectors in J2000 equatorial coordinates (EQJ).
 ---
 
 <a name="GeoVector"></a>
-### GeoVector(body, time, aberration)
+### GeoVector(body: astronomy.Body, time: astronomy.Time, aberration: bool) -&gt; astronomy.Vector
 
 **Calculates geocentric Cartesian coordinates of a body in the J2000 equatorial system.**
 
@@ -1727,7 +1727,7 @@ A geocentric position vector of the center of the given body.
 ---
 
 <a name="HelioDistance"></a>
-### HelioDistance(body, time)
+### HelioDistance(body: astronomy.Body, time: astronomy.Time) -&gt; float
 
 **Calculates the distance between a body and the Sun at a given time.**
 
@@ -1748,7 +1748,7 @@ The heliocentric distance in AU.
 ---
 
 <a name="HelioState"></a>
-### HelioState(body, time)
+### HelioState(body: astronomy.Body, time: astronomy.Time) -&gt; astronomy.StateVector
 
 **Calculates heliocentric position and velocity vectors for the given body.**
 
@@ -1773,7 +1773,7 @@ An object that contains heliocentric position and velocity vectors.
 ---
 
 <a name="HelioVector"></a>
-### HelioVector(body, time)
+### HelioVector(body: astronomy.Body, time: astronomy.Time) -&gt; astronomy.Vector
 
 **Calculates heliocentric Cartesian coordinates of a body in the J2000 equatorial system.**
 
@@ -1797,7 +1797,7 @@ at the given time.
 ---
 
 <a name="Horizon"></a>
-### Horizon(time, observer, ra, dec, refraction)
+### Horizon(time: astronomy.Time, observer: astronomy.Observer, ra: float, dec: float, refraction: astronomy.Refraction) -&gt; astronomy.HorizontalCoordinates
 
 **Calculates the apparent location of a body relative to the local horizon of an observer on the Earth.**
 
@@ -1839,7 +1839,7 @@ for more details.
 ---
 
 <a name="HorizonFromVector"></a>
-### HorizonFromVector(vector, refraction)
+### HorizonFromVector(vector: astronomy.Vector, refraction: astronomy.Refraction) -&gt; astronomy.Spherical
 
 **Converts Cartesian coordinates to horizontal coordinates.**
 
@@ -1865,7 +1865,7 @@ and is expressed in astronomical units (AU).
 ---
 
 <a name="HourAngle"></a>
-### HourAngle(body, time, observer)
+### HourAngle(body: astronomy.Body, time: astronomy.Time, observer: astronomy.Observer) -&gt; float
 
 **Finds the hour angle of a body for a given observer and time.**
 
@@ -1890,7 +1890,7 @@ The hour angle is a number in the half-open range [0, 24).
 ---
 
 <a name="IdentityMatrix"></a>
-### IdentityMatrix()
+### IdentityMatrix() -&gt; astronomy.RotationMatrix
 
 **Creates an identity rotation matrix.**
 
@@ -1905,7 +1905,7 @@ The identity rotation matrix.
 ---
 
 <a name="Illumination"></a>
-### Illumination(body, time)
+### Illumination(body: astronomy.Body, time: astronomy.Time) -&gt; astronomy.IlluminationInfo
 
 **Finds visual magnitude, phase angle, and other illumination information about a celestial body.**
 
@@ -1935,7 +1935,7 @@ the rings appear edge-on, and are thus nearly invisible from the Earth. The `rin
 ---
 
 <a name="InverseRefractionAngle"></a>
-### InverseRefractionAngle(refraction, bent_altitude)
+### InverseRefractionAngle(refraction: astronomy.Refraction, bent_altitude: float) -&gt; float
 
 **Calculates the inverse of an atmospheric refraction angle.**
 
@@ -1958,7 +1958,7 @@ This will be less than or equal to zero.
 ---
 
 <a name="InverseRotation"></a>
-### InverseRotation(rotation)
+### InverseRotation(rotation: astronomy.RotationMatrix) -&gt; astronomy.RotationMatrix
 
 **Calculates the inverse of a rotation matrix.**
 
@@ -1975,7 +1975,7 @@ The inverse rotation matrix.
 ---
 
 <a name="JupiterMoons"></a>
-### JupiterMoons(time)
+### JupiterMoons(time: astronomy.Time) -&gt; astronomy.JupiterMoonsInfo
 
 **Calculates jovicentric positions and velocities of Jupiter's largest 4 moons.**
 
@@ -2000,7 +2000,7 @@ The positions and velocities of Jupiter's 4 largest moons.
 ---
 
 <a name="LagrangePoint"></a>
-### LagrangePoint(point, time, major_body, minor_body)
+### LagrangePoint(point: int, time: astronomy.Time, major_body: astronomy.Body, minor_body: astronomy.Body) -&gt; astronomy.StateVector
 
 **Calculates one of the 5 Lagrange points for a pair of co-orbiting bodies.**
 
@@ -2039,7 +2039,7 @@ The position and velocity of the selected Lagrange point with respect to the maj
 ---
 
 <a name="LagrangePointFast"></a>
-### LagrangePointFast(point, major_state, major_mass, minor_state, minor_mass)
+### LagrangePointFast(point: int, major_state: astronomy.StateVector, major_mass: float, minor_state: astronomy.StateVector, minor_mass: float) -&gt; astronomy.StateVector
 
 **Calculates one of the 5 Lagrange points from body masses and state vectors.**
 
@@ -2077,7 +2077,7 @@ The position and velocity of the selected Lagrange point with respect to the maj
 ---
 
 <a name="Libration"></a>
-### Libration(time)
+### Libration(time: astronomy.Time) -&gt; astronomy.LibrationInfo
 
 **Calculates the Moon's libration angles at a given moment in time.**
 
@@ -2124,7 +2124,7 @@ The mass product of the given body in au^3/day^2.
 ---
 
 <a name="MoonPhase"></a>
-### MoonPhase(time)
+### MoonPhase(time: astronomy.Time) -&gt; float
 
 **Returns the Moon's phase as an angle from 0 to 360 degrees.**
 
@@ -2145,7 +2145,7 @@ Certain values of the angle have conventional definitions:
 ---
 
 <a name="NextGlobalSolarEclipse"></a>
-### NextGlobalSolarEclipse(prevEclipseTime)
+### NextGlobalSolarEclipse(prevEclipseTime: astronomy.Time) -&gt; astronomy.GlobalSolarEclipseInfo
 
 **Searches for the next global solar eclipse in a series.**
 
@@ -2164,7 +2164,7 @@ to find the next solar eclipse.
 ---
 
 <a name="NextLocalSolarEclipse"></a>
-### NextLocalSolarEclipse(prevEclipseTime, observer)
+### NextLocalSolarEclipse(prevEclipseTime: astronomy.Time, observer: astronomy.Observer) -&gt; astronomy.LocalSolarEclipseInfo
 
 **Searches for the next local solar eclipse in a series.**
 
@@ -2184,7 +2184,7 @@ to find the next solar eclipse.
 ---
 
 <a name="NextLunarApsis"></a>
-### NextLunarApsis(apsis)
+### NextLunarApsis(apsis: astronomy.Apsis) -&gt; astronomy.Apsis
 
 **Finds the next lunar perigee or apogee in a series.**
 
@@ -2203,7 +2203,7 @@ See [`SearchLunarApsis`](#SearchLunarApsis) for more details.
 ---
 
 <a name="NextLunarEclipse"></a>
-### NextLunarEclipse(prevEclipseTime)
+### NextLunarEclipse(prevEclipseTime: astronomy.Time) -&gt; astronomy.LunarEclipseInfo
 
 **Searches for the next lunar eclipse in a series.**
 
@@ -2222,7 +2222,7 @@ See [`SearchLunarApsis`](#SearchLunarApsis) for more details.
 ---
 
 <a name="NextMoonNode"></a>
-### NextMoonNode(prevNode)
+### NextMoonNode(prevNode: astronomy.NodeEventInfo) -&gt; astronomy.NodeEventInfo
 
 **Searches for the next time when the Moon's center crosses through the ecliptic plane.**
 
@@ -2238,7 +2238,7 @@ Then call `NextMoonNode` to find as many more consecutive nodes as desired.
 ---
 
 <a name="NextMoonQuarter"></a>
-### NextMoonQuarter(mq)
+### NextMoonQuarter(mq: astronomy.MoonQuarter) -&gt; astronomy.MoonQuarter
 
 **Continues searching for lunar quarters from a previous search.**
 
@@ -2256,7 +2256,7 @@ the one passed in as the parameter `mq`.
 ---
 
 <a name="NextPlanetApsis"></a>
-### NextPlanetApsis(body, apsis)
+### NextPlanetApsis(body: astronomy.Body, apsis: astronomy.Apsis) -&gt; astronomy.Apsis
 
 **Finds the next planetary perihelion or aphelion event in a series.**
 
@@ -2275,7 +2275,7 @@ See [`SearchPlanetApsis`](#SearchPlanetApsis) for more details.
 ---
 
 <a name="NextTransit"></a>
-### NextTransit(body, prevTransitTime)
+### NextTransit(body: astronomy.Body, prevTransitTime: astronomy.Time) -&gt; astronomy.TransitInfo
 
 **Searches for another transit of Mercury or Venus.**
 
@@ -2293,7 +2293,7 @@ Keep calling this function as many times as you want to keep finding more transi
 ---
 
 <a name="ObserverGravity"></a>
-### ObserverGravity(latitude, height)
+### ObserverGravity(latitude: float, height: float) -&gt; float
 
 **Calculates the gravitational acceleration experienced by an observer on the Earth.**
 
@@ -2317,7 +2317,7 @@ The effective gravitational acceleration expressed in meters per second squared
 ---
 
 <a name="ObserverState"></a>
-### ObserverState(time, observer, ofdate)
+### ObserverState(time: astronomy.Time, observer: astronomy.Observer, ofdate: bool) -&gt; astronomy.StateVector
 
 **Calculates geocentric equatorial position and velocity of an observer on the surface of the Earth.**
 
@@ -2344,7 +2344,7 @@ An equatorial position vector and velocity vector relative to the center of the
 ---
 
 <a name="ObserverVector"></a>
-### ObserverVector(time, observer, ofdate)
+### ObserverVector(time: astronomy.Time, observer: astronomy.Observer, ofdate: bool) -&gt; astronomy.Vector
 
 **Calculates geocentric equatorial coordinates of an observer on the surface of the Earth.**
 
@@ -2372,7 +2372,7 @@ on (or near) the Earth's surface.
 ---
 
 <a name="PairLongitude"></a>
-### PairLongitude(body1, body2, time)
+### PairLongitude(body1: astronomy.Body, body2: astronomy.Body, time: astronomy.Time) -&gt; float
 
 **Returns one body's ecliptic longitude with respect to another, as seen from the Earth.**
 
@@ -2402,7 +2402,7 @@ An angle in degrees in the range [0, 360).
 ---
 
 <a name="Pivot"></a>
-### Pivot(rotation, axis, angle)
+### Pivot(rotation: astronomy.RotationMatrix, axis: int, angle: float) -&gt; astronomy.RotationMatrix
 
 **Re-orients a rotation matrix by pivoting it by an angle around one of its axes.**
 
@@ -2427,7 +2427,7 @@ A pivoted matrix object.
 ---
 
 <a name="PlanetOrbitalPeriod"></a>
-### PlanetOrbitalPeriod(body)
+### PlanetOrbitalPeriod(body: astronomy.Body) -&gt; float
 
 **Returns the average number of days it takes for a planet to orbit the Sun.**
 
@@ -2441,7 +2441,7 @@ The mean orbital period of the body in days.
 ---
 
 <a name="RefractionAngle"></a>
-### RefractionAngle(refraction, altitude)
+### RefractionAngle(refraction: astronomy.Refraction, altitude: float) -&gt; float
 
 **Calculates the amount of "lift" to an altitude angle caused by atmospheric refraction.**
 
@@ -2463,7 +2463,7 @@ option selected by the `refraction` parameter.
 ---
 
 <a name="RotateState"></a>
-### RotateState(rotation, state)
+### RotateState(rotation: astronomy.RotationMatrix, state: astronomy.StateVector) -&gt; astronomy.StateVector
 
 **Applies a rotation to a state vector, yielding a rotated state vector.**
 
@@ -2482,7 +2482,7 @@ A state vector in the orientation specified by `rotation`.
 ---
 
 <a name="RotateVector"></a>
-### RotateVector(rotation, vector)
+### RotateVector(rotation: astronomy.RotationMatrix, vector: astronomy.Vector) -&gt; astronomy.Vector
 
 **Applies a rotation to a vector, yielding a rotated vector.**
 
@@ -2500,7 +2500,7 @@ A vector in the orientation specified by `rotation`.
 ---
 
 <a name="RotationAxis"></a>
-### RotationAxis(body, time)
+### RotationAxis(body: astronomy.Body, time: astronomy.Time) -&gt; astronomy.AxisInfo
 
 **Calculates information about a body's rotation axis at a given time.**
 
@@ -2523,7 +2523,7 @@ The body's north pole direction and angle of its prime meridian.
 ---
 
 <a name="Rotation_ECL_EQD"></a>
-### Rotation_ECL_EQD(time)
+### Rotation_ECL_EQD(time: astronomy.Time) -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from J2000 mean ecliptic (ECL) to equatorial of-date (EQD).**
 
@@ -2542,7 +2542,7 @@ A rotation matrix that converts ECL to EQD.
 ---
 
 <a name="Rotation_ECL_EQJ"></a>
-### Rotation_ECL_EQJ()
+### Rotation_ECL_EQJ() -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from J2000 mean ecliptic (ECL) to J2000 mean equator (EQJ).**
 
@@ -2557,7 +2557,7 @@ A rotation matrix that converts ECL to EQJ.
 ---
 
 <a name="Rotation_ECL_HOR"></a>
-### Rotation_ECL_HOR(time, observer)
+### Rotation_ECL_HOR(time: astronomy.Time, observer: astronomy.Observer) -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from J2000 mean ecliptic (ECL) to horizontal (HOR).**
 
@@ -2583,7 +2583,7 @@ and so that north represents the direction where azimuth = 0.
 ---
 
 <a name="Rotation_ECT_EQD"></a>
-### Rotation_ECT_EQD(time)
+### Rotation_ECT_EQD(time: astronomy.Time) -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from true ecliptic of date (ECT) to equator of date (EQD).**
 
@@ -2602,7 +2602,7 @@ A rotation matrix that converts ECT to EQD.
 ---
 
 <a name="Rotation_ECT_EQJ"></a>
-### Rotation_ECT_EQJ(time)
+### Rotation_ECT_EQJ(time: astronomy.Time) -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from true ecliptic of date (ECT) to J2000 mean equator (EQJ).**
 
@@ -2621,7 +2621,7 @@ A rotation matrix that converts ECT to EQJ at `time`.
 ---
 
 <a name="Rotation_EQD_ECL"></a>
-### Rotation_EQD_ECL(time)
+### Rotation_EQD_ECL(time: astronomy.Time) -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from equatorial of-date (EQD) to J2000 mean ecliptic (ECL).**
 
@@ -2640,7 +2640,7 @@ A rotation matrix that converts EQD to ECL.
 ---
 
 <a name="Rotation_EQD_ECT"></a>
-### Rotation_EQD_ECT(time)
+### Rotation_EQD_ECT(time: astronomy.Time) -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from equator of date (EQD) to true ecliptic of date (ECT).**
 
@@ -2659,7 +2659,7 @@ A rotation matrix that converts EQD to ECT.
 ---
 
 <a name="Rotation_EQD_EQJ"></a>
-### Rotation_EQD_EQJ(time)
+### Rotation_EQD_EQJ(time: astronomy.Time) -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from equatorial of-date (EQD) to J2000 mean equator (EQJ).**
 
@@ -2678,7 +2678,7 @@ A rotation matrix that converts EQD at `time` to EQJ.
 ---
 
 <a name="Rotation_EQD_HOR"></a>
-### Rotation_EQD_HOR(time, observer)
+### Rotation_EQD_HOR(time: astronomy.Time, observer: astronomy.Observer) -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from equatorial of-date (EQD) to horizontal (HOR).**
 
@@ -2704,7 +2704,7 @@ and so that north represents the direction where azimuth = 0.
 ---
 
 <a name="Rotation_EQJ_ECL"></a>
-### Rotation_EQJ_ECL()
+### Rotation_EQJ_ECL() -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from J2000 mean equator (EQJ) to J2000 mean ecliptic (ECL).**
 
@@ -2719,7 +2719,7 @@ A rotation matrix that converts EQJ to ECL.
 ---
 
 <a name="Rotation_EQJ_ECT"></a>
-### Rotation_EQJ_ECT(time)
+### Rotation_EQJ_ECT(time: astronomy.Time) -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from J2000 mean equator (EQJ) to true ecliptic of date (ECT).**
 
@@ -2738,7 +2738,7 @@ A rotation matrix that converts EQJ to ECT at `time`.
 ---
 
 <a name="Rotation_EQJ_EQD"></a>
-### Rotation_EQJ_EQD(time)
+### Rotation_EQJ_EQD(time: astronomy.Time) -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from J2000 mean equator (EQJ) to equatorial of-date (EQD).**
 
@@ -2757,7 +2757,7 @@ A rotation matrix that converts EQJ to EQD at `time`.
 ---
 
 <a name="Rotation_EQJ_GAL"></a>
-### Rotation_EQJ_GAL()
+### Rotation_EQJ_GAL() -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from J2000 mean equator (EQJ) to galactic (GAL).**
 
@@ -2772,7 +2772,7 @@ A rotation matrix that converts EQJ to GAL.
 ---
 
 <a name="Rotation_EQJ_HOR"></a>
-### Rotation_EQJ_HOR(time, observer)
+### Rotation_EQJ_HOR(time: astronomy.Time, observer: astronomy.Observer) -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from J2000 mean equator (EQJ) to horizontal (HOR).**
 
@@ -2798,7 +2798,7 @@ and so that north represents the direction where azimuth = 0.
 ---
 
 <a name="Rotation_GAL_EQJ"></a>
-### Rotation_GAL_EQJ()
+### Rotation_GAL_EQJ() -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from galactic (GAL) to J2000 mean equator (EQJ).**
 
@@ -2813,7 +2813,7 @@ A rotation matrix that converts GAL to EQJ.
 ---
 
 <a name="Rotation_HOR_ECL"></a>
-### Rotation_HOR_ECL(time, observer)
+### Rotation_HOR_ECL(time: astronomy.Time, observer: astronomy.Observer) -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from horizontal (HOR) to J2000 mean ecliptic (ECL).**
 
@@ -2833,7 +2833,7 @@ A rotation matrix that converts HOR to ECL.
 ---
 
 <a name="Rotation_HOR_EQD"></a>
-### Rotation_HOR_EQD(time, observer)
+### Rotation_HOR_EQD(time: astronomy.Time, observer: astronomy.Observer) -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from horizontal (HOR) to equatorial of-date (EQD).**
 
@@ -2853,7 +2853,7 @@ A rotation matrix that converts HOR to EQD at `time` and for `observer`.
 ---
 
 <a name="Rotation_HOR_EQJ"></a>
-### Rotation_HOR_EQJ(time, observer)
+### Rotation_HOR_EQJ(time: astronomy.Time, observer: astronomy.Observer) -&gt; astronomy.RotationMatrix
 
 **Calculates a rotation matrix from horizontal (HOR) to J2000 equatorial (EQJ).**
 
@@ -2873,7 +2873,7 @@ A rotation matrix that converts HOR to EQJ at `time` and for `observer`.
 ---
 
 <a name="Search"></a>
-### Search(func, context, t1, t2, dt_tolerance_seconds)
+### Search(func: Callable[[object, astronomy.Time], float], context: object, t1: astronomy.Time, t2: astronomy.Time, dt_tolerance_seconds: float) -&gt; Optional[astronomy.Time]
 
 **Searches for a time at which a function's value increases through zero.**
 
@@ -2930,7 +2930,7 @@ the function returns `None`.
 ---
 
 <a name="SearchAltitude"></a>
-### SearchAltitude(body, observer, direction, startTime, limitDays, altitude)
+### SearchAltitude(body: astronomy.Body, observer: astronomy.Observer, direction: astronomy.Direction, startTime: astronomy.Time, limitDays: float, altitude: float) -&gt; Optional[astronomy.Time]
 
 **Finds the next time the center of a body passes through a given altitude.**
 
@@ -2973,7 +2973,7 @@ this function returns that time. Otherwise, it returns `None`.
 ---
 
 <a name="SearchGlobalSolarEclipse"></a>
-### SearchGlobalSolarEclipse(startTime)
+### SearchGlobalSolarEclipse(startTime: astronomy.Time) -&gt; astronomy.GlobalSolarEclipseInfo
 
 **Searches for a solar eclipse visible anywhere on the Earth's surface.**
 
@@ -2993,7 +2993,7 @@ passing in the `peak` value returned from the previous call.
 ---
 
 <a name="SearchHourAngle"></a>
-### SearchHourAngle(body, observer, hourAngle, startTime, direction=1)
+### SearchHourAngle(body: astronomy.Body, observer: astronomy.Observer, hourAngle: float, startTime: astronomy.Time, direction: int = 1) -&gt; astronomy.HourAngleEvent
 
 **Searches for the time when the center of a body reaches a specified hour angle as seen by an observer on the Earth.**
 
@@ -3028,7 +3028,7 @@ of the body at that time, as seen by the given observer.
 ---
 
 <a name="SearchLocalSolarEclipse"></a>
-### SearchLocalSolarEclipse(startTime, observer)
+### SearchLocalSolarEclipse(startTime: astronomy.Time, observer: astronomy.Observer) -&gt; astronomy.LocalSolarEclipseInfo
 
 Searches for a solar eclipse visible at a specific location on the Earth's surface.
 This function finds the first solar eclipse that occurs after `startTime`.
@@ -3051,7 +3051,7 @@ See [`LocalSolarEclipseInfo`](#LocalSolarEclipseInfo) for more information about
 ---
 
 <a name="SearchLunarApsis"></a>
-### SearchLunarApsis(startTime)
+### SearchLunarApsis(startTime: astronomy.Time) -&gt; astronomy.Apsis
 
 **Finds the time of the first lunar apogee or perigee after the given time.**
 
@@ -3076,7 +3076,7 @@ another call of `NextLunarApsis` as many times as desired.
 ---
 
 <a name="SearchLunarEclipse"></a>
-### SearchLunarEclipse(startTime)
+### SearchLunarEclipse(startTime: astronomy.Time) -&gt; astronomy.LunarEclipseInfo
 
 **Searches for a lunar eclipse.**
 
@@ -3096,7 +3096,7 @@ passing in the `peak` value returned from the previous call.
 ---
 
 <a name="SearchMaxElongation"></a>
-### SearchMaxElongation(body, startTime)
+### SearchMaxElongation(body: astronomy.Body, startTime: astronomy.Time) -&gt; Optional[astronomy.ElongationEvent]
 
 **Finds a date and time when Mercury or Venus reaches its maximum angle from the Sun as seen from the Earth.**
 
@@ -3119,7 +3119,7 @@ observed in the morning or evening. See [`ElongationEvent`](#ElongationEvent) fo
 ---
 
 <a name="SearchMoonNode"></a>
-### SearchMoonNode(startTime)
+### SearchMoonNode(startTime: astronomy.Time) -&gt; astronomy.NodeEventInfo
 
 **Searches for a time when the Moon's center crosses through the ecliptic plane.**
 
@@ -3141,7 +3141,7 @@ Then call [`NextMoonNode`](#NextMoonNode) to find as many more consecutive nodes
 ---
 
 <a name="SearchMoonPhase"></a>
-### SearchMoonPhase(targetLon, startTime, limitDays)
+### SearchMoonPhase(targetLon: float, startTime: astronomy.Time, limitDays: float)
 
 **Searches for the time that the Moon reaches a specified phase.**
 
@@ -3166,7 +3166,7 @@ This function is useful for finding general phase angles outside those four quar
 ---
 
 <a name="SearchMoonQuarter"></a>
-### SearchMoonQuarter(startTime)
+### SearchMoonQuarter(startTime: astronomy.Time) -&gt; astronomy.MoonQuarter
 
 **Finds the first lunar quarter after the specified date and time.**
 
@@ -3186,7 +3186,7 @@ followed by calls to [`NextMoonQuarter`](#NextMoonQuarter) as many times as desi
 ---
 
 <a name="SearchPeakMagnitude"></a>
-### SearchPeakMagnitude(body, startTime)
+### SearchPeakMagnitude(body: astronomy.Body, startTime: astronomy.Time) -&gt; astronomy.IlluminationInfo
 
 **Searches for the date and time Venus will next appear brightest as seen from the Earth.**
 
@@ -3211,7 +3211,7 @@ However, the difference is minor and has little practical value.
 ---
 
 <a name="SearchPlanetApsis"></a>
-### SearchPlanetApsis(body, startTime)
+### SearchPlanetApsis(body: astronomy.Body, startTime: astronomy.Time) -&gt; astronomy.Apsis
 
 **Finds the next planet perihelion or aphelion, after a given time.**
 
@@ -3235,7 +3235,7 @@ into another call of `NextPlanetApsis` as many times as desired.
 ---
 
 <a name="SearchRelativeLongitude"></a>
-### SearchRelativeLongitude(body, targetRelLon, startTime)
+### SearchRelativeLongitude(body: astronomy.Body, targetRelLon: float, startTime: astronomy.Time) -&gt; astronomy.Time
 
 **Searches for when the Earth and another planet are separated by a certain ecliptic longitude.**
 
@@ -3279,7 +3279,7 @@ The date and time of the relative longitude event.
 ---
 
 <a name="SearchRiseSet"></a>
-### SearchRiseSet(body, observer, direction, startTime, limitDays)
+### SearchRiseSet(body: astronomy.Body, observer: astronomy.Observer, direction: astronomy.Direction, startTime: astronomy.Time, limitDays: float) -&gt; Optional[astronomy.Time]
 
 **Searches for the next time a celestial body rises or sets as seen by an observer on the Earth.**
 
@@ -3318,7 +3318,7 @@ this function returns that time. Otherwise, it returns `None`.
 ---
 
 <a name="SearchSunLongitude"></a>
-### SearchSunLongitude(targetLon, startTime, limitDays)
+### SearchSunLongitude(targetLon: float, startTime: astronomy.Time, limitDays: float) -&gt; Optional[astronomy.Time]
 
 **Searches for the time when the Sun reaches an apparent ecliptic longitude as seen from the Earth.**
 
@@ -3343,7 +3343,7 @@ It is recommended to keep the window smaller than 10 days when possible.
 ---
 
 <a name="SearchTransit"></a>
-### SearchTransit(body, startTime)
+### SearchTransit(body: astronomy.Body, startTime: astronomy.Time) -&gt; astronomy.TransitInfo
 
 **Searches for the first transit of Mercury or Venus after a given date.**
 
@@ -3363,7 +3363,7 @@ To continue the search, pass the `finish` time in the returned structure to
 ---
 
 <a name="Seasons"></a>
-### Seasons(year)
+### Seasons(year: int) -&gt; astronomy.SeasonInfo
 
 **Finds both equinoxes and both solstices for a given calendar year.**
 
@@ -3394,7 +3394,7 @@ of winter in the southern hemisphere.
 ---
 
 <a name="SiderealTime"></a>
-### SiderealTime(time)
+### SiderealTime(time: astronomy.Time) -&gt; float
 
 **Calculates Greenwich Apparent Sidereal Time (GAST).**
 
@@ -3423,7 +3423,7 @@ GAST expressed in sidereal hours.
 ---
 
 <a name="SphereFromVector"></a>
-### SphereFromVector(vector)
+### SphereFromVector(vector: astronomy.Vector) -&gt; astronomy.Spherical
 
 **Converts Cartesian coordinates to spherical coordinates.**
 
@@ -3439,7 +3439,7 @@ Spherical coordinates that are equivalent to the given vector.
 ---
 
 <a name="SunPosition"></a>
-### SunPosition(time)
+### SunPosition(time: astronomy.Time) -&gt; astronomy.EclipticCoordinates
 
 **Calculates geocentric ecliptic coordinates for the Sun.**
 
@@ -3466,7 +3466,7 @@ The ecliptic coordinates of the Sun using the Earth's true equator of date.
 ---
 
 <a name="VectorFromHorizon"></a>
-### VectorFromHorizon(sphere, time, refraction)
+### VectorFromHorizon(sphere: astronomy.Spherical, time: astronomy.Time, refraction: astronomy.Refraction) -&gt; astronomy.Vector
 
 **Given apparent angular horizontal coordinates in `sphere`, calculate horizontal vector.**
 
@@ -3482,7 +3482,7 @@ A vector in the horizontal system: `x` = north, `y` = west, and `z` = zenith (up
 ---
 
 <a name="VectorFromSphere"></a>
-### VectorFromSphere(sphere, time)
+### VectorFromSphere(sphere: astronomy.Spherical, time: astronomy.Time) -&gt; astronomy.Vector
 
 **Converts spherical coordinates to Cartesian coordinates.**
 
@@ -3501,7 +3501,7 @@ The vector form of the supplied spherical coordinates.
 ---
 
 <a name="VectorObserver"></a>
-### VectorObserver(vector, ofdate)
+### VectorObserver(vector: astronomy.Vector, ofdate: bool) -&gt; astronomy.Observer
 
 **Calculates the geographic location corresponding to an equatorial vector.**
 
diff --git a/source/python/astronomy/astronomy.py b/source/python/astronomy/astronomy.py
index fbd1003d..30f5e1ea 100644
--- a/source/python/astronomy/astronomy.py
+++ b/source/python/astronomy/astronomy.py
@@ -36,7 +36,7 @@
 import enum
 import re
 import abc
-from typing import Union
+from typing import List, Optional, Union, Callable
 
 def _cbrt(x):
     if x < 0.0:
@@ -374,7 +374,7 @@ def _UserDefinedStar(body):
         return star
     return None
 
-def DefineStar(body, ra, dec, distanceLightYears):
+def DefineStar(body: Body, ra: float, dec: float, distanceLightYears: float) -> None:
     """Assign equatorial coordinates to a user-defined star.
 
     Some Astronomy Engine functions allow their `body` parameter to
@@ -413,7 +413,7 @@ def DefineStar(body, ra, dec, distanceLightYears):
     star.dec = dec
     star.dist = distanceLightYears * AU_PER_LY
 
-def BodyCode(name):
+def BodyCode(name: str) -> Body:
     """Finds the Body enumeration value, given the name of a body.
 
     Parameters
@@ -439,7 +439,7 @@ def BodyCode(name):
         return Body.Invalid
     return Body[name]
 
-def _IsSuperiorPlanet(body):
+def _IsSuperiorPlanet(body: Body) -> bool:
     return body in [Body.Mars, Body.Jupiter, Body.Saturn, Body.Uranus, Body.Neptune, Body.Pluto]
 
 _PlanetOrbitalPeriod = [
@@ -456,27 +456,27 @@ def _IsSuperiorPlanet(body):
 
 class Error(Exception):
     """Indicates an error in an astronomical calculation."""
-    def __init__(self, message):
+    def __init__(self, message: str) -> None:
         Exception.__init__(self, message)
 
 class DateTimeFormatError(Error):
     """The syntax of a UTC date/time string was not valid, or it contains invalid values."""
-    def __init__(self, text):
+    def __init__(self, text: str) -> None:
         Error.__init__(self, 'The date/time string is not valid: "{}"'.format(text))
 
 class EarthNotAllowedError(Error):
     """The Earth is not allowed as the celestial body in this calculation."""
-    def __init__(self):
+    def __init__(self) -> None:
         Error.__init__(self, 'The Earth is not allowed as the body.')
 
 class InvalidBodyError(Error):
     """The celestial body is not allowed for this calculation."""
-    def __init__(self, body):
+    def __init__(self, body: Body) -> None:
         Error.__init__(self, 'This body is not valid, or is not supported for this calculation: {}'.format(body))
 
 class BadVectorError(Error):
     """A vector magnitude is too small to have a direction in space."""
-    def __init__(self):
+    def __init__(self) -> None:
         Error.__init__(self, 'Vector is too small to have a direction.')
 
 class InternalError(Error):
@@ -489,7 +489,7 @@ class InternalError(Error):
     of how to reproduce the error. This will help improve the quality of
     Astronomy Engine for everyone! (Thank you in advance from the author.)
     """
-    def __init__(self):
+    def __init__(self) -> None:
         Error.__init__(self, 'Internal error - please report issue, including stack trace, at https://github.com/cosinekitty/astronomy/issues')
 
 class NoConvergeError(Error):
@@ -502,10 +502,10 @@ class NoConvergeError(Error):
     of how to reproduce the error. This will help improve the quality of
     Astronomy Engine for everyone! (Thank you in advance from the author.)
     """
-    def __init__(self):
+    def __init__(self) -> None:
         Error.__init__(self, 'Numeric solver did not converge - please report issue at https://github.com/cosinekitty/astronomy/issues')
 
-def PlanetOrbitalPeriod(body):
+def PlanetOrbitalPeriod(body: Body) -> float:
     """Returns the average number of days it takes for a planet to orbit the Sun.
 
     Parameters
@@ -522,7 +522,7 @@ def PlanetOrbitalPeriod(body):
         return _PlanetOrbitalPeriod[body.value]
     raise InvalidBodyError(body)
 
-def _SynodicPeriod(body):
+def _SynodicPeriod(body: Body) -> float:
     if body == Body.Earth:
         raise EarthNotAllowedError()
     if body.value < 0 or body.value >= len(_PlanetOrbitalPeriod):
@@ -531,7 +531,7 @@ def _SynodicPeriod(body):
         return _MEAN_SYNODIC_MONTH
     return abs(_EARTH_ORBITAL_PERIOD / (_EARTH_ORBITAL_PERIOD/_PlanetOrbitalPeriod[body.value] - 1.0))
 
-def AngleBetween(a, b):
+def AngleBetween(a: Vector, b: Vector) -> float:
     """Calculates the angle in degrees between two vectors.
 
     Given a pair of vectors, this function returns the angle in degrees
@@ -551,10 +551,10 @@ def AngleBetween(a, b):
         The angle between the two vectors expressed in degrees.
         The value is in the range [0, 180].
     """
-    r = a.Length() * b.Length()
+    r: float = a.Length() * b.Length()
     if r < 1.0e-8:
-        return BadVectorError()
-    dot = (a.x*b.x + a.y*b.y + a.z*b.z) / r
+        raise BadVectorError()
+    dot: float = (a.x*b.x + a.y*b.y + a.z*b.z) / r
     if dot <= -1.0:
         return 180.0
     if dot >= +1.0:
@@ -562,7 +562,7 @@ def AngleBetween(a, b):
     return math.degrees(math.acos(dot))
 
 
-def DeltaT_EspenakMeeus(ut):
+def DeltaT_EspenakMeeus(ut: float) -> float:
     """The default Delta T function used by Astronomy Engine.
 
     Espenak and Meeus use a series of piecewise polynomials to
@@ -666,10 +666,10 @@ def DeltaT_EspenakMeeus(ut):
 _DeltaT = DeltaT_EspenakMeeus
 
 
-def _TerrestrialTime(ut):
+def _TerrestrialTime(ut: float) -> float:
     return ut + _DeltaT(ut) / 86400.0
 
-def _UniversalTime(tt):
+def _UniversalTime(tt: float) -> float:
     # This is the inverse function of _TerrestrialTime.
     # This is an iterative numerical solver, but because
     # the relationship between UT and TT is almost perfectly linear,
@@ -729,23 +729,23 @@ class Time:
         such as the orbits of planets around the Sun, or the Moon around the Earth.
         Historically, Terrestrial Time has also been known by the term *Ephemeris Time* (ET).
     """
-    def __init__(self, ut : Union[float, str], tt = None):
+    def __init__(self, ut : Union[float, str], tt: Optional[float] = None):
         if isinstance(ut, str):
             # Undocumented hack, to make repr(time) reversible.
             other = Time.Parse(ut)
-            self.ut = other.ut
-            self.tt = other.tt
+            self.ut: float = other.ut
+            self.tt: float = other.tt
         else:
             self.ut = ut
             if tt is None:
                 self.tt = _TerrestrialTime(ut)
             else:
                 self.tt = tt
-        self._et = None     # lazy-cache for earth tilt
-        self._st = None     # lazy-cache for sidereal time
+        self._et: Optional[float] = None     # lazy-cache for earth tilt
+        self._st: Optional[float] = None     # lazy-cache for sidereal time
 
     @staticmethod
-    def FromTerrestrialTime(tt):
+    def FromTerrestrialTime(tt: float) -> "Time":
         """Creates a #Time object from a Terrestrial Time day value.
 
         Parameters
@@ -760,7 +760,7 @@ def FromTerrestrialTime(tt):
         return Time(_UniversalTime(tt), tt)
 
     @staticmethod
-    def Parse(text):
+    def Parse(text: str) -> "Time":
         """Creates a #Time object from a string of the form 'yyyy-mm-ddThh:mm:ss.sssZ'
 
         Parses a UTC date and time from a string and returns a #Time object.
@@ -805,7 +805,7 @@ def Parse(text):
         return Time.Make(year, month, day, hour, minute, second)
 
     @staticmethod
-    def Make(year, month, day, hour, minute, second):
+    def Make(year: int, month: int, day: int, hour: int, minute: int, second: float) -> "Time":
         """Creates a #Time object from a UTC calendar date and time.
 
         Parameters
@@ -841,7 +841,7 @@ def Make(year, month, day, hour, minute, second):
         return Time(ut)
 
     @staticmethod
-    def Now():
+    def Now() -> "Time":
         """Returns the computer's current date and time in the form of a #Time object.
 
         Uses the computer's system clock to find the current UTC date and time.
@@ -856,7 +856,7 @@ def Now():
         ut = (datetime.datetime.utcnow() - _EPOCH).total_seconds() / 86400.0
         return Time(ut)
 
-    def AddDays(self, days):
+    def AddDays(self, days: float) -> "Time":
         """Calculates the sum or difference of a #Time with a specified real-valued number of days.
 
         Sometimes we need to adjust a given #Time value by a certain amount of time.
@@ -883,10 +883,10 @@ def AddDays(self, days):
         """
         return Time(self.ut + days)
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'Time(\'' + str(self) + '\')'
 
-    def __str__(self):
+    def __str__(self) -> str:
         # Adapted from the NOVAS C 3.1 function cal_date().
         djd = self.ut + 2451545.5
         jd = int(djd)
@@ -924,7 +924,7 @@ def __str__(self):
         text += '-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}.{:03d}Z'.format(month, day, hour, minute, millis // 1000, millis % 1000)
         return text
 
-    def Utc(self):
+    def Utc(self) -> datetime.datetime:
         """Returns the UTC date and time as a `datetime` object.
 
         Uses the standard [`datetime`](https://docs.python.org/3/library/datetime.html) class
@@ -944,22 +944,26 @@ def _etilt(self):
             self._et = _e_tilt(self)
         return self._et
 
-    def __lt__(self, other):
+    def __lt__(self, other: "Time") -> bool:
         return self.tt < other.tt
 
-    def __eq__(self, other):
+    def __eq__(self, other: object) -> bool:
+        if not isinstance(other, Time):
+            return NotImplemented
         return self.tt == other.tt
 
-    def __le__(self, other):
+    def __le__(self, other: "Time") -> bool:
         return self.tt <= other.tt
 
-    def __ne__(self, other):
+    def __ne__(self, other: object) -> bool:
+        if not isinstance(other, Time):
+            return NotImplemented
         return self.tt != other.tt
 
-    def __gt__(self, other):
+    def __gt__(self, other: "Time") -> bool:
         return self.tt > other.tt
 
-    def __ge__(self, other):
+    def __ge__(self, other: "Time") -> bool:
         return self.tt >= other.tt
 
 
@@ -975,15 +979,15 @@ class Observer:
     height : float
         Elevation above sea level in meters.
     """
-    def __init__(self, latitude, longitude, height=0.0):
+    def __init__(self, latitude: float, longitude: float, height: float = 0.0) -> None:
         self.latitude = latitude
         self.longitude = longitude
         self.height = height
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'Observer(latitude={}, longitude={}, height={})'.format(self.latitude, self.longitude, self.height)
 
-    def __str__(self):
+    def __str__(self) -> str:
         text = '('
         text += 'S' if (self.latitude < 0) else 'N'
         text += '{:0.8f}, '.format(abs(self.latitude))
@@ -1002,10 +1006,10 @@ class RotationMatrix:
     rot : float[3][3]
         A normalized 3x3 rotation matrix.
     """
-    def __init__(self, rot):
+    def __init__(self, rot: List[List[float]]) -> None:
         self.rot = rot
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'RotationMatrix({})'.format(self.rot)
 
 class Spherical:
@@ -1020,16 +1024,16 @@ class Spherical:
     dist : float
         Distance in AU.
     """
-    def __init__(self, lat, lon, dist):
+    def __init__(self, lat: float, lon: float, dist: float) -> None:
         self.lat = lat
         self.lon = lon
         self.dist = dist
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'Spherical(lat={}, lon={}, dist={})'.format(self.lat, self.lon, self.dist)
 
 class _iau2000b:
-    def __init__(self, time):
+    def __init__(self, time: Time) -> None:
         t = time.tt / 36525.0
         elp = math.fmod((1287104.79305 + t*129596581.0481),  _ASEC360) * _ASEC2RAD
         f   = math.fmod((335779.526232 + t*1739527262.8478), _ASEC360) * _ASEC2RAD
@@ -1067,7 +1071,7 @@ def __init__(self, time):
         self.dpsi = -0.000135 + (dp * 1.0e-7)
         self.deps = +0.000388 + (de * 1.0e-7)
 
-def _mean_obliq(tt):
+def _mean_obliq(tt: float) -> float:
     t = tt / 36525
     asec = (
         (((( -  0.0000000434   * t
@@ -1079,7 +1083,7 @@ def _mean_obliq(tt):
     return asec / 3600.0
 
 class _e_tilt:
-    def __init__(self, time):
+    def __init__(self, time: Time) -> None:
         e = _iau2000b(time)
         self.dpsi = e.dpsi
         self.deps = e.deps
@@ -1201,17 +1205,17 @@ class Equatorial:
         y = direction of the June solstice,
         z = north.
     """
-    def __init__(self, ra, dec, dist, vec):
+    def __init__(self, ra: float, dec: float, dist: float, vec: Vector) -> None:
         self.ra = ra
         self.dec = dec
         self.dist = dist
         self.vec = vec
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'Equatorial(ra={}, dec={}, dist={}, vec={})'.format(self.ra, self.dec, self.dist, repr(self.vec))
 
 
-def _vector2radec(pos, time):
+def _vector2radec(pos, time: Time) -> Equatorial:
     xyproj = pos[0]*pos[0] + pos[1]*pos[1]
     dist = math.sqrt(xyproj + pos[2]*pos[2])
     if xyproj == 0.0:
@@ -1232,7 +1236,7 @@ def _vector2radec(pos, time):
     return Equatorial(ra, dec, dist, vec)
 
 
-def _nutation_rot(time, direction):
+def _nutation_rot(time: Time, direction) -> RotationMatrix:
     tilt = time._etilt()
     oblm = math.radians(tilt.mobl)
     oblt = math.radians(tilt.tobl)
@@ -1288,7 +1292,7 @@ def _era(time):        # Earth Rotation Angle
         theta += 360.0
     return theta
 
-def SiderealTime(time):
+def SiderealTime(time: Time) -> float:
     """Calculates Greenwich Apparent Sidereal Time (GAST).
 
     Given a date and time, this function calculates the rotation of the
@@ -2235,7 +2239,7 @@ def ADDN(coeffn, p, q, r, s):
         (_ARC * _EARTH_EQUATORIAL_RADIUS_AU) / (0.999953253 * SINPI)
     )
 
-def GeoMoon(time):
+def GeoMoon(time: Time) -> Vector:
     """Calculates equatorial geocentric position of the Moon at a given time.
 
     Given a time of observation, calculates the Moon's position as a vector.
@@ -2278,7 +2282,7 @@ def GeoMoon(time):
     return Vector(mpos2[0], mpos2[1], mpos2[2], time)
 
 
-def EclipticGeoMoon(time):
+def EclipticGeoMoon(time: Time) -> Spherical:
     """Calculates spherical ecliptic geocentric position of the Moon.
 
     Given a time of observation, calculates the Moon's geocentric position
@@ -2336,7 +2340,7 @@ def EclipticGeoMoon(time):
     return Spherical(eclip.elat, eclip.elon, moon.distance_au)
 
 
-def GeoMoonState(time):
+def GeoMoonState(time: Time) -> StateVector:
     """Calculates equatorial geocentric position and velocity of the Moon at a given time.
 
     Given a time of observation, calculates the Moon's position and velocity vectors.
@@ -2378,7 +2382,7 @@ def GeoMoonState(time):
     )
 
 
-def GeoEmbState(time):
+def GeoEmbState(time: Time) -> StateVector:
     """Calculates the geocentric position and velocity of the Earth/Moon barycenter.
 
     Given a time of observation, calculates the geocentric position and velocity vectors
@@ -3265,45 +3269,45 @@ def _CalcEarth(time):
 
 
 class _TerseVector:
-    def __init__(self, x, y, z):
+    def __init__(self, x, y, z) -> None:
         self.x = x
         self.y = y
         self.z = z
 
-    def clone(self):
+    def clone(self) -> "_TerseVector":
         '''Create a copy of this vector.'''
         return _TerseVector(self.x, self.y, self.z)
 
     @staticmethod
-    def zero():
+    def zero() -> "_TerseVector":
         '''Return a zero vector.'''
         return _TerseVector(0.0, 0.0, 0.0)
 
-    def ToAstroVector(self, time):
+    def ToAstroVector(self, time: Time) -> Vector:
         '''Convert _TerseVector object to Vector object.'''
         return Vector(self.x, self.y, self.z, time)
 
-    def quadrature(self):
+    def quadrature(self) -> float:
         '''Return magnitude squared of this vector.'''
         return self.x**2 + self.y**2 + self.z**2
 
-    def mean(self, other):
+    def mean(self, other: "_TerseVector") -> "_TerseVector":
         '''Return the average of this vector and another vector.'''
         return _TerseVector((self.x + other.x)/2.0, (self.y + other.y)/2.0, (self.z + other.z)/2.0)
 
-    def __add__(self, other):
+    def __add__(self, other: "_TerseVector") -> "_TerseVector":
         return _TerseVector(self.x + other.x, self.y + other.y, self.z + other.z)
 
-    def __sub__(self, other):
+    def __sub__(self, other: "_TerseVector") -> "_TerseVector":
         return _TerseVector(self.x - other.x, self.y - other.y, self.z - other.z)
 
-    def __mul__(self, scalar):
+    def __mul__(self, scalar: float) -> "_TerseVector":
         return _TerseVector(scalar * self.x, scalar * self.y, scalar * self.z)
 
-    def __rmul__(self, scalar):
+    def __rmul__(self, scalar: float) -> "_TerseVector":
         return _TerseVector(scalar * self.x, scalar * self.y, scalar * self.z)
 
-    def __truediv__(self, scalar):
+    def __truediv__(self, scalar: float) -> "_TerseVector":
         return _TerseVector(self.x / scalar, self.y / scalar, self.z / scalar)
 
 
@@ -3690,13 +3694,13 @@ class JupiterMoonsInfo:
     callisto : StateVector
         The position and velocity of Jupiter's moon Callisto.
     """
-    def __init__(self, moon):
+    def __init__(self, moon: List[StateVector]) -> None:
         self.io = moon[0]
         self.europa = moon[1]
         self.ganymede = moon[2]
         self.callisto = moon[3]
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'JupiterMoonsInfo(io={}, europa={}, ganymede={}, callisto={})'.format(
             repr(self.io),
             repr(self.europa),
@@ -3782,7 +3786,7 @@ def _CalcJupiterMoon(time, mu, al0, al1, a, l, z, zeta):
     return RotateState(_Rotation_JUP_EQJ, state)
 
 
-def JupiterMoons(time):
+def JupiterMoons(time: Time) -> JupiterMoonsInfo:
     """Calculates jovicentric positions and velocities of Jupiter's largest 4 moons.
 
     Calculates position and velocity vectors for Jupiter's moons
@@ -3852,7 +3856,7 @@ def _QuadInterp(tm, dt, fa, fm, fb):
     df_dt = (2*Q*x + R) / dt
     return (t, df_dt)
 
-def Search(func, context, t1, t2, dt_tolerance_seconds):
+def Search(func: Callable[[object, Time], float], context: object, t1: Time, t2: Time, dt_tolerance_seconds: float) -> Optional[Time]:
     """Searches for a time at which a function's value increases through zero.
 
     Certain astronomy calculations involve finding a time when an event occurs.
@@ -4000,7 +4004,7 @@ def Search(func, context, t1, t2, dt_tolerance_seconds):
 #----------------------------------------------------------------------------
 
 
-def HelioVector(body, time):
+def HelioVector(body: Body, time: Time) -> Vector:
     """Calculates heliocentric Cartesian coordinates of a body in the J2000 equatorial system.
 
     This function calculates the position of the given celestial body as a vector,
@@ -4059,7 +4063,7 @@ def HelioVector(body, time):
     raise InvalidBodyError(body)
 
 
-def HelioDistance(body, time):
+def HelioDistance(body: Body, time: Time) -> float:
     """Calculates the distance between a body and the Sun at a given time.
 
     Given a date and time, this function calculates the distance between
@@ -4108,11 +4112,11 @@ class PositionFunction(abc.ABC):
     specified time. It is passed an instance of `PositionFunction`
     that expresses a relative position vector function.
     """
-    def __init__(self):
+    def __init__(self) -> None:
         pass
 
     @abc.abstractmethod
-    def Position(self, time):
+    def Position(self, time: Time) -> Vector:
         """Returns a relative position vector for a given time.
 
         Parameters
@@ -4125,7 +4129,7 @@ def Position(self, time):
         Vector
         """
 
-def CorrectLightTravel(func, time):
+def CorrectLightTravel(func: PositionFunction, time: Time) -> Vector:
     """Solve for light travel time of a vector function.
 
     When observing a distant object, for example Jupiter as seen from Earth,
@@ -4176,14 +4180,14 @@ def CorrectLightTravel(func, time):
 
 
 class _BodyPosition(PositionFunction):
-    def __init__(self, observerBody, targetBody, aberration, observerPos):
+    def __init__(self, observerBody: Body, targetBody: Body, aberration: bool, observerPos) -> None:
         super().__init__()
         self.observerBody = observerBody
         self.targetBody = targetBody
         self.aberration = aberration
         self.observerPos = observerPos
 
-    def Position(self, time):
+    def Position(self, time: Time) -> Vector:
         if self.aberration:
             # The following discussion is worded with the observer body being the Earth,
             # which is often the case. However, the same reasoning applies to any observer body
@@ -4209,7 +4213,7 @@ def Position(self, time):
         return HelioVector(self.targetBody, time) - observerPos
 
 
-def BackdatePosition(time, observerBody, targetBody, aberration):
+def BackdatePosition(time: Time, observerBody: Body, targetBody: Body, aberration: bool) -> Vector:
     """Solve for light travel time correction of apparent position.
 
     When observing a distant object, for example Jupiter as seen from Earth,
@@ -4277,7 +4281,7 @@ def BackdatePosition(time, observerBody, targetBody, aberration):
     return CorrectLightTravel(func, time)
 
 
-def GeoVector(body, time, aberration):
+def GeoVector(body: Body, time: Time, aberration: bool) -> Vector:
     """Calculates geocentric Cartesian coordinates of a body in the J2000 equatorial system.
 
     This function calculates the position of the given celestial body as a vector,
@@ -4324,7 +4328,7 @@ def GeoVector(body, time, aberration):
     return vec
 
 
-def _ExportState(terse, time):
+def _ExportState(terse, time: Time) -> StateVector:
     return StateVector(
         terse.r.x, terse.r.y, terse.r.z,
         terse.v.x, terse.v.y, terse.v.z,
@@ -4332,7 +4336,7 @@ def _ExportState(terse, time):
     )
 
 
-def BaryState(body, time):
+def BaryState(body: Body, time: Time) -> StateVector:
     """Calculates barycentric position and velocity vectors for the given body.
 
     Given a body and a time, calculates the barycentric position and velocity
@@ -4410,7 +4414,7 @@ def BaryState(body, time):
     raise InvalidBodyError(body)
 
 
-def HelioState(body, time):
+def HelioState(body: Body, time: Time) -> StateVector:
     """Calculates heliocentric position and velocity vectors for the given body.
 
     Given a body and a time, calculates the position and velocity
@@ -4484,7 +4488,7 @@ def HelioState(body, time):
     raise InvalidBodyError(body)
 
 
-def Equator(body, time, observer, ofdate, aberration):
+def Equator(body: Body, time: Time, observer: Observer, ofdate: bool, aberration: bool) -> Equatorial:
     """Calculates equatorial coordinates of a celestial body as seen by an observer on the Earth's surface.
 
     Calculates topocentric equatorial coordinates in one of two different systems:
@@ -4537,7 +4541,7 @@ def Equator(body, time, observer, ofdate, aberration):
     return _vector2radec(datevect, time)
 
 
-def ObserverVector(time, observer, ofdate):
+def ObserverVector(time: Time, observer: Observer, ofdate: bool) -> Vector:
     """Calculates geocentric equatorial coordinates of an observer on the surface of the Earth.
 
     This function calculates a vector from the center of the Earth to
@@ -4581,7 +4585,7 @@ def ObserverVector(time, observer, ofdate):
         ovec = _precession(ovec, time, _PrecessDir.Into2000)
     return Vector(ovec[0], ovec[1], ovec[2], time)
 
-def ObserverState(time, observer, ofdate):
+def ObserverState(time: Time, observer: Observer, ofdate: bool) -> StateVector:
     """Calculates geocentric equatorial position and velocity of an observer on the surface of the Earth.
 
     This function calculates position and velocity vectors of an observer
@@ -4628,7 +4632,7 @@ def ObserverState(time, observer, ofdate):
         state = _precession_posvel(state, time, _PrecessDir.Into2000)
     return state
 
-def VectorObserver(vector, ofdate):
+def VectorObserver(vector: Vector, ofdate: bool) -> Observer:
     """Calculates the geographic location corresponding to an equatorial vector.
 
     This is the inverse function of #ObserverVector.
@@ -4661,7 +4665,7 @@ def VectorObserver(vector, ofdate):
         ovec = _nutation(ovec, vector.t, _PrecessDir.From2000)
     return _inverse_terra(ovec, gast)
 
-def ObserverGravity(latitude, height):
+def ObserverGravity(latitude: float, height: float) -> float:
     """Calculates the gravitational acceleration experienced by an observer on the Earth.
 
     This function implements the WGS 84 Ellipsoidal Gravity Formula.
@@ -4731,13 +4735,13 @@ class HorizontalCoordinates:
     dec : float
         The declination in degrees.
     """
-    def __init__(self, azimuth, altitude, ra, dec):
+    def __init__(self, azimuth: float, altitude: float, ra: float, dec: float) -> None:
         self.azimuth = azimuth
         self.altitude = altitude
         self.ra = ra
         self.dec = dec
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'HorizontalCoordinates(azimuth={}, altitude={}, ra={}, dec={})'.format(
             self.azimuth,
             self.altitude,
@@ -4745,7 +4749,7 @@ def __repr__(self):
             self.dec
         )
 
-def Horizon(time, observer, ra, dec, refraction):
+def Horizon(time: Time, observer: Observer, ra: float, dec: float, refraction: Refraction) -> HorizontalCoordinates:
     """Calculates the apparent location of a body relative to the local horizon of an observer on the Earth.
 
     Given a date and time, the geographic location of an observer on the Earth, and
@@ -4908,7 +4912,7 @@ def Horizon(time, observer, ra, dec, refraction):
 
     return HorizontalCoordinates(az, 90.0 - zd, hor_ra, hor_dec)
 
-def RefractionAngle(refraction, altitude):
+def RefractionAngle(refraction: Refraction, altitude: float) -> float:
     """Calculates the amount of "lift" to an altitude angle caused by atmospheric refraction.
 
     Given an altitude angle and a refraction option, calculates
@@ -4964,7 +4968,7 @@ def RefractionAngle(refraction, altitude):
         raise Error('Inalid refraction option')
     return refr
 
-def InverseRefractionAngle(refraction, bent_altitude):
+def InverseRefractionAngle(refraction: Refraction, bent_altitude: float) -> float:
     """Calculates the inverse of an atmospheric refraction angle.
 
     Given an observed altitude angle that includes atmospheric refraction,
@@ -5018,12 +5022,12 @@ class EclipticCoordinates:
     elon : float
         Longitude in degrees around the ecliptic plane prograde from the equinox.
     """
-    def __init__(self, vec, elat, elon):
+    def __init__(self, vec: Vector, elat: float, elon: float) -> None:
         self.vec = vec
         self.elat = elat
         self.elon = elon
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'EclipticCoordinates({}, elat={}, elon={})'.format(repr(self.vec), self.elat, self.elon)
 
 def _RotateEquatorialToEcliptic(pos, obliq_radians, time):
@@ -5043,7 +5047,7 @@ def _RotateEquatorialToEcliptic(pos, obliq_radians, time):
     vec = Vector(ex, ey, ez, time)
     return EclipticCoordinates(vec, elat, elon)
 
-def SunPosition(time):
+def SunPosition(time: Time) -> EclipticCoordinates:
     """Calculates geocentric ecliptic coordinates for the Sun.
 
     This function calculates the position of the Sun as seen from the Earth.
@@ -5085,7 +5089,7 @@ def SunPosition(time):
     true_obliq = math.radians(adjusted_time._etilt().tobl)
     return _RotateEquatorialToEcliptic(sun_ofdate, true_obliq, time)
 
-def Ecliptic(eqj):
+def Ecliptic(eqj: Vector) -> EclipticCoordinates:
     """Converts a J2000 mean equator (EQJ) vector to a true ecliptic of date (ETC) vector and angles.
 
     Given coordinates relative to the Earth's equator at J2000 (the instant of noon UTC
@@ -5094,7 +5098,7 @@ def Ecliptic(eqj):
 
     Parameters
     ----------
-    eqj : Equatorial
+    eqj : Vector
         Equatorial coordinates in the J2000 frame of reference.
         You can call #GeoVector to obtain suitable equatorial coordinates.
 
@@ -5116,7 +5120,7 @@ def Ecliptic(eqj):
     return _RotateEquatorialToEcliptic(eqd_pos, math.radians(et.tobl), eqj.t)
 
 
-def EclipticLongitude(body, time):
+def EclipticLongitude(body: Body, time: Time) -> float:
     """Calculates heliocentric ecliptic longitude of a body.
 
     This function calculates the angle around the plane of the Earth's orbit
@@ -5142,7 +5146,7 @@ def EclipticLongitude(body, time):
     eclip = Ecliptic(hv)
     return eclip.elon
 
-def AngleFromSun(body, time):
+def AngleFromSun(body: Body, time: Time) -> float:
     """Returns the angle between the given body and the Sun, as seen from the Earth.
 
     This function calculates the angular separation between the given body and the Sun,
@@ -5169,7 +5173,7 @@ def AngleFromSun(body, time):
     bv = GeoVector(body, time, True)
     return AngleBetween(sv, bv)
 
-def PairLongitude(body1, body2, time):
+def PairLongitude(body1: Body, body2: Body, time: Time) -> float:
     """Returns one body's ecliptic longitude with respect to another, as seen from the Earth.
 
     This function determines where one body appears around the ecliptic plane
@@ -5228,13 +5232,13 @@ class ElongationEvent:
     ecliptic_separation : float
         The difference between the ecliptic longitudes of the body and the Sun, as seen from the Earth.
     """
-    def __init__(self, time, visibility, elongation, ecliptic_separation):
+    def __init__(self, time: Time, visibility: "Visibility", elongation: float, ecliptic_separation: float) -> None:
         self.time = time
         self.visibility = visibility
         self.elongation = elongation
         self.ecliptic_separation = ecliptic_separation
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'ElongationEvent({}, {}, elongation={}, ecliptic_separation={})'.format(
             repr(self.time),
             self.visibility,
@@ -5254,7 +5258,7 @@ class Visibility(enum.Enum):
     Morning = 0
     Evening = 1
 
-def Elongation(body, time):
+def Elongation(body: Body, time: Time) -> ElongationEvent:
     """Determines visibility of a celestial body relative to the Sun, as seen from the Earth.
 
     This function returns an #ElongationEvent object, which provides the following
@@ -5301,7 +5305,7 @@ def _rlon_offset(body, time, direction, targetRelLon):
     diff = direction * (elon - plon)
     return _LongitudeOffset(diff - targetRelLon)
 
-def SearchRelativeLongitude(body, targetRelLon, startTime):
+def SearchRelativeLongitude(body: Body, targetRelLon:float, startTime: Time) -> Time:
     """Searches for when the Earth and another planet are separated by a certain ecliptic longitude.
 
     Searches for the time when the Earth and another planet are separated by a specified angle
@@ -5393,7 +5397,7 @@ def _neg_elong_slope(body, time):
     e2 = AngleFromSun(body, t2)
     return (e1 - e2)/dt
 
-def SearchMaxElongation(body, startTime):
+def SearchMaxElongation(body: Body, startTime: Time) -> Optional[ElongationEvent]:
     """Finds a date and time when Mercury or Venus reaches its maximum angle from the Sun as seen from the Earth.
 
     Mercury and Venus are are often difficult to observe because they are closer to the Sun than the Earth is.
@@ -5507,7 +5511,7 @@ def _sun_offset(targetLon, time):
     ecl = SunPosition(time)
     return _LongitudeOffset(ecl.elon - targetLon)
 
-def SearchSunLongitude(targetLon, startTime, limitDays):
+def SearchSunLongitude(targetLon: float, startTime: Time, limitDays: float) -> Optional[Time]:
     """Searches for the time when the Sun reaches an apparent ecliptic longitude as seen from the Earth.
 
     This function finds the moment in time, if any exists in the given time window,
@@ -5544,7 +5548,7 @@ def SearchSunLongitude(targetLon, startTime, limitDays):
     t2 = startTime.AddDays(limitDays)
     return Search(_sun_offset, targetLon, startTime, t2, 0.01)
 
-def MoonPhase(time):
+def MoonPhase(time: Time) -> float:
     """Returns the Moon's phase as an angle from 0 to 360 degrees.
 
     This function determines the phase of the Moon using its apparent
@@ -5571,7 +5575,7 @@ def _moon_offset(targetLon, time):
     angle = MoonPhase(time)
     return _LongitudeOffset(angle - targetLon)
 
-def SearchMoonPhase(targetLon, startTime, limitDays):
+def SearchMoonPhase(targetLon: float, startTime: Time, limitDays: float):
     """Searches for the time that the Moon reaches a specified phase.
 
     Lunar phases are conventionally defined in terms of the Moon's geocentric ecliptic
@@ -5662,7 +5666,7 @@ def __init__(self, quarter, time):
     def __repr__(self):
         return 'MoonQuarter({}, {})'.format(self.quarter, repr(self.time))
 
-def SearchMoonQuarter(startTime):
+def SearchMoonQuarter(startTime: Time) -> MoonQuarter:
     """Finds the first lunar quarter after the specified date and time.
 
     A lunar quarter is one of the following four lunar phase events:
@@ -5690,7 +5694,7 @@ def SearchMoonQuarter(startTime):
         raise InternalError()
     return MoonQuarter(quarter, time)
 
-def NextMoonQuarter(mq):
+def NextMoonQuarter(mq: MoonQuarter) -> MoonQuarter:
     """Continues searching for lunar quarters from a previous search.
 
     After calling #SearchMoonQuarter, this function can be called
@@ -5751,7 +5755,7 @@ class IlluminationInfo:
         as seen from observers on the Earth, and are thus very difficult to see.
         For bodies other than Saturn, `ring_tilt` is `None`.
     """
-    def __init__(self, time, mag, phase, helio_dist, geo_dist, hc, gc, ring_tilt):
+    def __init__(self, time: Time, mag: float, phase: float, helio_dist: float, geo_dist: float, hc: Vector, gc: Vector, ring_tilt: Optional[float]) -> None:
         self.time = time
         self.mag = mag
         self.phase_angle = phase
@@ -5762,7 +5766,7 @@ def __init__(self, time, mag, phase, helio_dist, geo_dist, hc, gc, ring_tilt):
         self.gc = gc
         self.ring_tilt = ring_tilt
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'IlluminationInfo({}, mag={}, phase_angle={}, helio_dist={}, geo_dist={}, hc={}, gc={}, ring_tilt={})'.format(
             repr(self.time),
             self.mag,
@@ -5834,7 +5838,7 @@ def _VisualMagnitude(body, phase, helio_dist, geo_dist):
     mag += 5.0 * math.log10(helio_dist * geo_dist)
     return mag
 
-def Illumination(body, time):
+def Illumination(body: Body, time: Time) -> IlluminationInfo:
     """Finds visual magnitude, phase angle, and other illumination information about a celestial body.
 
     This function calculates information about how bright a celestial body appears from the Earth,
@@ -5910,7 +5914,7 @@ def _mag_slope(body, time):
     y2 = Illumination(body, t2)
     return (y2.mag - y1.mag) / dt
 
-def SearchPeakMagnitude(body, startTime):
+def SearchPeakMagnitude(body: Body, startTime: Time) -> IlluminationInfo:
     """Searches for the date and time Venus will next appear brightest as seen from the Earth.
 
     This function searches for the date and time Venus appears brightest as seen from the Earth.
@@ -6028,14 +6032,14 @@ class HourAngleEvent:
     hor : HorizontalCoordinates
         Apparent coordinates of the body at the time it crosses the specified hour angle.
     """
-    def __init__(self, time, hor):
+    def __init__(self, time: Time, hor: HorizontalCoordinates):
         self.time = time
         self.hor = hor
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'HourAngleEvent({}, {})'.format(repr(self.time), repr(self.hor))
 
-def SearchHourAngle(body, observer, hourAngle, startTime, direction = +1):
+def SearchHourAngle(body: Body, observer: Observer, hourAngle: float, startTime: Time, direction: int = +1) -> HourAngleEvent:
     """Searches for the time when the center of a body reaches a specified hour angle as seen by an observer on the Earth.
 
     The *hour angle* of a celestial body indicates its position in the sky with respect
@@ -6129,7 +6133,7 @@ def SearchHourAngle(body, observer, hourAngle, startTime, direction = +1):
         time = time.AddDays(delta_days)
 
 
-def HourAngle(body, time, observer):
+def HourAngle(body: Body, time: Time, observer: Observer) -> float:
     """Finds the hour angle of a body for a given observer and time.
 
     The *hour angle* of a celestial body indicates its position in the sky with respect
@@ -6361,7 +6365,7 @@ def _InternalSearchAltitude(body, observer, direction, startTime, limitDays, bod
             a1 = a2
 
 
-def SearchRiseSet(body, observer, direction, startTime, limitDays):
+def SearchRiseSet(body: Body, observer: Observer, direction: Direction, startTime: Time, limitDays: float) -> Optional[Time]:
     """Searches for the next time a celestial body rises or sets as seen by an observer on the Earth.
 
     This function finds the next rise or set time of the Sun, Moon, or planet other than the Earth.
@@ -6422,7 +6426,7 @@ def SearchRiseSet(body, observer, direction, startTime, limitDays):
     return _InternalSearchAltitude(body, observer, direction, startTime, limitDays, bodyRadiusAu, -_REFRACTION_NEAR_HORIZON)
 
 
-def SearchAltitude(body, observer, direction, startTime, limitDays, altitude):
+def SearchAltitude(body: Body, observer: Observer, direction: Direction, startTime: Time, limitDays: float, altitude: float) -> Optional[Time]:
     """Finds the next time the center of a body passes through a given altitude.
 
     Finds when the center of the given body ascends or descends through a given
@@ -6505,13 +6509,13 @@ class SeasonInfo:
     dec_solstice : Time
         The date and time of the December solstice for the specified year.
     """
-    def __init__(self, mar_equinox, jun_solstice, sep_equinox, dec_solstice):
+    def __init__(self, mar_equinox: Time, jun_solstice: Time, sep_equinox: Time, dec_solstice: Time) -> None:
         self.mar_equinox = mar_equinox
         self.jun_solstice = jun_solstice
         self.sep_equinox = sep_equinox
         self.dec_solstice = dec_solstice
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'SeasonInfo(mar_equinox={}, jun_solstice={}, sep_equinox={}, dec_solstice={})'.format(
             repr(self.mar_equinox),
             repr(self.jun_solstice),
@@ -6527,7 +6531,7 @@ def _FindSeasonChange(targetLon, year, month, day):
         raise InternalError()
     return time
 
-def Seasons(year):
+def Seasons(year: int) -> SeasonInfo:
     """Finds both equinoxes and both solstices for a given calendar year.
 
     The changes of seasons are defined by solstices and equinoxes.
@@ -6632,20 +6636,20 @@ class Apsis:
     dist_km : float
         The distance between the centers of the bodies in kilometers.
     """
-    def __init__(self, time, kind, dist_au):
+    def __init__(self, time: Time, kind: ApsisKind, dist_au: float) -> None:
         self.time = time
         self.kind = kind
         self.dist_au = dist_au
         self.dist_km = dist_au * KM_PER_AU
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'Apsis({}, {}, dist_au={})'.format(
             repr(self.time),
             self.kind,
             self.dist_au
         )
 
-def SearchLunarApsis(startTime):
+def SearchLunarApsis(startTime: Time) -> Apsis:
     """Finds the time of the first lunar apogee or perigee after the given time.
 
     Given a date and time to start the search in `startTime`, this function finds
@@ -6712,7 +6716,7 @@ def SearchLunarApsis(startTime):
     raise InternalError()
 
 
-def NextLunarApsis(apsis):
+def NextLunarApsis(apsis: Apsis) -> Apsis:
     """Finds the next lunar perigee or apogee in a series.
 
     This function requires an #Apsis value obtained from a call to
@@ -6751,7 +6755,7 @@ def _planet_distance_slope(context, time):
     return direction * (dist2 - dist1) / dt
 
 
-def SearchPlanetApsis(body, startTime):
+def SearchPlanetApsis(body: Body, startTime: Time) -> Apsis:
     """Finds the next planet perihelion or aphelion, after a given time.
 
     Given a date and time to start the search in `startTime`, this function finds the
@@ -6818,7 +6822,7 @@ def SearchPlanetApsis(body, startTime):
     raise InternalError()   # should have found planet apsis within 2 planet orbits
 
 
-def NextPlanetApsis(body, apsis):
+def NextPlanetApsis(body: Body, apsis: Apsis) -> Apsis:
     """Finds the next planetary perihelion or aphelion event in a series.
 
     This function requires an #Apsis value obtained from a call
@@ -6925,7 +6929,7 @@ def _BruteSearchPlanetApsis(body, startTime):
     raise InternalError()   # failed to find Neptune apsis
 
 
-def VectorFromSphere(sphere, time):
+def VectorFromSphere(sphere: Spherical, time: Time) -> Vector:
     """Converts spherical coordinates to Cartesian coordinates.
 
     Given spherical coordinates and a time at which they are valid,
@@ -6955,7 +6959,7 @@ def VectorFromSphere(sphere, time):
     )
 
 
-def EquatorFromVector(vec):
+def EquatorFromVector(vec: Vector) -> Equatorial:
     """Given an equatorial vector, calculates equatorial angular coordinates.
 
     Parameters
@@ -6972,7 +6976,7 @@ def EquatorFromVector(vec):
     return Equatorial(sphere.lon / 15.0, sphere.lat, sphere.dist, vec)
 
 
-def SphereFromVector(vector):
+def SphereFromVector(vector: Vector) -> Spherical:
     """Converts Cartesian coordinates to spherical coordinates.
 
     Given a Cartesian vector, returns latitude, longitude, and distance.
@@ -7014,7 +7018,7 @@ def _ToggleAzimuthDirection(az):
     return az
 
 
-def VectorFromHorizon(sphere, time, refraction):
+def VectorFromHorizon(sphere: Spherical, time: Time, refraction: Refraction) -> Vector:
     """Given apparent angular horizontal coordinates in `sphere`, calculate horizontal vector.
 
     Parameters
@@ -7041,7 +7045,7 @@ def VectorFromHorizon(sphere, time, refraction):
     return VectorFromSphere(xsphere, time)
 
 
-def HorizonFromVector(vector, refraction):
+def HorizonFromVector(vector: Vector, refraction: Refraction) -> Spherical:
     """Converts Cartesian coordinates to horizontal coordinates.
 
     Given a horizontal Cartesian vector, returns horizontal azimuth and altitude.
@@ -7075,7 +7079,7 @@ def HorizonFromVector(vector, refraction):
     return sphere
 
 
-def InverseRotation(rotation):
+def InverseRotation(rotation: RotationMatrix) -> RotationMatrix:
     """Calculates the inverse of a rotation matrix.
 
     Given a rotation matrix that performs some coordinate transform,
@@ -7098,7 +7102,7 @@ def InverseRotation(rotation):
     ])
 
 
-def CombineRotation(a, b):
+def CombineRotation(a: RotationMatrix, b: RotationMatrix) -> RotationMatrix:
     """Creates a rotation based on applying one rotation followed by another.
 
     Given two rotation matrices, returns a combined rotation matrix that is
@@ -7141,7 +7145,7 @@ def CombineRotation(a, b):
     ])
 
 
-def IdentityMatrix():
+def IdentityMatrix() -> RotationMatrix:
     """Creates an identity rotation matrix.
 
     Returns a rotation matrix that has no effect on orientation.
@@ -7161,7 +7165,7 @@ def IdentityMatrix():
     ])
 
 
-def Pivot(rotation, axis, angle):
+def Pivot(rotation: RotationMatrix, axis: int, angle: float) -> RotationMatrix:
     """Re-orients a rotation matrix by pivoting it by an angle around one of its axes.
 
     Given a rotation matrix, a selected coordinate axis, and an angle in degrees,
@@ -7209,7 +7213,7 @@ def Pivot(rotation, axis, angle):
     j = (axis + 2) % 3
     k = axis
 
-    rot = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
+    rot: List[List[float]] = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
 
     rot[i][i] = c*rotation.rot[i][i] - s*rotation.rot[i][j]
     rot[i][j] = s*rotation.rot[i][i] + c*rotation.rot[i][j]
@@ -7226,7 +7230,7 @@ def Pivot(rotation, axis, angle):
     return RotationMatrix(rot)
 
 
-def RotateVector(rotation, vector):
+def RotateVector(rotation: RotationMatrix, vector: Vector) -> Vector:
     """Applies a rotation to a vector, yielding a rotated vector.
 
     This function transforms a vector in one orientation to a vector
@@ -7252,7 +7256,7 @@ def RotateVector(rotation, vector):
     )
 
 
-def RotateState(rotation, state):
+def RotateState(rotation: RotationMatrix, state: StateVector) -> StateVector:
     """Applies a rotation to a state vector, yielding a rotated state vector.
 
     This function transforms a state vector in one orientation to a
@@ -7282,7 +7286,7 @@ def RotateState(rotation, state):
     )
 
 
-def Rotation_EQJ_ECL():
+def Rotation_EQJ_ECL() -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean equator (EQJ) to J2000 mean ecliptic (ECL).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7305,7 +7309,7 @@ def Rotation_EQJ_ECL():
     ])
 
 
-def Rotation_ECL_EQJ():
+def Rotation_ECL_EQJ() -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean ecliptic (ECL) to J2000 mean equator (EQJ).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7327,7 +7331,7 @@ def Rotation_ECL_EQJ():
         [ 0, -s, +c]
     ])
 
-def Rotation_EQJ_EQD(time):
+def Rotation_EQJ_EQD(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean equator (EQJ) to equatorial of-date (EQD).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7350,7 +7354,7 @@ def Rotation_EQJ_EQD(time):
     return CombineRotation(prec, nut)
 
 
-def Rotation_EQJ_ECT(time):
+def Rotation_EQJ_ECT(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean equator (EQJ) to true ecliptic of date (ECT).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7373,7 +7377,7 @@ def Rotation_EQJ_ECT(time):
     return CombineRotation(rot, step)
 
 
-def Rotation_ECT_EQJ(time):
+def Rotation_ECT_EQJ(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from true ecliptic of date (ECT) to J2000 mean equator (EQJ).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7396,7 +7400,7 @@ def Rotation_ECT_EQJ(time):
     return CombineRotation(rot, step)
 
 
-def Rotation_EQD_EQJ(time):
+def Rotation_EQD_EQJ(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from equatorial of-date (EQD) to J2000 mean equator (EQJ).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7419,7 +7423,7 @@ def Rotation_EQD_EQJ(time):
     return CombineRotation(nut, prec)
 
 
-def Rotation_EQD_HOR(time, observer):
+def Rotation_EQD_HOR(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from equatorial of-date (EQD) to horizontal (HOR).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7464,7 +7468,7 @@ def Rotation_EQD_HOR(time, observer):
     ])
 
 
-def Rotation_HOR_EQD(time, observer):
+def Rotation_HOR_EQD(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from horizontal (HOR) to equatorial of-date (EQD).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7488,7 +7492,7 @@ def Rotation_HOR_EQD(time, observer):
     return InverseRotation(rot)
 
 
-def Rotation_HOR_EQJ(time, observer):
+def Rotation_HOR_EQJ(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from horizontal (HOR) to J2000 equatorial (EQJ).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7513,7 +7517,7 @@ def Rotation_HOR_EQJ(time, observer):
     return CombineRotation(hor_eqd, eqd_eqj)
 
 
-def Rotation_EQJ_HOR(time, observer):
+def Rotation_EQJ_HOR(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean equator (EQJ) to horizontal (HOR).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7544,7 +7548,7 @@ def Rotation_EQJ_HOR(time, observer):
     return InverseRotation(rot)
 
 
-def Rotation_EQD_ECL(time):
+def Rotation_EQD_ECL(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from equatorial of-date (EQD) to J2000 mean ecliptic (ECL).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7567,7 +7571,7 @@ def Rotation_EQD_ECL(time):
     return CombineRotation(eqd_eqj, eqj_ecl)
 
 
-def Rotation_ECL_EQD(time):
+def Rotation_ECL_EQD(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean ecliptic (ECL) to equatorial of-date (EQD).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7589,7 +7593,7 @@ def Rotation_ECL_EQD(time):
     return InverseRotation(rot)
 
 
-def Rotation_ECL_HOR(time, observer):
+def Rotation_ECL_HOR(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean ecliptic (ECL) to horizontal (HOR).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7621,7 +7625,7 @@ def Rotation_ECL_HOR(time, observer):
     return CombineRotation(ecl_eqd, eqd_hor)
 
 
-def Rotation_HOR_ECL(time, observer):
+def Rotation_HOR_ECL(time: Time, observer: Observer) -> RotationMatrix:
     """Calculates a rotation matrix from horizontal (HOR) to J2000 mean ecliptic (ECL).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7644,7 +7648,7 @@ def Rotation_HOR_ECL(time, observer):
     rot = Rotation_ECL_HOR(time, observer)
     return InverseRotation(rot)
 
-def Rotation_EQJ_GAL():
+def Rotation_EQJ_GAL() -> RotationMatrix:
     """Calculates a rotation matrix from J2000 mean equator (EQJ) to galactic (GAL).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7666,7 +7670,7 @@ def Rotation_EQJ_GAL():
         [-0.4838000529948520, +0.7470034631630423, +0.4559861124470794]
     ])
 
-def Rotation_GAL_EQJ():
+def Rotation_GAL_EQJ() -> RotationMatrix:
     """Calculates a rotation matrix from galactic (GAL) to J2000 mean equator (EQJ).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7688,7 +7692,7 @@ def Rotation_GAL_EQJ():
         [-0.8676668813529025, -0.1980677870294097, +0.4559861124470794]
     ])
 
-def Rotation_ECT_EQD(time):
+def Rotation_ECT_EQD(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from true ecliptic of date (ECT) to equator of date (EQD).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7716,7 +7720,7 @@ def Rotation_ECT_EQD(time):
         [0.0,  -s,  +c]
     ])
 
-def Rotation_EQD_ECT(time):
+def Rotation_EQD_ECT(time: Time) -> RotationMatrix:
     """Calculates a rotation matrix from equator of date (EQD) to true ecliptic of date (ECT).
 
     This is one of the family of functions that returns a rotation matrix
@@ -7765,13 +7769,13 @@ class ConstellationInfo:
     dec1875 : float
         Declination expressed in B1875 coordinates.
     """
-    def __init__(self, symbol, name, ra1875, dec1875):
+    def __init__(self, symbol: str, name: str, ra1875: float, dec1875: float) -> None:
         self.symbol = symbol
         self.name = name
         self.ra1875 = ra1875
         self.dec1875 = dec1875
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'ConstellationInfo(symbol={}, name={}, ra1875={}, dec1875={})'.format(
             repr(self.symbol),
             repr(self.name),
@@ -8236,7 +8240,7 @@ def __repr__(self):
 
 
 
-def Constellation(ra, dec):
+def Constellation(ra: float, dec: float) -> ConstellationInfo:
     """Determines the constellation that contains the given point in the sky.
 
     Given J2000 equatorial (EQJ) coordinates of a point in the sky, determines the
@@ -8483,7 +8487,7 @@ class LunarEclipseInfo:
     sd_total : float
          The semi-duration of the penumbral phase in minutes, or 0.0 if none.
     """
-    def __init__(self, kind, obscuration, peak, sd_penum, sd_partial, sd_total):
+    def __init__(self, kind: EclipseKind, obscuration: float, peak: Time, sd_penum: float, sd_partial: float, sd_total: float) -> None:
         self.kind = kind
         self.obscuration = obscuration
         self.peak = peak
@@ -8491,7 +8495,7 @@ def __init__(self, kind, obscuration, peak, sd_penum, sd_partial, sd_total):
         self.sd_partial = sd_partial
         self.sd_total = sd_total
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'LunarEclipseInfo({}, obscuration={}, peak={}, sd_penum={}, sd_partial={}, sd_total={})'.format(
             self.kind,
             self.obscuration,
@@ -8552,7 +8556,7 @@ class GlobalSolarEclipseInfo:
     longitude : float
         The geographic longitude at the center of the peak eclipse shadow.
     """
-    def __init__(self, kind, obscuration, peak, distance, latitude, longitude):
+    def __init__(self, kind: EclipseKind, obscuration: float, peak: Time, distance: float, latitude: float, longitude: float) -> None:
         self.kind = kind
         self.obscuration = obscuration
         self.peak = peak
@@ -8560,7 +8564,7 @@ def __init__(self, kind, obscuration, peak, distance, latitude, longitude):
         self.latitude = latitude
         self.longitude = longitude
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'GlobalSolarEclipseInfo({}, obscuration={}, peak={}, distance={}, latitude={}, longitude={})'.format(
             self.kind,
             self.obscuration,
@@ -8593,11 +8597,11 @@ class EclipseEvent:
         The angular altitude of the center of the Sun above/below the horizon, at `time`,
         corrected for atmospheric refraction and expressed in degrees.
     """
-    def __init__(self, time, altitude):
+    def __init__(self, time: Time, altitude: float) -> None:
         self.time = time
         self.altitude = altitude
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'EclipseEvent({}, altitude={})'.format(
             repr(self.time),
             self.altitude
@@ -8653,7 +8657,7 @@ class LocalSolarEclipseInfo:
     partial_end : EclipseEvent
         The time and Sun altitude at the end of the eclipse.
     """
-    def __init__(self, kind, obscuration, partial_begin, total_begin, peak, total_end, partial_end):
+    def __init__(self, kind: EclipseKind, obscuration: float, partial_begin: EclipseEvent, total_begin: EclipseEvent, peak: EclipseEvent, total_end: EclipseEvent, partial_end: EclipseEvent) -> None:
         self.kind = kind
         self.obscuration = obscuration
         self.partial_begin = partial_begin
@@ -8662,7 +8666,7 @@ def __init__(self, kind, obscuration, partial_begin, total_begin, peak, total_en
         self.total_end = total_end
         self.partial_end = partial_end
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'LocalSolarEclipseInfo({}, obscuration={}, partial_begin={}, total_begin={}, peak={}, total_end={}, partial_end={})'.format(
             self.kind,
             self.obscuration,
@@ -8921,7 +8925,7 @@ def _SolarEclipseObscuration(hm, lo):
     return min(0.9999, obscuration)
 
 
-def SearchLunarEclipse(startTime):
+def SearchLunarEclipse(startTime: Time) -> LunarEclipseInfo:
     """Searches for a lunar eclipse.
 
     This function finds the first lunar eclipse that occurs after `startTime`.
@@ -8986,7 +8990,7 @@ def SearchLunarEclipse(startTime):
     raise Error('Failed to find lunar eclipse within 12 full moons.')
 
 
-def NextLunarEclipse(prevEclipseTime):
+def NextLunarEclipse(prevEclipseTime: Time) -> LunarEclipseInfo:
     """Searches for the next lunar eclipse in a series.
 
      After using #SearchLunarEclipse to find the first lunar eclipse
@@ -9008,7 +9012,7 @@ def NextLunarEclipse(prevEclipseTime):
     return SearchLunarEclipse(startTime)
 
 
-def SearchGlobalSolarEclipse(startTime):
+def SearchGlobalSolarEclipse(startTime: Time) -> GlobalSolarEclipseInfo:
     """Searches for a solar eclipse visible anywhere on the Earth's surface.
 
     This function finds the first solar eclipse that occurs after `startTime`.
@@ -9055,7 +9059,7 @@ def SearchGlobalSolarEclipse(startTime):
     raise Error('Failed to find solar eclipse within 12 full moons.')
 
 
-def NextGlobalSolarEclipse(prevEclipseTime):
+def NextGlobalSolarEclipse(prevEclipseTime: Time) -> GlobalSolarEclipseInfo:
     """Searches for the next global solar eclipse in a series.
 
     After using #SearchGlobalSolarEclipse to find the first solar eclipse
@@ -9077,7 +9081,7 @@ def NextGlobalSolarEclipse(prevEclipseTime):
     return SearchGlobalSolarEclipse(startTime)
 
 
-def SearchLocalSolarEclipse(startTime, observer):
+def SearchLocalSolarEclipse(startTime: Time, observer: Observer) -> LocalSolarEclipseInfo:
     """Searches for a solar eclipse visible at a specific location on the Earth's surface.
     This function finds the first solar eclipse that occurs after `startTime`.
     A solar eclipse may be partial, annular, or total.
@@ -9132,7 +9136,7 @@ def SearchLocalSolarEclipse(startTime, observer):
         nmtime = newmoon.AddDays(10.0)
 
 
-def NextLocalSolarEclipse(prevEclipseTime, observer):
+def NextLocalSolarEclipse(prevEclipseTime: Time, observer: Observer) -> LocalSolarEclipseInfo:
     """Searches for the next local solar eclipse in a series.
 
     After using #SearchLocalSolarEclipse to find the first solar eclipse
@@ -9180,13 +9184,13 @@ class TransitInfo:
         The minimum angular separation, in arcminutes, between the centers of the Sun and the planet.
         This angle pertains to the time stored in `peak`.
     """
-    def __init__(self, start, peak, finish, separation):
+    def __init__(self, start: Time, peak: Time, finish: Time, separation: float) -> None:
         self.start = start
         self.peak = peak
         self.finish = finish
         self.separation = separation
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'TransitInfo(start={}, peak={}, finish={}, separation={})'.format(
             repr(self.start),
             repr(self.peak),
@@ -9210,7 +9214,7 @@ def _PlanetTransitBoundary(body, planet_radius_km, t1, t2, direction):
     return tx
 
 
-def SearchTransit(body, startTime):
+def SearchTransit(body: Body, startTime: Time) -> TransitInfo:
     """Searches for the first transit of Mercury or Venus after a given date.
 
     Finds the first transit of Mercury or Venus after a specified date.
@@ -9270,7 +9274,7 @@ def SearchTransit(body, startTime):
         search_time = conj.AddDays(10.0)
 
 
-def NextTransit(body, prevTransitTime):
+def NextTransit(body: Body, prevTransitTime: Time) -> TransitInfo:
     """Searches for another transit of Mercury or Venus.
 
     After calling #SearchTransit to find a transit of Mercury or Venus,
@@ -9319,11 +9323,11 @@ class NodeEventInfo:
     time : Time
         The time when the body passes through the ecliptic plane.
     """
-    def __init__(self, kind, time):
+    def __init__(self, kind: NodeEventKind, time: Time) -> None:
         self.kind = kind
         self.time = time
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'NodeEventInfo({}, {})'.format(self.kind, repr(self.time))
 
 _MoonNodeStepDays = +10.0   # a safe number of days to step without missing a Moon node
@@ -9331,7 +9335,7 @@ def __repr__(self):
 def _MoonNodeSearchFunc(direction, time):
     return direction * EclipticGeoMoon(time).lat
 
-def SearchMoonNode(startTime):
+def SearchMoonNode(startTime: Time) -> NodeEventInfo:
     """Searches for a time when the Moon's center crosses through the ecliptic plane.
 
     Searches for the first ascending or descending node of the Moon after `startTime`.
@@ -9371,7 +9375,7 @@ def SearchMoonNode(startTime):
         eclip1 = eclip2
 
 
-def NextMoonNode(prevNode):
+def NextMoonNode(prevNode: NodeEventInfo) -> NodeEventInfo:
     """Searches for the next time when the Moon's center crosses through the ecliptic plane.
 
     Call #SearchMoonNode to find the first of a series of nodes.
@@ -9420,7 +9424,7 @@ class LibrationInfo:
     diam_deg : float
         The apparent angular diameter of the Moon as seen from the center of the Earth.
     """
-    def __init__(self, elat, elon, mlat, mlon, dist_km, diam_deg):
+    def __init__(self, elat: float, elon: float, mlat: float, mlon: float, dist_km: float, diam_deg: float) -> None:
         self.elat = elat
         self.elon = elon
         self.mlat = mlat
@@ -9428,7 +9432,7 @@ def __init__(self, elat, elon, mlat, mlon, dist_km, diam_deg):
         self.dist_km = dist_km
         self.diam_deg = diam_deg
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'LibrationInfo(elat={}, elon={}, mlat={}, mlon={}, dist_km={}, diam_deg={})'.format(
             self.elat,
             self.elon,
@@ -9439,7 +9443,7 @@ def __repr__(self):
         )
 
 
-def Libration(time):
+def Libration(time: Time) -> LibrationInfo:
     """Calculates the Moon's libration angles at a given moment in time.
 
     Libration is an observed back-and-forth wobble of the portion of the
@@ -9599,13 +9603,13 @@ class AxisInfo:
     north : Vector
         A J2000 dimensionless unit vector pointing in the direction of the body's north pole.
     """
-    def __init__(self, ra, dec, spin, north):
+    def __init__(self, ra: float, dec: float, spin: float, north: Vector) -> None:
         self.ra = ra
         self.dec = dec
         self.spin = spin
         self.north = north
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return 'AxisInfo(ra={}, dec={}, spin={}, north={})'.format(
             self.ra,
             self.dec,
@@ -9635,7 +9639,7 @@ def _EarthRotationAxis(time):
     return AxisInfo(equ.ra, equ.dec, spin, north)
 
 
-def RotationAxis(body, time):
+def RotationAxis(body: Body, time: Time) -> AxisInfo:
     """Calculates information about a body's rotation axis at a given time.
 
     Calculates the orientation of a body's rotation axis, along with
@@ -9836,7 +9840,7 @@ def RotationAxis(body, time):
     return AxisInfo(ra/15.0, dec, w, north)
 
 
-def LagrangePoint(point, time, major_body, minor_body):
+def LagrangePoint(point: int, time: Time, major_body: Body, minor_body: Body) -> StateVector:
     """Calculates one of the 5 Lagrange points for a pair of co-orbiting bodies.
 
     Given a more massive "major" body and a much less massive "minor" body,
@@ -9902,7 +9906,7 @@ def LagrangePoint(point, time, major_body, minor_body):
     )
 
 
-def LagrangePointFast(point, major_state, major_mass, minor_state, minor_mass):
+def LagrangePointFast(point: int, major_state: StateVector, major_mass: float, minor_state: StateVector, minor_mass: float) -> StateVector:
     """Calculates one of the 5 Lagrange points from body masses and state vectors.
 
     Given a more massive "major" body and a much less massive "minor" body,
@@ -10090,7 +10094,7 @@ class GravitySimulator:
     time steps.
     """
 
-    def __init__(self, originBody, time, bodyStates):
+    def __init__(self, originBody: Body, time: "Time", bodyStates: List[StateVector]) -> None:
         """Creates a gravity simulation object.
 
         Parameters
@@ -10129,7 +10133,7 @@ def __init__(self, originBody, time, bodyStates):
 
         # Create a stub list of small body states that we will append to later.
         # We just need the stub to put into `self.curr`
-        smallBodyList = []
+        smallBodyList: List = []
 
         # Calculate the states of the Sun and planets at the initial time.
         largeBodyDict = _CalcSolarSystem(time)
@@ -10160,7 +10164,7 @@ def Time(self):
         """
         return self.curr.time
 
-    def OriginBody(self):
+    def OriginBody(self) -> Body:
         """The origin of the reference frame. See constructor for more info.
 
         Returns
@@ -10169,7 +10173,7 @@ def OriginBody(self):
         """
         return self._originBody
 
-    def Update(self, time):
+    def Update(self, time) -> List[StateVector]:
         """Advances the gravity simulation by a small time step.
 
         Updates the simulation of the user-supplied small bodies
@@ -10269,7 +10273,7 @@ def Update(self, time):
         return bodyStates
 
 
-    def Swap(self):
+    def Swap(self) -> None:
         """Exchange the current time step with the previous time step.
 
         Sometimes it is helpful to "explore" various times near a given
@@ -10295,7 +10299,7 @@ def Swap(self):
         """
         (self.curr, self.prev) = (self.prev, self.curr)
 
-    def SolarSystemBodyState(self, body):
+    def SolarSystemBodyState(self, body: Body) -> StateVector:
         """Get the position and velocity of a Solar System body included in the simulation.
 
         In order to simulate the movement of small bodies through the Solar System,


Test patch:
diff --git a/generate/ctest.c b/generate/ctest.c
index 929a059a..ae0df7ce 100644
--- a/generate/ctest.c
+++ b/generate/ctest.c
@@ -3542,7 +3542,7 @@ static int EclipticTest(void)
         ++count;
     }
 
-    if (max_angle_diff > 2.910e-18)
+    if (max_angle_diff > 3.110e-18)
         FFAIL("EXCESSIVE ANGLE DIFF = %0.6le AU.\n", max_angle_diff);
 
     if (max_vec_diff > 3.388e-18)