Bladeren bron

Merge pull request #420 from Kosmorro/features

tags/v1.0.0rc1
Deuchnord 4 maanden geleden
committed by GitHub
bovenliggende
commit
13a78a8f8d
Geen bekende sleutel gevonden voor deze handtekening in de database GPG sleutel-ID: B5690EEEBB952194
30 gewijzigde bestanden met toevoegingen van 1198 en 1443 verwijderingen
  1. +0
    -7
      .coveragerc
  2. +6
    -0
      .github/ISSUE_TEMPLATE/config.yml
  3. +60
    -0
      .github/ISSUE_TEMPLATE/feature_request.yml
  4. +0
    -4
      .github/workflows/tests.yml
  5. +0
    -581
      .pylintrc
  6. +0
    -2
      MANIFEST.in
  7. +6
    -1
      README.md
  8. +149
    -73
      kosmorro/__main__.py
  9. +178
    -0
      kosmorro/assets/latex/template.tex
  10. +0
    -115
      kosmorro/assets/pdf/kosmorro.sty
  11. +0
    -68
      kosmorro/assets/pdf/template.tex
  12. +16
    -17
      kosmorro/dumper.py
  13. +3
    -0
      kosmorro/environment.py
  14. +13
    -0
      kosmorro/exceptions.py
  15. +48
    -0
      kosmorro/geolocation.py
  16. +81
    -17
      kosmorro/i18n/strings.py
  17. +136
    -71
      kosmorro/locales/messages.pot
  18. +17
    -4
      kosmorro/utils.py
  19. +16
    -14
      manpage/kosmorro.1.md
  20. +255
    -350
      poetry.lock
  21. +6
    -4
      pyproject.toml
  22. +0
    -12
      setup.cfg
  23. +20
    -0
      tests/completion.py
  24. +18
    -8
      tests/dates.py
  25. +30
    -0
      tests/events.py
  26. +43
    -39
      tests/general.py
  27. +27
    -3
      tests/output.py
  28. +4
    -7
      tests/position.py
  29. +65
    -45
      tests/timezone.py
  30. +1
    -1
      tests/utils.py

+ 0
- 7
.coveragerc Bestand weergeven

@@ -1,7 +0,0 @@
[run]
branch = true
source =
kosmorrolib
omit =
kosmorrolib/main.py
test/*

+ 6
- 0
.github/ISSUE_TEMPLATE/config.yml Bestand weergeven

@@ -0,0 +1,6 @@
blank_issue_enabled: true

contact_links:
- name: Event type
description: Suggest an event type that is not supported yet
url: https://github.com/Kosmorro/lib/issues/new/choose

+ 60
- 0
.github/ISSUE_TEMPLATE/feature_request.yml Bestand weergeven

@@ -0,0 +1,60 @@
name: Feature request
description: Suggest a new feature for Kosmorro
labels:
- enhancement

body:
- type: checkboxes
id: terms
attributes:
label: I have searched for an opened issue and didn't find my bug
description: |
Before continuing, please verify that your bug is not already known, i.e.:

- there is an issue that describe your bug;
- the issue is not closed.

If you have found a closed issue that describes the same bug as yours, please don't comment inside and open a new issue instead.
Even though it may look the same, your bug might be totally different :smile:

options:
- label: I confirm I didn't find any issue regarding my bug
required: true

- type: textarea
id: description
validations:
required: true
attributes:
label: Feature description
description: |
Describe the feature you would like to see in Kosmorro.

- type: textarea
id: context
validations:
required: false
attributes:
label: Suggestion context
description: |
If you have some context to share about your suggestion, feel free to describe here.
For instance, a frustration.

- type: textarea
id: alternatives
validations:
required: false
attributes:
label: Considered alternatives
description: |
Did you find any alternative solution that meet your need?
It can be a workaround in Kosmorro usage, or even the use of another software with or in replacement.

- type: textarea
id: additional-info
validations:
required: false
attributes:
label: Additional information
description: |
Anything else to say?

+ 0
- 4
.github/workflows/tests.yml Bestand weergeven

@@ -20,10 +20,6 @@ jobs:
- ubuntu-latest - ubuntu-latest
- macos-latest - macos-latest
python-version: python-version:
- '3.8'
- '3.9'
- '3.10'
- '3.11'
- '3.12' - '3.12'
- '3.13' - '3.13'




+ 0
- 581
.pylintrc Bestand weergeven

@@ -1,581 +0,0 @@
[MASTER]

# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code.
extension-pkg-whitelist=

# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS

# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
ignore-patterns=

# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=

# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
# number of processors available to use.
jobs=1

# Control the amount of potential inferred values when inferring a single
# object. This can help the performance when dealing with large functions or
# complex, nested conditions.
limit-inference-results=100

# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=pylintfileheader

file-header=#!/usr/bin/env python3\n\n# Kosmorro - Compute The Next Ephemerides\n# Copyright \(C\) 2019 Jérôme Deuchnord <jerome@deuchnord.fr>\n#\n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU Affero General Public License as\n# published by the Free Software Foundation, either version 3 of the\n# License, or \(at your option\) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU Affero General Public License for more details.\n#\n# You should have received a copy of the GNU Affero General Public License\n# along with this program. If not, see <https://www.gnu.org/licenses/>.\n

# Pickle collected data for later comparisons.
persistent=yes

# Specify a configuration file.
#rcfile=

# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages.
suggestion-mode=yes

# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no


[MESSAGES CONTROL]

# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
confidence=

# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once). You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use "--disable=all --enable=classes
# --disable=W".
disable=print-statement,
parameter-unpacking,
unpacking-in-except,
old-raise-syntax,
backtick,
long-suffix,
old-ne-operator,
old-octal-literal,
import-star-module-level,
non-ascii-bytes-literal,
raw-checker-failed,
bad-inline-option,
locally-disabled,
file-ignored,
suppressed-message,
useless-suppression,
deprecated-pragma,
use-symbolic-message-instead,
apply-builtin,
basestring-builtin,
buffer-builtin,
cmp-builtin,
coerce-builtin,
execfile-builtin,
file-builtin,
long-builtin,
raw_input-builtin,
reduce-builtin,
standarderror-builtin,
unicode-builtin,
xrange-builtin,
coerce-method,
delslice-method,
getslice-method,
setslice-method,
no-absolute-import,
old-division,
dict-iter-method,
dict-view-method,
next-method-called,
metaclass-assignment,
indexing-exception,
raising-string,
reload-builtin,
oct-method,
hex-method,
nonzero-method,
cmp-method,
input-builtin,
round-builtin,
intern-builtin,
unichr-builtin,
map-builtin-not-iterating,
zip-builtin-not-iterating,
range-builtin-not-iterating,
filter-builtin-not-iterating,
using-cmp-argument,
eq-without-hash,
div-method,
idiv-method,
rdiv-method,
exception-message-attribute,
invalid-str-codec,
sys-max-int,
bad-python3-import,
deprecated-string-function,
deprecated-str-translate-call,
deprecated-itertools-function,
deprecated-types-field,
next-method-defined,
dict-items-not-iterating,
dict-keys-not-iterating,
dict-values-not-iterating,
deprecated-operator-function,
deprecated-urllib-function,
xreadlines-attribute,
deprecated-sys-function,
exception-escape,
comprehension-escape,
missing-docstring,
too-many-locals,
too-many-branches,
too-few-public-methods,
protected-access,
unnecessary-comprehension,
too-many-arguments,
unsubscriptable-object,
too-many-return-statements

# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=c-extension-no-member


[REPORTS]

# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)

# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details.
#msg-template=

# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio). You can also give a reporter class, e.g.
# mypackage.mymodule.MyReporterClass.
output-format=text

# Tells whether to display a full report or only the messages.
reports=no

# Activate the evaluation score.
score=yes


[REFACTORING]

# Maximum number of nested blocks for function / method body
max-nested-blocks=5

# Complete name of functions that never returns. When checking for
# inconsistent-return-statements if a never returning function is called then
# it will be considered as an explicit return statement and no message will be
# printed.
never-returning-functions=sys.exit


[BASIC]

# Naming style matching correct argument names.
argument-naming-style=snake_case

# Regular expression matching correct argument names. Overrides argument-
# naming-style.
#argument-rgx=

# Naming style matching correct attribute names.
attr-naming-style=snake_case

# Regular expression matching correct attribute names. Overrides attr-naming-
# style.
#attr-rgx=

# Bad variable names which should always be refused, separated by a comma.
bad-names=foo,
bar,
baz,
toto,
tutu,
tata

# Naming style matching correct class attribute names.
class-attribute-naming-style=any

# Regular expression matching correct class attribute names. Overrides class-
# attribute-naming-style.
#class-attribute-rgx=

# Naming style matching correct class names.
class-naming-style=PascalCase

# Regular expression matching correct class names. Overrides class-naming-
# style.
#class-rgx=

# Naming style matching correct constant names.
const-naming-style=UPPER_CASE

# Regular expression matching correct constant names. Overrides const-naming-
# style.
#const-rgx=

# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1

# Naming style matching correct function names.
function-naming-style=snake_case

# Regular expression matching correct function names. Overrides function-
# naming-style.
#function-rgx=

# Good variable names which should always be accepted, separated by a comma.
good-names=i,
j,
k,
ex,
Run,
_

# Include a hint for the correct naming format with invalid-name.
include-naming-hint=no

# Naming style matching correct inline iteration names.
inlinevar-naming-style=any

# Regular expression matching correct inline iteration names. Overrides
# inlinevar-naming-style.
#inlinevar-rgx=

# Naming style matching correct method names.
method-naming-style=snake_case

# Regular expression matching correct method names. Overrides method-naming-
# style.
#method-rgx=

# Naming style matching correct module names.
module-naming-style=snake_case

# Regular expression matching correct module names. Overrides module-naming-
# style.
#module-rgx=

# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=

# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_

# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
# These decorators are taken in consideration only for invalid-name.
property-classes=abc.abstractproperty

# Naming style matching correct variable names.
variable-naming-style=snake_case

# Regular expression matching correct variable names. Overrides variable-
# naming-style.
#variable-rgx=


[FORMAT]

# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=

# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$

# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4

# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '

# Maximum number of characters on a single line.
max-line-length=120

# Maximum number of lines in a module.
max-module-lines=1000

# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,
dict-separator

# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no

# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no


[LOGGING]

# Format style used to check logging format string. `old` means using %
# formatting, while `new` is for `{}` formatting.
logging-format-style=old

# Logging modules to check that the string format arguments are in logging
# function parameter format.
logging-modules=logging


[MISCELLANEOUS]

# List of note tags to take in consideration, separated by a comma.
notes=FIXME,
XXX,
TODO


[SIMILARITIES]

# Ignore comments when computing similarities.
ignore-comments=yes

# Ignore docstrings when computing similarities.
ignore-docstrings=yes

# Ignore imports when computing similarities.
ignore-imports=no

# Minimum lines number of a similarity.
min-similarity-lines=4


[SPELLING]

# Limits count of emitted suggestions for spelling mistakes.
max-spelling-suggestions=4

# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package..
spelling-dict=

# List of comma separated words that should not be checked.
spelling-ignore-words=

# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=

# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no


[STRING]

# This flag controls whether the implicit-str-concat-in-sequence should
# generate a warning on implicit string concatenation in sequences defined over
# several lines.
check-str-concat-over-line-jumps=no


[TYPECHECK]

# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager

# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=

# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes

# Tells whether to warn about missing members when the owner of the attribute
# is inferred to be None.
ignore-none=yes

# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes

# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local

# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=

# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes

# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1

# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1


[VARIABLES]

# List of additional names supposed to be defined in builtins. Remember that
# you should avoid defining new builtins when possible.
additional-builtins=

# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes

# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,
_cb

# A regular expression matching the name of dummy variables (i.e. expected to
# not be used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_

# Argument names that match this expression will be ignored. Default to name
# with leading underscore.
ignored-argument-names=_.*|^ignored_|^unused_

# Tells whether we should check for unused import in __init__ files.
init-import=no

# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io


[CLASSES]

# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,
__new__,
setUp

# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,
_fields,
_replace,
_source,
_make

# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls

# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=cls


[DESIGN]

# Maximum number of arguments for function / method.
max-args=5

# Maximum number of attributes for a class (see R0902).
max-attributes=7

# Maximum number of boolean expressions in an if statement.
max-bool-expr=5

# Maximum number of branch for function / method body.
max-branches=12

# Maximum number of locals for function / method body.
max-locals=15

# Maximum number of parents for a class (see R0901).
max-parents=7

# Maximum number of public methods for a class (see R0904).
max-public-methods=20

# Maximum number of return / yield for function / method body.
max-returns=6

# Maximum number of statements in function / method body.
max-statements=50

# Minimum number of public methods for a class (see R0903).
min-public-methods=2


[IMPORTS]

# Allow wildcard imports from modules that define __all__.
allow-wildcard-with-all=no

# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no

# Deprecated modules which should not be used, separated by a comma.
deprecated-modules=optparse,tkinter.tix

# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled).
ext-import-graph=

# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled).
import-graph=

# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled).
int-import-graph=

# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=

# Force import order to recognize a module as part of a third party library.
known-third-party=enchant


[EXCEPTIONS]

# Exceptions that will emit a warning when being caught. Defaults to
# "BaseException, Exception".
overgeneral-exceptions=BaseException,
Exception

+ 0
- 2
MANIFEST.in Bestand weergeven

@@ -1,2 +0,0 @@
recursive-include _kosmorro/locales *
recursive-include _kosmorro/assets *

+ 6
- 1
README.md Bestand weergeven

@@ -1,5 +1,5 @@
# ![Kosmorro](https://github.com/Kosmorro/logos/raw/main/kosmorro/kosmorro-artwork.jpg) # ![Kosmorro](https://github.com/Kosmorro/logos/raw/main/kosmorro/kosmorro-artwork.jpg)
[![Version on PyPI](https://img.shields.io/pypi/v/kosmorro)](https://pypi.org/project/kosmorro) [![Packaging status](https://repology.org/badge/tiny-repos/kosmorro.svg)](https://repology.org/project/kosmorro/versions) [![Help translating Kosmorro!](https://hosted.weblate.org/widgets/kosmorro/-/cli/svg-badge.svg)](https://hosted.weblate.org/engage/kosmorro/)
[![Version on PyPI](https://img.shields.io/pypi/v/kosmorro)](https://pypi.org/project/kosmorro) [![Packaging status](https://repology.org/badge/tiny-repos/kosmorro.svg)](https://repology.org/project/kosmorro/versions) [![Help translating Kosmorro!](https://hosted.weblate.org/widgets/kosmorro/-/cli/svg-badge.svg)](https://hosted.weblate.org/engage/kosmorro/) [![IRC: #kosmorro on Libera.Chat](https://img.shields.io/badge/Libera.Chat-%23kosmorro-blueviolet)](https://web.libera.chat/?nick=Astronaut?#kosmorro)


Kosmorro is a program that calculates your astronomical ephemerides. Kosmorro is a program that calculates your astronomical ephemerides.


@@ -24,6 +24,11 @@ By default, it will give you the current Moon phase and, if any, the events that


Kosmorro has a lot of available options to get exactly what you want, including the possibility to get planets rise and set. To get a list of them, run `kosmorro --help`, or read its manual with `man kosmorro`. You can also find usage examples in [the `tldr` manual](https://tldr.sh) with [`tldr kosmorro`](https://tldr.inbrowser.app/pages/common/kosmorro). Kosmorro has a lot of available options to get exactly what you want, including the possibility to get planets rise and set. To get a list of them, run `kosmorro --help`, or read its manual with `man kosmorro`. You can also find usage examples in [the `tldr` manual](https://tldr.sh) with [`tldr kosmorro`](https://tldr.inbrowser.app/pages/common/kosmorro).


### Exporting to PDF

Kosmorro can export the computation results to PDF files, but this feature requires first that you install some additional dependencies.
You can find documentation about this on [Kosmorro's website](https://kosmorro.space/cli/generate-pdf/).

## Help translating Kosmorro! ## Help translating Kosmorro!


Kosmorro is translated on [Weblate](https://hosted.weblate.org/engage/kosmorro/), a popular free platform for crowd-sourced internationalization. Kosmorro is translated on [Weblate](https://hosted.weblate.org/engage/kosmorro/), a popular free platform for crowd-sourced internationalization.


+ 149
- 73
kosmorro/__main__.py Bestand weergeven

@@ -17,8 +17,11 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.


import argparse import argparse
import argcomplete
import sys import sys
import os.path


import pytz
from babel.dates import format_date from babel.dates import format_date
from kosmorrolib import Position, get_ephemerides, get_events, get_moon_phase from kosmorrolib import Position, get_ephemerides, get_events, get_moon_phase
from kosmorrolib.exceptions import OutOfRangeDateError from kosmorrolib.exceptions import OutOfRangeDateError
@@ -26,8 +29,20 @@ from datetime import date


from . import dumper, environment, debug from . import dumper, environment, debug
from .date import parse_date from .date import parse_date
from .utils import KOSMORRO_VERSION, KOSMORROLIB_VERSION, colored, set_colors_activated
from .exceptions import UnavailableFeatureError, OutOfRangeDateError as DateRangeError
from .geolocation import get_position
from .utils import (
KOSMORRO_VERSION,
KOSMORROLIB_VERSION,
colored,
set_colors_activated,
print_stderr,
get_timezone,
)
from .exceptions import (
InvalidOutputFormatError,
UnavailableFeatureError,
OutOfRangeDateError as DateRangeError,
)
from kosmorro.i18n.utils import _ from kosmorro.i18n.utils import _




@@ -40,21 +55,33 @@ def run():


set_colors_activated(args.colors) set_colors_activated(args.colors)


if args.completion is not None:
return 0 if output_completion(args.completion) else 1

if args.special_action is not None: if args.special_action is not None:
return 0 if args.special_action() else 1 return 0 if args.special_action() else 1


try: try:
compute_date = parse_date(args.date) compute_date = parse_date(args.date)
except ValueError as error: except ValueError as error:
print(colored(error.args[0], color="red", attrs=["bold"]))
print_stderr(colored(error.args[0], color="red", attrs=["bold"]))
return -1 return -1


position = None position = None
if args.position not in [None, ""]:
position = get_position(args.position)
elif env_vars.position not in [None, ""]:
position = get_position(env_vars.position)

# if output format is not specified, try to use output file extension as output format
if args.output is not None and output_format is None:
file_extension = os.path.splitext(args.output)[-1][1:].lower()
if file_extension:
output_format = file_extension


if args.latitude is not None or args.longitude is not None:
position = Position(args.latitude, args.longitude)
elif env_vars.latitude is not None and env_vars.longitude is not None:
position = Position(float(env_vars.latitude), float(env_vars.longitude))
# default to .txt if output format was not given and output file did not have file extension
if output_format is None:
output_format = "txt"


if output_format == "pdf": if output_format == "pdf":
print( print(
@@ -64,8 +91,7 @@ def run():
) )
) )
if position is None: if position is None:
print()
print(
print_stderr(
colored( colored(
_( _(
"PDF output will not contain the ephemerides, because you didn't provide the observation " "PDF output will not contain the ephemerides, because you didn't provide the observation "
@@ -75,42 +101,68 @@ def run():
) )
) )


timezone = args.timezone
timezone = 0


if timezone is None and env_vars.timezone is not None:
timezone = int(env_vars.timezone)
elif timezone is None:
timezone = 0
try:
if args.timezone is not None:
timezone = get_timezone(args.timezone)
elif env_vars.tz is not None:
timezone = get_timezone(env_vars.tz)
elif env_vars.timezone is not None:
print_stderr(
colored(
_(
"Environment variable KOSMORRO_TIMEZONE is deprecated. Use TZ instead, which is more standard."
),
"yellow",
)
)
timezone = get_timezone(env_vars.timezone)
except pytz.UnknownTimeZoneError as error:
print_stderr(
colored(
_("Unknown timezone: {timezone}").format(timezone=error.args[0]),
color="red",
)
)
return -1


try: try:
use_colors = not environment.NO_COLOR and args.colors

output = get_information( output = get_information(
compute_date, compute_date,
position, position,
timezone, timezone,
output_format, output_format,
args.colors,
use_colors,
args.show_graph, args.show_graph,
) )
except InvalidOutputFormatError as error:
print_stderr(colored(error.msg, "red"))
debug.debug_print(error)
return 3
except UnavailableFeatureError as error: except UnavailableFeatureError as error:
print(colored(error.msg, "red"))
print_stderr(colored(error.msg, "red"))
debug.debug_print(error) debug.debug_print(error)
return 2 return 2
except DateRangeError as error: except DateRangeError as error:
print(colored(error.msg, "red"))
print_stderr(colored(error.msg, "red"))
debug.debug_print(error) debug.debug_print(error)
return 1 return 1


if args.output is not None: if args.output is not None:
try: try:
pdf_content = output.to_string()
with open(args.output, "wb") as output_file:
output_file.write(pdf_content)
file_content = output.to_string()
opening_mode = get_opening_mode(output_format)
with open(args.output, opening_mode) as output_file:
output_file.write(file_content)
except UnavailableFeatureError as error: except UnavailableFeatureError as error:
print(colored(error.msg, "red"))
print_stderr(colored(error.msg, "red"))
debug.debug_print(error) debug.debug_print(error)
return 2 return 2
except OSError as error: except OSError as error:
print(
print_stderr(
colored( colored(
_('The file could not be saved in "{path}": {error}').format( _('The file could not be saved in "{path}": {error}').format(
path=args.output, error=error.strerror path=args.output, error=error.strerror
@@ -124,7 +176,7 @@ def run():
elif not output.is_file_output_needed(): elif not output.is_file_output_needed():
print(output) print(output)
else: else:
print(
print_stderr(
colored( colored(
_("Please provide a file path to export in this format (--output)."), _("Please provide a file path to export in this format (--output)."),
color="red", color="red",
@@ -143,53 +195,63 @@ def get_information(
colors: bool, colors: bool,
show_graph: bool, show_graph: bool,
) -> dumper.Dumper: ) -> dumper.Dumper:
if position is not None:
try:
try:
if position is not None:
eph = get_ephemerides( eph = get_ephemerides(
for_date=compute_date, position=position, timezone=timezone for_date=compute_date, position=position, timezone=timezone
) )
except OutOfRangeDateError as error:
raise DateRangeError(error.min_date, error.max_date)
else:
eph = []
else:
eph = []


try:
moon_phase = get_moon_phase(for_date=compute_date, timezone=timezone)
except OutOfRangeDateError as error:
moon_phase = None
print(
colored(
_(
"Moon phase can only be computed between {min_date} and {max_date}"
).format(
min_date=format_date(error.min_date, "long"),
max_date=format_date(error.max_date, "long"),
),
"yellow",
try:
moon_phase = get_moon_phase(for_date=compute_date, timezone=timezone)
except OutOfRangeDateError as error:
moon_phase = None
print_stderr(
colored(
_(
"Moon phase can only be computed between {min_date} and {max_date}"
).format(
min_date=format_date(error.min_date, "long"),
max_date=format_date(error.max_date, "long"),
),
"yellow",
)
) )
)


events_list = get_events(compute_date, timezone)
events_list = get_events(compute_date, timezone)


return get_dumpers()[output_format](
ephemerides=eph,
moon_phase=moon_phase,
events=events_list,
date=compute_date,
timezone=timezone,
with_colors=colors,
show_graph=show_graph,
)
return get_dumpers()[output_format](
ephemerides=eph,
moon_phase=moon_phase,
events=events_list,
date=compute_date,
timezone=timezone,
with_colors=colors,
show_graph=show_graph,
)
except KeyError as error:
raise InvalidOutputFormatError(output_format, list(get_dumpers().keys()))
except OutOfRangeDateError as error:
raise DateRangeError(error.min_date, error.max_date)




def get_dumpers() -> {str: dumper.Dumper}: def get_dumpers() -> {str: dumper.Dumper}:
return { return {
"text": dumper.TextDumper,
"txt": dumper.TextDumper,
"json": dumper.JsonDumper, "json": dumper.JsonDumper,
"pdf": dumper.PdfDumper, "pdf": dumper.PdfDumper,
"tex": dumper.LatexDumper,
} }




def get_opening_mode(format: str) -> str:
if format == "pdf":
return "wb"

return "w"


def output_version() -> bool: def output_version() -> bool:
python_version = "%d.%d.%d" % ( python_version = "%d.%d.%d" % (
sys.version_info[0], sys.version_info[0],
@@ -233,28 +295,21 @@ def get_args(output_formats: [str]):
"--format", "--format",
"-f", "-f",
type=str, type=str,
default=output_formats[0],
choices=output_formats,
help=_("The format to output the information to"),
)
parser.add_argument(
"--latitude",
"-lat",
type=float,
default=None, default=None,
choices=output_formats,
help=_( help=_(
"The observer's latitude on Earth. Can also be set in the KOSMORRO_LATITUDE environment "
"variable."
"The format to output the information to. If not provided, the output format "
"will be inferred from the file extension of the output file."
), ),
) )
parser.add_argument( parser.add_argument(
"--longitude",
"-lon",
type=float,
"--position",
"-p",
type=str,
default=None, default=None,
help=_( help=_(
"The observer's longitude on Earth. Can also be set in the KOSMORRO_LONGITUDE "
"environment variable."
'The observer\'s position on Earth, in the "{latitude},{longitude}" format. '
"Can also be set in the KOSMORRO_POSITION environment variable."
), ),
) )
parser.add_argument( parser.add_argument(
@@ -271,11 +326,12 @@ def get_args(output_formats: [str]):
parser.add_argument( parser.add_argument(
"--timezone", "--timezone",
"-t", "-t",
type=int,
type=str,
default=None, default=None,
help=_( help=_(
"The timezone to display the hours in (e.g. 2 for UTC+2 or -3 for UTC-3). "
"Can also be set in the KOSMORRO_TIMEZONE environment variable."
"The timezone to use to display the hours. It can be either a number (e.g. 1 for UTC+1) or a timezone name (e.g. Europe/Paris). "
"See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones to find your timezone. "
"Can also be set in the TZ environment variable."
), ),
) )
parser.add_argument( parser.add_argument(
@@ -299,7 +355,7 @@ def get_args(output_formats: [str]):
dest="show_graph", dest="show_graph",
action="store_false", action="store_false",
help=_( help=_(
"Do not generate a graph to represent the rise and set times in the PDF format."
"Do not generate a graph to represent the rise and set times in the LaTeX or PDF file."
), ),
) )
parser.add_argument( parser.add_argument(
@@ -309,8 +365,28 @@ def get_args(output_formats: [str]):
help=_("Show debugging messages"), help=_("Show debugging messages"),
) )


argcomplete.autocomplete(parser)

parser.add_argument(
"--completion",
type=str,
help=_("Print a script allowing completion for your shell"),
)

return parser.parse_args() return parser.parse_args()




def output_completion(shell: str) -> bool:
shellcode = argcomplete.shellcode([sys.argv[0]], shell=shell)
if shellcode == "":
print_stderr(
colored(_("No completion script available for this shell."), "red")
)
return False

print(shellcode)
return True


def main(): def main():
sys.exit(run()) sys.exit(run())

+ 178
- 0
kosmorro/assets/latex/template.tex Bestand weergeven

@@ -0,0 +1,178 @@
\documentclass[a4paper,12pt]{article}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[margin=25mm]{geometry}
\usepackage{graphicx}
\usepackage{hyperref}
\usepackage{xcolor}
\usepackage{fp}

% Command showing the Moon phase
\newcommand{\moonphase}[2]{
\begin{center}
\begin{minipage}{2cm}
\includegraphics[width=\linewidth]{#1}
\end{minipage}
\hspace{5mm}
\begin{minipage}{7cm}
\textbf{\currentmoonphasetitle}\\#2
\end{minipage}
\end{center}
}

% Environment for the ephemerides, when --no-graph is given on the command line
\newenvironment{ephemerides}{
\begin{table}[h]
\centering
\begin{tabular}{lccc}
\textbf{\ephemeridesobjecttitle} &
\textbf{\ephemeridesrisetimetitle} &
\textbf{\ephemeridesculminationtimetitle} &
\textbf{\ephemeridessettimetitle}\\
\hline
}{
\end{tabular}
\end{table}
}

% Command adding an object to the ephemerides environment
\newcommand{\object}[4]{
\hline
\textbf{#1} & {#2} & {#3} & {#4}\\
}

% Environment to insert the ephemerides graph
\newenvironment{graphephemerides}{\setlength{\unitlength}{0.02\linewidth}
\begin{picture}(20,20)
% Axes
\put(0,-2){\vector(1,0){50}}
\multiput(0,-2)(2,0){24}{
\line(0,-1){0.25}
}
\newcounter{hour}
\multiput(-0.25,-3.5)(4,0){12}{
\sffamily\footnotesize
\arabic{hour}\stepcounter{hour}\stepcounter{hour}
}
\put(49,-3.5){\sffamily\footnotesize \hourslabel}

% Graduation

\put(50,-0.5){\sffamily\footnotesize \Pluto}
\put(50,1.5){\sffamily\footnotesize \Neptune}
\put(50,3.5){\sffamily\footnotesize \Uranus}
\put(50,5.5){\sffamily\footnotesize \Saturn}
\put(50,7.5){\sffamily\footnotesize \Jupiter}
\put(50,9.5){\sffamily\footnotesize \Mars}
\put(50,11.5){\sffamily\footnotesize \Venus}
\put(50,13.5){\sffamily\footnotesize \Mercury}
\put(50,15.5){\sffamily\footnotesize \Moon}
\put(50,17.5){\sffamily\footnotesize \Sun}

\multiput(0,0)(0,2){10}{
\color{gray}\line(1,0){48}
}

\linethickness{1.5mm}
}{
\end{picture}
\vspace{1cm}
}

% Command to add an object to the graph
\newcommand{\graphobject}[8]{%
% #1: Y coordinate component
% #2: Color
% #3: Hour rise time
% #4: Minute rise time
% #5: Hour set time
% #6: Minute set time
% #7: Human-readable rise time
% #8: Human-readable set time

\FPeval{\start}{#3*2+(#4/60)*2}%
\FPeval{\length}{#5*2+(#6/60)*2 - \start}%
\FPeval{\starttext}{\start+0.7}%
\FPeval{\endtext}{\start+\length-3.25}%

{\color{#2}%
\put(\start,#1){%
\line(1, 0){\length}%
}}%

\put(\starttext,#1.5){\sffamily\footnotesize #7}%
\put(\endtext,#1.5){\sffamily\footnotesize #8}%
}

\newcommand{\event}[2]{
\textbf{#1} & {#2}\\
}

\newenvironment{events}{
\begin{table}[h]
\begin{tabular}{ll}
}{
\end{tabular}
\end{table}
}

% Commands to handle the translated strings
\newcommand{\currentmoonphasetitle}{+++CURRENT-MOON-PHASE-TITLE+++}
\newcommand{\ephemeridesobjecttitle}{+++EPHEMERIDES-OBJECT+++}
\newcommand{\ephemeridesrisetimetitle}{+++EPHEMERIDES-RISE-TIME+++}
\newcommand{\ephemeridesculminationtimetitle}{+++EPHEMERIDES-CULMINATION-TIME+++}
\newcommand{\ephemeridessettimetitle}{+++EPHEMERIDES-SET-TIME+++}
\newcommand{\hourslabel}{+++GRAPH_LABEL_HOURS+++}

\newcommand{\Pluto}{+++ASTER_PLUTO+++}
\newcommand{\Neptune}{+++ASTER_NEPTUNE+++}
\newcommand{\Uranus}{+++ASTER_URANUS+++}
\newcommand{\Saturn}{+++ASTER_SATURN+++}
\newcommand{\Jupiter}{+++ASTER_JUPITER+++}
\newcommand{\Mars}{+++ASTER_MARS+++}
\newcommand{\Venus}{+++ASTER_VENUS+++}
\newcommand{\Mercury}{+++ASTER_MERCURY+++}
\newcommand{\Moon}{+++ASTER_MOON+++}
\newcommand{\Sun}{+++ASTER_SUN+++}

% Fix Unicode issues
\DeclareUnicodeCharacter{202F}{~}
\DeclareUnicodeCharacter{00B0}{$^\circ$}

\hypersetup{pdfinfo={%
Title={+++DOCUMENT-TITLE+++},
Creator={Kosmorro v+++KOSMORRO-VERSION+++}
}}

\pagenumbering{gobble}
\setcounter{secnumdepth}{0}

\title{\sffamily\href{http://kosmorro.space}{\includegraphics[width=5cm]{+++KOSMORRO-LOGO+++}}\\+++DOCUMENT-TITLE+++}
\date{\vspace{-11mm}\sffamily +++DOCUMENT-DATE+++}

\begin{document}

\maketitle

+++INTRODUCTION+++

\moonphase{+++MOON-PHASE-GRAPHICS+++}{+++CURRENT-MOON-PHASE+++}

%%% BEGIN-EPHEMERIDES-SECTION
\section{\sffamily +++SECTION-EPHEMERIDES+++}

\begin{ephemerides}
+++EPHEMERIDES+++
\end{ephemerides}
%%% END-EPHEMERIDES-SECTION

%%% BEGIN-EVENTS-SECTION
\section{\sffamily +++SECTION-EVENTS+++}

\begin{events}
+++EVENTS+++
\end{events}
%%% END-EVENTS-SECTION

\end{document}

+ 0
- 115
kosmorro/assets/pdf/kosmorro.sty Bestand weergeven

@@ -1,115 +0,0 @@
%! Package = kosmorro
%! Author = Jérôme Deuchnord
%! Date = 2020-04-26

\NeedsTeXFormat{LaTeX2e}[1994/06/01]
\ProvidesPackage{kosmorro}[2020/04/26 Kosmorro Package]

\RequirePackage{xcolor}
\RequirePackage{fp}

\newcommand{\moonphase}[2]{
\begin{center}
\begin{minipage}{2cm}
\includegraphics[width=\linewidth]{#1}
\end{minipage}
\hspace{5mm}
\begin{minipage}{7cm}
\textbf{\currentmoonphasetitle}\\#2
\end{minipage}
\end{center}
}

\newenvironment{ephemerides}{
\begin{table}[h]
\centering
\begin{tabular}{lccc}
\textbf{\ephemeridesobjecttitle} &
\textbf{\ephemeridesrisetimetitle} &
\textbf{\ephemeridesculminationtimetitle} &
\textbf{\ephemeridessettimetitle}\\
\hline
}{
\end{tabular}
\end{table}
}

\newcommand{\object}[4]{
\hline
\textbf{#1} & {#2} & {#3} & {#4}\\
}

\newenvironment{graphephemerides}{\setlength{\unitlength}{0.02\linewidth}
\begin{picture}(20,20)
% Axes
\put(0,-2){\vector(1,0){50}}
\multiput(0,-2)(2,0){24}{
\line(0,-1){0.25}
}
\newcounter{hour}
\multiput(-0.25,-3.5)(4,0){12}{
\sffamily\footnotesize
\arabic{hour}\stepcounter{hour}\stepcounter{hour}
}
\put(49,-3.5){\sffamily\footnotesize \hourslabel}

% Graduation

\put(50,-0.5){\sffamily\footnotesize \Pluto}
\put(50,1.5){\sffamily\footnotesize \Neptune}
\put(50,3.5){\sffamily\footnotesize \Uranus}
\put(50,5.5){\sffamily\footnotesize \Saturn}
\put(50,7.5){\sffamily\footnotesize \Jupiter}
\put(50,9.5){\sffamily\footnotesize \Mars}
\put(50,11.5){\sffamily\footnotesize \Venus}
\put(50,13.5){\sffamily\footnotesize \Mercury}
\put(50,15.5){\sffamily\footnotesize \Moon}
\put(50,17.5){\sffamily\footnotesize \Sun}

\multiput(0,0)(0,2){10}{
\color{gray}\line(1,0){48}
}

\linethickness{1.5mm}
}{
\end{picture}
\vspace{1cm}
}

\newcommand{\graphobject}[8]{%
% #1: Y coordinate component
% #2: Color
% #3: Hour rise time
% #4: Minute rise time
% #5: Hour set time
% #6: Minute set time
% #7: Human-readable rise time
% #8: Human-readable set time

\FPeval{\start}{#3*2+(#4/60)*2}%
\FPeval{\length}{#5*2+(#6/60)*2 - \start}%
\FPeval{\starttext}{\start+0.7}%
\FPeval{\endtext}{\start+\length-3.25}%

{\color{#2}%
\put(\start,#1){%
\line(1, 0){\length}%
}}%

\put(\starttext,#1.5){\sffamily\footnotesize #7}%
\put(\endtext,#1.5){\sffamily\footnotesize #8}%
}

\newcommand{\event}[2]{
\textbf{#1} & {#2}\\
}

\newenvironment{events}{
\begin{table}[h]
\begin{tabular}{ll}
}{
\end{tabular}
\end{table}
}

\endinput

+ 0
- 68
kosmorro/assets/pdf/template.tex Bestand weergeven

@@ -1,68 +0,0 @@
\documentclass[a4paper,12pt]{article}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[margin=25mm]{geometry}
\usepackage{graphicx}
\usepackage{hyperref}
\usepackage{kosmorro}
\usepackage{lmodern}

\newcommand{\currentmoonphasetitle}{+++CURRENT-MOON-PHASE-TITLE+++}
\newcommand{\ephemeridesobjecttitle}{+++EPHEMERIDES-OBJECT+++}
\newcommand{\ephemeridesrisetimetitle}{+++EPHEMERIDES-RISE-TIME+++}
\newcommand{\ephemeridesculminationtimetitle}{+++EPHEMERIDES-CULMINATION-TIME+++}
\newcommand{\ephemeridessettimetitle}{+++EPHEMERIDES-SET-TIME+++}
\newcommand{\hourslabel}{+++GRAPH_LABEL_HOURS+++}

\newcommand{\Pluto}{+++ASTER_PLUTO+++}
\newcommand{\Neptune}{+++ASTER_NEPTUNE+++}
\newcommand{\Uranus}{+++ASTER_URANUS+++}
\newcommand{\Saturn}{+++ASTER_SATURN+++}
\newcommand{\Jupiter}{+++ASTER_JUPITER+++}
\newcommand{\Mars}{+++ASTER_MARS+++}
\newcommand{\Venus}{+++ASTER_VENUS+++}
\newcommand{\Mercury}{+++ASTER_MERCURY+++}
\newcommand{\Moon}{+++ASTER_MOON+++}
\newcommand{\Sun}{+++ASTER_SUN+++}

% Fix Unicode issues
\DeclareUnicodeCharacter{202F}{~}
\DeclareUnicodeCharacter{00B0}{$^\circ$}

\hypersetup{pdfinfo={%
Title={+++DOCUMENT-TITLE+++},
Creator={Kosmorro v+++KOSMORRO-VERSION+++}
}}

\pagenumbering{gobble}
\setcounter{secnumdepth}{0}

\title{\sffamily\href{http://kosmorro.space}{\includegraphics[width=5cm]{+++KOSMORRO-LOGO+++}}\\+++DOCUMENT-TITLE+++}
\date{\vspace{-11mm}\sffamily +++DOCUMENT-DATE+++}

\begin{document}

\maketitle

+++INTRODUCTION+++

\moonphase{+++MOON-PHASE-GRAPHICS+++}{+++CURRENT-MOON-PHASE+++}

%%% BEGIN-EPHEMERIDES-SECTION
\section{\sffamily +++SECTION-EPHEMERIDES+++}

\begin{ephemerides}
+++EPHEMERIDES+++
\end{ephemerides}
%%% END-EPHEMERIDES-SECTION

%%% BEGIN-EVENTS-SECTION
\section{\sffamily +++SECTION-EVENTS+++}

\begin{events}
+++EVENTS+++
\end{events}
%%% END-EVENTS-SECTION

\end{document}

+ 16
- 17
kosmorro/dumper.py Bestand weergeven

@@ -43,9 +43,9 @@ from .utils import KOSMORRO_VERSION




class Dumper(ABC): class Dumper(ABC):
ephemerides: [AsterEphemerides]
ephemerides: list[AsterEphemerides]
moon_phase: MoonPhase moon_phase: MoonPhase
events: [Event]
events: list[Event]
date: datetime.date date: datetime.date
timezone: int timezone: int
with_colors: bool with_colors: bool
@@ -53,9 +53,9 @@ class Dumper(ABC):


def __init__( def __init__(
self, self,
ephemerides: [AsterEphemerides],
ephemerides: list[AsterEphemerides],
moon_phase: MoonPhase, moon_phase: MoonPhase,
events: [Event],
events: list[Event],
date: datetime.date, date: datetime.date,
timezone: int, timezone: int,
with_colors: bool, with_colors: bool,
@@ -233,11 +233,8 @@ class TextDumper(Dumper):
if moon_phase is None: if moon_phase is None:
return _("Moon phase is unavailable for this date.") return _("Moon phase is unavailable for this date.")


current_moon_phase = " ".join(
[
self.style(_("Moon phase:"), "strong"),
strings.from_moon_phase(moon_phase.phase_type),
]
current_moon_phase = self.style(
strings.from_moon_phase(moon_phase.phase_type), "strong"
) )
new_moon_phase = _( new_moon_phase = _(
"{next_moon_phase} on {next_moon_phase_date} at {next_moon_phase_time}" "{next_moon_phase} on {next_moon_phase_date} at {next_moon_phase_time}"
@@ -250,10 +247,13 @@ class TextDumper(Dumper):
return "\n".join([current_moon_phase, new_moon_phase]) return "\n".join([current_moon_phase, new_moon_phase])




class _LatexDumper(Dumper):
class LatexDumper(Dumper):
def to_string(self): def to_string(self):
template_path = os.path.join( template_path = os.path.join(
os.path.abspath(os.path.dirname(__file__)), "assets", "pdf", "template.tex"
os.path.abspath(os.path.dirname(__file__)),
"assets",
"latex",
"template.tex",
) )


with open(template_path, mode="r") as file: with open(template_path, mode="r") as file:
@@ -281,7 +281,7 @@ class _LatexDumper(Dumper):


document = template document = template


if self.ephemerides is None:
if len(self.ephemerides) == 0:
document = self._remove_section(document, "ephemerides") document = self._remove_section(document, "ephemerides")


if len(self.events) == 0: if len(self.events) == 0:
@@ -301,6 +301,9 @@ class _LatexDumper(Dumper):
def add_strings( def add_strings(
self, document: str, kosmorro_logo_path: str, moon_phase_graphics: str self, document: str, kosmorro_logo_path: str, moon_phase_graphics: str
) -> str: ) -> str:
document = document.replace(
"+++CURRENT-DATE+++", datetime.datetime.now().isoformat()
)
document = document.replace("+++KOSMORRO-VERSION+++", KOSMORRO_VERSION) document = document.replace("+++KOSMORRO-VERSION+++", KOSMORRO_VERSION)
document = document.replace("+++KOSMORRO-LOGO+++", kosmorro_logo_path) document = document.replace("+++KOSMORRO-LOGO+++", kosmorro_logo_path)
document = document.replace("+++DOCUMENT-TITLE+++", _("Overview of your sky")) document = document.replace("+++DOCUMENT-TITLE+++", _("Overview of your sky"))
@@ -471,7 +474,7 @@ class _LatexDumper(Dumper):
class PdfDumper(Dumper): class PdfDumper(Dumper):
def to_string(self): def to_string(self):
try: try:
latex_dumper = _LatexDumper(
latex_dumper = LatexDumper(
self.ephemerides, self.ephemerides,
self.moon_phase, self.moon_phase,
self.events, self.events,
@@ -497,7 +500,6 @@ class PdfDumper(Dumper):


@staticmethod @staticmethod
def _compile(latex_input) -> bytes: def _compile(latex_input) -> bytes:
package = str(Path(__file__).parent.absolute()) + "/assets/pdf/kosmorro.sty"
timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S") timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
current_dir = ( current_dir = (
os.getcwd() os.getcwd()
@@ -505,9 +507,6 @@ class PdfDumper(Dumper):


try: try:
temp_dir = tempfile.mkdtemp() temp_dir = tempfile.mkdtemp()

shutil.copy(package, temp_dir)

temp_tex = "%s/%s.tex" % (temp_dir, timestamp) temp_tex = "%s/%s.tex" % (temp_dir, timestamp)


with open(temp_tex, "w") as tex_file: with open(temp_tex, "w") as tex_file:


+ 3
- 0
kosmorro/environment.py Bestand weergeven

@@ -21,6 +21,7 @@ import re
from pathlib import Path from pathlib import Path


CACHE_FOLDER = str(Path.home()) + "/.kosmorro-cache" CACHE_FOLDER = str(Path.home()) + "/.kosmorro-cache"
NO_COLOR = "NO_COLOR" in os.environ




class Environment: class Environment:
@@ -43,6 +44,8 @@ class Environment:
def get_env_vars() -> Environment: def get_env_vars() -> Environment:
environment = Environment() environment = Environment()


environment.tz = os.getenv("TZ")

for var in os.environ: for var in os.environ:
if not re.search("^KOSMORRO_", var): if not re.search("^KOSMORRO_", var):
continue continue


+ 13
- 0
kosmorro/exceptions.py Bestand weergeven

@@ -40,6 +40,19 @@ class OutOfRangeDateError(RuntimeError):
) )




class InvalidOutputFormatError(RuntimeError):
def __init__(self, output_format: str, accepted_extensions: [str]):
super().__init__()
self.output_format = output_format
self.accepted_extensions = accepted_extensions
self.msg = _(
"Invalid output format: {output_format}. Output file must end with: {accepted_extensions}"
).format(
output_format=output_format,
accepted_extensions=", ".join(accepted_extensions),
)


class CompileError(RuntimeError): class CompileError(RuntimeError):
def __init__(self, msg): def __init__(self, msg):
super().__init__() super().__init__()


+ 48
- 0
kosmorro/geolocation.py Bestand weergeven

@@ -0,0 +1,48 @@
#!/usr/bin/env python3

import re
from typing import Union

from kosmorrolib import Position
from openlocationcode import openlocationcode

from .i18n.utils import _


def _parse_latitude_longitude(from_str: str) -> Position:
if not re.search(r"^([\d.-]+)[,;]([\d.-]+)$", from_str):
raise ValueError(_("The given position (%s) is not valid." % from_str))

latitude_longitude = from_str.split(";")
if len(latitude_longitude) == 1:
latitude_longitude = from_str.split(",")

return Position(float(latitude_longitude[0]), float(latitude_longitude[1]))


def _parse_plus_code(from_str: str) -> Union[None, Position]:
if not openlocationcode.isValid(from_str):
return None

if not openlocationcode.isFull(from_str):
raise ValueError(
_(
"The given Plus Code seems to be a short code, please provide a full code."
)
)

pos = openlocationcode.decode(from_str)

return Position(
latitude=(pos.latitudeLo + pos.latitudeHi) / 2,
longitude=(pos.longitudeLo + pos.longitudeHi) / 2,
)


def get_position(from_str: str) -> Position:
pos = _parse_plus_code(from_str)

if pos is not None:
return pos

return _parse_latitude_longitude(from_str)

+ 81
- 17
kosmorro/i18n/strings.py Bestand weergeven

@@ -1,30 +1,94 @@
#!/usr/bin/env python3 #!/usr/bin/env python3


from typing import Union from typing import Union
from babel.dates import format_time
from .utils import _ from .utils import _
from kosmorrolib import (
EventType,
MoonPhaseType,
ObjectIdentifier,
Event,
SeasonType,
LunarEclipseType,
)


from kosmorrolib import EventType, MoonPhaseType, ObjectIdentifier, Event


def from_event(event: Event) -> Union[None, str]:
string = None
match event.event_type:
case EventType.OPPOSITION:
string, details = (
_("%s is in opposition") % from_object(event.objects[0].identifier),
None,
)
case EventType.CONJUNCTION:
string, details = (
_("%s and %s are in conjunction")
% (
from_object(event.objects[0].identifier),
from_object(event.objects[1].identifier),
),
None,
)
case EventType.OCCULTATION:
string, details = (
_("%s occults %s")
% (
from_object(event.objects[0].identifier),
from_object(event.objects[1].identifier),
),
None,
)
case EventType.MAXIMAL_ELONGATION:
string, details = (
_("Elongation of %s is maximal")
% from_object(event.objects[0].identifier),
lambda e: "{:.3n}°".format(e.details["deg"]),
)
case EventType.PERIGEE:
string, details = (
_("%s is at its periapsis") % from_object(event.objects[0].identifier),
None,
)
case EventType.APOGEE:
string, details = (
_("%s is at its apoapsis") % from_object(event.objects[0].identifier),
None,
)
case EventType.SEASON_CHANGE:
match event.details["season"]:
case SeasonType.MARCH_EQUINOX:
string = _("March equinox")
case SeasonType.JUNE_SOLSTICE:
string = _("June solstice")
case SeasonType.SEPTEMBER_EQUINOX:
string = _("September equinox")
case _:
string = _("December solstice")


def from_event(event: Event, with_description: bool = True) -> Union[None, str]:
string, details = {
EventType.OPPOSITION: (_("%s is in opposition"), None),
EventType.CONJUNCTION: (_("%s and %s are in conjunction"), None),
EventType.OCCULTATION: (_("%s occults %s"), None),
EventType.MAXIMAL_ELONGATION: (
_("Elongation of %s is maximal"),
lambda e: "{:.3n}°".format(e.details["deg"]),
),
EventType.PERIGEE: (_("%s is at its periapsis"), None),
EventType.APOGEE: (_("%s is at its apoapsis"), None),
}.get(event.event_type, (None, None))
details = None
case EventType.LUNAR_ECLIPSE:
match event.details["type"]:
case LunarEclipseType.TOTAL:
string = _("Total lunar eclipse until %(hour)s") % {
"hour": format_time(event.end_time, "short")
}


if string is None:
return None
case LunarEclipseType.PENUMBRAL:
string = _("Penumbral lunar eclipse until %(hour)s") % {
"hour": format_time(event.end_time, "short")
}

case LunarEclipseType.PARTIAL:
string = _("Partial lunar eclipse until %(hour)s") % {
"hour": format_time(event.end_time, "short")
}


string = string % tuple([from_object(o.identifier) for o in event.objects])
details = None
case _:
return None


if details is not None and with_description:
if details is not None:
return "%s (%s)" % (string, details(event)) return "%s (%s)" % (string, details(event))


return string return string


+ 136
- 71
kosmorro/locales/messages.pot Bestand weergeven

@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PROJECT VERSION\n" "Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2025-03-16 11:59+0100\n"
"POT-Creation-Date: 2025-10-19 16:46+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,104 +17,122 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.17.0\n" "Generated-By: Babel 2.17.0\n"


#: kosmorro/__main__.py:62
#: kosmorro/__main__.py:89
msgid "" msgid ""
"Save the planet and paper!\n" "Save the planet and paper!\n"
"Consider printing your PDF document only if really necessary, and use the" "Consider printing your PDF document only if really necessary, and use the"
" other side of the sheet." " other side of the sheet."
msgstr "" msgstr ""


#: kosmorro/__main__.py:71
#: kosmorro/__main__.py:97
msgid "" msgid ""
"PDF output will not contain the ephemerides, because you didn't provide " "PDF output will not contain the ephemerides, because you didn't provide "
"the observation coordinates." "the observation coordinates."
msgstr "" msgstr ""


#: kosmorro/__main__.py:115 #: kosmorro/__main__.py:115
msgid ""
"Environment variable KOSMORRO_TIMEZONE is deprecated. Use TZ instead, "
"which is more standard."
msgstr ""

#: kosmorro/__main__.py:124
#, python-brace-format
msgid "Unknown timezone: {timezone}"
msgstr ""

#: kosmorro/__main__.py:167
#, python-brace-format #, python-brace-format
msgid "The file could not be saved in \"{path}\": {error}" msgid "The file could not be saved in \"{path}\": {error}"
msgstr "" msgstr ""


#: kosmorro/__main__.py:129
#: kosmorro/__main__.py:181
msgid "Please provide a file path to export in this format (--output)." msgid "Please provide a file path to export in this format (--output)."
msgstr "" msgstr ""


#: kosmorro/__main__.py:163
#: kosmorro/__main__.py:213
#, python-brace-format #, python-brace-format
msgid "Moon phase can only be computed between {min_date} and {max_date}" msgid "Moon phase can only be computed between {min_date} and {max_date}"
msgstr "" msgstr ""


#: kosmorro/__main__.py:202
#: kosmorro/__main__.py:264
#, python-brace-format #, python-brace-format
msgid "Running on Python {python_version} with Kosmorrolib v{kosmorrolib_version}" msgid "Running on Python {python_version} with Kosmorrolib v{kosmorrolib_version}"
msgstr "" msgstr ""


#: kosmorro/__main__.py:215
#: kosmorro/__main__.py:277
msgid "" msgid ""
"Compute the ephemerides and the events for a given date and a given " "Compute the ephemerides and the events for a given date and a given "
"position on Earth." "position on Earth."
msgstr "" msgstr ""


#: kosmorro/__main__.py:218
#: kosmorro/__main__.py:280
msgid "" msgid ""
"By default, only the events will be computed for today.\n" "By default, only the events will be computed for today.\n"
"To compute also the ephemerides, latitude and longitude arguments are " "To compute also the ephemerides, latitude and longitude arguments are "
"needed." "needed."
msgstr "" msgstr ""


#: kosmorro/__main__.py:230
#: kosmorro/__main__.py:292
msgid "Show the program version" msgid "Show the program version"
msgstr "" msgstr ""


#: kosmorro/__main__.py:238
msgid "The format to output the information to"
msgstr ""

#: kosmorro/__main__.py:246
#: kosmorro/__main__.py:301
msgid "" msgid ""
"The observer's latitude on Earth. Can also be set in the "
"KOSMORRO_LATITUDE environment variable."
"The format to output the information to. If not provided, the output "
"format will be inferred from the file extension of the output file."
msgstr "" msgstr ""


#: kosmorro/__main__.py:256
#: kosmorro/__main__.py:311
#, python-brace-format
msgid "" msgid ""
"The observer's longitude on Earth. Can also be set in the "
"KOSMORRO_LONGITUDE environment variable."
"The observer's position on Earth, in the \"{latitude},{longitude}\" "
"format. Can also be set in the KOSMORRO_POSITION environment variable."
msgstr "" msgstr ""


#: kosmorro/__main__.py:266
#: kosmorro/__main__.py:321
msgid "" msgid ""
"The date for which the ephemerides must be calculated. Can be in the " "The date for which the ephemerides must be calculated. Can be in the "
"YYYY-MM-DD format or an interval in the \"[+-]YyMmDd\" format (with Y, M," "YYYY-MM-DD format or an interval in the \"[+-]YyMmDd\" format (with Y, M,"
" and D numbers). Defaults to current date." " and D numbers). Defaults to current date."
msgstr "" msgstr ""


#: kosmorro/__main__.py:277
#: kosmorro/__main__.py:332
msgid "" msgid ""
"The timezone to display the hours in (e.g. 2 for UTC+2 or -3 for UTC-3). "
"Can also be set in the KOSMORRO_TIMEZONE environment variable."
"The timezone to use to display the hours. It can be either a number (e.g."
" 1 for UTC+1) or a timezone name (e.g. Europe/Paris). See "
"https://en.wikipedia.org/wiki/List_of_tz_database_time_zones to find your"
" timezone. Can also be set in the TZ environment variable."
msgstr "" msgstr ""


#: kosmorro/__main__.py:285
#: kosmorro/__main__.py:341
msgid "Disable the colors in the console." msgid "Disable the colors in the console."
msgstr "" msgstr ""


#: kosmorro/__main__.py:293
#: kosmorro/__main__.py:349
msgid "" msgid ""
"A file to export the output to. If not given, the standard output is " "A file to export the output to. If not given, the standard output is "
"used. This argument is needed for PDF format." "used. This argument is needed for PDF format."
msgstr "" msgstr ""


#: kosmorro/__main__.py:302
#: kosmorro/__main__.py:358
msgid "" msgid ""
"Do not generate a graph to represent the rise and set times in the PDF "
"format."
"Do not generate a graph to represent the rise and set times in the LaTeX "
"or PDF file."
msgstr "" msgstr ""


#: kosmorro/__main__.py:309
#: kosmorro/__main__.py:365
msgid "Show debugging messages" msgid "Show debugging messages"
msgstr "" msgstr ""


#: kosmorro/__main__.py:373
msgid "Print a script allowing completion for your shell"
msgstr ""

#: kosmorro/__main__.py:383
msgid "No completion script available for this shell."
msgstr ""

#: kosmorro/date.py:17 #: kosmorro/date.py:17
#, python-brace-format #, python-brace-format
msgid "The date {date} is not valid: {error}" msgid "The date {date} is not valid: {error}"
@@ -140,19 +158,19 @@ msgstr ""
msgid "Note: All the hours are given in the UTC{offset} timezone." msgid "Note: All the hours are given in the UTC{offset} timezone."
msgstr "" msgstr ""


#: kosmorro/dumper.py:205 kosmorro/dumper.py:333
#: kosmorro/dumper.py:205 kosmorro/dumper.py:336
msgid "Object" msgid "Object"
msgstr "" msgstr ""


#: kosmorro/dumper.py:206 kosmorro/dumper.py:334
#: kosmorro/dumper.py:206 kosmorro/dumper.py:337
msgid "Rise time" msgid "Rise time"
msgstr "" msgstr ""


#: kosmorro/dumper.py:207 kosmorro/dumper.py:336
#: kosmorro/dumper.py:207 kosmorro/dumper.py:339
msgid "Culmination time" msgid "Culmination time"
msgstr "" msgstr ""


#: kosmorro/dumper.py:208 kosmorro/dumper.py:338
#: kosmorro/dumper.py:208 kosmorro/dumper.py:341
msgid "Set time" msgid "Set time"
msgstr "" msgstr ""


@@ -160,20 +178,16 @@ msgstr ""
msgid "Moon phase is unavailable for this date." msgid "Moon phase is unavailable for this date."
msgstr "" msgstr ""


#: kosmorro/dumper.py:238 kosmorro/dumper.py:342
msgid "Moon phase:"
msgstr ""

#: kosmorro/dumper.py:243
#: kosmorro/dumper.py:240
#, python-brace-format #, python-brace-format
msgid "{next_moon_phase} on {next_moon_phase_date} at {next_moon_phase_time}" msgid "{next_moon_phase} on {next_moon_phase_date} at {next_moon_phase_time}"
msgstr "" msgstr ""


#: kosmorro/dumper.py:306
#: kosmorro/dumper.py:309
msgid "Overview of your sky" msgid "Overview of your sky"
msgstr "" msgstr ""


#: kosmorro/dumper.py:315
#: kosmorro/dumper.py:318
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"This document summarizes the ephemerides and the events of {date}. It " "This document summarizes the ephemerides and the events of {date}. It "
@@ -181,25 +195,29 @@ msgid ""
"given in {timezone}." "given in {timezone}."
msgstr "" msgstr ""


#: kosmorro/dumper.py:325
#: kosmorro/dumper.py:328
msgid "" msgid ""
"Don't forget to check the weather forecast before you go out with your " "Don't forget to check the weather forecast before you go out with your "
"equipment." "equipment."
msgstr "" msgstr ""


#: kosmorro/dumper.py:331
#: kosmorro/dumper.py:334
msgid "Ephemerides of the day" msgid "Ephemerides of the day"
msgstr "" msgstr ""


#: kosmorro/dumper.py:340
#: kosmorro/dumper.py:343
msgid "hours" msgid "hours"
msgstr "" msgstr ""


#: kosmorro/dumper.py:347
#: kosmorro/dumper.py:345
msgid "Moon phase:"
msgstr ""

#: kosmorro/dumper.py:350
msgid "Expected events" msgid "Expected events"
msgstr "" msgstr ""


#: kosmorro/dumper.py:488
#: kosmorro/dumper.py:491
msgid "" msgid ""
"Building PDF was not possible, because some dependencies are not " "Building PDF was not possible, because some dependencies are not "
"installed.\n" "installed.\n"
@@ -207,7 +225,7 @@ msgid ""
"pdf/ for more information." "pdf/ for more information."
msgstr "" msgstr ""


#: kosmorro/dumper.py:541
#: kosmorro/dumper.py:540
#, python-format #, python-format
msgid "" msgid ""
"An error occurred during the compilation of the PDF.\n" "An error occurred during the compilation of the PDF.\n"
@@ -220,109 +238,156 @@ msgstr ""
msgid "The date must be between {minimum_date} and {maximum_date}" msgid "The date must be between {minimum_date} and {maximum_date}"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:11
#: kosmorro/exceptions.py:49
#, python-brace-format
msgid ""
"Invalid output format: {output_format}. Output file must end with: "
"{accepted_extensions}"
msgstr ""

#: kosmorro/geolocation.py:14
#, python-format
msgid "The given position (%s) is not valid."
msgstr ""

#: kosmorro/geolocation.py:30
msgid "The given Plus Code seems to be a short code, please provide a full code."
msgstr ""

#: kosmorro/i18n/strings.py:21
#, python-format #, python-format
msgid "%s is in opposition" msgid "%s is in opposition"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:12
#: kosmorro/i18n/strings.py:26
#, python-format #, python-format
msgid "%s and %s are in conjunction" msgid "%s and %s are in conjunction"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:13
#: kosmorro/i18n/strings.py:35
#, python-format #, python-format
msgid "%s occults %s" msgid "%s occults %s"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:15
#: kosmorro/i18n/strings.py:44
#, python-format #, python-format
msgid "Elongation of %s is maximal" msgid "Elongation of %s is maximal"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:18
#: kosmorro/i18n/strings.py:50
#, python-format #, python-format
msgid "%s is at its periapsis" msgid "%s is at its periapsis"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:19
#: kosmorro/i18n/strings.py:55
#, python-format #, python-format
msgid "%s is at its apoapsis" msgid "%s is at its apoapsis"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:35
#: kosmorro/i18n/strings.py:61
msgid "March equinox"
msgstr ""

#: kosmorro/i18n/strings.py:63
msgid "June solstice"
msgstr ""

#: kosmorro/i18n/strings.py:65
msgid "September equinox"
msgstr ""

#: kosmorro/i18n/strings.py:67
msgid "December solstice"
msgstr ""

#: kosmorro/i18n/strings.py:73
#, python-format
msgid "Total lunar eclipse until %(hour)s"
msgstr ""

#: kosmorro/i18n/strings.py:78
#, python-format
msgid "Penumbral lunar eclipse until %(hour)s"
msgstr ""

#: kosmorro/i18n/strings.py:83
#, python-format
msgid "Partial lunar eclipse until %(hour)s"
msgstr ""

#: kosmorro/i18n/strings.py:99
msgid "New Moon" msgid "New Moon"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:36
#: kosmorro/i18n/strings.py:100
msgid "Waxing Crescent" msgid "Waxing Crescent"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:37
#: kosmorro/i18n/strings.py:101
msgid "First Quarter" msgid "First Quarter"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:38
#: kosmorro/i18n/strings.py:102
msgid "Waxing Gibbous" msgid "Waxing Gibbous"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:39
#: kosmorro/i18n/strings.py:103
msgid "Full Moon" msgid "Full Moon"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:40
#: kosmorro/i18n/strings.py:104
msgid "Waning Gibbous" msgid "Waning Gibbous"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:41
#: kosmorro/i18n/strings.py:105
msgid "Last Quarter" msgid "Last Quarter"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:42
#: kosmorro/i18n/strings.py:106
msgid "Waning Crescent" msgid "Waning Crescent"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:53
#: kosmorro/i18n/strings.py:117
msgid "Sun" msgid "Sun"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:54
#: kosmorro/i18n/strings.py:118
msgid "Moon" msgid "Moon"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:55
#: kosmorro/i18n/strings.py:119
msgid "Mercury" msgid "Mercury"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:56
#: kosmorro/i18n/strings.py:120
msgid "Venus" msgid "Venus"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:57
#: kosmorro/i18n/strings.py:121
msgid "Earth" msgid "Earth"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:58
#: kosmorro/i18n/strings.py:122
msgid "Mars" msgid "Mars"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:59
#: kosmorro/i18n/strings.py:123
msgid "Jupiter" msgid "Jupiter"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:60
#: kosmorro/i18n/strings.py:124
msgid "Saturn" msgid "Saturn"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:61
#: kosmorro/i18n/strings.py:125
msgid "Uranus" msgid "Uranus"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:62
#: kosmorro/i18n/strings.py:126
msgid "Neptune" msgid "Neptune"
msgstr "" msgstr ""


#: kosmorro/i18n/strings.py:63
#: kosmorro/i18n/strings.py:127
msgid "Pluto" msgid "Pluto"
msgstr "" msgstr ""




+ 17
- 4
kosmorro/utils.py Bestand weergeven

@@ -1,11 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from datetime import datetime


import pytz
from termcolor import colored as do_color from termcolor import colored as do_color
from sys import stderr


try:
from importlib.metadata import version
except ImportError:
from importlib_metadata import version
from importlib.metadata import version


KOSMORRO_VERSION = version("kosmorro") KOSMORRO_VERSION = version("kosmorro")
KOSMORROLIB_VERSION = version("kosmorrolib") KOSMORROLIB_VERSION = version("kosmorrolib")
@@ -25,3 +25,16 @@ def colored(text, color=None, on_color=None, attrs=None):
return text return text


return do_color(text, color, on_color, attrs) return do_color(text, color, on_color, attrs)


def print_stderr(*values: object):
print(*values, file=stderr)


def get_timezone(value: int | str) -> float:
try:
timezone = float(value)
except ValueError:
timezone = pytz.timezone(value).utcoffset(datetime.now()).total_seconds() / 3600

return timezone

+ 16
- 14
manpage/kosmorro.1.md Bestand weergeven

@@ -16,17 +16,14 @@
`--clear-cache` `--clear-cache`
delete all the files Kosmorro stored in the cache delete all the files Kosmorro stored in the cache


`--latitude=`_LATITUDE_, `-lat` _LATITUDE_
the observer's latitude on Earth

`--longitude=`_LONGITUDE_, `-lon` _LONGITUDE_
the observer's longitude on Earth
`--position=`"_LATITUDE_,_LONGITUDE_", `-p` "_LATITUDE_,_LONGITUDE"
the observer's position on Earth


`--date=`_DATE_, `-d` _DATE_ `--date=`_DATE_, `-d` _DATE_
The date for which the ephemerides must be computed, either in the YYYY-MM-DD format or as an interval in the "[+-]YyMmDd" format (with Y, M, and D numbers); defaults to the current date The date for which the ephemerides must be computed, either in the YYYY-MM-DD format or as an interval in the "[+-]YyMmDd" format (with Y, M, and D numbers); defaults to the current date


`--timezone=`_TIMEZONE_, `-t` _TIMEZONE_ `--timezone=`_TIMEZONE_, `-t` _TIMEZONE_
the timezone to display the hours in; e.g. 2 for UTC+2 or -3 for UTC-3
the timezone to use to display the hours; it can be either a number (e.g. 1 for UTC+1) or a timezone name (e.g. Europe/Paris)


`--no-colors` `--no-colors`
disable the colors in the console disable the colors in the console
@@ -34,12 +31,17 @@
`--output=`_OUTPUT_, `-o` _OUTPUT_ `--output=`_OUTPUT_, `-o` _OUTPUT_
a file to export the output to; if not given, the standard output is used a file to export the output to; if not given, the standard output is used


`--format=`_FORMAT_, `-f` _FORMAT_
the format under which the information have to be output; one of the following: text, json, pdf
`--format=`_FORMAT_, `-f` _FORMAT_ (optional)
the format under which the information have to be output; one of the following:
text (plain text, like normal console output), json, tex (LaTeX), pdf.
If no format is provided, the output format will be inferred from the extension of the output file


`--no-graph` `--no-graph`
present the ephemerides in a table instead of a graph; PDF output format only present the ephemerides in a table instead of a graph; PDF output format only


`--completion [SHELL]`
generate completion scripts for the specified shell (bash, zsh, fish, powershell)

## ENVIRONMENT VARIABLES ## ENVIRONMENT VARIABLES


The environment variable listed below may be used instead of the options. The environment variable listed below may be used instead of the options.
@@ -48,15 +50,15 @@ As a consequence, any option that would be given to `kosmorro` will override its


Available environment variables are: Available environment variables are:


`KOSMORRO_LATITUDE`
the observer's latitude on Earth (alternative to `--latitude`)
`KOSMORRO_LONGITUDE`
the observer's longitude on Earth (alternative to `--longitude`)
`KOSMORRO_POSITION`
the observer's position on Earth (alternative to `--position`)
`KOSMORRO_TIMEZONE` `KOSMORRO_TIMEZONE`
the observer's timezone (alternative to `--timezone`) the observer's timezone (alternative to `--timezone`)


`NO_COLOR`
disable colored console output (alternative to `--no-colors`)

## EXAMPLES ## EXAMPLES


Compute the events only for the current date: Compute the events only for the current date:
@@ -74,7 +76,7 @@ kosmorro --latitude=50.5876 --longitude=3.0624 --date=2022-04-01
Compute the ephemerides for Lille, France, on April 1st, 2022, and export them in a PDF document: Compute the ephemerides for Lille, France, on April 1st, 2022, and export them in a PDF document:


``` ```
kosmorro --latitude=50.5876 --longitude=3.0624 -date=2022-04-01 --format=pdf --output=file.pdf
kosmorro --latitude=50.5876 --longitude=3.0624 -date=2022-04-01 --output=file.pdf
``` ```


## AUTHOR ## AUTHOR


+ 255
- 350
poetry.lock Bestand weergeven

@@ -1,4 +1,19 @@
# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand.

[[package]]
name = "argcomplete"
version = "3.6.2"
description = "Bash tab completion for argparse"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "argcomplete-3.6.2-py3-none-any.whl", hash = "sha256:65b3133a29ad53fb42c48cf5114752c7ab66c1c38544fdf6460f450c09b42591"},
{file = "argcomplete-3.6.2.tar.gz", hash = "sha256:d0519b1bc867f5f4f4713c41ad0aba73a4a5f007449716b16f385f2166dc6adf"},
]

[package.extras]
test = ["coverage", "mypy", "pexpect", "ruff", "wheel"]


[[package]] [[package]]
name = "aurornis" name = "aurornis"
@@ -7,7 +22,6 @@ description = "A command line program test helper"
optional = false optional = false
python-versions = "<4.0,>=3.7" python-versions = "<4.0,>=3.7"
groups = ["dev"] groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "aurornis-1.6.0-py3-none-any.whl", hash = "sha256:457ff4b8b3b0f1f16b434071c267a706bb96a23e5ada37f611f3a6520536e5ea"}, {file = "aurornis-1.6.0-py3-none-any.whl", hash = "sha256:457ff4b8b3b0f1f16b434071c267a706bb96a23e5ada37f611f3a6520536e5ea"},
{file = "aurornis-1.6.0.tar.gz", hash = "sha256:3b86689370fdf17f63f32db56795234923a031c783cf7a47b0578093cc26b5ee"}, {file = "aurornis-1.6.0.tar.gz", hash = "sha256:3b86689370fdf17f63f32db56795234923a031c783cf7a47b0578093cc26b5ee"},
@@ -23,49 +37,44 @@ description = "Internationalization utilities"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
groups = ["main"] groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"}, {file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"},
{file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"}, {file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"},
] ]


[package.dependencies]
pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""}

[package.extras] [package.extras]
dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""]


[[package]] [[package]]
name = "black" name = "black"
version = "24.8.0"
version = "24.10.0"
description = "The uncompromising code formatter." description = "The uncompromising code formatter."
optional = false optional = false
python-versions = ">=3.8"
python-versions = ">=3.9"
groups = ["dev"] groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "black-24.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6"},
{file = "black-24.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb"},
{file = "black-24.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42"},
{file = "black-24.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a"},
{file = "black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1"},
{file = "black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af"},
{file = "black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4"},
{file = "black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af"},
{file = "black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368"},
{file = "black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed"},
{file = "black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018"},
{file = "black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2"},
{file = "black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd"},
{file = "black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2"},
{file = "black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e"},
{file = "black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920"},
{file = "black-24.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c"},
{file = "black-24.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e"},
{file = "black-24.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47"},
{file = "black-24.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb"},
{file = "black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed"},
{file = "black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f"},
{file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"},
{file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"},
{file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"},
{file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"},
{file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"},
{file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"},
{file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"},
{file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"},
{file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"},
{file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"},
{file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"},
{file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"},
{file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"},
{file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"},
{file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"},
{file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"},
{file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"},
{file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"},
{file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"},
{file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"},
{file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"},
{file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"},
] ]


[package.dependencies] [package.dependencies]
@@ -74,39 +83,35 @@ mypy-extensions = ">=0.4.3"
packaging = ">=22.0" packaging = ">=22.0"
pathspec = ">=0.9.0" pathspec = ">=0.9.0"
platformdirs = ">=2" platformdirs = ">=2"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}


[package.extras] [package.extras]
colorama = ["colorama (>=0.4.3)"] colorama = ["colorama (>=0.4.3)"]
d = ["aiohttp (>=3.7.4) ; sys_platform != \"win32\" or implementation_name != \"pypy\"", "aiohttp (>=3.7.4,!=3.9.0) ; sys_platform == \"win32\" and implementation_name == \"pypy\""]
d = ["aiohttp (>=3.10)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
uvloop = ["uvloop (>=0.15.2)"] uvloop = ["uvloop (>=0.15.2)"]


[[package]] [[package]]
name = "certifi" name = "certifi"
version = "2024.7.4"
version = "2025.10.5"
description = "Python package for providing Mozilla's CA Bundle." description = "Python package for providing Mozilla's CA Bundle."
optional = false optional = false
python-versions = ">=3.6"
python-versions = ">=3.7"
groups = ["main"] groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"},
{file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"},
{file = "certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de"},
{file = "certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43"},
] ]


[[package]] [[package]]
name = "click" name = "click"
version = "8.1.7"
version = "8.3.0"
description = "Composable command line interface toolkit" description = "Composable command line interface toolkit"
optional = false optional = false
python-versions = ">=3.7"
python-versions = ">=3.10"
groups = ["dev"] groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
{file = "click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc"},
{file = "click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4"},
] ]


[package.dependencies] [package.dependencies]
@@ -119,7 +124,7 @@ description = "Cross-platform colored terminal text."
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
groups = ["dev"] groups = ["dev"]
markers = "(python_version < \"3.10.dev0\" or python_version >= \"3.10\") and (platform_system == \"Windows\" or sys_platform == \"win32\")"
markers = "platform_system == \"Windows\" or sys_platform == \"win32\""
files = [ files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
@@ -132,7 +137,6 @@ description = "A library to handle automated deprecations"
optional = false optional = false
python-versions = "*" python-versions = "*"
groups = ["dev"] groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a"}, {file = "deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a"},
{file = "deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff"}, {file = "deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff"},
@@ -141,71 +145,28 @@ files = [
[package.dependencies] [package.dependencies]
packaging = "*" packaging = "*"


[[package]]
name = "exceptiongroup"
version = "1.2.0"
description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version == \"3.10\""
files = [
{file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"},
{file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"},
]

[package.extras]
test = ["pytest (>=6)"]

[[package]]
name = "importlib-metadata"
version = "8.5.0"
description = "Read metadata from Python packages"
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [
{file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"},
{file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"},
]

[package.dependencies]
zipp = ">=3.20"

[package.extras]
check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""]
cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
enabler = ["pytest-enabler (>=2.2)"]
perf = ["ipython"]
test = ["flufl.flake8", "importlib-resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"]
type = ["pytest-mypy"]

[[package]] [[package]]
name = "iniconfig" name = "iniconfig"
version = "2.0.0"
version = "2.3.0"
description = "brain-dead simple config-ini parsing" description = "brain-dead simple config-ini parsing"
optional = false optional = false
python-versions = ">=3.7"
python-versions = ">=3.10"
groups = ["dev"] groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
{file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"},
{file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"},
] ]


[[package]] [[package]]
name = "jplephem" name = "jplephem"
version = "2.21"
version = "2.23"
description = "Use a JPL ephemeris to predict planet positions." description = "Use a JPL ephemeris to predict planet positions."
optional = false optional = false
python-versions = "*" python-versions = "*"
groups = ["main"] groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "jplephem-2.21-py3-none-any.whl", hash = "sha256:487fd8c94c458bba74f43bcf332702bbcb2b8e5a4e3fb15c36159fc92e69e6a1"},
{file = "jplephem-2.21.tar.gz", hash = "sha256:34194b610695f21b89217b9852b8dabadbce80848cb369d9567ef12dc4828d55"},
{file = "jplephem-2.23-py3-none-any.whl", hash = "sha256:66110814810b0b30213bdd058a85a41bedbc030bb8a365c85088674fe02546cf"},
{file = "jplephem-2.23.tar.gz", hash = "sha256:d3fb9477e4bf4c39d10497d4ff15e5271b7ac03fa101e1821aac527d646eccf9"},
] ]


[package.dependencies] [package.dependencies]
@@ -218,151 +179,134 @@ description = "A library to computes the ephemerides."
optional = false optional = false
python-versions = "<4.0,>=3.8" python-versions = "<4.0,>=3.8"
groups = ["main"] groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "kosmorrolib-1.0.12-py3-none-any.whl", hash = "sha256:4ea6b0cb2933836b32684f92f7df29a48b8a60cf27a4c513ac38189d47dbcbdc"}, {file = "kosmorrolib-1.0.12-py3-none-any.whl", hash = "sha256:4ea6b0cb2933836b32684f92f7df29a48b8a60cf27a4c513ac38189d47dbcbdc"},
{file = "kosmorrolib-1.0.12.tar.gz", hash = "sha256:8c9da76165c91503406b2cae395236d37c3899c0116cd4e7e338e58643ef0cc7"}, {file = "kosmorrolib-1.0.12.tar.gz", hash = "sha256:8c9da76165c91503406b2cae395236d37c3899c0116cd4e7e338e58643ef0cc7"},
] ]


[package.dependencies] [package.dependencies]
numpy = [
{version = "<1.25", markers = "python_version >= \"3.8.dev0\" and python_version < \"3.9.dev0\""},
{version = "<2.1", markers = "python_version >= \"3.9.dev0\" and python_version < \"3.10.dev0\""},
{version = ">=2.1,<3.0", markers = "python_version >= \"3.10\" and python_version < \"4.0\""},
]
numpy = {version = ">=2.1,<3.0", markers = "python_version >= \"3.10\" and python_version < \"4.0\""}
python-dateutil = ">=2.8,<3.0" python-dateutil = ">=2.8,<3.0"
skyfield = ">=1.49,<2.0" skyfield = ">=1.49,<2.0"
skyfield-data = "*" skyfield-data = "*"


[[package]] [[package]]
name = "mypy-extensions" name = "mypy-extensions"
version = "1.0.0"
version = "1.1.0"
description = "Type system extensions for programs checked with the mypy type checker." description = "Type system extensions for programs checked with the mypy type checker."
optional = false optional = false
python-versions = ">=3.5"
python-versions = ">=3.8"
groups = ["dev"] groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
{file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"},
{file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"},
] ]


[[package]] [[package]]
name = "numpy" name = "numpy"
version = "1.24.4"
version = "2.3.4"
description = "Fundamental package for array computing in Python" description = "Fundamental package for array computing in Python"
optional = false optional = false
python-versions = ">=3.8"
python-versions = ">=3.11"
groups = ["main"] groups = ["main"]
markers = "python_version < \"3.10.dev0\""
files = [ files = [
{file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"},
{file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"},
{file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"},
{file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"},
{file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"},
{file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"},
{file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"},
{file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"},
{file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"},
{file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"},
{file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"},
{file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"},
{file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"},
{file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"},
{file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"},
{file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"},
{file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"},
{file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"},
{file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"},
{file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"},
{file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"},
{file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"},
{file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"},
{file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"},
{file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"},
{file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"},
{file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"},
{file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"},
{file = "numpy-2.3.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e78aecd2800b32e8347ce49316d3eaf04aed849cd5b38e0af39f829a4e59f5eb"},
{file = "numpy-2.3.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7fd09cc5d65bda1e79432859c40978010622112e9194e581e3415a3eccc7f43f"},
{file = "numpy-2.3.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:1b219560ae2c1de48ead517d085bc2d05b9433f8e49d0955c82e8cd37bd7bf36"},
{file = "numpy-2.3.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:bafa7d87d4c99752d07815ed7a2c0964f8ab311eb8168f41b910bd01d15b6032"},
{file = "numpy-2.3.4-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36dc13af226aeab72b7abad501d370d606326a0029b9f435eacb3b8c94b8a8b7"},
{file = "numpy-2.3.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7b2f9a18b5ff9824a6af80de4f37f4ec3c2aab05ef08f51c77a093f5b89adda"},
{file = "numpy-2.3.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9984bd645a8db6ca15d850ff996856d8762c51a2239225288f08f9050ca240a0"},
{file = "numpy-2.3.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:64c5825affc76942973a70acf438a8ab618dbd692b84cd5ec40a0a0509edc09a"},
{file = "numpy-2.3.4-cp311-cp311-win32.whl", hash = "sha256:ed759bf7a70342f7817d88376eb7142fab9fef8320d6019ef87fae05a99874e1"},
{file = "numpy-2.3.4-cp311-cp311-win_amd64.whl", hash = "sha256:faba246fb30ea2a526c2e9645f61612341de1a83fb1e0c5edf4ddda5a9c10996"},
{file = "numpy-2.3.4-cp311-cp311-win_arm64.whl", hash = "sha256:4c01835e718bcebe80394fd0ac66c07cbb90147ebbdad3dcecd3f25de2ae7e2c"},
{file = "numpy-2.3.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ef1b5a3e808bc40827b5fa2c8196151a4c5abe110e1726949d7abddfe5c7ae11"},
{file = "numpy-2.3.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c2f91f496a87235c6aaf6d3f3d89b17dba64996abadccb289f48456cff931ca9"},
{file = "numpy-2.3.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:f77e5b3d3da652b474cc80a14084927a5e86a5eccf54ca8ca5cbd697bf7f2667"},
{file = "numpy-2.3.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:8ab1c5f5ee40d6e01cbe96de5863e39b215a4d24e7d007cad56c7184fdf4aeef"},
{file = "numpy-2.3.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77b84453f3adcb994ddbd0d1c5d11db2d6bda1a2b7fd5ac5bd4649d6f5dc682e"},
{file = "numpy-2.3.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4121c5beb58a7f9e6dfdee612cb24f4df5cd4db6e8261d7f4d7450a997a65d6a"},
{file = "numpy-2.3.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:65611ecbb00ac9846efe04db15cbe6186f562f6bb7e5e05f077e53a599225d16"},
{file = "numpy-2.3.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dabc42f9c6577bcc13001b8810d300fe814b4cfbe8a92c873f269484594f9786"},
{file = "numpy-2.3.4-cp312-cp312-win32.whl", hash = "sha256:a49d797192a8d950ca59ee2d0337a4d804f713bb5c3c50e8db26d49666e351dc"},
{file = "numpy-2.3.4-cp312-cp312-win_amd64.whl", hash = "sha256:985f1e46358f06c2a09921e8921e2c98168ed4ae12ccd6e5e87a4f1857923f32"},
{file = "numpy-2.3.4-cp312-cp312-win_arm64.whl", hash = "sha256:4635239814149e06e2cb9db3dd584b2fa64316c96f10656983b8026a82e6e4db"},
{file = "numpy-2.3.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c090d4860032b857d94144d1a9976b8e36709e40386db289aaf6672de2a81966"},
{file = "numpy-2.3.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a13fc473b6db0be619e45f11f9e81260f7302f8d180c49a22b6e6120022596b3"},
{file = "numpy-2.3.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:3634093d0b428e6c32c3a69b78e554f0cd20ee420dcad5a9f3b2a63762ce4197"},
{file = "numpy-2.3.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:043885b4f7e6e232d7df4f51ffdef8c36320ee9d5f227b380ea636722c7ed12e"},
{file = "numpy-2.3.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4ee6a571d1e4f0ea6d5f22d6e5fbd6ed1dc2b18542848e1e7301bd190500c9d7"},
{file = "numpy-2.3.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc8a63918b04b8571789688b2780ab2b4a33ab44bfe8ccea36d3eba51228c953"},
{file = "numpy-2.3.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:40cc556d5abbc54aabe2b1ae287042d7bdb80c08edede19f0c0afb36ae586f37"},
{file = "numpy-2.3.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ecb63014bb7f4ce653f8be7f1df8cbc6093a5a2811211770f6606cc92b5a78fd"},
{file = "numpy-2.3.4-cp313-cp313-win32.whl", hash = "sha256:e8370eb6925bb8c1c4264fec52b0384b44f675f191df91cbe0140ec9f0955646"},
{file = "numpy-2.3.4-cp313-cp313-win_amd64.whl", hash = "sha256:56209416e81a7893036eea03abcb91c130643eb14233b2515c90dcac963fe99d"},
{file = "numpy-2.3.4-cp313-cp313-win_arm64.whl", hash = "sha256:a700a4031bc0fd6936e78a752eefb79092cecad2599ea9c8039c548bc097f9bc"},
{file = "numpy-2.3.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:86966db35c4040fdca64f0816a1c1dd8dbd027d90fca5a57e00e1ca4cd41b879"},
{file = "numpy-2.3.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:838f045478638b26c375ee96ea89464d38428c69170360b23a1a50fa4baa3562"},
{file = "numpy-2.3.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d7315ed1dab0286adca467377c8381cd748f3dc92235f22a7dfc42745644a96a"},
{file = "numpy-2.3.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:84f01a4d18b2cc4ade1814a08e5f3c907b079c847051d720fad15ce37aa930b6"},
{file = "numpy-2.3.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:817e719a868f0dacde4abdfc5c1910b301877970195db9ab6a5e2c4bd5b121f7"},
{file = "numpy-2.3.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85e071da78d92a214212cacea81c6da557cab307f2c34b5f85b628e94803f9c0"},
{file = "numpy-2.3.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2ec646892819370cf3558f518797f16597b4e4669894a2ba712caccc9da53f1f"},
{file = "numpy-2.3.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:035796aaaddfe2f9664b9a9372f089cfc88bd795a67bd1bfe15e6e770934cf64"},
{file = "numpy-2.3.4-cp313-cp313t-win32.whl", hash = "sha256:fea80f4f4cf83b54c3a051f2f727870ee51e22f0248d3114b8e755d160b38cfb"},
{file = "numpy-2.3.4-cp313-cp313t-win_amd64.whl", hash = "sha256:15eea9f306b98e0be91eb344a94c0e630689ef302e10c2ce5f7e11905c704f9c"},
{file = "numpy-2.3.4-cp313-cp313t-win_arm64.whl", hash = "sha256:b6c231c9c2fadbae4011ca5e7e83e12dc4a5072f1a1d85a0a7b3ed754d145a40"},
{file = "numpy-2.3.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:81c3e6d8c97295a7360d367f9f8553973651b76907988bb6066376bc2252f24e"},
{file = "numpy-2.3.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7c26b0b2bf58009ed1f38a641f3db4be8d960a417ca96d14e5b06df1506d41ff"},
{file = "numpy-2.3.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:62b2198c438058a20b6704351b35a1d7db881812d8512d67a69c9de1f18ca05f"},
{file = "numpy-2.3.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:9d729d60f8d53a7361707f4b68a9663c968882dd4f09e0d58c044c8bf5faee7b"},
{file = "numpy-2.3.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd0c630cf256b0a7fd9d0a11c9413b42fef5101219ce6ed5a09624f5a65392c7"},
{file = "numpy-2.3.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5e081bc082825f8b139f9e9fe42942cb4054524598aaeb177ff476cc76d09d2"},
{file = "numpy-2.3.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:15fb27364ed84114438fff8aaf998c9e19adbeba08c0b75409f8c452a8692c52"},
{file = "numpy-2.3.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:85d9fb2d8cd998c84d13a79a09cc0c1091648e848e4e6249b0ccd7f6b487fa26"},
{file = "numpy-2.3.4-cp314-cp314-win32.whl", hash = "sha256:e73d63fd04e3a9d6bc187f5455d81abfad05660b212c8804bf3b407e984cd2bc"},
{file = "numpy-2.3.4-cp314-cp314-win_amd64.whl", hash = "sha256:3da3491cee49cf16157e70f607c03a217ea6647b1cea4819c4f48e53d49139b9"},
{file = "numpy-2.3.4-cp314-cp314-win_arm64.whl", hash = "sha256:6d9cd732068e8288dbe2717177320723ccec4fb064123f0caf9bbd90ab5be868"},
{file = "numpy-2.3.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:22758999b256b595cf0b1d102b133bb61866ba5ceecf15f759623b64c020c9ec"},
{file = "numpy-2.3.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9cb177bc55b010b19798dc5497d540dea67fd13a8d9e882b2dae71de0cf09eb3"},
{file = "numpy-2.3.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:0f2bcc76f1e05e5ab58893407c63d90b2029908fa41f9f1cc51eecce936c3365"},
{file = "numpy-2.3.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:8dc20bde86802df2ed8397a08d793da0ad7a5fd4ea3ac85d757bf5dd4ad7c252"},
{file = "numpy-2.3.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e199c087e2aa71c8f9ce1cb7a8e10677dc12457e7cc1be4798632da37c3e86e"},
{file = "numpy-2.3.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85597b2d25ddf655495e2363fe044b0ae999b75bc4d630dc0d886484b03a5eb0"},
{file = "numpy-2.3.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04a69abe45b49c5955923cf2c407843d1c85013b424ae8a560bba16c92fe44a0"},
{file = "numpy-2.3.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e1708fac43ef8b419c975926ce1eaf793b0c13b7356cfab6ab0dc34c0a02ac0f"},
{file = "numpy-2.3.4-cp314-cp314t-win32.whl", hash = "sha256:863e3b5f4d9915aaf1b8ec79ae560ad21f0b8d5e3adc31e73126491bb86dee1d"},
{file = "numpy-2.3.4-cp314-cp314t-win_amd64.whl", hash = "sha256:962064de37b9aef801d33bc579690f8bfe6c5e70e29b61783f60bcba838a14d6"},
{file = "numpy-2.3.4-cp314-cp314t-win_arm64.whl", hash = "sha256:8b5a9a39c45d852b62693d9b3f3e0fe052541f804296ff401a72a1b60edafb29"},
{file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6e274603039f924c0fe5cb73438fa9246699c78a6df1bd3decef9ae592ae1c05"},
{file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d149aee5c72176d9ddbc6803aef9c0f6d2ceeea7626574fc68518da5476fa346"},
{file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:6d34ed9db9e6395bb6cd33286035f73a59b058169733a9db9f85e650b88df37e"},
{file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:fdebe771ca06bb8d6abce84e51dca9f7921fe6ad34a0c914541b063e9a68928b"},
{file = "numpy-2.3.4-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e92defe6c08211eb77902253b14fe5b480ebc5112bc741fd5e9cd0608f847"},
{file = "numpy-2.3.4-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13b9062e4f5c7ee5c7e5be96f29ba71bc5a37fed3d1d77c37390ae00724d296d"},
{file = "numpy-2.3.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:81b3a59793523e552c4a96109dde028aa4448ae06ccac5a76ff6532a85558a7f"},
{file = "numpy-2.3.4.tar.gz", hash = "sha256:a7d018bfedb375a8d979ac758b120ba846a7fe764911a64465fd87b8729f4a6a"},
] ]


[[package]] [[package]]
name = "numpy"
version = "2.2.3"
description = "Fundamental package for array computing in Python"
name = "openlocationcode"
version = "1.0.1"
description = "Python library for Open Location Code (Plus Codes)"
optional = false optional = false
python-versions = ">=3.10"
python-versions = "*"
groups = ["main"] groups = ["main"]
markers = "python_version >= \"3.10\""
files = [ files = [
{file = "numpy-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cbc6472e01952d3d1b2772b720428f8b90e2deea8344e854df22b0618e9cce71"},
{file = "numpy-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdfe0c22692a30cd830c0755746473ae66c4a8f2e7bd508b35fb3b6a0813d787"},
{file = "numpy-2.2.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:e37242f5324ffd9f7ba5acf96d774f9276aa62a966c0bad8dae692deebec7716"},
{file = "numpy-2.2.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:95172a21038c9b423e68be78fd0be6e1b97674cde269b76fe269a5dfa6fadf0b"},
{file = "numpy-2.2.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5b47c440210c5d1d67e1cf434124e0b5c395eee1f5806fdd89b553ed1acd0a3"},
{file = "numpy-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0391ea3622f5c51a2e29708877d56e3d276827ac5447d7f45e9bc4ade8923c52"},
{file = "numpy-2.2.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f6b3dfc7661f8842babd8ea07e9897fe3d9b69a1d7e5fbb743e4160f9387833b"},
{file = "numpy-2.2.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1ad78ce7f18ce4e7df1b2ea4019b5817a2f6a8a16e34ff2775f646adce0a5027"},
{file = "numpy-2.2.3-cp310-cp310-win32.whl", hash = "sha256:5ebeb7ef54a7be11044c33a17b2624abe4307a75893c001a4800857956b41094"},
{file = "numpy-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:596140185c7fa113563c67c2e894eabe0daea18cf8e33851738c19f70ce86aeb"},
{file = "numpy-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:16372619ee728ed67a2a606a614f56d3eabc5b86f8b615c79d01957062826ca8"},
{file = "numpy-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5521a06a3148686d9269c53b09f7d399a5725c47bbb5b35747e1cb76326b714b"},
{file = "numpy-2.2.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:7c8dde0ca2f77828815fd1aedfdf52e59071a5bae30dac3b4da2a335c672149a"},
{file = "numpy-2.2.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:77974aba6c1bc26e3c205c2214f0d5b4305bdc719268b93e768ddb17e3fdd636"},
{file = "numpy-2.2.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d42f9c36d06440e34226e8bd65ff065ca0963aeecada587b937011efa02cdc9d"},
{file = "numpy-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2712c5179f40af9ddc8f6727f2bd910ea0eb50206daea75f58ddd9fa3f715bb"},
{file = "numpy-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c8b0451d2ec95010d1db8ca733afc41f659f425b7f608af569711097fd6014e2"},
{file = "numpy-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9b4a8148c57ecac25a16b0e11798cbe88edf5237b0df99973687dd866f05e1b"},
{file = "numpy-2.2.3-cp311-cp311-win32.whl", hash = "sha256:1f45315b2dc58d8a3e7754fe4e38b6fce132dab284a92851e41b2b344f6441c5"},
{file = "numpy-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f48ba6f6c13e5e49f3d3efb1b51c8193215c42ac82610a04624906a9270be6f"},
{file = "numpy-2.2.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12c045f43b1d2915eca6b880a7f4a256f59d62df4f044788c8ba67709412128d"},
{file = "numpy-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:87eed225fd415bbae787f93a457af7f5990b92a334e346f72070bf569b9c9c95"},
{file = "numpy-2.2.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:712a64103d97c404e87d4d7c47fb0c7ff9acccc625ca2002848e0d53288b90ea"},
{file = "numpy-2.2.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a5ae282abe60a2db0fd407072aff4599c279bcd6e9a2475500fc35b00a57c532"},
{file = "numpy-2.2.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5266de33d4c3420973cf9ae3b98b54a2a6d53a559310e3236c4b2b06b9c07d4e"},
{file = "numpy-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b787adbf04b0db1967798dba8da1af07e387908ed1553a0d6e74c084d1ceafe"},
{file = "numpy-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:34c1b7e83f94f3b564b35f480f5652a47007dd91f7c839f404d03279cc8dd021"},
{file = "numpy-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4d8335b5f1b6e2bce120d55fb17064b0262ff29b459e8493d1785c18ae2553b8"},
{file = "numpy-2.2.3-cp312-cp312-win32.whl", hash = "sha256:4d9828d25fb246bedd31e04c9e75714a4087211ac348cb39c8c5f99dbb6683fe"},
{file = "numpy-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:83807d445817326b4bcdaaaf8e8e9f1753da04341eceec705c001ff342002e5d"},
{file = "numpy-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7bfdb06b395385ea9b91bf55c1adf1b297c9fdb531552845ff1d3ea6e40d5aba"},
{file = "numpy-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:23c9f4edbf4c065fddb10a4f6e8b6a244342d95966a48820c614891e5059bb50"},
{file = "numpy-2.2.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:a0c03b6be48aaf92525cccf393265e02773be8fd9551a2f9adbe7db1fa2b60f1"},
{file = "numpy-2.2.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:2376e317111daa0a6739e50f7ee2a6353f768489102308b0d98fcf4a04f7f3b5"},
{file = "numpy-2.2.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8fb62fe3d206d72fe1cfe31c4a1106ad2b136fcc1606093aeab314f02930fdf2"},
{file = "numpy-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52659ad2534427dffcc36aac76bebdd02b67e3b7a619ac67543bc9bfe6b7cdb1"},
{file = "numpy-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1b416af7d0ed3271cad0f0a0d0bee0911ed7eba23e66f8424d9f3dfcdcae1304"},
{file = "numpy-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1402da8e0f435991983d0a9708b779f95a8c98c6b18a171b9f1be09005e64d9d"},
{file = "numpy-2.2.3-cp313-cp313-win32.whl", hash = "sha256:136553f123ee2951bfcfbc264acd34a2fc2f29d7cdf610ce7daf672b6fbaa693"},
{file = "numpy-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:5b732c8beef1d7bc2d9e476dbba20aaff6167bf205ad9aa8d30913859e82884b"},
{file = "numpy-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:435e7a933b9fda8126130b046975a968cc2d833b505475e588339e09f7672890"},
{file = "numpy-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7678556eeb0152cbd1522b684dcd215250885993dd00adb93679ec3c0e6e091c"},
{file = "numpy-2.2.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:2e8da03bd561504d9b20e7a12340870dfc206c64ea59b4cfee9fceb95070ee94"},
{file = "numpy-2.2.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:c9aa4496fd0e17e3843399f533d62857cef5900facf93e735ef65aa4bbc90ef0"},
{file = "numpy-2.2.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4ca91d61a4bf61b0f2228f24bbfa6a9facd5f8af03759fe2a655c50ae2c6610"},
{file = "numpy-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:deaa09cd492e24fd9b15296844c0ad1b3c976da7907e1c1ed3a0ad21dded6f76"},
{file = "numpy-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:246535e2f7496b7ac85deffe932896a3577be7af8fb7eebe7146444680297e9a"},
{file = "numpy-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:daf43a3d1ea699402c5a850e5313680ac355b4adc9770cd5cfc2940e7861f1bf"},
{file = "numpy-2.2.3-cp313-cp313t-win32.whl", hash = "sha256:cf802eef1f0134afb81fef94020351be4fe1d6681aadf9c5e862af6602af64ef"},
{file = "numpy-2.2.3-cp313-cp313t-win_amd64.whl", hash = "sha256:aee2512827ceb6d7f517c8b85aa5d3923afe8fc7a57d028cffcd522f1c6fd082"},
{file = "numpy-2.2.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3c2ec8a0f51d60f1e9c0c5ab116b7fc104b165ada3f6c58abf881cb2eb16044d"},
{file = "numpy-2.2.3-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:ed2cf9ed4e8ebc3b754d398cba12f24359f018b416c380f577bbae112ca52fc9"},
{file = "numpy-2.2.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39261798d208c3095ae4f7bc8eaeb3481ea8c6e03dc48028057d3cbdbdb8937e"},
{file = "numpy-2.2.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:783145835458e60fa97afac25d511d00a1eca94d4a8f3ace9fe2043003c678e4"},
{file = "numpy-2.2.3.tar.gz", hash = "sha256:dbdc15f0c81611925f382dfa97b3bd0bc2c1ce19d4fe50482cb0ddc12ba30020"},
{file = "openlocationcode-1.0.1.tar.gz", hash = "sha256:6fc0108a8214b65d74964105bd69645a8a7529237f0de6aadcfa83cc3373b359"},
] ]


[[package]] [[package]]
name = "packaging" name = "packaging"
version = "23.2"
version = "25.0"
description = "Core utilities for Python packages" description = "Core utilities for Python packages"
optional = false optional = false
python-versions = ">=3.7"
python-versions = ">=3.8"
groups = ["dev"] groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"},
{file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
{file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"},
{file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"},
] ]


[[package]] [[package]]
@@ -372,7 +316,6 @@ description = "Utility library for gitignore style pattern matching of file path
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
groups = ["dev"] groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
@@ -380,61 +323,73 @@ files = [


[[package]] [[package]]
name = "platformdirs" name = "platformdirs"
version = "4.1.0"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
version = "4.5.0"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
optional = false optional = false
python-versions = ">=3.8"
python-versions = ">=3.10"
groups = ["dev"] groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"},
{file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"},
{file = "platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3"},
{file = "platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312"},
] ]


[package.extras] [package.extras]
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"]
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"]
docs = ["furo (>=2025.9.25)", "proselint (>=0.14)", "sphinx (>=8.2.3)", "sphinx-autodoc-typehints (>=3.2)"]
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.4.2)", "pytest-cov (>=7)", "pytest-mock (>=3.15.1)"]
type = ["mypy (>=1.18.2)"]


[[package]] [[package]]
name = "pluggy" name = "pluggy"
version = "1.5.0"
version = "1.6.0"
description = "plugin and hook calling mechanisms for python" description = "plugin and hook calling mechanisms for python"
optional = false optional = false
python-versions = ">=3.8"
python-versions = ">=3.9"
groups = ["dev"] groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
{file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
{file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"},
{file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"},
] ]


[package.extras] [package.extras]
dev = ["pre-commit", "tox"] dev = ["pre-commit", "tox"]
testing = ["pytest", "pytest-benchmark"]
testing = ["coverage", "pytest", "pytest-benchmark"]

[[package]]
name = "pygments"
version = "2.19.2"
description = "Pygments is a syntax highlighting package written in Python."
optional = false
python-versions = ">=3.8"
groups = ["dev"]
files = [
{file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"},
{file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"},
]

[package.extras]
windows-terminal = ["colorama (>=0.4.6)"]


[[package]] [[package]]
name = "pytest" name = "pytest"
version = "8.3.5"
version = "8.4.2"
description = "pytest: simple powerful testing with Python" description = "pytest: simple powerful testing with Python"
optional = false optional = false
python-versions = ">=3.8"
python-versions = ">=3.9"
groups = ["dev"] groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"},
{file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"},
{file = "pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79"},
{file = "pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01"},
] ]


[package.dependencies] [package.dependencies]
colorama = {version = "*", markers = "sys_platform == \"win32\""}
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
iniconfig = "*"
packaging = "*"
colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""}
iniconfig = ">=1"
packaging = ">=20"
pluggy = ">=1.5,<2" pluggy = ">=1.5,<2"
tomli = {version = ">=1", markers = "python_version < \"3.11\""}
pygments = ">=2.7.2"


[package.extras] [package.extras]
dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"]


[[package]] [[package]]
name = "python-dateutil" name = "python-dateutil"
@@ -443,7 +398,6 @@ description = "Extensions to the standard Python datetime module"
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
groups = ["main"] groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
{file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
@@ -454,115 +408,115 @@ six = ">=1.5"


[[package]] [[package]]
name = "pytz" name = "pytz"
version = "2023.3.post1"
version = "2025.2"
description = "World timezone definitions, modern and historical" description = "World timezone definitions, modern and historical"
optional = false optional = false
python-versions = "*" python-versions = "*"
groups = ["main"] groups = ["main"]
markers = "python_version < \"3.9.dev0\""
files = [ files = [
{file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"},
{file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"},
{file = "pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"},
{file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"},
] ]


[[package]] [[package]]
name = "sgp4" name = "sgp4"
version = "2.23"
version = "2.25"
description = "Track Earth satellites given TLE data, using up-to-date 2020 SGP4 routines." description = "Track Earth satellites given TLE data, using up-to-date 2020 SGP4 routines."
optional = false optional = false
python-versions = "*" python-versions = "*"
groups = ["main"] groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "sgp4-2.23-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ebf585c09bebf7f7b9c89cff42e0f097654c4c5e092181fbbbee29c338dc11ed"},
{file = "sgp4-2.23-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c71fec3278274a0edd5bb93ba83b22db5407040d95d62166e81fbd97633d756"},
{file = "sgp4-2.23-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f07f11fc70fa76ad7f538bcff4ee960faab270279cbb2d1149b15cbb37696e86"},
{file = "sgp4-2.23-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9a777e4173194965ec9466b307c3a929770d058be303ead8179c251fc37ed2e"},
{file = "sgp4-2.23-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3884d50cba79f4dbeda16b4eb1d768bd3400b7a2c137a8c88eca056738bab94d"},
{file = "sgp4-2.23-cp310-cp310-win32.whl", hash = "sha256:ce19d23a4276bab2bbba03ce5bbcc308c5472be69219d877f83d4b12c07f5ea1"},
{file = "sgp4-2.23-cp310-cp310-win_amd64.whl", hash = "sha256:2d6b56adb8771f3092ff5d59697d19f6f3bf2510fcca03795eedae41a42624b2"},
{file = "sgp4-2.23-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:90dbea63ea1f288ce90448b3d7a1e9728292f1b9c9fa61839053e9277d98e96f"},
{file = "sgp4-2.23-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e7b043fb0f628a3759ef649ee12b6e76ee65a0ec86b94dc41dfc90129fcbc81e"},
{file = "sgp4-2.23-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7d55529102283821054ece00f95dd2b82843d1c72c80e39026c78e2f400ac9b9"},
{file = "sgp4-2.23-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d9f4f39be2b85a4772a184cd4d160f9ed345116afcda79a0a1852ccfa12b030"},
{file = "sgp4-2.23-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72868cd01169f45562954cdaaa9f1a2f738cac3c9ba3fdbd12b07a5f99bcb9d1"},
{file = "sgp4-2.23-cp311-cp311-win32.whl", hash = "sha256:137adf0e0fbe4d9a514284bb809590c5a2c52dc506b977ec7896165df8bc2a5e"},
{file = "sgp4-2.23-cp311-cp311-win_amd64.whl", hash = "sha256:34efb27f9f281c76b5650c9a39a0b8f43d383d5575a4f7b3d4d597c9b7ff3d75"},
{file = "sgp4-2.23-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c45fa362763b5ae955a52bfdf05fee8d98351d1fa9db8fd1809b4f380cd9b0c6"},
{file = "sgp4-2.23-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3765d0efae2c537228311591691a8fd7d44686d5322810be15eb7f204688f336"},
{file = "sgp4-2.23-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b80dd3c3ee73a1bc24c0f63316889b3eff32e623ca67a91774c9c92ac663e98c"},
{file = "sgp4-2.23-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ec001c6b5bd9a330ffa40d29ebf85f1cc2bfa558ba8f330efcb1aa50a8b733"},
{file = "sgp4-2.23-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7424adc1d5f8cf93bf6ddeb079a9122af25c8a6b9234e7ed71d1868e128afe4a"},
{file = "sgp4-2.23-cp312-cp312-win32.whl", hash = "sha256:4d954aa01a9f8c68a7b20e91ea6b5e0a195bb42b25e63698ea770d12c01927ea"},
{file = "sgp4-2.23-cp312-cp312-win_amd64.whl", hash = "sha256:cc08bc23327f7b3cd052e79b026f02a1da885a273f10fa2a78734e5fa5ccfddd"},
{file = "sgp4-2.23-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0312155fe5ec1f224510508c2298ee810821e66cd075686b041d921fba2f5b3b"},
{file = "sgp4-2.23-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6922c6086e3a6dec71a2df0e9c884ffa3edb7276daff36c6c8aa1e4fe711de"},
{file = "sgp4-2.23-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:77db876e61e5740ad10deb368041411ec1be8d885b0890f37cd81fb12d294dd4"},
{file = "sgp4-2.23-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e7b9c513efbdf2e27d88e2cd72599f5c2a930e6e8b2dd18ec7a1b62ad57ed58"},
{file = "sgp4-2.23-cp37-cp37m-win32.whl", hash = "sha256:f612f8f33ba22425bf9975170586ad1b61648abe113f5b82e35a07a426597107"},
{file = "sgp4-2.23-cp37-cp37m-win_amd64.whl", hash = "sha256:4f49aae8dff21747c5605d924f92149a4613b981ae13b31499390526cbcd2dba"},
{file = "sgp4-2.23-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:081aa74d55ee2d5c8c6a89e24915af069499ec66fe3ef01b58c4a93a741c4f47"},
{file = "sgp4-2.23-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:80eb86ebb66938542eb4b2fb660884538e48e14362e7b50313a6ecc888a93638"},
{file = "sgp4-2.23-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ff8797c36e7dff0b13c7f6bc4c9bf6ad31590dc4509e6b9cfac26819e7a61769"},
{file = "sgp4-2.23-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1a67628ca344e1abaf6ff447ccfc1e5ea3d0d829cecf07aa05dea21b0119470"},
{file = "sgp4-2.23-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf18eee8ce8dddee047785b3fb399ff45d1907e4d1e581a7466ac00798993d7e"},
{file = "sgp4-2.23-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7688173441f97680f4804e482e6ed47fb3a6341715f280ce38783fef7120c7c"},
{file = "sgp4-2.23-cp38-cp38-win32.whl", hash = "sha256:5be9be672ad810f01db18f4515fca47e3e4502139642d077d06a187e0c9dc312"},
{file = "sgp4-2.23-cp38-cp38-win_amd64.whl", hash = "sha256:7277523e83115d5e0c37bdb3d05fec924b6fdf0af0b1679bbb66455b8d00da61"},
{file = "sgp4-2.23-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:474598a642b77b2f2243ccdfb6204c92219f5182a261b8a89c09b9fef840fbd1"},
{file = "sgp4-2.23-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3423c1f7efcc72fb7bd92bd549812add1a8712fa7d9c3d475c187817ef844e77"},
{file = "sgp4-2.23-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:54e77baeb145e77884754e4c6cbc92b008d00f12563e5175c3197b484b61a651"},
{file = "sgp4-2.23-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6da74f4d0710445595ad8635bf29a608a6ef51d0ffdb5ae137d09fb7e32ac916"},
{file = "sgp4-2.23-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cd67a3eee025d62fff045807134ea4b1d377e0d88bea43a1e3153239b5d533b"},
{file = "sgp4-2.23-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5bb5e59ee41bdeb0beec5c9a156e82e4f5d9c8b7b5e950083f04ef66a8a7b61"},
{file = "sgp4-2.23-cp39-cp39-win32.whl", hash = "sha256:11962eee12a7422ebee88ef1b569851cd2db41830737f8c4669b2b5204ce2b39"},
{file = "sgp4-2.23-cp39-cp39-win_amd64.whl", hash = "sha256:4536de17b1a501ca94a9d7ea336de0efc5bb22eb358d88d29a080d1c03d39326"},
{file = "sgp4-2.23.tar.gz", hash = "sha256:d8addc53a2fb9f88dee6bfd401d2865b014cc0b57bf2cee69bdee8d9685d5429"},
{file = "sgp4-2.25-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29fd9ad2ded9517f6ba10f91e2d993144400c6a925e2b7931198646625beafd4"},
{file = "sgp4-2.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9ad88a8ced4b78f337765e8463f7f11c5f86d9267f83fc8e3dd8982df67bff45"},
{file = "sgp4-2.25-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc0c6ccb0f83e670e50dcd8a90b8a5bfe5bbf4225ce8450f807e14acc517ab21"},
{file = "sgp4-2.25-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3282ec0931e57692f3bf875342f28f41b1155cb575cbe24a30c3cd272ea46fb5"},
{file = "sgp4-2.25-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18e44f66670c61ae2372d6fecde076cb655f76d211b34b8de440cad5a273409f"},
{file = "sgp4-2.25-cp310-cp310-win32.whl", hash = "sha256:a2cc50b72b7d2b04c4012b492ec0e76f085e84de45f5e56d3baa4d3ef5f65dac"},
{file = "sgp4-2.25-cp310-cp310-win_amd64.whl", hash = "sha256:2b92506eef5c07063ab7595db58373bd965f8969fb1fb5b76cbffeb39027ba93"},
{file = "sgp4-2.25-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:93b22b9ae35db33664f2ddc37955a8d86c3a28f5c668d201e8c6f195a184496f"},
{file = "sgp4-2.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:33048ff064a4c0b6d8e3c2c79449a49ff45f5dabe8594622f0fb7ed17fa27c0e"},
{file = "sgp4-2.25-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac94f1d6fae120beeb40f2af587b351f9cb198837ae0fb3678e3bce44334a2a2"},
{file = "sgp4-2.25-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b164e636c4f1c64e09c6164b85985395c28c8556bc72ea56e42a889826287a0"},
{file = "sgp4-2.25-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfaddc20c4d6aa2e86119d13e3fd94a1d05e5bd17cb4fddb2ca5116842bc9228"},
{file = "sgp4-2.25-cp311-cp311-win32.whl", hash = "sha256:0ecd7d8833f83fe426d7926149665f4f23f4dab34b844e50876a1df88ee9aa7b"},
{file = "sgp4-2.25-cp311-cp311-win_amd64.whl", hash = "sha256:6b023f81fb20e62f8fa0b6f506201539ca8306779ef8565422bbf000f1e5a3dc"},
{file = "sgp4-2.25-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:170ec2882cd166ff9d8dccfb8018f86d5cc033ea8a07c27a1825999c62439f05"},
{file = "sgp4-2.25-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:64c7597a60b770caac51566b1f621d1cd74df0409ef19c5e7ea3505d0dfbc677"},
{file = "sgp4-2.25-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e1d18b8972643dd29e758e67c062cfb68fbe2421fe3f6398f1957a9825119f6"},
{file = "sgp4-2.25-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35649388a06cbee7def24cbb789f452c31d42ed9e87bddd89935ed78f19451ed"},
{file = "sgp4-2.25-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:911460477f1c52dcda2b3eb20538435b89b0a43668bcb5edd1e7700b7a1a0225"},
{file = "sgp4-2.25-cp312-cp312-win32.whl", hash = "sha256:128edd3d6061e833600d93e77d4c08d1a5002293997e368256b0b777ea525dda"},
{file = "sgp4-2.25-cp312-cp312-win_amd64.whl", hash = "sha256:979eb60e74aff5dc318cfe1a6c817db884486bdfc8496d2c5bc07b05fe833280"},
{file = "sgp4-2.25-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c4d4eab0f2c94aad3a0ab0bedd59f2137484af5480a3b40df8e4ab5a1fbc6b86"},
{file = "sgp4-2.25-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2822ca25f3724694bfced16cad8b3018678bee47fa3baf4eea20876d0e35ad33"},
{file = "sgp4-2.25-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7beca36492eb6d20ef15eeedd9520b8af4fa0cbaaae46a9269d5a2e7c8e56e46"},
{file = "sgp4-2.25-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e9dfd18cacf6bfb1faad29c89a6cec98a642558f805851080dea9c394520db2"},
{file = "sgp4-2.25-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5789b7add136362684dfcbf0862919f8c3018f74ab11a05a9964edd5fdd4d2a7"},
{file = "sgp4-2.25-cp313-cp313-win32.whl", hash = "sha256:94219b486def29aa1246f42de8bea05ccb8e98a5458dd08ce42b9811c79ca814"},
{file = "sgp4-2.25-cp313-cp313-win_amd64.whl", hash = "sha256:dec2f6c842d9bf40c67d5764bd752980844f91f338020d2af7f85847364d0ff7"},
{file = "sgp4-2.25-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2a1e3c501db1c56e57749e5d0bb82bf6d1cad886f549cb430222a3cd5b92067e"},
{file = "sgp4-2.25-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:521dca90a438494818dad7e67476b884791bb781753a9ccc6a4db46e4d33713b"},
{file = "sgp4-2.25-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:defcc785e99b0514c2022da8d5b3fefb1ef2cb318807979c030e674f6cf4ed9f"},
{file = "sgp4-2.25-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ee2dc8695e125449d755520da98b73906cdea0a164ae888812a4cd7ad4085a2"},
{file = "sgp4-2.25-cp37-cp37m-win32.whl", hash = "sha256:c170fedef5fbfc8459983ff39e3a2b175c19289d2dff649676f9066012d3c903"},
{file = "sgp4-2.25-cp37-cp37m-win_amd64.whl", hash = "sha256:7ad52a3dc8eae8324855ca432ed5cebc82fe9c18ae2fb0868d7bc14a7be84e1c"},
{file = "sgp4-2.25-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5af641d9a02bd1eeea87c337b784aeebec7054ebe013ef7f280a913e24803beb"},
{file = "sgp4-2.25-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0e5ce7926632c00baa45a3a663e4d47a462bb3932a659488a876230ce1f650c1"},
{file = "sgp4-2.25-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:036df88b7cfebdea8b1ff7ce6497db08526978d879a8a63f4ed681454faf92c3"},
{file = "sgp4-2.25-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:976c1403a88c12cd3b73713ab456ee240e4e41c4f1284f2d3623cf7cb09a052d"},
{file = "sgp4-2.25-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8804d0ab31eab7c93b1b98030136b32b1dfe7ecbb55b37407ef71aa10cd13d93"},
{file = "sgp4-2.25-cp38-cp38-win32.whl", hash = "sha256:cc5e89160097499e51e0787b114cc82da29f895fd2d3feca8508c8b4d5b8001e"},
{file = "sgp4-2.25-cp38-cp38-win_amd64.whl", hash = "sha256:bf27b614cc027a0319667e94931c32f3800050ec7f52ed71b415c865d003d978"},
{file = "sgp4-2.25-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9578d02300cb1e625e5ab842691b82ff690697078a371e255c57b8a3146c8521"},
{file = "sgp4-2.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f8db621e144877aa9c0ad4f1794590503bc57d318be94b8b9e5029ba8986cc4b"},
{file = "sgp4-2.25-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06bdb8166829cc172b7761cfae63633f127ff3ba38e337144c4255d60bc57fb4"},
{file = "sgp4-2.25-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed72e3f9e90ef98ef87819ad991a8be44a4f40d6a01191434685543d6ea64660"},
{file = "sgp4-2.25-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce68ee521e3acce25c2dfc977132039794fbaa4e21bc6d2eeabb4b8b34062362"},
{file = "sgp4-2.25-cp39-cp39-win32.whl", hash = "sha256:46e9e3809f43cc6512cf2667fddc9bb5535dcb4d0dac1f56290d3811134a80ff"},
{file = "sgp4-2.25-cp39-cp39-win_amd64.whl", hash = "sha256:5418ccf4a8ea8cccf6b90142c7c984374d03abae7537526295ec40cb676d7dc3"},
{file = "sgp4-2.25.tar.gz", hash = "sha256:e19edc6dcc25d69fb8fde0a267b8f0c44d7e915c7bcbeacf5d3a8b595baf0674"},
] ]


[[package]] [[package]]
name = "six" name = "six"
version = "1.16.0"
version = "1.17.0"
description = "Python 2 and 3 compatibility utilities" description = "Python 2 and 3 compatibility utilities"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
groups = ["main"] groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
{file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
{file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
] ]


[[package]] [[package]]
name = "skyfield" name = "skyfield"
version = "1.49"
version = "1.53"
description = "Elegant astronomy for Python" description = "Elegant astronomy for Python"
optional = false optional = false
python-versions = "*" python-versions = "*"
groups = ["main"] groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "skyfield-1.49-py3-none-any.whl", hash = "sha256:4986b7d5368f159050106282dec0f97e193c32689605ee4077d7d49465aaf13e"},
{file = "skyfield-1.49.tar.gz", hash = "sha256:20883027b2bbf4017dd916b64faaeb3713a8f88d7c8e353c15cd030ac63be92c"},
{file = "skyfield-1.53-py3-none-any.whl", hash = "sha256:f2028bba5f3617ef34afab1cabac251601f72a8cd70298ca5def72c4beadce00"},
{file = "skyfield-1.53.tar.gz", hash = "sha256:24099855f3ba3906663ac1c10e650041e747680b986e807400eddedc0be4a8b4"},
] ]


[package.dependencies] [package.dependencies]
certifi = ">=2017.4.17" certifi = ">=2017.4.17"
jplephem = ">=2.13" jplephem = ">=2.13"
numpy = "*" numpy = "*"
sgp4 = ">=2.2"
sgp4 = ">=2.13"


[[package]] [[package]]
name = "skyfield-data" name = "skyfield-data"
version = "5.0.0"
version = "7.0.0"
description = "Data package for Skyfield" description = "Data package for Skyfield"
optional = false optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, <4"
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7,<4,>=2.6"
groups = ["main"] groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "skyfield-data-5.0.0.tar.gz", hash = "sha256:fe3484028cf96eb8040104d0626ec712f73e22e0f97a1eee62527207eead66c8"},
{file = "skyfield_data-5.0.0-py2.py3-none-any.whl", hash = "sha256:af5a04f704b1024f5cba039be2022aa72daab1fa4c3663eeaeb358ded5f8217b"},
{file = "skyfield_data-7.0.0-py2.py3-none-any.whl", hash = "sha256:4279f999f7f8c5ef5d8bf1b714f301a0844ae5df3a3f0d23610b20d8789073f5"},
{file = "skyfield_data-7.0.0.tar.gz", hash = "sha256:df3b4f0f5b5b57e5adf5a0a5d30d73ca23dd4066ee666da3222d7bd63d580bbd"},
] ]


[package.extras] [package.extras]
@@ -576,7 +530,6 @@ description = "Pretty-print tabular data"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
groups = ["main"] groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"},
{file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"},
@@ -587,68 +540,20 @@ widechars = ["wcwidth"]


[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "2.4.0"
version = "3.1.0"
description = "ANSI color formatting for output in terminal" description = "ANSI color formatting for output in terminal"
optional = false optional = false
python-versions = ">=3.8"
python-versions = ">=3.9"
groups = ["main"] groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [ files = [
{file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"},
{file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"},
{file = "termcolor-3.1.0-py3-none-any.whl", hash = "sha256:591dd26b5c2ce03b9e43f391264626557873ce1d379019786f99b0c2bee140aa"},
{file = "termcolor-3.1.0.tar.gz", hash = "sha256:6a6dd7fbee581909eeec6a756cff1d7f7c376063b14e4a298dc4980309e55970"},
] ]


[package.extras] [package.extras]
tests = ["pytest", "pytest-cov"] tests = ["pytest", "pytest-cov"]


[[package]]
name = "tomli"
version = "2.0.1"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.7"
groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version == \"3.10\""
files = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]

[[package]]
name = "typing-extensions"
version = "4.9.0"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version == \"3.10\""
files = [
{file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"},
{file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"},
]

[[package]]
name = "zipp"
version = "3.20.2"
description = "Backport of pathlib-compatible object wrapper for zip files"
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [
{file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"},
{file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"},
]

[package.extras]
check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""]
cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
enabler = ["pytest-enabler (>=2.2)"]
test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"]
type = ["pytest-mypy"]

[metadata] [metadata]
lock-version = "2.1" lock-version = "2.1"
python-versions = "^3.8"
content-hash = "a4fa3a2b71ef294caf512c090faae95e9f940303ddba7e34740db0c30ddafc3f"
python-versions = "^3.12"
content-hash = "d26e3a8141cafb8eeb2a154bac7c09ac665bcbdd012a7204a7ac5c3c00332c09"

+ 6
- 4
pyproject.toml Bestand weergeven

@@ -15,15 +15,17 @@ include = [
kosmorro = 'kosmorro.__main__:main' kosmorro = 'kosmorro.__main__:main'


[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.8"
python = "^3.12"
tabulate = ">=0.8,<0.10" tabulate = ">=0.8,<0.10"
termcolor = ">=1.1,<3.0"
termcolor = "^3.0"
kosmorrolib = "^1.0" kosmorrolib = "^1.0"
python-dateutil = "^2.8" python-dateutil = "^2.8"
Babel = "^2.9" Babel = "^2.9"
importlib-metadata = ">=4.11,<9.0"
openlocationcode = "^1.0"
pytz = "^2025.2"
argcomplete = "^3.6.2"


[tool.poetry.dev-dependencies]
[tool.poetry.group.dev.dependencies]
black = "^24.8" black = "^24.8"
pytest = "^8.3" pytest = "^8.3"
aurornis = "^1.6" aurornis = "^1.6"


+ 0
- 12
setup.cfg Bestand weergeven

@@ -1,12 +0,0 @@
[extract_message]
charset = utf-8
keywords = _ ngettext
width = 120
output_file = kosmorro/locales/messages.pot
omit_header = true
copyright_holder = Jérôme Deuchnord
input_paths=kosmorro

[compile_catalog]
domain = messages
directory = kosmorro/locales

+ 20
- 0
tests/completion.py Bestand weergeven

@@ -0,0 +1,20 @@
#!/usr/bin/env python3

from .utils import execute


def test_completion_script_is_generated():
for shell in ["bash", "zsh", "fish", "powershell"]:
result = execute(["kosmorro", f"--completion={shell}"])

assert result.successful
assert result.stdout != ""
assert result.stderr == ""


def test_completion_script_returns_error_for_unsupported_shell():
result = execute(["kosmorro", "--completion=deuchshell"])

assert not result.successful
assert result.stderr == "No completion script available for this shell.\n"
assert result.stdout == ""

+ 18
- 8
tests/dates.py Bestand weergeven

@@ -6,13 +6,13 @@ from .utils import execute, KOSMORRO
def test_with_date(): def test_with_date():
for arg in [["-d", "2020-01-27"], ["--date", "2020-01-27"], ["-d2020-01-27"]]: for arg in [["-d", "2020-01-27"], ["--date", "2020-01-27"], ["-d2020-01-27"]]:
result = execute(KOSMORRO + arg) result = execute(KOSMORRO + arg)
assert result.is_successful()
assert result.successful


assert ( assert (
result.stdout result.stdout
== """Monday, January 27, 2020 == """Monday, January 27, 2020


Moon phase: New Moon
New Moon
First Quarter on Sunday, February 2, 2020 at 1:41 AM First Quarter on Sunday, February 2, 2020 at 1:41 AM


Expected events: Expected events:
@@ -27,26 +27,36 @@ def test_with_incorrect_date_values():
value = "yolo-yo-lo" value = "yolo-yo-lo"
for arg in [["-d", value], ["--date", value], [f"-d{value}"]]: for arg in [["-d", value], ["--date", value], [f"-d{value}"]]:
result = execute(KOSMORRO + arg) result = execute(KOSMORRO + arg)
assert not result.is_successful()
assert not result.successful
assert ( assert (
result.stdout
result.stderr
== f"The date {value} does not match the required YYYY-MM-DD format or the offset format.\n" == f"The date {value} does not match the required YYYY-MM-DD format or the offset format.\n"
) )


value = "2020-13-32" value = "2020-13-32"
for arg in [["-d", value], ["--date", value], [f"-d{value}"]]: for arg in [["-d", value], ["--date", value], [f"-d{value}"]]:
result = execute(KOSMORRO + arg) result = execute(KOSMORRO + arg)
assert not result.is_successful()
assert not result.successful
assert ( assert (
result.stdout == f"The date {value} is not valid: month must be in 1..12\n"
result.stderr == f"The date {value} is not valid: month must be in 1..12\n"
) )




def test_with_out_of_range_dates(): def test_with_out_of_range_dates():
for arg in [["-d", "1789-05-05"], ["-d", "3000-01-01"]]: for arg in [["-d", "1789-05-05"], ["-d", "3000-01-01"]]:
result = execute(KOSMORRO + arg) result = execute(KOSMORRO + arg)
assert not result.is_successful()
assert not result.successful
assert ( assert (
result.stdout
result.stderr
== "Moon phase can only be computed between August 9, 1899 and September 26, 2053\nThe date must be between July 28, 1899 and October 8, 2053\n"
)


def test_with_out_of_range_dates_for_moon_phase_only():
for arg in [["-d", "1899-07-30"], ["-d", "2053-10-06"]]:
result = execute(KOSMORRO + arg)
assert result.successful
assert (
result.stderr
== "Moon phase can only be computed between August 9, 1899 and September 26, 2053\n" == "Moon phase can only be computed between August 9, 1899 and September 26, 2053\n"
) )

+ 30
- 0
tests/events.py Bestand weergeven

@@ -0,0 +1,30 @@
#!/usr/bin/env python3

from .utils import (
execute,
KOSMORRO,
)


def test_lunar_eclipse_wording():
result = execute(KOSMORRO + ["--date=2025-03-14"])
assert result.successful
assert "4:07\u202fAM Total lunar eclipse until 9:50\u202fAM" in result.stdout


def test_seasons():
result = execute(KOSMORRO + ["--date=2025-03-20"])
assert result.successful
assert "9:01\u202fAM March equinox" in result.stdout

result = execute(KOSMORRO + ["--date=2025-06-21"])
assert result.successful
assert "2:42\u202fAM June solstice" in result.stdout

result = execute(KOSMORRO + ["--date=2025-09-22"])
assert result.successful
assert "6:19\u202fPM September equinox" in result.stdout

result = execute(KOSMORRO + ["--date=2025-12-21"])
assert result.successful
assert "3:03\u202fPM December solstice" in result.stdout

+ 43
- 39
tests/general.py Bestand weergeven

@@ -13,7 +13,7 @@ from babel.dates import format_date


def test_run_without_argument(): def test_run_without_argument():
result = execute(KOSMORRO) result = execute(KOSMORRO)
assert result.is_successful()
assert result.successful


stdout = result.stdout.split("\n") stdout = result.stdout.split("\n")
print(stdout) print(stdout)
@@ -36,62 +36,62 @@ def test_help_message():


assert result.is_successful() assert result.is_successful()


# Options header has changed from "optional arguments" to "options" in Python 3.10.
options_header = (
"optional arguments" if python_version.minor < 10 else "options"
)
assert result.successful


if python_version.major == 3 and python_version.minor < 13: if python_version.major == 3 and python_version.minor < 13:
assert ( assert (
result.stdout result.stdout
== """usage: kosmorro [-h] [--version] [--format {text,json,pdf}]
[--latitude LATITUDE] [--longitude LONGITUDE] [--date DATE]
[--timezone TIMEZONE] [--no-colors] [--output OUTPUT]
[--no-graph] [--debug]
== """usage: kosmorro [-h] [--version] [--format {txt,json,pdf,tex}]
[--position POSITION] [--date DATE] [--timezone TIMEZONE]
[--no-colors] [--output OUTPUT] [--no-graph] [--debug]
[--completion COMPLETION]


Compute the ephemerides and the events for a given date and a given position Compute the ephemerides and the events for a given date and a given position
on Earth. on Earth.


%s:
options:
-h, --help show this help message and exit -h, --help show this help message and exit
--version, -v Show the program version --version, -v Show the program version
--format {text,json,pdf}, -f {text,json,pdf}
The format to output the information to
--latitude LATITUDE, -lat LATITUDE
The observer's latitude on Earth. Can also be set in
the KOSMORRO_LATITUDE environment variable.
--longitude LONGITUDE, -lon LONGITUDE
The observer's longitude on Earth. Can also be set in
the KOSMORRO_LONGITUDE environment variable.
--format {txt,json,pdf,tex}, -f {txt,json,pdf,tex}
The format to output the information to. If not
provided, the output format will be inferred from the
file extension of the output file.
--position POSITION, -p POSITION
The observer's position on Earth, in the
"{latitude},{longitude}" format. Can also be set in
the KOSMORRO_POSITION environment variable.
--date DATE, -d DATE The date for which the ephemerides must be calculated. --date DATE, -d DATE The date for which the ephemerides must be calculated.
Can be in the YYYY-MM-DD format or an interval in the Can be in the YYYY-MM-DD format or an interval in the
"[+-]YyMmDd" format (with Y, M, and D numbers). "[+-]YyMmDd" format (with Y, M, and D numbers).
Defaults to current date. Defaults to current date.
--timezone TIMEZONE, -t TIMEZONE --timezone TIMEZONE, -t TIMEZONE
The timezone to display the hours in (e.g. 2 for UTC+2
or -3 for UTC-3). Can also be set in the
KOSMORRO_TIMEZONE environment variable.
The timezone to use to display the hours. It can be
either a number (e.g. 1 for UTC+1) or a timezone name
(e.g. Europe/Paris). See https://en.wikipedia.org/wiki
/List_of_tz_database_time_zones to find your timezone.
Can also be set in the TZ environment variable.
--no-colors Disable the colors in the console. --no-colors Disable the colors in the console.
--output OUTPUT, -o OUTPUT --output OUTPUT, -o OUTPUT
A file to export the output to. If not given, the A file to export the output to. If not given, the
standard output is used. This argument is needed for standard output is used. This argument is needed for
PDF format. PDF format.
--no-graph Do not generate a graph to represent the rise and set --no-graph Do not generate a graph to represent the rise and set
times in the PDF format.
times in the LaTeX or PDF file.
--debug Show debugging messages --debug Show debugging messages
--completion COMPLETION
Print a script allowing completion for your shell


By default, only the events will be computed for today. To compute also the By default, only the events will be computed for today. To compute also the
ephemerides, latitude and longitude arguments are needed. ephemerides, latitude and longitude arguments are needed.
""" """
% options_header
) )
else: else:
assert ( assert (
result.stdout result.stdout
== """usage: kosmorro [-h] [--version] [--format {text,json,pdf}]
[--latitude LATITUDE] [--longitude LONGITUDE] [--date DATE]
[--timezone TIMEZONE] [--no-colors] [--output OUTPUT]
[--no-graph] [--debug]
== """usage: kosmorro [-h] [--version] [--format {txt,json,pdf,tex}]
[--position POSITION] [--date DATE] [--timezone TIMEZONE]
[--no-colors] [--output OUTPUT] [--no-graph] [--debug]
[--completion COMPLETION]


Compute the ephemerides and the events for a given date and a given position Compute the ephemerides and the events for a given date and a given position
on Earth. on Earth.
@@ -99,29 +99,33 @@ on Earth.
options: options:
-h, --help show this help message and exit -h, --help show this help message and exit
--version, -v Show the program version --version, -v Show the program version
--format, -f {text,json,pdf}
The format to output the information to
--latitude, -lat LATITUDE
The observer's latitude on Earth. Can also be set in
the KOSMORRO_LATITUDE environment variable.
--longitude, -lon LONGITUDE
The observer's longitude on Earth. Can also be set in
the KOSMORRO_LONGITUDE environment variable.
--format, -f {txt,json,pdf,tex}
The format to output the information to. If not
provided, the output format will be inferred from the
file extension of the output file.
--position, -p POSITION
The observer's position on Earth, in the
"{latitude},{longitude}" format. Can also be set in
the KOSMORRO_POSITION environment variable.
--date, -d DATE The date for which the ephemerides must be calculated. --date, -d DATE The date for which the ephemerides must be calculated.
Can be in the YYYY-MM-DD format or an interval in the Can be in the YYYY-MM-DD format or an interval in the
"[+-]YyMmDd" format (with Y, M, and D numbers). "[+-]YyMmDd" format (with Y, M, and D numbers).
Defaults to current date. Defaults to current date.
--timezone, -t TIMEZONE --timezone, -t TIMEZONE
The timezone to display the hours in (e.g. 2 for UTC+2
or -3 for UTC-3). Can also be set in the
KOSMORRO_TIMEZONE environment variable.
The timezone to use to display the hours. It can be
either a number (e.g. 1 for UTC+1) or a timezone name
(e.g. Europe/Paris). See https://en.wikipedia.org/wiki
/List_of_tz_database_time_zones to find your timezone.
Can also be set in the TZ environment variable.
--no-colors Disable the colors in the console. --no-colors Disable the colors in the console.
--output, -o OUTPUT A file to export the output to. If not given, the --output, -o OUTPUT A file to export the output to. If not given, the
standard output is used. This argument is needed for standard output is used. This argument is needed for
PDF format. PDF format.
--no-graph Do not generate a graph to represent the rise and set --no-graph Do not generate a graph to represent the rise and set
times in the PDF format.
times in the LaTeX or PDF file.
--debug Show debugging messages --debug Show debugging messages
--completion COMPLETION
Print a script allowing completion for your shell


By default, only the events will be computed for today. To compute also the By default, only the events will be computed for today. To compute also the
ephemerides, latitude and longitude arguments are needed. ephemerides, latitude and longitude arguments are needed.


+ 27
- 3
tests/output.py Bestand weergeven

@@ -1,5 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3


from importlib.metadata import version
from .utils import ( from .utils import (
execute, execute,
KOSMORRO, KOSMORRO,
@@ -11,10 +12,9 @@ from sys import platform


def test_json_output(): def test_json_output():
result = execute( result = execute(
KOSMORRO
+ ["--latitude=50.5876", "--longitude=3.0624", "-d2020-01-27", "--format=json"]
KOSMORRO + ["--position=50.5876,3.0624", "-d2020-01-27", "--format=json"]
) )
assert result.is_successful()
assert result.successful
assert ( assert (
result.stdout result.stdout
== """{ == """{
@@ -151,3 +151,27 @@ def test_json_output():
} }
""" """
) )


def test_latex_output():
result = execute(
KOSMORRO + ["--position=50.5876,3.0624", "-d2020-01-27", "--format=tex"]
)
assert result.successful

with open(
path.join(path.dirname(__file__), "outputs", "2020-01-27-with-position.tex")
) as expected_output:
expected_output = (
expected_output.read()
.replace(
"__PROJECT_PATH__",
path.join(path.dirname(path.dirname(__file__)), "kosmorro"),
)
.replace(
"__APP_VERSION__",
version("kosmorro"),
)
)

assert result.stdout == expected_output

+ 4
- 7
tests/position.py Bestand weergeven

@@ -7,7 +7,7 @@ from .utils import (




def check_command_return(result): def check_command_return(result):
assert result.is_successful()
assert result.successful
assert ( assert (
result.stdout result.stdout
== """Monday, January 27, 2020 == """Monday, January 27, 2020
@@ -25,7 +25,7 @@ Uranus 10:21 AM 5:25 PM 12:33 AM
Neptune 9:01 AM 2:36 PM 8:10 PM Neptune 9:01 AM 2:36 PM 8:10 PM
Pluto 6:57 AM 11:04 AM 3:11 PM Pluto 6:57 AM 11:04 AM 3:11 PM


Moon phase: New Moon
New Moon
First Quarter on Sunday, February 2, 2020 at 1:41 AM First Quarter on Sunday, February 2, 2020 at 1:41 AM


Expected events: Expected events:
@@ -37,9 +37,7 @@ Note: All the hours are given in UTC.




def test_with_position(): def test_with_position():
result = execute(
KOSMORRO + ["--latitude=50.5876", "--longitude=3.0624", "-d2020-01-27"]
)
result = execute(KOSMORRO + ["--position=50.5876,3.0624", "-d2020-01-27"])
check_command_return(result) check_command_return(result)




@@ -48,8 +46,7 @@ def test_with_position_env_vars():
execute( execute(
KOSMORRO + ["-d2020-01-27"], KOSMORRO + ["-d2020-01-27"],
environment={ environment={
"KOSMORRO_LATITUDE": "50.5876",
"KOSMORRO_LONGITUDE": "3.0624",
"KOSMORRO_POSITION": "50.5876,3.0624",
}, },
) )
) )

+ 65
- 45
tests/timezone.py Bestand weergeven

@@ -6,68 +6,88 @@ from .utils import (
) )




def check_command_return_t_plus_one(result):
assert result.is_successful()
assert (
result.stdout
== """Monday, January 27, 2020
def test_timezone_with_command_line_arg():
result = execute(KOSMORRO + ["--timezone=1", "-d2020-01-27"])
assert result.successful
assert "Note: All the hours are given in the UTC+1.0 timezone." in result.stdout


Moon phase: New Moon
First Quarter on Sunday, February 2, 2020 at 2:41 AM
result = execute(KOSMORRO + ["--timezone=Europe/Paris", "-d2020-01-27"])
assert result.successful
assert "Note: All the hours are given in the UTC+1.0 timezone." not in result.stdout


Expected events:
9:00 PM Venus and Neptune are in conjunction
result = execute(KOSMORRO + ["--timezone=-5", "-d2020-01-27"])
assert result.successful
assert "Note: All the hours are given in the UTC-5.0 timezone." in result.stdout


Note: All the hours are given in the UTC+1 timezone.
"""
)
result = execute(KOSMORRO + ["--timezone=America/Chicago", "-d2020-01-27"])
assert result.successful
assert "Note: All the hours are given in the UTC-5.0 timezone." in result.stdout




def check_command_return_t_minus_one(result):
assert result.is_successful()
assert (
result.stdout
== """Monday, January 27, 2020
def test_timezone_with_env_var():
result = execute(KOSMORRO + ["-d2020-01-27"], environment={"TZ": "1"})
assert result.successful
assert "Note: All the hours are given in the UTC+1.0 timezone." in result.stdout


Moon phase: New Moon
First Quarter on Sunday, February 2, 2020 at 12:41 AM
result = execute(KOSMORRO + ["-d2020-01-27"], environment={"TZ": "Europe/Paris"})
assert result.successful
assert "Note: All the hours are given in the UTC+1.0 timezone." not in result.stdout


Expected events:
7:00 PM Venus and Neptune are in conjunction
result = execute(KOSMORRO + ["-d2020-01-27"], environment={"TZ": "-5"})
assert result.successful
assert "Note: All the hours are given in the UTC-5.0 timezone." in result.stdout


Note: All the hours are given in the UTC-1 timezone.
"""
result = execute(KOSMORRO + ["-d2020-01-27"], environment={"TZ": "America/Chicago"})
assert result.successful
assert "Note: All the hours are given in the UTC-5.0 timezone." in result.stdout


def test_timezone_with_env_var_and_command_line_arg():
result = execute(
KOSMORRO + ["--timezone=3", "-d2020-01-27"], environment={"TZ": "Europe/Paris"}
) )
assert result.successful
assert "Note: All the hours are given in the UTC+3.0 timezone." in result.stdout




def test_timezone():
check_command_return_t_plus_one(
execute(KOSMORRO + ["--timezone=1", "-d2020-01-27"])
def test_timezone_with_deprecated_env_var():
result = execute(
KOSMORRO + ["-d2020-01-27"], environment={"KOSMORRO_TIMEZONE": "1"}
) )
check_command_return_t_minus_one(
execute(KOSMORRO + ["--timezone=-1", "-d2020-01-27"])
assert result.successful
assert (
"Environment variable KOSMORRO_TIMEZONE is deprecated. Use TZ instead, which is more standard."
in result.stderr
) )
assert "Note: All the hours are given in the UTC+1.0 timezone." in result.stdout



def test_timezone_with_env_var():
check_command_return_t_plus_one(
execute(KOSMORRO + ["-d2020-01-27"], environment={"KOSMORRO_TIMEZONE": "1"})
result = execute(
KOSMORRO + ["-d2020-01-27"], environment={"KOSMORRO_TIMEZONE": "Europe/Paris"}
) )
check_command_return_t_minus_one(
execute(KOSMORRO + ["-d2020-01-27"], environment={"KOSMORRO_TIMEZONE": "-1"})
assert result.successful
assert (
"Environment variable KOSMORRO_TIMEZONE is deprecated. Use TZ instead, which is more standard."
in result.stderr
) )
assert "Note: All the hours are given in the UTC+1.0 timezone." not in result.stdout


# If both environment variable and argument are set, use argument:
result = execute(
KOSMORRO + ["-d2020-01-27"], environment={"KOSMORRO_TIMEZONE": "-5"}
)
assert result.successful
assert (
"Environment variable KOSMORRO_TIMEZONE is deprecated. Use TZ instead, which is more standard."
in result.stderr
)
assert "Note: All the hours are given in the UTC-5.0 timezone." in result.stdout


check_command_return_t_plus_one(
execute(
KOSMORRO + ["--timezone=1", "-d2020-01-27"],
environment={"KOSMORRO_TIMEZONE": "-1"},
)
result = execute(
KOSMORRO + ["-d2020-01-27"],
environment={"KOSMORRO_TIMEZONE": "America/Chicago"},
) )
check_command_return_t_minus_one(
execute(
KOSMORRO + ["--timezone=-1", "-d2020-01-27"],
environment={"KOSMORRO_TIMEZONE": "1"},
)
assert result.successful
assert (
"Environment variable KOSMORRO_TIMEZONE is deprecated. Use TZ instead, which is more standard."
in result.stderr
) )
assert "Note: All the hours are given in the UTC-5.0 timezone." in result.stdout

+ 1
- 1
tests/utils.py Bestand weergeven

@@ -10,7 +10,7 @@ DEFAULT_ENVIRONMENT = {"PATH": environ["PATH"]}
KOSMORRO = ["kosmorro", "--no-color"] KOSMORRO = ["kosmorro", "--no-color"]


CURRENT_MOON_PHASE_PATTERN = re.compile( CURRENT_MOON_PHASE_PATTERN = re.compile(
r"^Moon phase: ("
r"^("
r"(New Moon)|(Waxing Crescent)|" r"(New Moon)|(Waxing Crescent)|"
r"(First Quarter)|(Waxing Gibbous)|" r"(First Quarter)|(Waxing Gibbous)|"
r"(Full Moon)|(Waning Gibbous)|" r"(Full Moon)|(Waning Gibbous)|"


Laden…
Annuleren
Opslaan