| @@ -1,4 +1,4 @@ | |||
| name: E2E tests | |||
| name: Tests | |||
| on: | |||
| push: | |||
| @@ -17,14 +17,15 @@ jobs: | |||
| fail-fast: false | |||
| matrix: | |||
| os: | |||
| - ubuntu-18.04 | |||
| - ubuntu-20.04 | |||
| - ubuntu-latest | |||
| - macos-latest | |||
| python-version: | |||
| - '3.7' | |||
| - '3.8' | |||
| - '3.9' | |||
| - '3.10' | |||
| name: E2E tests (Python ${{ matrix.python-version }} on ${{ matrix.os }}) | |||
| name: Python ${{ matrix.python-version }} on ${{ matrix.os }} | |||
| steps: | |||
| - uses: actions/checkout@v1 | |||
| @@ -35,20 +36,30 @@ jobs: | |||
| - name: Prepare tests | |||
| run: | | |||
| sudo apt update | |||
| sudo apt install ruby | |||
| sudo gem install ronn | |||
| pip install -U setuptools pip requests wheel Babel | |||
| pip install -U pip pipenv | |||
| pipenv sync --dev | |||
| make manpage | |||
| - name: E2E tests | |||
| run: | | |||
| export ENVIRONMENT="CI" | |||
| bash .scripts/tests-e2e.sh | |||
| make tests | |||
| - name: Install TeXLive (Ubuntu) | |||
| if: ${{ matrix.os == 'ubuntu-latest' }} | |||
| run: | | |||
| sudo apt-get install -y texlive texlive-latex-extra | |||
| - name: E2E tests | |||
| env: | |||
| TEXLIVE_INSTALLED: 1 | |||
| run: | | |||
| make tests | |||
| - name: manpage (section 1) | |||
| run: | | |||
| man -P $(which cat) kosmorro | |||
| man -P $(which cat) manpage/kosmorro.1 | |||
| - name: manpage (section 7) | |||
| run: | | |||
| man -P $(which cat) 7 kosmorro | |||
| man -P $(which cat) manpage/kosmorro.7 | |||
| @@ -1,128 +0,0 @@ | |||
| #!/bin/bash | |||
| VERSION=$(grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' _kosmorro/__version__.py) | |||
| PYTHON_BIN=$(command -v python) | |||
| PIP_BIN=$(command -v pip) | |||
| if python3 --version > /dev/null; then | |||
| PYTHON_BIN=$(command -v python3) | |||
| PIP_BIN=$(command -v pip3) | |||
| fi | |||
| failures='' | |||
| function fail() { | |||
| failures="$failures\n\n - $1\n\n$2" | |||
| } | |||
| function run() { | |||
| eval "$1" &> /tmp/output.txt | |||
| return $? | |||
| } | |||
| function canRun() { | |||
| if [[ "$1" != "" && "$1" != "$ENVIRONMENT" ]]; then | |||
| return 1 | |||
| fi | |||
| return 0 | |||
| } | |||
| # Asserts that command $1 has finished with sucess | |||
| # $1: the command to run | |||
| function assertSuccess() { | |||
| if ! canRun "$2"; then | |||
| echo -n 'I' | |||
| return | |||
| fi | |||
| run "$1" | |||
| returned=$? | |||
| if [ $returned -ne 0 ]; then | |||
| fail "Failed asserting that command '$1' finishes with success, returned status $returned." "$(cat /tmp/output.txt)" | |||
| echo -n 'F' | |||
| return | |||
| fi | |||
| echo -n '.' | |||
| } | |||
| # Asserts that command $1 has finished with sucess | |||
| # $1: the command to run | |||
| function assertFailure() { | |||
| if ! canRun "$2"; then | |||
| echo -n 'I' | |||
| return | |||
| fi | |||
| run "$1" | |||
| returned=$? | |||
| if [ $returned -eq 0 ]; then | |||
| fail "Failed asserting that command '$1' finishes with failure." "$(cat /tmp/output.txt)" | |||
| echo -n 'F' | |||
| return | |||
| fi | |||
| echo -n '.' | |||
| } | |||
| mkdir -p $HOME/kosmorro/export | |||
| echo | |||
| echo "==== RUNNING E2E TESTS ====" | |||
| echo | |||
| # Create the package and install it | |||
| assertSuccess "make build" | |||
| assertSuccess "$PIP_BIN install dist/kosmorro-$VERSION.tar.gz" "CI" | |||
| KOSMORRO_COMMAND="kosmorro --debug" | |||
| assertSuccess "$KOSMORRO_COMMAND" | |||
| assertSuccess "$KOSMORRO_COMMAND -h" | |||
| assertSuccess "$KOSMORRO_COMMAND -d 2020-01-27" | |||
| assertFailure "$KOSMORRO_COMMAND -d yolo-yo-lo" | |||
| assertFailure "$KOSMORRO_COMMAND -d 2020-13-32" | |||
| assertFailure "$KOSMORRO_COMMAND --date=1789-05-05" | |||
| assertFailure "$KOSMORRO_COMMAND --date=3000-01-01" | |||
| assertSuccess "$KOSMORRO_COMMAND --date='+3y 5m3d'" | |||
| assertSuccess "$KOSMORRO_COMMAND --date='-1y3d'" | |||
| assertFailure "$KOSMORRO_COMMAND --date='+3d4m" | |||
| assertFailure "$KOSMORRO_COMMAND -date='3y'" | |||
| assertSuccess "$KOSMORRO_COMMAND --latitude=50.5876 --longitude=3.0624" | |||
| assertSuccess "$KOSMORRO_COMMAND --latitude=50.5876 --longitude=3.0624 -d 2020-01-27" | |||
| assertSuccess "$KOSMORRO_COMMAND --latitude=50.5876 --longitude=3.0624 -d 2020-01-27 --timezone=1" | |||
| assertSuccess "$KOSMORRO_COMMAND --latitude=50.5876 --longitude=3.0624 -d 2020-01-27 --timezone=-1" | |||
| assertSuccess "$KOSMORRO_COMMAND --latitude=50.5876 --longitude=3.0624 -d 2020-01-27 --format=json" | |||
| assertFailure "$KOSMORRO_COMMAND --latitude=50.5876 --longitude=3.0624 -d 2020-01-27 --format=pdf" | |||
| assertSuccess "$KOSMORRO_COMMAND -d 2020-01-27 --format=json" | |||
| # Environment variables | |||
| assertSuccess "LATITUDE=50.5876 LONGITUDE=3.0624 TIMEZONE=1 kosmorro -d 2020-01-27" | |||
| assertSuccess "LATITUDE=50.5876 LONGITUDE=3.0624 TIMEZONE=-1 kosmorro -d 2020-01-27" | |||
| # Missing dependencies, should fail | |||
| assertFailure "$KOSMORRO_COMMAND --latitude=50.5876 --longitude=3.0624 -d 2020-01-27 --format=pdf -o $HOME/kosmorro/export/document.pdf" | |||
| assertFailure "ls $HOME/kosmorro/export/document.pdf" | |||
| assertSuccess "sudo apt-get install -y texlive texlive-latex-extra" "CI" | |||
| # Dependencies installed, should not fail | |||
| assertSuccess "$KOSMORRO_COMMAND --latitude=50.5876 --longitude=3.0624 -d 2020-01-27 --format=pdf -o $HOME/kosmorro/export/document.pdf" | |||
| assertSuccess "ls $HOME/kosmorro/export/document.pdf" | |||
| assertSuccess "$KOSMORRO_COMMAND --latitude=50.5876 --longitude=3.0624 -d 2020-01-27 --format=pdf -o $HOME/kosmorro/export/document-no-graph.pdf --no-graph" | |||
| assertSuccess "ls $HOME/kosmorro/export/document-no-graph.pdf" | |||
| # man page | |||
| assertSuccess "man --pager=cat kosmorro" | |||
| if [ "$failures" != "" ]; then | |||
| echo -e "\n$failures" | |||
| exit 2 | |||
| fi | |||
| echo -e "\n\n==== TESTS RAN SUCCESSFULLY 👍 ====" | |||
| @@ -1,5 +1,14 @@ | |||
| black: | |||
| pipenv run black kosmorro _kosmorro setup.py | |||
| pipenv run black kosmorro _kosmorro tests setup.py | |||
| .PHONY: tests | |||
| tests: | |||
| @if [ "$${TEXLIVE_INSTALLED}" == "" ]; then \ | |||
| echo "If you are running the tests locally and TeXLive is installed on your machine, you will need to set the TEXLIVE_INSTALLED environment variable."; \ | |||
| echo; \ | |||
| fi | |||
| pipenv run python3 -m pytest tests/*.py | |||
| .PHONY: build | |||
| build: manpage | |||
| @@ -6,6 +6,8 @@ verify_ssl = true | |||
| [dev-packages] | |||
| babel = "*" | |||
| black = "*" | |||
| pytest = "*" | |||
| aurornis = "*" | |||
| [packages] | |||
| tabulate = "*" | |||
| @@ -1,7 +1,7 @@ | |||
| { | |||
| "_meta": { | |||
| "hash": { | |||
| "sha256": "c1f6551ee33e3015fa1aaa679059da0744c447948707b7e517cce926f336f6f9" | |||
| "sha256": "3ff7290b32da63ca9585dbe947830ae1d1e4692f0ca9a0faeaa3601d7f9c4b8b" | |||
| }, | |||
| "pipfile-spec": 6, | |||
| "requires": { | |||
| @@ -59,7 +59,6 @@ | |||
| "sha256:badca914580eb46385e7f7e4e426fea6de0a37b9e06bec252e481ae7ec287082", | |||
| "sha256:d76a26c5118c4d96e264acc9e3242d72e1a2b92e739807b3b69d8d47684b6677" | |||
| ], | |||
| "markers": "python_version >= '3.8'", | |||
| "version": "==1.22.2" | |||
| }, | |||
| "python-dateutil": { | |||
| @@ -109,7 +108,6 @@ | |||
| "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", | |||
| "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" | |||
| ], | |||
| "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", | |||
| "version": "==1.16.0" | |||
| }, | |||
| "skyfield": { | |||
| @@ -123,7 +121,6 @@ | |||
| "sha256:128d407e43a04be66c44b03914f9147b5e65b96078db776e6a4f5538ab0b74bf", | |||
| "sha256:bd81bf9032d4833a766f4127e868d62674083ca2ccaea07e6d025e132c9c574e" | |||
| ], | |||
| "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' and python_version < '4'", | |||
| "version": "==4.0.0" | |||
| }, | |||
| "tabulate": { | |||
| @@ -143,6 +140,21 @@ | |||
| } | |||
| }, | |||
| "develop": { | |||
| "attrs": { | |||
| "hashes": [ | |||
| "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", | |||
| "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" | |||
| ], | |||
| "version": "==21.4.0" | |||
| }, | |||
| "aurornis": { | |||
| "hashes": [ | |||
| "sha256:660b57e9d1701d88fb7cc4af3118c927e9e001d2ab39cb145695eb8470f4642a", | |||
| "sha256:bc68845be5cdf2d69d26c677214f7435365967b4a65dc3772ab05353b2136d95" | |||
| ], | |||
| "index": "pypi", | |||
| "version": "==1.2.0" | |||
| }, | |||
| "babel": { | |||
| "hashes": [ | |||
| "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9", | |||
| @@ -185,9 +197,15 @@ | |||
| "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1", | |||
| "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb" | |||
| ], | |||
| "markers": "python_version >= '3.6'", | |||
| "version": "==8.0.4" | |||
| }, | |||
| "iniconfig": { | |||
| "hashes": [ | |||
| "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", | |||
| "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" | |||
| ], | |||
| "version": "==1.1.1" | |||
| }, | |||
| "mypy-extensions": { | |||
| "hashes": [ | |||
| "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", | |||
| @@ -195,6 +213,13 @@ | |||
| ], | |||
| "version": "==0.4.3" | |||
| }, | |||
| "packaging": { | |||
| "hashes": [ | |||
| "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", | |||
| "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" | |||
| ], | |||
| "version": "==21.3" | |||
| }, | |||
| "pathspec": { | |||
| "hashes": [ | |||
| "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a", | |||
| @@ -207,9 +232,37 @@ | |||
| "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d", | |||
| "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227" | |||
| ], | |||
| "markers": "python_version >= '3.7'", | |||
| "version": "==2.5.1" | |||
| }, | |||
| "pluggy": { | |||
| "hashes": [ | |||
| "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", | |||
| "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" | |||
| ], | |||
| "version": "==1.0.0" | |||
| }, | |||
| "py": { | |||
| "hashes": [ | |||
| "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", | |||
| "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" | |||
| ], | |||
| "version": "==1.11.0" | |||
| }, | |||
| "pyparsing": { | |||
| "hashes": [ | |||
| "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea", | |||
| "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484" | |||
| ], | |||
| "version": "==3.0.7" | |||
| }, | |||
| "pytest": { | |||
| "hashes": [ | |||
| "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db", | |||
| "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171" | |||
| ], | |||
| "index": "pypi", | |||
| "version": "==7.0.1" | |||
| }, | |||
| "pytz": { | |||
| "hashes": [ | |||
| "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c", | |||
| @@ -222,8 +275,15 @@ | |||
| "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", | |||
| "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" | |||
| ], | |||
| "markers": "python_version >= '3.7'", | |||
| "version": "==2.0.1" | |||
| }, | |||
| "typing-extensions": { | |||
| "hashes": [ | |||
| "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42", | |||
| "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2" | |||
| ], | |||
| "markers": "python_version < '3.10'", | |||
| "version": "==4.1.1" | |||
| } | |||
| } | |||
| } | |||
| @@ -6,6 +6,7 @@ | |||
| \usepackage{graphicx} | |||
| \usepackage{hyperref} | |||
| \usepackage{kosmorro} | |||
| \usepackage{lmodern} | |||
| \newcommand{\currentmoonphasetitle}{+++CURRENT-MOON-PHASE-TITLE+++} | |||
| \newcommand{\ephemeridesobjecttitle}{+++EPHEMERIDES-OBJECT+++} | |||
| @@ -8,7 +8,7 @@ msgid "" | |||
| msgstr "" | |||
| "Project-Id-Version: PROJECT VERSION\n" | |||
| "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | |||
| "POT-Creation-Date: 2022-02-04 13:30+0100\n" | |||
| "POT-Creation-Date: 2022-02-16 13:58+0100\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" | |||
| @@ -116,98 +116,98 @@ msgstr "" | |||
| msgid "The date must be between {minimum_date} and {maximum_date}" | |||
| msgstr "" | |||
| #: _kosmorro/main.py:60 | |||
| #: _kosmorro/main.py:62 | |||
| 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:69 | |||
| #: _kosmorro/main.py:71 | |||
| msgid "" | |||
| "PDF output will not contain the ephemerides, because you didn't provide " | |||
| "the observation coordinates." | |||
| msgstr "" | |||
| #: _kosmorro/main.py:114 | |||
| #: _kosmorro/main.py:116 | |||
| msgid "The file could not be saved in \"{path}\": {error}" | |||
| msgstr "" | |||
| #: _kosmorro/main.py:128 | |||
| #: _kosmorro/main.py:130 | |||
| msgid "Please provide a file path to export in this format (--output)." | |||
| msgstr "" | |||
| #: _kosmorro/main.py:161 | |||
| #: _kosmorro/main.py:163 | |||
| msgid "Moon phase can only be displayed between {min_date} and {max_date}" | |||
| msgstr "" | |||
| #: _kosmorro/main.py:200 | |||
| #: _kosmorro/main.py:202 | |||
| msgid "Running on Python {python_version} with Kosmorrolib v{kosmorrolib_version}" | |||
| msgstr "" | |||
| #: _kosmorro/main.py:213 | |||
| #: _kosmorro/main.py:215 | |||
| msgid "" | |||
| "Compute the ephemerides and the events for a given date and a given " | |||
| "position on Earth." | |||
| msgstr "" | |||
| #: _kosmorro/main.py:216 | |||
| #: _kosmorro/main.py:218 | |||
| msgid "" | |||
| "By default, only the events will be computed for today ({date}).\n" | |||
| "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:231 | |||
| msgid "Show the program version" | |||
| msgstr "" | |||
| #: _kosmorro/main.py:238 | |||
| #: _kosmorro/main.py:239 | |||
| msgid "The format to output the information to" | |||
| msgstr "" | |||
| #: _kosmorro/main.py:245 | |||
| #: _kosmorro/main.py:246 | |||
| msgid "" | |||
| "The observer's latitude on Earth. Can also be set in the " | |||
| "KOSMORRO_LATITUDE environment variable." | |||
| msgstr "" | |||
| #: _kosmorro/main.py:255 | |||
| #: _kosmorro/main.py:256 | |||
| msgid "" | |||
| "The observer's longitude on Earth. Can also be set in the " | |||
| "KOSMORRO_LONGITUDE environment variable." | |||
| msgstr "" | |||
| #: _kosmorro/main.py:265 | |||
| #: _kosmorro/main.py:266 | |||
| 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 today ({default_date})." | |||
| " and D numbers). Defaults to current date." | |||
| msgstr "" | |||
| #: _kosmorro/main.py:276 | |||
| #: _kosmorro/main.py:277 | |||
| 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." | |||
| msgstr "" | |||
| #: _kosmorro/main.py:285 | |||
| #: _kosmorro/main.py:286 | |||
| msgid "Disable the colors in the console." | |||
| msgstr "" | |||
| #: _kosmorro/main.py:292 | |||
| #: _kosmorro/main.py:293 | |||
| 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:301 | |||
| #: _kosmorro/main.py:302 | |||
| msgid "" | |||
| "Do not generate a graph to represent the rise and set times in the PDF " | |||
| "format." | |||
| msgstr "" | |||
| #: _kosmorro/main.py:309 | |||
| #: _kosmorro/main.py:310 | |||
| msgid "Show debugging messages" | |||
| msgstr "" | |||
| @@ -23,10 +23,10 @@ from kosmorrolib import Position, get_ephemerides, get_events, get_moon_phase | |||
| from kosmorrolib.__version__ import __version__ as kosmorrolib_version | |||
| from kosmorrolib.exceptions import OutOfRangeDateError | |||
| from datetime import date | |||
| from termcolor import colored | |||
| from . import dumper, environment, debug | |||
| from .date import parse_date | |||
| from .utils import colored, set_colors_activated | |||
| from .__version__ import __version__ as kosmorro_version | |||
| from .exceptions import UnavailableFeatureError, OutOfRangeDateError as DateRangeError | |||
| from _kosmorro.i18n.utils import _, SHORT_DATE_FORMAT | |||
| @@ -39,6 +39,8 @@ def main(): | |||
| debug.show_debug_messages = args.show_debug_messages | |||
| output_format = args.format | |||
| set_colors_activated(args.colors) | |||
| if args.special_action is not None: | |||
| return 0 if args.special_action() else 1 | |||
| @@ -214,9 +216,8 @@ def get_args(output_formats: [str]): | |||
| "Compute the ephemerides and the events for a given date and a given position on Earth." | |||
| ), | |||
| epilog=_( | |||
| "By default, only the events will be computed for today ({date}).\n" | |||
| "To compute also the ephemerides, latitude and longitude arguments" | |||
| " are needed." | |||
| "By default, only the events will be computed for today.\n" | |||
| "To compute also the ephemerides, latitude and longitude arguments are needed." | |||
| ).format(date=today.strftime(dumper.FULL_DATE_FORMAT)), | |||
| ) | |||
| @@ -265,7 +266,7 @@ def get_args(output_formats: [str]): | |||
| help=_( | |||
| "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 today ({default_date})." | |||
| "Defaults to current date." | |||
| ).format(default_date=today.strftime("%Y-%m-%d")), | |||
| ) | |||
| parser.add_argument( | |||
| @@ -0,0 +1,19 @@ | |||
| #!/usr/bin/env python3 | |||
| from termcolor import colored as do_color | |||
| global _COLORS_ACTIVATED | |||
| def set_colors_activated(activated: bool): | |||
| global _COLORS_ACTIVATED | |||
| _COLORS_ACTIVATED = activated | |||
| def colored(text, color=None, on_color=None, attrs=None): | |||
| """Decorator to use colors only when they are activated""" | |||
| if not _COLORS_ACTIVATED: | |||
| return text | |||
| return do_color(text, color, on_color, attrs) | |||
| @@ -0,0 +1,52 @@ | |||
| #!/usr/bin/env python3 | |||
| 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.stdout | |||
| == """Monday January 27, 2020 | |||
| Moon phase: New Moon | |||
| First Quarter on Sunday February 02, 2020 at 01:41 | |||
| Expected events: | |||
| 20:00 Venus and Neptune are in conjunction | |||
| Note: All the hours are given in UTC. | |||
| """ | |||
| ) | |||
| 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 ( | |||
| result.stdout | |||
| == 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 ( | |||
| result.stdout == 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 ( | |||
| result.stdout | |||
| == "Moon phase can only be displayed between Aug 09, 1899 and Sep 26, 2053\n" | |||
| ) | |||
| @@ -0,0 +1,85 @@ | |||
| #!/usr/bin/env python3 | |||
| from sys import version_info | |||
| from .utils import ( | |||
| execute, | |||
| KOSMORRO, | |||
| CURRENT_MOON_PHASE_PATTERN, | |||
| NEXT_MOON_PHASE_PATTERN, | |||
| ) | |||
| from datetime import date | |||
| def test_run_without_argument(): | |||
| result = execute(KOSMORRO) | |||
| assert result.is_successful() | |||
| stdout = result.stdout.split("\n") | |||
| # It always starts with the current date, an empty line and the current and next Moon date: | |||
| assert stdout[0] == date.today().strftime("%A %B %d, %Y") | |||
| assert stdout[1] == "" | |||
| assert CURRENT_MOON_PHASE_PATTERN.match(stdout[2]) | |||
| assert NEXT_MOON_PHASE_PATTERN.match(stdout[3]) | |||
| # It always finishes with an empty line, a note about UTC timezone and an empty line: | |||
| assert stdout[-3] == "" | |||
| assert stdout[-2] == "Note: All the hours are given in UTC." | |||
| assert stdout[-1] == "" | |||
| def test_help_message(): | |||
| python_version = (version_info.major, version_info.minor) | |||
| for arg in ["--help", "-h"]: | |||
| result = execute(KOSMORRO + [arg]) | |||
| assert result.is_successful() | |||
| # Options header has changed from "optional arguments" to "options" in Python 3.10. | |||
| options_header = ( | |||
| "options" if python_version == (3, 10) else "optional arguments" | |||
| ) | |||
| 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] | |||
| Compute the ephemerides and the events for a given date and a given position | |||
| on Earth. | |||
| %s: | |||
| -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. | |||
| --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. | |||
| --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. | |||
| --debug Show debugging messages | |||
| By default, only the events will be computed for today. To compute also the | |||
| ephemerides, latitude and longitude arguments are needed. | |||
| """ | |||
| % options_header | |||
| ) | |||
| @@ -0,0 +1,195 @@ | |||
| #!/usr/bin/env python3 | |||
| from .utils import ( | |||
| execute, | |||
| KOSMORRO, | |||
| ) | |||
| import tempfile | |||
| from os import path, environ | |||
| from sys import platform | |||
| def test_json_output(): | |||
| result = execute( | |||
| KOSMORRO | |||
| + ["--latitude=50.5876", "--longitude=3.0624", "-d2020-01-27", "--format=json"] | |||
| ) | |||
| assert result.is_successful() | |||
| assert ( | |||
| result.stdout | |||
| == """{ | |||
| "ephemerides": [ | |||
| { | |||
| "object": { | |||
| "identifier": "SUN", | |||
| "type": "STAR", | |||
| "radius": 696342 | |||
| }, | |||
| "rise_time": "2020-01-27T07:31:00", | |||
| "culmination_time": "2020-01-27T12:01:00", | |||
| "set_time": "2020-01-27T16:30:00" | |||
| }, | |||
| { | |||
| "object": { | |||
| "identifier": "MOON", | |||
| "type": "SATELLITE", | |||
| "radius": 1737.4 | |||
| }, | |||
| "rise_time": "2020-01-27T09:06:00", | |||
| "culmination_time": "2020-01-27T14:09:00", | |||
| "set_time": "2020-01-27T19:13:00" | |||
| }, | |||
| { | |||
| "object": { | |||
| "identifier": "MERCURY", | |||
| "type": "PLANET", | |||
| "radius": 2439.7 | |||
| }, | |||
| "rise_time": "2020-01-27T08:10:00", | |||
| "culmination_time": "2020-01-27T12:49:00", | |||
| "set_time": "2020-01-27T17:28:00" | |||
| }, | |||
| { | |||
| "object": { | |||
| "identifier": "VENUS", | |||
| "type": "PLANET", | |||
| "radius": 6051.8 | |||
| }, | |||
| "rise_time": "2020-01-27T09:01:00", | |||
| "culmination_time": "2020-01-27T14:35:00", | |||
| "set_time": "2020-01-27T20:10:00" | |||
| }, | |||
| { | |||
| "object": { | |||
| "identifier": "MARS", | |||
| "type": "PLANET", | |||
| "radius": 3396.2 | |||
| }, | |||
| "rise_time": "2020-01-27T04:19:00", | |||
| "culmination_time": "2020-01-27T08:23:00", | |||
| "set_time": "2020-01-27T12:28:00" | |||
| }, | |||
| { | |||
| "object": { | |||
| "identifier": "JUPITER", | |||
| "type": "PLANET", | |||
| "radius": 71492 | |||
| }, | |||
| "rise_time": "2020-01-27T06:15:00", | |||
| "culmination_time": "2020-01-27T10:18:00", | |||
| "set_time": "2020-01-27T14:21:00" | |||
| }, | |||
| { | |||
| "object": { | |||
| "identifier": "SATURN", | |||
| "type": "PLANET", | |||
| "radius": 60268 | |||
| }, | |||
| "rise_time": "2020-01-27T06:56:00", | |||
| "culmination_time": "2020-01-27T11:09:00", | |||
| "set_time": "2020-01-27T15:22:00" | |||
| }, | |||
| { | |||
| "object": { | |||
| "identifier": "URANUS", | |||
| "type": "PLANET", | |||
| "radius": 25559 | |||
| }, | |||
| "rise_time": "2020-01-27T10:21:00", | |||
| "culmination_time": "2020-01-27T17:25:00", | |||
| "set_time": "2020-01-27T00:33:00" | |||
| }, | |||
| { | |||
| "object": { | |||
| "identifier": "NEPTUNE", | |||
| "type": "PLANET", | |||
| "radius": 24764 | |||
| }, | |||
| "rise_time": "2020-01-27T09:01:00", | |||
| "culmination_time": "2020-01-27T14:36:00", | |||
| "set_time": "2020-01-27T20:10:00" | |||
| }, | |||
| { | |||
| "object": { | |||
| "identifier": "PLUTO", | |||
| "type": "PLANET", | |||
| "radius": 1185 | |||
| }, | |||
| "rise_time": "2020-01-27T06:57:00", | |||
| "culmination_time": "2020-01-27T11:04:00", | |||
| "set_time": "2020-01-27T15:11:00" | |||
| } | |||
| ], | |||
| "moon_phase": { | |||
| "phase": "NEW_MOON", | |||
| "time": "2020-01-24T21:41:59.705921+00:00", | |||
| "next": { | |||
| "phase": "FIRST_QUARTER", | |||
| "time": "2020-02-02T01:41:40.282275+00:00" | |||
| } | |||
| }, | |||
| "events": [ | |||
| { | |||
| "objects": [ | |||
| { | |||
| "identifier": "VENUS", | |||
| "type": "PLANET", | |||
| "radius": 6051.8 | |||
| }, | |||
| { | |||
| "identifier": "NEPTUNE", | |||
| "type": "PLANET", | |||
| "radius": 24764 | |||
| } | |||
| ], | |||
| "EventType": "CONJUNCTION", | |||
| "starts_at": "2020-01-27T20:00:23.242750+00:00", | |||
| "ends_at": null, | |||
| "details": null | |||
| } | |||
| ] | |||
| } | |||
| """ | |||
| ) | |||
| def test_pdf_output(): | |||
| if platform != "linux": | |||
| # Consider it works everywhere if it does at least on Linux | |||
| return | |||
| tmp_dir = tempfile.mkdtemp() | |||
| result = execute( | |||
| KOSMORRO | |||
| + [ | |||
| "--latitude=50.5876", | |||
| "--longitude=3.0624", | |||
| "-d2020-01-27", | |||
| "--format=pdf", | |||
| f"--output={tmp_dir}/document.pdf", | |||
| ] | |||
| ) | |||
| if environ.get("TEXLIVE_INSTALLED") is None: | |||
| assert not result.is_successful() | |||
| assert ( | |||
| result.stdout | |||
| == """Save the planet and paper! | |||
| Consider printing your PDF document only if really necessary, and use the other side of the sheet. | |||
| Building PDF was not possible, because some dependencies are not installed. | |||
| Please look at the documentation at https://kosmorro.space/cli/generate-pdf/ for more information. | |||
| """ | |||
| ) | |||
| return | |||
| assert result.is_successful() | |||
| assert ( | |||
| result.stdout | |||
| == """Save the planet and paper! | |||
| Consider printing your PDF document only if really necessary, and use the other side of the sheet. | |||
| """ | |||
| "" | |||
| ) | |||
| assert path.exists(f"{tmp_dir}/document.pdf") | |||
| @@ -0,0 +1,55 @@ | |||
| #!/usr/bin/env python3 | |||
| from .utils import ( | |||
| execute, | |||
| KOSMORRO, | |||
| ) | |||
| def check_command_return(result): | |||
| assert result.is_successful() | |||
| assert ( | |||
| result.stdout | |||
| == """Monday January 27, 2020 | |||
| Object Rise time Culmination time Set time | |||
| -------- ----------- ------------------ ---------- | |||
| Sun 07:31 12:01 16:30 | |||
| Moon 09:06 14:09 19:13 | |||
| Mercury 08:10 12:49 17:28 | |||
| Venus 09:01 14:35 20:10 | |||
| Mars 04:19 08:23 12:28 | |||
| Jupiter 06:15 10:18 14:21 | |||
| Saturn 06:56 11:09 15:22 | |||
| Uranus 10:21 17:25 00:33 | |||
| Neptune 09:01 14:36 20:10 | |||
| Pluto 06:57 11:04 15:11 | |||
| Moon phase: New Moon | |||
| First Quarter on Sunday February 02, 2020 at 01:41 | |||
| Expected events: | |||
| 20:00 Venus and Neptune are in conjunction | |||
| Note: All the hours are given in UTC. | |||
| """ | |||
| ) | |||
| def test_with_position(): | |||
| result = execute( | |||
| KOSMORRO + ["--latitude=50.5876", "--longitude=3.0624", "-d2020-01-27"] | |||
| ) | |||
| check_command_return(result) | |||
| def test_with_position_env_vars(): | |||
| check_command_return( | |||
| execute( | |||
| KOSMORRO + ["-d2020-01-27"], | |||
| environment={ | |||
| "KOSMORRO_LATITUDE": "50.5876", | |||
| "KOSMORRO_LONGITUDE": "3.0624", | |||
| }, | |||
| ) | |||
| ) | |||
| @@ -0,0 +1,73 @@ | |||
| #!/usr/bin/env python3 | |||
| from .utils import ( | |||
| execute, | |||
| KOSMORRO, | |||
| ) | |||
| def check_command_return_t_plus_one(result): | |||
| assert result.is_successful() | |||
| assert ( | |||
| result.stdout | |||
| == """Monday January 27, 2020 | |||
| Moon phase: New Moon | |||
| First Quarter on Sunday February 02, 2020 at 02:41 | |||
| Expected events: | |||
| 21:00 Venus and Neptune are in conjunction | |||
| Note: All the hours are given in the UTC+1 timezone. | |||
| """ | |||
| ) | |||
| def check_command_return_t_minus_one(result): | |||
| assert result.is_successful() | |||
| assert ( | |||
| result.stdout | |||
| == """Monday January 27, 2020 | |||
| Moon phase: New Moon | |||
| First Quarter on Sunday February 02, 2020 at 00:41 | |||
| Expected events: | |||
| 19:00 Venus and Neptune are in conjunction | |||
| Note: All the hours are given in the UTC-1 timezone. | |||
| """ | |||
| ) | |||
| def test_timezone(): | |||
| check_command_return_t_plus_one( | |||
| execute(KOSMORRO + ["--timezone=1", "-d2020-01-27"]) | |||
| ) | |||
| check_command_return_t_minus_one( | |||
| execute(KOSMORRO + ["--timezone=-1", "-d2020-01-27"]) | |||
| ) | |||
| def test_timezone_with_env_var(): | |||
| check_command_return_t_plus_one( | |||
| execute(KOSMORRO + ["-d2020-01-27"], environment={"KOSMORRO_TIMEZONE": "1"}) | |||
| ) | |||
| check_command_return_t_minus_one( | |||
| execute(KOSMORRO + ["-d2020-01-27"], environment={"KOSMORRO_TIMEZONE": "-1"}) | |||
| ) | |||
| # If both environment variable and argument are set, use argument: | |||
| check_command_return_t_plus_one( | |||
| execute( | |||
| KOSMORRO + ["--timezone=1", "-d2020-01-27"], | |||
| environment={"KOSMORRO_TIMEZONE": "-1"}, | |||
| ) | |||
| ) | |||
| check_command_return_t_minus_one( | |||
| execute( | |||
| KOSMORRO + ["--timezone=-1", "-d2020-01-27"], | |||
| environment={"KOSMORRO_TIMEZONE": "1"}, | |||
| ) | |||
| ) | |||
| @@ -0,0 +1,50 @@ | |||
| #!/usr/bin/env python3 | |||
| import aurornis | |||
| import re | |||
| from os import environ | |||
| from typing import Union | |||
| DEFAULT_ENVIRONMENT = {"PATH": environ["PATH"]} | |||
| KOSMORRO = ["./kosmorro", "--no-color"] | |||
| CURRENT_MOON_PHASE_PATTERN = re.compile( | |||
| r"^Moon phase: (" | |||
| r"(New Moon)|(Waxing Crescent)|" | |||
| r"(First Quarter)|(Waxing Gibbous)|" | |||
| r"(Full Moon)|(Waning Gibbous)|" | |||
| r"(Last Quarter)|(Waning Crescent)" | |||
| r")$" | |||
| ) | |||
| NEXT_MOON_PHASE_PATTERN = re.compile( | |||
| r"^((New Moon)|(Waxing Crescent)|" | |||
| r"(First Quarter)|(Waxing Gibbous)|" | |||
| r"(Full Moon)|(Waning Gibbous)|" | |||
| r"(Last Quarter)|(Waning Crescent)" | |||
| r") " | |||
| r"on ((Monday)|(Tuesday)|(Wednesday)|(Thursday)|(Friday)|(Saturday)|(Sunday)) " | |||
| r"((January)|(February)|(March)|(April)|(May)|(June)|" | |||
| r"(July)|(August)|(September)|(October)|(November)|(December)) " | |||
| r"[0-9]{2}, [0-9]{4} at [0-9]{2}:[0-9]{2}$" | |||
| ) | |||
| def execute( | |||
| command, environment: {str: Union[int, str]} = None | |||
| ) -> aurornis.CommandResult: | |||
| if environment is None: | |||
| environment = DEFAULT_ENVIRONMENT | |||
| else: | |||
| for variable in DEFAULT_ENVIRONMENT: | |||
| environment[variable] = DEFAULT_ENVIRONMENT[variable] | |||
| return aurornis.run(command, environment) | |||
| def assert_nb_lines(expected_nb: int, in_str: str): | |||
| """Check that the string has the specified number of lines and that the last one is empty.""" | |||
| lines = in_str.split("\n") | |||
| assert len(lines) == expected_nb | |||
| assert lines[len(lines) - 1] == "" | |||