Selaa lähdekoodia

Merge pull request #420 from Kosmorro/features

tags/v1.0.0rc1
Deuchnord 1 kuukausi sitten
committed by GitHub
vanhempi
commit
13a78a8f8d
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
30 muutettua tiedostoa jossa 1198 lisäystä ja 1443 poistoa
  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 Näytä tiedosto

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

+ 6
- 0
.github/ISSUE_TEMPLATE/config.yml Näytä tiedosto

@@ -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 Näytä tiedosto

@@ -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 Näytä tiedosto

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



+ 0
- 581
.pylintrc Näytä tiedosto

@@ -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 Näytä tiedosto

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

+ 6
- 1
README.md Näytä tiedosto

@@ -1,5 +1,5 @@
# ![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.

@@ -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).

### 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!

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


+ 149
- 73
kosmorro/__main__.py Näytä tiedosto

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

import argparse
import argcomplete
import sys
import os.path

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

from . import dumper, environment, debug
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 _


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

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:
return 0 if args.special_action() else 1

try:
compute_date = parse_date(args.date)
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

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":
print(
@@ -64,8 +91,7 @@ def run():
)
)
if position is None:
print()
print(
print_stderr(
colored(
_(
"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:
use_colors = not environment.NO_COLOR and args.colors

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

if args.output is not None:
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:
print(colored(error.msg, "red"))
print_stderr(colored(error.msg, "red"))
debug.debug_print(error)
return 2
except OSError as error:
print(
print_stderr(
colored(
_('The file could not be saved in "{path}": {error}').format(
path=args.output, error=error.strerror
@@ -124,7 +176,7 @@ def run():
elif not output.is_file_output_needed():
print(output)
else:
print(
print_stderr(
colored(
_("Please provide a file path to export in this format (--output)."),
color="red",
@@ -143,53 +195,63 @@ def get_information(
colors: bool,
show_graph: bool,
) -> dumper.Dumper:
if position is not None:
try:
try:
if position is not None:
eph = get_ephemerides(
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}:
return {
"text": dumper.TextDumper,
"txt": dumper.TextDumper,
"json": dumper.JsonDumper,
"pdf": dumper.PdfDumper,
"tex": dumper.LatexDumper,
}


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

return "w"


def output_version() -> bool:
python_version = "%d.%d.%d" % (
sys.version_info[0],
@@ -233,28 +295,21 @@ def get_args(output_formats: [str]):
"--format",
"-f",
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,
choices=output_formats,
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(
"--longitude",
"-lon",
type=float,
"--position",
"-p",
type=str,
default=None,
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(
@@ -271,11 +326,12 @@ def get_args(output_formats: [str]):
parser.add_argument(
"--timezone",
"-t",
type=int,
type=str,
default=None,
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(
@@ -299,7 +355,7 @@ def get_args(output_formats: [str]):
dest="show_graph",
action="store_false",
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(
@@ -309,8 +365,28 @@ def get_args(output_formats: [str]):
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()


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():
sys.exit(run())

+ 178
- 0
kosmorro/assets/latex/template.tex Näytä tiedosto

@@ -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 Näytä tiedosto

@@ -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 Näytä tiedosto

@@ -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 Näytä tiedosto

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


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

def __init__(
self,
ephemerides: [AsterEphemerides],
ephemerides: list[AsterEphemerides],
moon_phase: MoonPhase,
events: [Event],
events: list[Event],
date: datetime.date,
timezone: int,
with_colors: bool,
@@ -233,11 +233,8 @@ class TextDumper(Dumper):
if moon_phase is None:
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 = _(
"{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])


class _LatexDumper(Dumper):
class LatexDumper(Dumper):
def to_string(self):
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:
@@ -281,7 +281,7 @@ class _LatexDumper(Dumper):

document = template

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

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

@staticmethod
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")
current_dir = (
os.getcwd()
@@ -505,9 +507,6 @@ class PdfDumper(Dumper):

try:
temp_dir = tempfile.mkdtemp()

shutil.copy(package, temp_dir)

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

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


+ 3
- 0
kosmorro/environment.py Näytä tiedosto

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

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


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

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

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


+ 13
- 0
kosmorro/exceptions.py Näytä tiedosto

@@ -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):
def __init__(self, msg):
super().__init__()


+ 48
- 0
kosmorro/geolocation.py Näytä tiedosto

@@ -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 Näytä tiedosto

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

from typing import Union
from babel.dates import format_time
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 string


+ 136
- 71
kosmorro/locales/messages.pot Näytä tiedosto

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\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"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,104 +17,122 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.17.0\n"

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

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

#: 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
msgid "The file could not be saved in \"{path}\": {error}"
msgstr ""

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

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

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

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

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

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

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

#: kosmorro/__main__.py:246
#: kosmorro/__main__.py:301
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 ""

#: kosmorro/__main__.py:256
#: kosmorro/__main__.py:311
#, python-brace-format
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 ""

#: kosmorro/__main__.py:266
#: kosmorro/__main__.py:321
msgid ""
"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,"
" and D numbers). Defaults to current date."
msgstr ""

#: kosmorro/__main__.py:277
#: kosmorro/__main__.py:332
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 ""

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

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

#: kosmorro/__main__.py:302
#: kosmorro/__main__.py:358
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 ""

#: kosmorro/__main__.py:309
#: kosmorro/__main__.py:365
msgid "Show debugging messages"
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
#, python-brace-format
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."
msgstr ""

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#: kosmorro/dumper.py:541
#: kosmorro/dumper.py:540
#, python-format
msgid ""
"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}"
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
msgid "%s is in opposition"
msgstr ""

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

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

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

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

#: kosmorro/i18n/strings.py:19
#: kosmorro/i18n/strings.py:55
#, python-format
msgid "%s is at its apoapsis"
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"
msgstr ""

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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



+ 17
- 4
kosmorro/utils.py Näytä tiedosto

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

import pytz
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")
KOSMORROLIB_VERSION = version("kosmorrolib")
@@ -25,3 +25,16 @@ def colored(text, color=None, on_color=None, attrs=None):
return text

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 Näytä tiedosto

@@ -16,17 +16,14 @@
`--clear-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_
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_
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`
disable the colors in the console
@@ -34,12 +31,17 @@
`--output=`_OUTPUT_, `-o` _OUTPUT_
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`
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

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:

`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`
the observer's timezone (alternative to `--timezone`)

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

## EXAMPLES

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:

```
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


+ 255
- 350
poetry.lock Näytä tiedosto

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

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

[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\""]

[[package]]
name = "black"
version = "24.8.0"
version = "24.10.0"
description = "The uncompromising code formatter."
optional = false
python-versions = ">=3.8"
python-versions = ">=3.9"
groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
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]
@@ -74,39 +83,35 @@ mypy-extensions = ">=0.4.3"
packaging = ">=22.0"
pathspec = ">=0.9.0"
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]
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)"]
uvloop = ["uvloop (>=0.15.2)"]

[[package]]
name = "certifi"
version = "2024.7.4"
version = "2025.10.5"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
python-versions = ">=3.7"
groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
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]]
name = "click"
version = "8.1.7"
version = "8.3.0"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.7"
python-versions = ">=3.10"
groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
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]
@@ -119,7 +124,7 @@ description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
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 = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
@@ -132,7 +137,6 @@ description = "A library to handle automated deprecations"
optional = false
python-versions = "*"
groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [
{file = "deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a"},
{file = "deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff"},
@@ -141,71 +145,28 @@ files = [
[package.dependencies]
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]]
name = "iniconfig"
version = "2.0.0"
version = "2.3.0"
description = "brain-dead simple config-ini parsing"
optional = false
python-versions = ">=3.7"
python-versions = ">=3.10"
groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
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]]
name = "jplephem"
version = "2.21"
version = "2.23"
description = "Use a JPL ephemeris to predict planet positions."
optional = false
python-versions = "*"
groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
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]
@@ -218,151 +179,134 @@ description = "A library to computes the ephemerides."
optional = false
python-versions = "<4.0,>=3.8"
groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [
{file = "kosmorrolib-1.0.12-py3-none-any.whl", hash = "sha256:4ea6b0cb2933836b32684f92f7df29a48b8a60cf27a4c513ac38189d47dbcbdc"},
{file = "kosmorrolib-1.0.12.tar.gz", hash = "sha256:8c9da76165c91503406b2cae395236d37c3899c0116cd4e7e338e58643ef0cc7"},
]

[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"
skyfield = ">=1.49,<2.0"
skyfield-data = "*"

[[package]]
name = "mypy-extensions"
version = "1.0.0"
version = "1.1.0"
description = "Type system extensions for programs checked with the mypy type checker."
optional = false
python-versions = ">=3.5"
python-versions = ">=3.8"
groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
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]]
name = "numpy"
version = "1.24.4"
version = "2.3.4"
description = "Fundamental package for array computing in Python"
optional = false
python-versions = ">=3.8"
python-versions = ">=3.11"
groups = ["main"]
markers = "python_version < \"3.10.dev0\""
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]]
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
python-versions = ">=3.10"
python-versions = "*"
groups = ["main"]
markers = "python_version >= \"3.10\""
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]]
name = "packaging"
version = "23.2"
version = "25.0"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.7"
python-versions = ">=3.8"
groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
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]]
@@ -372,7 +316,6 @@ description = "Utility library for gitignore style pattern matching of file path
optional = false
python-versions = ">=3.8"
groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [
{file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
@@ -380,61 +323,73 @@ files = [

[[package]]
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
python-versions = ">=3.8"
python-versions = ">=3.10"
groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
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]
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]]
name = "pluggy"
version = "1.5.0"
version = "1.6.0"
description = "plugin and hook calling mechanisms for python"
optional = false
python-versions = ">=3.8"
python-versions = ">=3.9"
groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
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]
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]]
name = "pytest"
version = "8.3.5"
version = "8.4.2"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.8"
python-versions = ">=3.9"
groups = ["dev"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
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]
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"
tomli = {version = ">=1", markers = "python_version < \"3.11\""}
pygments = ">=2.7.2"

[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]]
name = "python-dateutil"
@@ -443,7 +398,6 @@ description = "Extensions to the standard Python datetime module"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
files = [
{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"},
@@ -454,115 +408,115 @@ six = ">=1.5"

[[package]]
name = "pytz"
version = "2023.3.post1"
version = "2025.2"
description = "World timezone definitions, modern and historical"
optional = false
python-versions = "*"
groups = ["main"]
markers = "python_version < \"3.9.dev0\""
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]]
name = "sgp4"
version = "2.23"
version = "2.25"
description = "Track Earth satellites given TLE data, using up-to-date 2020 SGP4 routines."
optional = false
python-versions = "*"
groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
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]]
name = "six"
version = "1.16.0"
version = "1.17.0"
description = "Python 2 and 3 compatibility utilities"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
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]]
name = "skyfield"
version = "1.49"
version = "1.53"
description = "Elegant astronomy for Python"
optional = false
python-versions = "*"
groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
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]
certifi = ">=2017.4.17"
jplephem = ">=2.13"
numpy = "*"
sgp4 = ">=2.2"
sgp4 = ">=2.13"

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

[[package]]
name = "termcolor"
version = "2.4.0"
version = "3.1.0"
description = "ANSI color formatting for output in terminal"
optional = false
python-versions = ">=3.8"
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version < \"3.10.dev0\" or python_version >= \"3.10\""
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]
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]
lock-version = "2.1"
python-versions = "^3.8"
content-hash = "a4fa3a2b71ef294caf512c090faae95e9f940303ddba7e34740db0c30ddafc3f"
python-versions = "^3.12"
content-hash = "d26e3a8141cafb8eeb2a154bac7c09ac665bcbdd012a7204a7ac5c3c00332c09"

+ 6
- 4
pyproject.toml Näytä tiedosto

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

[tool.poetry.dependencies]
python = "^3.8"
python = "^3.12"
tabulate = ">=0.8,<0.10"
termcolor = ">=1.1,<3.0"
termcolor = "^3.0"
kosmorrolib = "^1.0"
python-dateutil = "^2.8"
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"
pytest = "^8.3"
aurornis = "^1.6"


+ 0
- 12
setup.cfg Näytä tiedosto

@@ -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 Näytä tiedosto

@@ -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 Näytä tiedosto

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

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

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

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

value = "2020-13-32"
for arg in [["-d", value], ["--date", value], [f"-d{value}"]]:
result = execute(KOSMORRO + arg)
assert not result.is_successful()
assert not result.successful
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():
for arg in [["-d", "1789-05-05"], ["-d", "3000-01-01"]]:
result = execute(KOSMORRO + arg)
assert not result.is_successful()
assert not result.successful
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"
)

+ 30
- 0
tests/events.py Näytä tiedosto

@@ -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 Näytä tiedosto

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

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

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

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:
assert (
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
on Earth.

%s:
options:
-h, --help show this help message and exit
--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.
Can be in the YYYY-MM-DD format or an interval in the
"[+-]YyMmDd" format (with Y, M, and D numbers).
Defaults to current date.
--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.
--output OUTPUT, -o OUTPUT
A file to export the output to. If not given, the
standard output is used. This argument is needed for
PDF format.
--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
--completion COMPLETION
Print a script allowing completion for your shell

By default, only the events will be computed for today. To compute also the
ephemerides, latitude and longitude arguments are needed.
"""
% options_header
)
else:
assert (
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
on Earth.
@@ -99,29 +99,33 @@ on Earth.
options:
-h, --help show this help message and exit
--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.
Can be in the YYYY-MM-DD format or an interval in the
"[+-]YyMmDd" format (with Y, M, and D numbers).
Defaults to current date.
--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.
--output, -o OUTPUT A file to export the output to. If not given, the
standard output is used. This argument is needed for
PDF format.
--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
--completion COMPLETION
Print a script allowing completion for your shell

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


+ 27
- 3
tests/output.py Näytä tiedosto

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

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

def test_json_output():
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 (
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 Näytä tiedosto

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


def check_command_return(result):
assert result.is_successful()
assert result.successful
assert (
result.stdout
== """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
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

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


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)


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

+ 65
- 45
tests/timezone.py Näytä tiedosto

@@ -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 Näytä tiedosto

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

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


Ladataan…
Peruuta
Tallenna