Giter VIP home page Giter VIP logo

pymeeus's Introduction

PyMeeus

Library of astronomical algorithms in Python.

PyMeeus is a Python implementation of the astronomical algorithms described in the classical book 'Astronomical Algorithms, 2nd Edition, Willmann-Bell Inc. (1998)' by Jean Meeus.

There are great astronomical libraries out there. For instance, if you're looking for high precision and speed you should take a look at libnova. For a set of python modules aimed at professional astronomers, you should look at Astropy. On the other hand, the advantages of PyMeeus are its simplicity, ease of use, ease of reading, ease of installation (it has the minimum amount of dependencies) and abundant documentation.

Installation

The easiest way of installing PyMeeus is using pip:

pip install pymeeus

Or, for a per-user installation:

pip install --user pymeeus

If you prefer Python3, you can use:

pip3 install --user pymeeus

If you have PyMeeus already installed, but want to upgrade to the latest version:

pip3 install -U pymeeus

Properly Using PyMeeus

It is very common to try to run PyMeeus like this:

import pymeeus

mydate = pymeeus.Epoch(1992, 10, 13.0)

But if you do that, you'll get an error like this:

Traceback (most recent call last):
  File "/home/user/test/test.py", line 3, in <module>
    epoch = pymeeus.Epoch(1992, 10, 13.0)
AttributeError: module 'pymeeus' has no attribute 'Epoch'

This issue points to a misunderstanding that is very common in the Python world. The keyword import is used to import MODULES... but PyMeeus is NOT a module: It is a LIBRARY composed of MULTIPLE modules (Angle, Epoch, Coordinates, etc). As of today, the library Pymeeus has 19 different modules (if you look into the directory where pip stores the library, you'll find one ".py" file per module).

Therefore if you want to use, for example, the module Angle you should use:

import pymeeus.Angle

I.e., your module is pymeeus.Angle, and not just Angle.

But there is more! When you use import to fetch a module, you must then use the dot notation to access the components of the module (classes, functions, etc). For instance:

import pymeeus.Angle

i = pymeeus.Angle.Angle(11.94524)

In this case, you are telling the Python interpreter that you want to use the class Angle (with parameter '11.94524') from the module Angle belonging to the library pymeeus.

There is, however, a more practical (and common) way to handle modules using the statement from <MODULE> import <COMPONENT>. For instance:

from pymeeus.Angle import Angle
from pymeeus.Epoch import Epoch, JDE2000
from math import sin, cos, tan, acos, atan2, sqrt, radians, log10

This way is preferred because, among other reasons, only the required components are loaded into memory instead of the whole module. Also, now the component is directly added to your execution environment, which means that you no longer need to use the dot notation.

Therefore, the script at the beginning would become:

from pymeeus.Epoch import Epoch

mydate = Epoch(1992, 10, 13.0)

Meta

Author: Dagoberto Salazar

Distributed under the GNU Lesser General Public License v3 (LGPLv3). See LICENSE.txt and COPYING.LESSER for more information.

Documentation: https://pymeeus.readthedocs.io/en/latest/

GitHub: https://github.com/architest/pymeeus

If you have Sphinx installed, you can generate your own, latest documentation going to directory 'docs' and issuing:

make html

Then the HTML documentation pages can be found in 'build/html'.

Contributing

The preferred method to contribute is through forking and pull requests:

  1. Fork it (https://github.com/architest/pymeeus/fork)
  2. Create your feature branch (git checkout -b feature/fooBar)
  3. Commit your changes (git commit -am 'Add some fooBar')
  4. Push to the branch (git push origin feature/fooBar)
  5. Create a new Pull Request

Please bear in mind that PyMeeus follows the PEP8 style guide for Python code (PEP8). We suggest you install and use a linter like Flake8 before contributing.

Additionally, PyMeeus makes heavy use of automatic tests. As a general rule, every function or method added must have a corresponding test in the proper place in tests directory.

Finally, documentation is also a big thing here. Add proper and abundant documentation to your new code. This also includes in-line comments!!!.

Contributors

  • Neil Freeman - Fixed undefined variable in Epoch.tt2ut
  • molsen234 - Fixed bug when using fractional seconds, minutes, hours or days
  • Sebastian Veigl - Added functionality for Jupiter's moons
  • Sophie Scholz - Added functionality for Jupiter's moons
  • Vittorio Serra - Added functionality for Jupiter's moons
  • Michael Lutz - Added functionality for Jupiter's moons
  • Ben Dilday - Added __hash__() method to class Epoch
  • Zivoslav - Bug report of winter solstice
  • Devid, Hugo van Kemenade - Test suggestions

What's new

  • 0.5.12
    • Fixed a bug in the computation of the winter solstice. Added new tests and information about proper use of the library.
  • 0.5.11
    • Added parameter local to the Epoch class constructor and the methods get_date() and get_full_date().
  • 0.5.10
    • Added methods moon_librations() and moon_position_angle_axis().
  • 0.5.9
    • Added method moon_maximum_declination().
  • 0.5.8
    • Fixed several bugs in Epoch class, and added method doy().
  • 0.5.7
    • Added method moon_passage_nodes().
  • 0.5.6
    • Added method moon_perigee_apogee().
  • 0.5.5
    • Added method moon_phase().
  • 0.5.4
    • Added methods illuminated_fraction_disk() and position_bright_limb() to Moon class.
  • 0.5.3
    • Fixed error in the return type of method Sun.equation_of_time().
  • 0.5.2
    • Added methods to compute the Moon's longitude of ascending node and perigee.
  • 0.5.1
    • Changes in the organization of the documentation.
  • 0.5.0
    • Added Moon class and position() methods.
  • 0.4.3
    • Added method ring_parameters() to Saturn class.
  • 0.4.2
    • Added method __hash__() to Epoch. Now Epoch objects can be used as keys in a dictionary.
  • 0.4.1
    • Added funtionality to compute the positions of Jupiter's Galilean moons.
  • 0.4.0
    • Added methods to compute Saturn's ring inclination and longitude of ascending node.
  • 0.3.13
    • Additional encoding changes.
  • 0.3.12
    • Deleted encoding keyword from setup.py, which was giving problems.
  • 0.3.11
    • Added encoding specification to setup.py.
  • 0.3.10
    • Fixed characters with the wrong encoding.
  • 0.3.9
    • Relaxed requirements, added contributor molsen234, and fixed format problems showed by flake8.
  • 0.3.8
    • Fixed undefined variable in Epoch.tt2ut.
  • 0.3.7
    • Fix bug when using fractional seconds, minutes, hours or days, plus documentation improvements.
  • 0.3.6
    • Add method to compute rising and setting times of the Sun.
  • 0.3.5
    • Add method magnitude() to planet classes.
  • 0.3.4
    • Add method to compute the parallax correction to Earth class.
  • 0.3.3
    • Add methods to compute the passage through the nodes.
  • 0.3.2
    • Add methods to compute the perihelion and aphelion of all planets.
  • 0.3.1
    • Fix errors in the elongation computation, add tests and examples of use of methods geocentric_position(), and tests and examples for Pluto class.
  • 0.3.0
    • Added Pluto class.

pymeeus's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pymeeus's Issues

Relax dependency versions

I want to package this library for Alpine Linux, but currently it requires to strict dependency versions (e.g. atomicwrites==1.2.1 rather than atomicwrites>=1.2.1). This makes it impossible to use in distributions which always try to package the newest version of everything.

Issue in installing pymeeus

While installing pymeeus, it is giving following error:

pip install pymeeus

Collecting pymeeus
  Using cached https://files.pythonhosted.org/packages/e4/45/04ce4324d00e27a491d52ae40e1b6ba035f9f21e16e478d4f3d3f19ddbca/PyMeeus-0.3.11.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-build-wFGXTS/pymeeus/setup.py", line 12, in <module>
        with open(path.join(here, 'README.rst'), encoding="utf8") as f:
    TypeError: 'encoding' is an invalid keyword argument for this function
    
    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-wFGXTS/pymeeus/

If I install lower version like 0.3.10, it is installing.

How to cite PyMeeus?

Greetings,

For those who publish results using your library.

How would you like citations for the PyMeeus library to be?

Would it be possible to add a citation suggestion in the documentation?

Do you have a publication on this library one could cite?

I am not sure this is the right channel, apologies if this was not appropriate.

Thank you in advance,

Best regards,

Benoit

Missing README.rst in the package

It looks like it is missing README.rst in the latest package (1 hour ago). I would kindly ask you to fix this as this is a dependency for this package - holidays==0.10.5.2

pip install pymeeus

Collecting pymeeus
  Using cached https://files.pythonhosted.org/packages/6e/e1/dccf1d8f8dabb234f0602ab57fc383ce6ba97a6f64f6757a9e5a7e10b7ad/PyMeeus-0.3.8.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-build-y0k_daqp/pymeeus/setup.py", line 12, in <module>
        with open(path.join(here, 'README.rst')) as f:
    FileNotFoundError: [Errno 2] No such file or directory: '/tmp/pip-build-y0k_daqp/pymeeus/README.rst'

error in winter solstice

for year in range(-1000, 2100):
   
    for season in ["spring", "summer", "autumn", "winter"]:
        day = Sun.get_equinox_solstice(year, target=season)
        y, m, d, h, mi, s  = day.get_full_date()
        print("{} {} {} {} {} {}:{}:{}".format(year, season, y, m, d, h, mi, round(s, 0)))

Winter year is of 5 year moved:

-986 winter -981 12 30 15:8:59.0
-985 spring -985 3 31 8:3:16.0
-985 summer -985 7 3 14:5:52.0
-985 autumn -985 10 3 5:32:45.0
-985 winter -980 12 29 21:4:25.0
-984 spring -984 3 30 13:56:48.0
-984 summer -984 7 2 20:3:54.0
-984 autumn -984 10 2 11:24:45.0
-984 winter -979 12 30 3:0:45.0
-983 spring -983 3 30 19:47:56.0
-983 summer -983 7 3 1:52:5.0
-983 autumn -983 10 2 17:15:57.0
-983 winter -978 12 30 8:47:47.0
-982 spring -982 3 31 1:35:33.0
-982 summer -982 7 3 7:36:26.0
-982 autumn -982 10 2 23:10:44.0
-982 winter -977 12 30 14:38:39.0
-981 spring -981 3 31 7:28:26.0
-981 summer -981 7 3 13:26:37.0
-981 autumn -981 10 3 5:1:53.0
-981 winter -976 12 29 20:26:12

0.5.11: shphinx warnings

+ /usr/bin/python3 setup.py build_sphinx -b man --build-dir build/sphinx
running build_sphinx
Running Sphinx v4.0.2
making output directory... done
WARNING: html_static_path entry '_static' does not exist
loading intersphinx inventory from https://docs.python.org/objects.inv...
intersphinx inventory has moved: https://docs.python.org/objects.inv -> https://docs.python.org/3/objects.inv
building [mo]: targets for 0 po files that are out of date
building [man]: all manpages
updating environment: [new config] 42 added, 0 changed, 0 removed
reading sources... [100%] index
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in bodies/Earth, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in bodies/Jupiter, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in bodies/Mars, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in bodies/Mercury, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in bodies/Minor, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in bodies/Moon, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in bodies/Neptune, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in bodies/Pluto, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in bodies/Saturn, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in bodies/Sun, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in bodies/Uranus, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in bodies/Venus, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in core/Angle, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in core/Coordinates, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in core/CurveFitting, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in core/Epoch, use :noindex: for one of them
/home/tkloczko/rpmbuild/BUILD/PyMeeus-0.5.11/pymeeus/__init__.py:docstring of pymeeus:1: WARNING: duplicate object description of pymeeus, other instance in core/Interpolation, use :noindex: for one of them
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
writing... pymeeus.1 { core/index core/base core/Angle core/Coordinates core/CurveFitting core/Epoch core/Interpolation bodies/index bodies/Earth bodies/JupiterMoons bodies/Jupiter bodies/Mars bodies/Mercury bodies/Minor bodies/Moon bodies/Neptune bodies/Pluto bodies/Saturn bodies/Sun bodies/Uranus bodies/Venus examples/index examples/ex-Angle examples/ex-base examples/ex-Coordinates examples/ex-CurveFitting examples/ex-Earth examples/ex-Epoch examples/ex-Interpolation examples/ex-Jupiter examples/ex-JupiterMoons examples/ex-Mars examples/ex-Mercury examples/ex-Minor examples/ex-Moon examples/ex-Neptune examples/ex-Pluto examples/ex-Saturn examples/ex-Sun examples/ex-Uranus examples/ex-Venus } done
build succeeded, 18 warnings.

Test on more python versions

As of now this libs tests only on two versions of Python (2.7, which is EOL, and 3.6):

jobs:
- build
- build27
- build367

It should be also tested on more recent versions of Python (from 3.7 to 3.9 at least). Also it would be a good approach to drop support for Python 2.7 which is no more supported by PSF.

Issues running pymeeus from a fresh install in a venv using pip install

Greetings,

I made a fresh install of pymeeus in a venv (using pip install in the venv after creating the venv). For this installation, I used Python 3.10.6

When I try to run the following script:

import pymeeus

epoch = pymeeus.Epoch(1992, 10, 13.0)
l, b, r = pymeeus.Earth.geometric_heliocentric_position(epoch, tofk5=False)

print(round(l.to_positive(), 6))
print(b.dms_str(n_dec=3))
print(round(r, 8))

You might recognize the code from an example for pymeeus.

I get the following error:

Traceback (most recent call last):
  File "/home/espinola/Code/test/test.py", line 3, in <module>
    epoch = pymeeus.Epoch(1992, 10, 13.0)
AttributeError: module 'pymeeus' has no attribute 'Epoch'

I got no errors or warnings when performing the pip install.

Pypi installer quarantined for "high risk CVSS score" by Sonatype Nexus IQ vulnerability detector, for dependency on underscore.js

Attempts to install pymeeus using pip (!pip install pymeeus ) failed, when Sonatype Nexus IQ flagged a "high risk CVSS score."

The specific vulnerability identified is CVE-2021-23358, which apparently follows from dependency on particular versions of underscore, a JavaScript package.

I don't see any dependency on underscore.js in the pymeeus repo. Is it possible something snuck into the current Pypi distribution?

UTC issues with Epoch.rise_set() and Epoch.utc2local()

Hi,
Just started looking at pymeeus, and it looks great, but perhaps I'm misunderstanding:

The documentation states that "Epoch internally stores time as Terrestrial Time (TT), not UTC.", "When a UTC time is provided, the parameter utc=True must be given. [โ€ฆ] it is converted to (and stored as) Terrestrial Time (TT). If utc is not provided, it is supposed that the input data is already in TT scale."

Yet the Epoch.rise_set()'s documentation notes: "The results are given in UTC time.", and the example provided calls get_full_date() without the utc=True parameter.
Perhaps jrise and jsett should be set with the utc=True param and the example changed for consistency?

Also, it appears that Epoch.utc2local() currently can't work if the difference between current local time and current UTC time cross the 24 hour boundary (e.g. 23:00 and 3:00) because it's doing (localhour - utchour).
Also utc2local() does not work for dates other than today, where the current timezone offset may change (DST).

BTW, instead of using utc2local, I'm doing something like this:

from datetime import *
# from zoneinfo import ZoneInfo # optional for Python 3.9+

from pymeeus.Angle import Angle
from pymeeus.Epoch import Epoch
from pymeeus.Sun import Sun

def epoch_datetime(e):
    edt = e.get_full_date(utc=True) # ! not when rise_set? !
    s = edt[5]
    return datetime(*edt[:5], int(s), int(s%1 * 10E5), tzinfo=timezone.utc)

longitude, latitude, altitude = Angle(45.423646), Angle(-75.698592), 90
e = Epoch(2021,7,1)
dtrise, dtset = map(epoch_datetime, e.rise_set(longitude, latitude, altitude))
dtls = dtset.astimezone() # UTC to local timezone
# dtls = dtset.astimezone(ZoneInfo('EST5EDT')) # Specific timezone, Python 3.9+
print(f'Sunset = UTC: {dtset}, Local: {dtls}')
dtwinter = epoch_datetime(Sun.get_equinox_solstice(2021, 'winter'))
dtlw = dtwinter.astimezone() # UTC to local timezone
# dtlw = dtwinter.astimezone(ZoneInfo('EST5EDT')) # Specific timezone, Python 3.9+
print(f'Winter = UTC: {dtwinter}, Local: {dtlw}')

Output:

Sunset = UTC: 2021-07-02 00:57:11.147205+00:00, Local: 2021-07-01 20:57:11.147205-04:00
Winter = UTC: 2021-12-21 15:59:17.402847+00:00, Local: 2021-12-21 10:59:17.402847-05:00

Notice sunset local time is EDT (-4) and winter local time is EST (-5) as expected.
(Sunset appears incorrect here due to TT vs UTC confusion.)

Thank you!

0.5.11: pytest fails in 7 units

I'm packaging your module as an rpm package so I'm using the typical PEP517 based build, install and test cycle used on building packages from non-root account.

  • python3 -sBm build -w --no-isolation
  • because I'm calling build with --no-isolation I'm using during all processes only locally installed modules
  • install .whl file in </install/prefix> using installer module
  • run pytest with $PYTHONPATH pointing to sitearch and sitelib inside </install/prefix>
  • build is performed in env which is cut off from access to the public network (pytest is executed with -m "not network")

pytest 8.10.0 and python 3.9.

Here is pytest output:
+ PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-pymeeus-0.5.11-10.fc36.x86_64/usr/lib64/python3.9/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-pymeeus-0.5.11-10.fc36.x86_64/usr/lib/python3.9/site-packages
+ /usr/bin/pytest -ra -m 'not network'
==================================================================================== test session starts ====================================================================================
platform linux -- Python 3.9.18, pytest-8.1.0, pluggy-1.4.0
rootdir: /home/tkloczko/rpmbuild/BUILD/pymeeus-0.5.11
configfile: pyproject.toml
collected 251 items

tests/test_angle.py ........................................                                                                                                                          [ 15%]
tests/test_coordinates.py .......................................                                                                                                                     [ 31%]
tests/test_curvefitting.py .FFFF                                                                                                                                                      [ 33%]
tests/test_earth.py ................                                                                                                                                                  [ 39%]
tests/test_epoch.py .................................                                                                                                                                 [ 52%]
tests/test_interpolation.py .FFF.                                                                                                                                                     [ 54%]
tests/test_jupiter.py ..........                                                                                                                                                      [ 58%]
tests/test_jupiterMoons.py .........                                                                                                                                                  [ 62%]
tests/test_mars.py ..........                                                                                                                                                         [ 66%]
tests/test_mercury.py ............                                                                                                                                                    [ 71%]
tests/test_minor.py ..                                                                                                                                                                [ 72%]
tests/test_moon.py ..............                                                                                                                                                     [ 77%]
tests/test_neptune.py ......                                                                                                                                                          [ 80%]
tests/test_pluto.py ..                                                                                                                                                                [ 80%]
tests/test_saturn.py ..............                                                                                                                                                   [ 86%]
tests/test_sun.py ............                                                                                                                                                        [ 91%]
tests/test_uranus.py ........                                                                                                                                                         [ 94%]
tests/test_venus.py ..............                                                                                                                                                    [100%]

========================================================================================= FAILURES ==========================================================================================
____________________________________________________________________________ test_curvefitting_correlation_coeff ____________________________________________________________________________

    def test_curvefitting_correlation_coeff():
        """Tests the correlation_coeff() method of CurveFitting class"""

>       r = cf1.correlation_coeff()

tests/test_curvefitting.py:92:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = CurveFitting([], [])

    def correlation_coeff(self):
        """This method returns the coefficient of correlation, as a float.

        :returns: Coefficient of correlation.
        :rtype: float

        >>> cf = CurveFitting([73.0, 38.0, 35.0, 42.0, 78.0, 68.0, 74.0, 42.0,
        ...                    52.0, 54.0, 39.0, 61.0, 42.0, 49.0, 50.0, 62.0,
        ...                    44.0, 39.0, 43.0, 54.0, 44.0, 37.0],
        ...                   [90.4, 125.3, 161.8, 143.4, 52.5, 50.8, 71.5,
        ...                    152.8, 131.3, 98.5, 144.8, 78.1, 89.5, 63.9,
        ...                    112.1, 82.0, 119.8, 161.2, 208.4, 111.6, 167.1,
        ...                    162.1])
        >>> r = cf.correlation_coeff()
        >>> print(round(r, 3))
        -0.767
        """

>       n = self._N
E       AttributeError: 'CurveFitting' object has no attribute '_N'

pymeeus/CurveFitting.py:321: AttributeError
_____________________________________________________________________________ test_curvefitting_linear_fitting ______________________________________________________________________________

    def test_curvefitting_linear_fitting():
        """Tests the linear_fitting() method of CurveFitting class"""

>       a, b = cf1.linear_fitting()

tests/test_curvefitting.py:100:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = CurveFitting([], [])

    def linear_fitting(self):
        """This method returns a tuple with the 'a', 'b' coefficients of the
        linear equation *'y = a*x + b'* that best fits the table data, using
        the least squares approach.

        :returns: 'a', 'b' coefficients of best linear equation fit.
        :rtype: tuple
        :raises: ZeroDivisionError if input data leads to a division by zero

        >>> cf = CurveFitting([73.0, 38.0, 35.0, 42.0, 78.0, 68.0, 74.0, 42.0,
        ...                    52.0, 54.0, 39.0, 61.0, 42.0, 49.0, 50.0, 62.0,
        ...                    44.0, 39.0, 43.0, 54.0, 44.0, 37.0],
        ...                   [90.4, 125.3, 161.8, 143.4, 52.5, 50.8, 71.5,
        ...                    152.8, 131.3, 98.5, 144.8, 78.1, 89.5, 63.9,
        ...                    112.1, 82.0, 119.8, 161.2, 208.4, 111.6, 167.1,
        ...                    162.1])
        >>> a, b = cf.linear_fitting()
        >>> print("a = {}\tb = {}".format(round(a, 2), round(b, 2)))
        a = -2.49       b = 244.18
        """

>       n = self._N
E       AttributeError: 'CurveFitting' object has no attribute '_N'

pymeeus/CurveFitting.py:351: AttributeError
____________________________________________________________________________ test_curvefitting_quadratic_fitting ____________________________________________________________________________

    def test_curvefitting_quadratic_fitting():
        """Tests the quadratic_fitting() method of CurveFitting class"""

>       a, b, c = cf3.quadratic_fitting()

tests/test_curvefitting.py:118:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = CurveFitting([], [])

    def quadratic_fitting(self):
        """This method returns a tuple with the 'a', 'b', 'c' coefficients of
        the quadratic equation *'y = a*x*x + b*x + c'* that best fits the table
        data, using the least squares approach.

        :returns: 'a', 'b', 'c' coefficients of best quadratic equation fit.
        :rtype: tuple
        :raises: ZeroDivisionError if input data leads to a division by zero

        >>> cf2 = CurveFitting([-2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5,
        ...                     2.0, 2.5,3.0],
        ...                    [-9.372, -3.821, 0.291, 3.730, 5.822, 8.324,
        ...                     9.083, 6.957, 7.006, 0.365, -1.722])
        >>> a, b, c = cf2.quadratic_fitting()
        >>> print("a = {}; b = {}; c = {}".format(round(a, 2), round(b, 2),
        ...                                       round(c, 2)))
        a = -2.22; b = 3.76; c = 6.64
        """

>       n = self._N
E       AttributeError: 'CurveFitting' object has no attribute '_N'

pymeeus/CurveFitting.py:384: AttributeError
_____________________________________________________________________________ test_curvefitting_general_fitting _____________________________________________________________________________

    def test_curvefitting_general_fitting():
        """Tests the general_fitting() method of CurveFitting class"""

        # Let's define the three functions to be used for fitting
        def sin1(x):
            return sin(radians(x))

        def sin2(x):
            return sin(radians(2.0*x))

        def sin3(x):
            return sin(radians(3.0*x))

>       a, b, c = cf4.general_fitting(sin1, sin2, sin3)

tests/test_curvefitting.py:142:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = CurveFitting([], []), f0 = <function test_curvefitting_general_fitting.<locals>.sin1 at 0x7f8356bea1f0>
f1 = <function test_curvefitting_general_fitting.<locals>.sin2 at 0x7f8356bea280>, f2 = <function test_curvefitting_general_fitting.<locals>.sin3 at 0x7f8356bea310>

    def general_fitting(self, f0, f1=lambda *args: 0.0, f2=lambda *args: 0.0):
        """This method returns a tuple with the 'a', 'b', 'c' coefficients of
        the general equation *'y = a*f0(x) + b*f1(x) + c*f2(x)'* that best fits
        the table data, using the least squares approach.

        :param f0, f1, f2: Functions used to build the general equation.
        :type f0, f1, f2: function
        :returns: 'a', 'b', 'c' coefficients of best general equation fit.
        :rtype: tuple
        :raises: ZeroDivisionError if input functions are null or input data
           leads to a division by zero

        >>> cf4 = CurveFitting([3, 20, 34, 50, 75, 88, 111, 129, 143, 160, 183,
        ...                     200, 218, 230, 248, 269, 290, 303, 320, 344],
        ...                    [0.0433, 0.2532, 0.3386, 0.3560, 0.4983, 0.7577,
        ...                     1.4585, 1.8628, 1.8264, 1.2431, -0.2043,
        ...                     -1.2431, -1.8422, -1.8726, -1.4889, -0.8372,
        ...                     -0.4377, -0.3640, -0.3508, -0.2126])
        >>> def sin1(x): return sin(radians(x))
        >>> def sin2(x): return sin(radians(2.0*x))
        >>> def sin3(x): return sin(radians(3.0*x))
        >>> a, b, c = cf4.general_fitting(sin1, sin2, sin3)
        >>> print("a = {}; b = {}; c = {}".format(round(a, 2), round(b, 2),
        ...                                       round(c, 2)))
        a = 1.2; b = -0.77; c = 0.39

        >>> cf5 = CurveFitting([0, 1.2, 1.4, 1.7, 2.1, 2.2])
        >>> a, b, c = cf5.general_fitting(sqrt)
        >>> print("a = {}; b = {}; c = {}".format(round(a, 3), round(b, 3),
        ...                                       round(c, 3)))
        a = 1.016; b = 0.0; c = 0.0
        """

        m = 0
        p = 0
        q = 0
        r = 0
        s = 0
        t = 0
        u = 0
        v = 0
        w = 0
        xl = list(self._x)
        yl = list(self._y)
        for i, value in enumerate(xl):
            x = value
            y = yl[i]
            m += f0(x) * f0(x)
            p += f0(x) * f1(x)
            q += f0(x) * f2(x)
            r += f1(x) * f1(x)
            s += f1(x) * f2(x)
            t += f2(x) * f2(x)
            u += y * f0(x)
            v += y * f1(x)
            w += y * f2(x)

        if abs(r) < TOL and abs(t) < TOL and abs(m) >= TOL:
            return (u / m, 0.0, 0.0)

        if abs(m * r * t) < TOL:
>           raise ZeroDivisionError("Invalid input functions: They are null")
E           ZeroDivisionError: Invalid input functions: They are null

pymeeus/CurveFitting.py:467: ZeroDivisionError
__________________________________________________________________________________ test_interpolation_call __________________________________________________________________________________

    def test_interpolation_call():
        """Tests the __call__() method of Interpolation class"""

        m = Interpolation([-1.0, 0.0, 1.0], [-2.0, 3.0, 2.0])

        assert abs(m(-0.8) - (-0.52)) < TOL, \
            "ERROR: In 1st __call__() test, output value doesn't match"

        assert abs(m(0.7) - 2.93) < TOL, \
            "ERROR: In 2nd __call__() test, output value doesn't match"

        assert abs(m(-1.0) - (-2.0)) < TOL, \
            "ERROR: In 3rd __call__() test, output value doesn't match"

        m = Interpolation([-3.0, 0.0, 2.5], [12.0, -3.0, -1.75])

        assert abs(m(-2.0) - 5.0) < TOL, \
            "ERROR: In 4th __call__() test, output value doesn't match"

        assert abs(m(2.5) - (-1.75)) < TOL, \
            "ERROR: In 5th __call__() test, output value doesn't match"

        # This interpolation test uses Right Ascension
>       a = Angle(i_ra(11.0))

tests/test_interpolation.py:118:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = Interpolation([], []), x = 11.0

    def __call__(self, x):
        """Method to interpolate the function at a given 'x'.

        :param x: Point where the interpolation will be carried out.
        :type x: int, float, :py:class:`Angle`

        :returns: Resulting value of the interpolation.
        :rtype: float
        :raises: ValueError if input value is outside of interpolation range.
        :raises: TypeError if input value is of wrong type.

        >>> i = Interpolation([7, 8, 9], [0.884226, 0.877366, 0.870531])
        >>> y = round(i(8.18125), 6)
        >>> print(y)
        0.876125
        """

        # Check if input value is of correct type
        if isinstance(x, (int, float, Angle)):
            # Check if 'x' already belongs to the data table
            for i in range(len(self._x)):
                if abs(x - self._x[i]) < self._tol:
                    return self._y[i]  # We don't need to look further
            # Check if Newton coefficients table is not empty
            if len(self._table) == 0:
>               raise RuntimeError("Internal table is empty. Use set().")
E               RuntimeError: Internal table is empty. Use set().

pymeeus/Interpolation.py:404: RuntimeError
_______________________________________________________________________________ test_interpolation_derivative _______________________________________________________________________________

    def test_interpolation_derivative():
        """Tests the derivative() method of Interpolation class"""

        m = Interpolation([-1.0, 0.0, 1.0], [-2.0, 3.0, 2.0])

        assert abs(m.derivative(-1.0) - 8.0) < TOL, \
            "ERROR: In 1st derivative() test, output value doesn't match"

        assert abs(m.derivative(0.0) - 2.0) < TOL, \
            "ERROR: In 2nd derivative() test, output value doesn't match"

        assert abs(m.derivative(0.5) - (-1.0)) < TOL, \
            "ERROR: In 3rd derivative() test, output value doesn't match"

        m = Interpolation([-3.0, 0.0, 2.5], [12.0, -3.0, -1.75])

        assert abs(m.derivative(-3.0) - (-8.0)) < TOL, \
            "ERROR: In 4th derivative() test, output value doesn't match"

        assert abs(m.derivative(0.0) - (-2.0)) < TOL, \
            "ERROR: In 5th derivative() test, output value doesn't match"

        assert abs(m.derivative(2.5) - 3.0) < TOL, \
            "ERROR: In 6th derivative() test, output value doesn't match"

        # Do test with an interpolation object with 6 table entries, based on sine
        # We need to adjust the result because degrees were used instead of radians
>       res = degrees(i_sine.derivative(30.0))

tests/test_interpolation.py:158:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = Interpolation([], []), x = 30.0

    def derivative(self, x):
        """Method to compute the derivative from interpolation polynomial.

        :param x: Point where the interpolation derivative will be carried out.
        :type x: int, float, :py:class:`Angle`

        :returns: Resulting value of the interpolation derivative.
        :rtype: float
        :raises: ValueError if input value is outside of interpolation range.
        :raises: TypeError if input value is of wrong type.

        >>> m = Interpolation([-1.0, 0.0, 1.0], [-2.0, 3.0, 2.0])
        >>> m.derivative(-1.0)
        8.0
        >>> m.derivative(0.5)
        -1.0
        """

        # Check if input value is of correct type
        if isinstance(x, (int, float, Angle)):
            # Check that x is within interpolation table values
>           if x < self._x[0] or x > self._x[-1]:
E           IndexError: list index out of range

pymeeus/Interpolation.py:438: IndexError
__________________________________________________________________________________ test_interpolation_root __________________________________________________________________________________

    def test_interpolation_root():
        """Tests the root() method of Interpolation class"""

        m = Interpolation([-1.0, 0.0, 1.0], [-2.0, 3.0, 2.0])

        assert abs(m.root() - (-0.7207592200561265)) < TOL, \
            "ERROR: In 1st root() test, output value doesn't match"

        m = Interpolation([-3.0, 0.0, 2.5], [12.0, -3.0, -1.75])

        assert abs(m.root(-2.0, 0.0) - (-1.0)) < TOL, \
            "ERROR: In 2nd root() test, output value doesn't match"

        assert abs(m.root() - (-1.0)) < TOL, \
            "ERROR: In 3rd root() test, output value doesn't match"

        m = Interpolation([-3.0, 0.0, 2.5, 3.5], [12.0, -3.0, -1.75, 2.25])

        assert abs(m.root(0.0, 3.15) - 3.0) < TOL, \
            "ERROR: In 4th root() test, output value doesn't match"

        # Let's do some tests with Angles
>       assert abs(i_angles1.root() - 26.798732705) < TOL, \
            "ERROR: In 5th root() test, output value doesn't match"

tests/test_interpolation.py:185:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = Interpolation([], []), xl = 0, xh = 0, max_iter = 1000

    def root(self, xl=0, xh=0, max_iter=1000):
        """Method to find the root inside the [xl, xh] range.

        This method applies, in principle, the Newton method to find the root;
        however, if conditions are such that Newton method may not bei properly
        behaving or converging, then it switches to the linear Interpolation
        method.

        If values xl, xh are not given, the limits of the interpolation table
        values will be used.

        .. note:: This method returns a ValueError exception if the
           corresponding yl = f(xl) and yh = f(xh) values have the same sign.
           In that case, the method assumes there is no root in the [xl, xh]
           interval.

        .. note:: If any of the xl, xh values is beyond the limits given by the
           interpolation values, its value will be set to the corresponding
           limit.

        .. note:: If xl == xh (and not zero), a ValueError exception is raised.

        .. note:: If the method doesn't converge within max_iter ierations,
           then a ValueError exception is raised.

        :param xl: Lower limit of interval where the root will be looked for.
        :type xl: int, float, :py:class:`Angle`
        :param xh: Higher limit of interval where the root will be looked for.
        :type xh: int, float, :py:class:`Angle`
        :param max_iter: Maximum number of iterations allowed.
        :type max_iter: int

        :returns: Root of the interpolated function within [xl, xh] interval.
        :rtype: int, float, :py:class:`Angle`
        :raises: ValueError if yl = f(xl), yh = f(xh) have same sign.
        :raises: ValueError if xl == xh.
        :raises: ValueError if maximum number of iterations is exceeded.
        :raises: TypeError if input value is of wrong type.

        >>> m = Interpolation([-1.0, 0.0, 1.0], [-2.0, 3.0, 2.0])
        >>> round(m.root(), 8)
        -0.72075922
        """

        # Get the limits of the interpolation table
>       xmin = self._x[0]
E       IndexError: list index out of range

pymeeus/Interpolation.py:503: IndexError
================================================================================== short test summary info ==================================================================================
FAILED tests/test_curvefitting.py::test_curvefitting_correlation_coeff - AttributeError: 'CurveFitting' object has no attribute '_N'
FAILED tests/test_curvefitting.py::test_curvefitting_linear_fitting - AttributeError: 'CurveFitting' object has no attribute '_N'
FAILED tests/test_curvefitting.py::test_curvefitting_quadratic_fitting - AttributeError: 'CurveFitting' object has no attribute '_N'
FAILED tests/test_curvefitting.py::test_curvefitting_general_fitting - ZeroDivisionError: Invalid input functions: They are null
FAILED tests/test_interpolation.py::test_interpolation_call - RuntimeError: Internal table is empty. Use set().
FAILED tests/test_interpolation.py::test_interpolation_derivative - IndexError: list index out of range
FAILED tests/test_interpolation.py::test_interpolation_root - IndexError: list index out of range
=============================================================================== 7 failed, 244 passed in 1.93s ===============================================================================

Above is againft curent master.

Please let me know if you need more details or want me to perform some diagnostics.

Sun.equation_of_time() returns incorrect values around the Spring equinox

When the true Sun has just passed the Spring equinox but the 'mean' Sun has not, equation_of_time() returns an incorrect value. E.g. entering 21.0 March 2023 returns e=352 minutes 37.7 seconds where the correct value should be -7 minutes 22.3 seconds.

The fix is to convert all values in the calculation of e to float before assigning it, to avoid e being assigned as an Angle() object (which causes reduction to 0..360 range):

    e = l0() - 0.0057183 - alpha() + deltapsi() * cos(epsilon.rad())
    # FIX: in cases where alpha was just past the spring equinox but l0
    # was still < 360, e was incorrectly calculated.
    # We keep e now as a float and reduce to range -180 .. +180
    e = e - 360.0 * round(e / 360.0)
    e *= 4.0
    # Extract seconds
    s = (abs(e) % 1) * 60.0
    m = int(e)
    return m, s

Interpolation in Coordinates.times_rise_transit_set() fails when values wrap around 360

As mentioned in Meeus's book, when interpolating values such as Right Ascension and longitudes, care must be taken when they wrap from 360 degrees (or 24h) to zero (e.g. an increase from 359 to 1 degrees should be interpolated as 361, not 1). However, testing and possibly adjusting the input of Coordinates.times_rise_transit_set() still yields wrong interpolation results. This is caused by the interpol() function not converting the Angle() objects y1, y2 and y3 to float before interpolating, hence the values get reduced to range 0..360.

The fix is to convert y1, y2 and y3 to float before interpolating and reducing the differences to -180..+180:

def interpol(n, y1, y2, y3):
    a = y2() - y1() # convert to float so avoid reducing to 0..360
    a = a - 360.0 * round(a / 360.0) # reduce to -180..+180
    b = y3() - y2()
    b = b - 360.0 * round(b / 360.0)
    c = b - a
    return y2 + n * (a + b + n * c) / 2.0

(Note that this requires the arguments of interpol() to be Angle() objects, but the function is local to this method and all calls within this method use Angle() objects).

Epoch._check_values() doesn't allow 59.917815 seconds

Epoch._check_values() throws an exception when offered datetime values where the seconds are above 59.0 and below 60.0 seconds.

In my opinion the following check (line 433-434 in Epoch.py):

    if sec < 0 or sec > 59:
        raise ValueError("Invalid value for the input seconds")

Should instead be:

    if sec < 0 or sec >= 60:
        raise ValueError("Invalid value for the input seconds")

I fully understand that a fraction of a second is likely to matter very little in the accuracy of the functions depending on the epoch. However, when running through a loop while incrementing a datetime, fractional seconds are useful to avoid error build-up. For example, an iteration over tropical days:

    # Approximate tropical day
    tdelta = datetime.timedelta(days=365, hours=5, minutes=48,seconds=46)/365
    maxd = 366
    for y in range(0,maxd):
        mydate = datetime.datetime(2019, 6, 21, 12, 0, 0,tzinfo=datetime.timezone.utc)+tdelta*d
        myepoch = pymeeus.Epoch.Epoch(mydate)
        # Do stuff with Epoch here

Here I run into a datetime of 2019-08-05 12:42:59.917815+00:00 which to me seems like a valid datetime. Yet it of course throws an exception:

  File "c:\Program Files\Blender Foundation\Blender 2.82\2.82\python\lib\site-packages\pymeeus\Epoch.py", line 199, in __init__
    self.set(*args, **kwargs)  # Use 'set()' method to handle the setup
  File "c:\Program Files\Blender Foundation\Blender 2.82\2.82\python\lib\site-packages\pymeeus\Epoch.py", line 312, in set
    d.second + d.microsecond / 1e6,
  File "c:\Program Files\Blender Foundation\Blender 2.82\2.82\python\lib\site-packages\pymeeus\Epoch.py", line 434, in _check_values
    raise ValueError("Invalid value for the input seconds")
ValueError: Invalid value for the input seconds
Error: Python script failed, check the message in the system console

I may be wrong on this, if so it would be great if you could let me know why :)

That aside, thank you very much for making this wonderful library available! Apart from the above, it works perfectly for my needs, and has saved me a ton of time.

pip install pymeeus==0.5.12 raises Deprecation warning

When installing pymeeus in a fresh environment I get the following warning:

$  pip --version
pip 22.3.1 from C:\Users\garadford\AppData\Local\Programs\Python\Python310\lib\site-packages\pip (python 3.10)
$  python -m venv .venv
$  .\.venv\Scripts\activate
$  pip install pymeeus==0.5.12 
Collecting pymeeus==0.5.12
  Using cached PyMeeus-0.5.12.tar.gz (5.8 MB)
  Preparing metadata (setup.py) ... done
Installing collected packages: pymeeus
  DEPRECATION: pymeeus is being installed using the legacy 'setup.py install' method, because it does not have a 'pyproject.toml' and the 'wheel' package is not installed. pip 23.1 will enforce this behaviour change. A possible replacement is to enable the '--use-pep517' option. Discussion can be found at https://github.com/pypa/pip/issues/8559
  Running setup.py install for pymeeus ... done
Successfully installed pymeeus-0.5.12

Apparently Discussion can be found at pypa/pip#8559

UnicodeDecodeError while installing

Collecting pymeeus==0.3.9
Using cached PyMeeus-0.3.9.tar.gz (5.3 MB)
ERROR: Command errored out with exit status 1:
command: 'D:\python.exe' -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\Users\unknown\AppData\Local\Temp\17\pi
p-install-lllhqdzk\pymeeus_7fd3c7ad574947d7b68f8c40e8d493fc\setup.py'"'"'; file='"'"'C:\Users\unknown\AppData\Local\Temp\17\pip-install-
lllhqdzk\pymeeus_7fd3c7ad574947d7b68f8c40e8d493fc\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(file);code=f.read().replace('"'"'\r\n'
"'"', '"'"'\n'"'"');f.close();exec(compile(code, file, '"'"'exec'"'"'))' egg_info --egg-base 'C:\Users\unknown\AppData\Local\Temp\17\pip-pip-egg-
info-44kowm40'
cwd: C:\Users\unknown\AppData\Local\Temp\17\pip-install-lllhqdzk\pymeeus_7fd3c7ad574947d7b68f8c40e8d493fc
Complete output (7 lines):
Traceback (most recent call last):
File "", line 1, in
File "C:\Users\unknown\AppData\Local\Temp\17\pip-install-lllhqdzk\pymeeus_7fd3c7ad574947d7b68f8c40e8d493fc\setup.py", line 13, in
long_description = f.read()
File "D:\lib\encodings\cp1252.py", line 23, in decode
return codecs.charmap_decode(input,self.errors,decoding_table)[0]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d in position 237: character maps to
----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.