From f982c49db7bf92191a1c098b957567adf7a2e48d Mon Sep 17 00:00:00 2001 From: Thomas Touhey Date: Thu, 18 Jul 2024 21:41:49 +0200 Subject: [PATCH] Add more complete documentation --- .gitignore | 2 + docs/_ext/custom_autodoc.py | 42 ++++++++++++ docs/code.rst | 13 ++++ docs/code/leapseconddata.rst | 7 ++ docs/conf.py | 25 +++++++- docs/developer-guides.rst | 16 +++++ docs/developer-guides/check-date-leap.py | 14 ++++ .../check-date-leap.py.license | 3 + .../checking-if-date-is-leap.rst | 21 ++++++ docs/developer-guides/convert-tai-to-utc.py | 9 +++ .../convert-tai-to-utc.py.license | 3 + docs/developer-guides/convert-utc-to-tai.py | 9 +++ .../convert-utc-to-tai.py.license | 3 + .../converting-tai-to-utc.rst | 22 +++++++ .../converting-utc-to-tai.rst | 22 +++++++ .../obtaining-leap-seconds.rst | 64 +++++++++++++++++++ docs/guides.rst | 12 ++++ docs/guides/install.rst | 17 +++++ docs/index.rst | 58 +++++++++++++++-- docs/topics.rst | 13 ++++ docs/topics/leap-second-distribution.rst | 50 +++++++++++++++ docs/topics/leap-seconds.rst | 43 +++++++++++++ leapseconddata/__init__.py | 1 - pyproject.toml | 1 + 24 files changed, 460 insertions(+), 10 deletions(-) create mode 100644 docs/_ext/custom_autodoc.py create mode 100644 docs/code.rst create mode 100644 docs/code/leapseconddata.rst create mode 100644 docs/developer-guides.rst create mode 100644 docs/developer-guides/check-date-leap.py create mode 100644 docs/developer-guides/check-date-leap.py.license create mode 100644 docs/developer-guides/checking-if-date-is-leap.rst create mode 100644 docs/developer-guides/convert-tai-to-utc.py create mode 100644 docs/developer-guides/convert-tai-to-utc.py.license create mode 100644 docs/developer-guides/convert-utc-to-tai.py create mode 100644 docs/developer-guides/convert-utc-to-tai.py.license create mode 100644 docs/developer-guides/converting-tai-to-utc.rst create mode 100644 docs/developer-guides/converting-utc-to-tai.rst create mode 100644 docs/developer-guides/obtaining-leap-seconds.rst create mode 100644 docs/guides.rst create mode 100644 docs/guides/install.rst create mode 100644 docs/topics.rst create mode 100644 docs/topics/leap-second-distribution.rst create mode 100644 docs/topics/leap-seconds.rst diff --git a/.gitignore b/.gitignore index a377a74..2ef8011 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ __pycache__ *,cover /.reuse __version__.py +/docs/_build +/.idea diff --git a/docs/_ext/custom_autodoc.py b/docs/_ext/custom_autodoc.py new file mode 100644 index 0000000..4242a9d --- /dev/null +++ b/docs/_ext/custom_autodoc.py @@ -0,0 +1,42 @@ +# SPDX-FileCopyrightText: 2024 Thomas Touhey +# SPDX-License-Identifier: GPL-3.0-only +"""Sphinx extension to remove the first line from module docstrings.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: + from sphinx.application import Sphinx + + +def remove_first_line_in_module_docstring( + _app: Sphinx, + what: str, + _name: str, + _obj: Any, + _options: Any, + lines: list[str], +) -> None: + """Remove the first line from the docstring. + + This is because the first line of the docstring is summed up in the + document title, before the module autodoc. + """ + if what != "module" or not lines: + return + + for i in range(1, len(lines)): + if not lines[i]: + lines[: i + 1] = [] + return + + lines[:] = [] + + +def setup(app: Sphinx) -> None: + """Set up the extension.""" + app.connect( + "autodoc-process-docstring", + remove_first_line_in_module_docstring, + ) diff --git a/docs/code.rst b/docs/code.rst new file mode 100644 index 0000000..57c1b83 --- /dev/null +++ b/docs/code.rst @@ -0,0 +1,13 @@ +.. SPDX-FileCopyrightText: 2024 Thomas Touhey +.. SPDX-License-Identifier: GPL-3.0-only + +Code reference +============== + +If you are looking for information on a specific function, class or method, +this part of the documentation is for you. + +.. toctree:: + :maxdepth: 1 + + code/leapseconddata diff --git a/docs/code/leapseconddata.rst b/docs/code/leapseconddata.rst new file mode 100644 index 0000000..984b83f --- /dev/null +++ b/docs/code/leapseconddata.rst @@ -0,0 +1,7 @@ +.. SPDX-FileCopyrightText: 2024 Thomas Touhey +.. SPDX-License-Identifier: GPL-3.0-only + +``leapseconddata`` -- main namespace for the project +==================================================== + +.. automodule:: leapseconddata diff --git a/docs/conf.py b/docs/conf.py index 8d93ead..5b874aa 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,6 +17,7 @@ import sys import pathlib sys.path.insert(0, str(pathlib.Path(__file__).parent.parent)) +sys.path.append(str(pathlib.Path(__file__).parent / "_ext")) # Define the canonical URL if you are using a custom domain on Read the Docs html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "") @@ -29,7 +30,7 @@ if os.environ.get("READTHEDOCS", "") == "True": # -- Project information ----------------------------------------------------- project = 'leapseconddata' -copyright = '2021, Jeff Epler' +copyright = '2021-2024, Jeff Epler' author = 'Jeff Epler' # The full version, including alpha/beta/rc tags @@ -43,6 +44,9 @@ release = '1.1.0' # ones. extensions = [ 'sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'custom_autodoc', ] # Add any paths that contain templates here, relative to this directory. @@ -51,7 +55,10 @@ templates_path = ['_templates'] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '_env'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '_env', '.license'] + +# Show the contents of todo directives. +todo_include_todos = True # -- Options for HTML output ------------------------------------------------- @@ -66,8 +73,22 @@ html_theme = 'sphinx_rtd_theme' # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), +} + autodoc_typehints = "description" +autodoc_typehints_format = "short" autodoc_class_signature = "separated" +autodoc_default_options = { + "members": True, + "undoc-members": True, + "inherited-members": False, + "special-members": False, + "exclude-members": "__init__", + "show-inheritance": True, +} +autodoc_member_order = "bysource" # SPDX-FileCopyrightText: 2021 Jeff Epler # diff --git a/docs/developer-guides.rst b/docs/developer-guides.rst new file mode 100644 index 0000000..29be9c3 --- /dev/null +++ b/docs/developer-guides.rst @@ -0,0 +1,16 @@ +.. SPDX-FileCopyrightText: 2024 Thomas Touhey +.. SPDX-License-Identifier: GPL-3.0-only + +Developer guides +================ + +This section consists of multiple guides for solving specific problems, +targeted towards developers using the component. + +.. toctree:: + :maxdepth: 2 + + developer-guides/obtaining-leap-seconds + developer-guides/converting-tai-to-utc + developer-guides/converting-utc-to-tai + developer-guides/checking-if-date-is-leap.rst diff --git a/docs/developer-guides/check-date-leap.py b/docs/developer-guides/check-date-leap.py new file mode 100644 index 0000000..caadac0 --- /dev/null +++ b/docs/developer-guides/check-date-leap.py @@ -0,0 +1,14 @@ +from datetime import date, timedelta + +from leapseconddata import LeapSecondData + +my_date = date(2015, 12, 31) +data = LeapSecondData.from_standard_source() + +for leap in data.leap_seconds: + time = leap.start - timedelta(seconds=1) + if my_date.year == time.year and my_date.month == time.month and my_date.day == time.day: + print(f"{my_date} has a leap second!") + break +else: + print(f"{my_date} does not have a leap second.") diff --git a/docs/developer-guides/check-date-leap.py.license b/docs/developer-guides/check-date-leap.py.license new file mode 100644 index 0000000..10512f1 --- /dev/null +++ b/docs/developer-guides/check-date-leap.py.license @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2024 Thomas Touhey +# SPDX-License-Identifier: Unlicense +# Placed in a separate file so that it does not appear in the produced docs. diff --git a/docs/developer-guides/checking-if-date-is-leap.rst b/docs/developer-guides/checking-if-date-is-leap.rst new file mode 100644 index 0000000..665d7aa --- /dev/null +++ b/docs/developer-guides/checking-if-date-is-leap.rst @@ -0,0 +1,21 @@ +.. SPDX-FileCopyrightText: 2024 Thomas Touhey +.. SPDX-License-Identifier: GPL-3.0-only + +Checking if a date has a leap second +==================================== + +In order to check if a date has a leap second, you must first +obtain the leap second data by using one of the methods described +in :ref:`devguide-obtaining-leaps`. Then, you can iterate over +the fetched leap seconds to check for the date. + +For example, in order to check if December 31st, 2016 has a leap +second, you can use the following code: + +.. literalinclude:: check-date-leap.py + +The output of this program is the following: + +.. code-block:: text + + 2016-12-31 has a leap second! diff --git a/docs/developer-guides/convert-tai-to-utc.py b/docs/developer-guides/convert-tai-to-utc.py new file mode 100644 index 0000000..32b63ef --- /dev/null +++ b/docs/developer-guides/convert-tai-to-utc.py @@ -0,0 +1,9 @@ +from datetime import datetime + +from leapseconddata import LeapSecondData, tai + +my_date = datetime(2024, 7, 18, 22, 0, 37, tzinfo=tai) +data = LeapSecondData.from_standard_source() + +my_tai_date = data.tai_to_utc(my_date) +print(my_tai_date.isoformat()) diff --git a/docs/developer-guides/convert-tai-to-utc.py.license b/docs/developer-guides/convert-tai-to-utc.py.license new file mode 100644 index 0000000..10512f1 --- /dev/null +++ b/docs/developer-guides/convert-tai-to-utc.py.license @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2024 Thomas Touhey +# SPDX-License-Identifier: Unlicense +# Placed in a separate file so that it does not appear in the produced docs. diff --git a/docs/developer-guides/convert-utc-to-tai.py b/docs/developer-guides/convert-utc-to-tai.py new file mode 100644 index 0000000..2cac6da --- /dev/null +++ b/docs/developer-guides/convert-utc-to-tai.py @@ -0,0 +1,9 @@ +from datetime import UTC, datetime + +from leapseconddata import LeapSecondData + +my_date = datetime(2024, 7, 18, 22, 0, 0, tzinfo=UTC) +data = LeapSecondData.from_standard_source() + +my_tai_date = data.to_tai(my_date) +print(my_tai_date.isoformat()) diff --git a/docs/developer-guides/convert-utc-to-tai.py.license b/docs/developer-guides/convert-utc-to-tai.py.license new file mode 100644 index 0000000..10512f1 --- /dev/null +++ b/docs/developer-guides/convert-utc-to-tai.py.license @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2024 Thomas Touhey +# SPDX-License-Identifier: Unlicense +# Placed in a separate file so that it does not appear in the produced docs. diff --git a/docs/developer-guides/converting-tai-to-utc.rst b/docs/developer-guides/converting-tai-to-utc.rst new file mode 100644 index 0000000..c81ec12 --- /dev/null +++ b/docs/developer-guides/converting-tai-to-utc.rst @@ -0,0 +1,22 @@ +.. SPDX-FileCopyrightText: 2024 Thomas Touhey +.. SPDX-License-Identifier: GPL-3.0-only + +Converting a TAI date and time to UTC +===================================== + +.. py:currentmodule:: leapseconddata + +In order to convert a TAI date and time to UTC, you must first +obtain the leap second data by using one of the methods described +in :ref:`devguide-obtaining-leaps`. Then, you can use the +:py:meth:`LeapSecondData.tai_to_utc` method to convert the date and time. + +For example: + +.. literalinclude:: convert-tai-to-utc.py + +This program will provide you with the following output: + +.. code-block:: text + + 2024-07-18T22:00:00g+00:00 diff --git a/docs/developer-guides/converting-utc-to-tai.rst b/docs/developer-guides/converting-utc-to-tai.rst new file mode 100644 index 0000000..4049b3a --- /dev/null +++ b/docs/developer-guides/converting-utc-to-tai.rst @@ -0,0 +1,22 @@ +.. SPDX-FileCopyrightText: 2024 Thomas Touhey +.. SPDX-License-Identifier: GPL-3.0-only + +Converting a UTC date and time to TAI +===================================== + +.. py:currentmodule:: leapseconddata + +In order to convert a UTC date and time to TAI, you must first +obtain the leap second data by using one of the methods described +in :ref:`devguide-obtaining-leaps`. Then, you can use the +:py:meth:`LeapSecondData.to_tai` method to convert the date and time. + +For example: + +.. literalinclude:: convert-utc-to-tai.py + +This program will provide you with the following output: + +.. code-block:: text + + 2024-07-18T22:00:37+00:00 diff --git a/docs/developer-guides/obtaining-leap-seconds.rst b/docs/developer-guides/obtaining-leap-seconds.rst new file mode 100644 index 0000000..2902aff --- /dev/null +++ b/docs/developer-guides/obtaining-leap-seconds.rst @@ -0,0 +1,64 @@ +.. SPDX-FileCopyrightText: 2024 Thomas Touhey +.. SPDX-License-Identifier: GPL-3.0-only + +.. _devguide-obtaining-leaps: + +Obtaining a list of leap seconds +================================ + +.. py:currentmodule:: leapseconddata + +In order to obtain the current leap second list, you must use one of +:py:class:`LeapSecondData` ``from_*`` class methods. + +Using the first available standard source +----------------------------------------- + +If you do not have any particular restrictions on your Internet access, +you can try the "magic" method :py:meth:`LeapSecondData.from_standard_source`, +which will try known local then network sources: + +.. code-block:: python + + from leapseconddata import LeapSecondData + + data = LeapSecondData.from_standard_source() + ... + +Using a custom file source +-------------------------- + +If you have a custom path for the ``leap-seconds.list`` the module can use, +you can use the :py:meth:`LeapSecondData.from_file` method. For example, +if your file is located at ``/etc/my-program/leap-seconds.list``: + +.. code-block:: python + + from leapseconddata import LeapSecondData + + data = LeapSecondData.from_file("/etc/my-program/leap-seconds.list") + +Using a custom URL +------------------ + +If you have restrictions on your Internet access and can only access the +file from a specific URL available to your machine, you can use +:py:meth:`LeapSecondData.from_url`: + +.. code-block:: python + + from leapseconddata import LeapSecondData + + data = LeapSecondData.from_url("https://tz.example/leap-seconds.list") + +You can also still try local sources before your custom URL, by using +:py:meth:`LeapSecondData.from_standard_source` with the ``custom_sources`` +keyword parameter set: + +.. code-block:: python + + from leapseconddata import LeapSecondData + + data = LeapSecondData.from_standard_source( + custom_sources=["https://tz.example/leap-seconds.list"], + ) diff --git a/docs/guides.rst b/docs/guides.rst new file mode 100644 index 0000000..d0d89ec --- /dev/null +++ b/docs/guides.rst @@ -0,0 +1,12 @@ +.. SPDX-FileCopyrightText: 2024 Thomas Touhey +.. SPDX-License-Identifier: GPL-3.0-only + +General guides +============== + +This section consists of multiple guides for solving specific problems. + +.. toctree:: + :maxdepth: 2 + + guides/install diff --git a/docs/guides/install.rst b/docs/guides/install.rst new file mode 100644 index 0000000..d5141f7 --- /dev/null +++ b/docs/guides/install.rst @@ -0,0 +1,17 @@ +.. SPDX-FileCopyrightText: 2024 Thomas Touhey +.. SPDX-License-Identifier: GPL-3.0-only + +.. _guide-install: + +Installing leapseconddata +========================= + +In order to install leapseconddata, the instructions may depend on the system +you want to install it on. + +pip (generic) +------------- + +leapseconddata can be installed via ``pip``:: + + pip install leapseconddata diff --git a/docs/index.rst b/docs/index.rst index ddae01d..be11a63 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,9 +1,9 @@ .. SPDX-FileCopyrightText: 2021 Jeff Epler -.. +.. SPDX-FileCopyrightText: 2024 Thomas Touhey .. SPDX-License-Identifier: GPL-3.0-only -leapseconddata -============== +leapseconddata |version| +======================== .. image:: https://github.com/jepler/leapseconddata/actions/workflows/test.yml/badge.svg :target: https://github.com/jepler/leapseconddata/actions/workflows/test.yml @@ -13,10 +13,54 @@ leapseconddata :target: https://pypi.org/project/leapseconddata :alt: PyPI +This module allows you to download and extract leap second data from +various trusted sources, both offline and online, in order to: + +* Convert dates and times between TAI and UTC; +* Determine if a date has an extra second at the end in UTC. + +You can also find the project in the following locations: + +* `jelper/leapseconddata repository on Github + `_; +* `leapseconddata project on PyPI + `_. + +The project’s code and documentation contents are licensed under GNU General +Public License version 3. + +How-to guides +------------- + +These sections provide guides, i.e. recipes, targeted towards various actors. +They guide you through the steps involved in addressing key problems +and use-cases. .. toctree:: - :maxdepth: 2 - :caption: Contents: + :maxdepth: 3 -.. automodule:: leapseconddata - :members: + guides + developer-guides + +Discussion topics +----------------- + +These sections discuss key topics and concepts at a fairly high level, and +provide useful background information and explanation. + +.. toctree:: + :maxdepth: 3 + + topics + +References +---------- + +These sections provide technical reference for APIs and other aspects of +the project's machinery. They go into detail, and therefore, assume you +have a basic understanding of key concepts. + +.. toctree:: + :maxdepth: 2 + + code diff --git a/docs/topics.rst b/docs/topics.rst new file mode 100644 index 0000000..7a112a0 --- /dev/null +++ b/docs/topics.rst @@ -0,0 +1,13 @@ +.. SPDX-FileCopyrightText: 2024 Thomas Touhey +.. SPDX-License-Identifier: GPL-3.0-only + +General topics +============== + +These topics explore general concepts behind the project. + +.. toctree:: + :maxdepth: 2 + + topics/leap-seconds + topics/leap-second-distribution diff --git a/docs/topics/leap-second-distribution.rst b/docs/topics/leap-second-distribution.rst new file mode 100644 index 0000000..99b7953 --- /dev/null +++ b/docs/topics/leap-second-distribution.rst @@ -0,0 +1,50 @@ +.. SPDX-FileCopyrightText: 2024 Thomas Touhey +.. SPDX-License-Identifier: GPL-3.0-only + +How is leap second data distributed? +==================================== + +Leap seconds are announced **every six months** by the IERS in the +`Bulletin C publications`_: + +* On beginning of January if they are introduced on June 30th (UTC); +* On beginning of July if they are introduced in December 31st (UTC). + +For example: + +* `Bulletin C 52`_, published on July 6th, 2016, announces a leap + second will be introduced on December 31st, 2016 (UTC). +* `Bulletin C 67`_, published on July 4th, 2024, announces **no** + leap second will be introduced on June 30th, 2024 (UTC). + +The IERS also distributes a file named ``leap-seconds.list``, at the +following URL:: + + https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list + +From here, there are multiple approaches to how systems can receive +the information, in order to display the time correctly: + +* NTP supports informing clients of minutes with a leap second. + See `The NTP Timescale and Leap Seconds`_ for more information; +* Debian and derivatives distribute the file provided by the IERS, as + well as some commodities, through the tzdata_ package. + This file is available at ``/usr/share/zoneinfo/leap-seconds.list``; +* FreeBSD's ntpd has a ntpleapfetch_ command that fetches ``leap-seconds.list`` + file, and stores it in ``/var/db/ntpd.leap-seconds.list``. +* Programs can fetch the file directly from network sources, if the network + is not restricted. + +If using :py:meth:`LeapSecondData.from_standard_source`, ``leapseconddata`` +will use local sources if available, and official network sources if +not found. + +.. _Bulletin C publications: + https://datacenter.iers.org/availableVersions.php?id=16 +.. _Bulletin C 52: + https://datacenter.iers.org/data/16/bulletinc-052.txt +.. _Bulletin C 67: + https://datacenter.iers.org/data/16/bulletinc-067.txt +.. _The NTP Timescale and Leap Seconds: https://www.ntp.org/reflib/leap/ +.. _tzdata: https://salsa.debian.org/glibc-team/tzdata +.. _ntpleapfetch: https://docs.ntpsec.org/latest/ntpleapfetch.html diff --git a/docs/topics/leap-seconds.rst b/docs/topics/leap-seconds.rst new file mode 100644 index 0000000..df218dd --- /dev/null +++ b/docs/topics/leap-seconds.rst @@ -0,0 +1,43 @@ +.. SPDX-FileCopyrightText: 2024 Thomas Touhey +.. SPDX-License-Identifier: GPL-3.0-only + +What are leap seconds? +====================== + +`Coordinated Universal Time (UTC) `_ is a time standard based on two +other standards, `International Atomic Time (TAI) `_ and +`Universal Time (UT1) `_. It aims at being at a whole second offset +from TAI, while keeping UTC and UT1 within 0.9 seconds of each other. + +In order to accomplish that, UTC bases itself on TAI, and gets `leap seconds`_ +added to it when considered necessary by the `International Earth Rotation +Service (IERS) `_, in a semi-annually published bulletin called +`Bulletin C`_ which announces whether or not a leap second is inserted +in June 30th and/or December 31st, meaning the UTC clock may reach ``23:59:60`` +on these dates. + +.. note:: + + With timezones, the leap second may not be inserted at ``23:59``, but + at another time. For example: + + * In France, using Central European Time (CET, UTC+01:00), the leap second + was inserted on January 1st, 2017, at ``00:59:60``. + * In Australia, using Australian Western Central Standard Time (AWCST, + UTC+08:45), the leap second was inserted on January 1st, 2017, + at ``08:44:60``. + * In the United States, using Mountain Time Zone (UTC-07:00), the leap + second was inserted on December 31st, 2016, at ``16:59:60``. + +For more information, you can read `The Unix leap second mess (madore.org) +`_, as +well as the Wikipedia pages linked above. + +.. _UTC: https://en.wikipedia.org/wiki/Coordinated_Universal_Time +.. _TAI: https://en.wikipedia.org/wiki/International_Atomic_Time +.. _UT1: https://en.wikipedia.org/wiki/Universal_Time +.. _leap seconds: https://en.wikipedia.org/wiki/Leap_second +.. _IERS: + https://en.wikipedia.org/wiki/ + International_Earth_Rotation_and_Reference_Systems_Service +.. _Bulletin C: https://datacenter.iers.org/productMetadata.php?id=16 diff --git a/leapseconddata/__init__.py b/leapseconddata/__init__.py index dc97011..7787402 100755 --- a/leapseconddata/__init__.py +++ b/leapseconddata/__init__.py @@ -17,7 +17,6 @@ For example, to retrieve the UTC-TAI offset on January 1, 2011: >>> when = datetime.datetime(2011, 1, 1, tzinfo=datetime.timezone.utc) >>> ls.tai_offset(when).total_seconds() 34.0 - """ from __future__ import annotations diff --git a/pyproject.toml b/pyproject.toml index cccc58a..aaf6f30 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,6 +20,7 @@ line-length=120 [tool.ruff.lint] select = ["E", "F", "D", "I", "N", "UP", "YTT", "BLE", "B", "FBT", "A", "COM", "C4", "DTZ", "FA", "ISC", "ICN", "PIE", "PYI", "Q", "RET", "SIM", "TID", "TCH", "ARG", "PTH", "C", "R", "W", "FLY", "RUF", "PL"] ignore = ["D203", "D213", "D400", "D415", "ISC001", "COM812"] +exclude = ["docs/**/*.py"] [project] name = "leapseconddata" authors = [{name = "Jeff Epler", email = "jepler@gmail.com"}]