diff --git a/.gitignore b/.gitignore
index 6beac87..4480c6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,8 @@ kosmorro.egg-info
coverage.xml
node_modules/
package-lock.json
+/kosmorrolib/assets/pdf/*
+!/assets/pdf/*.tex
# Translation files are taken care on https://poeditor.com/join/project/GXuhLpdaoh
*.mo
diff --git a/Pipfile b/Pipfile
index e716458..f72dd1a 100644
--- a/Pipfile
+++ b/Pipfile
@@ -14,6 +14,7 @@ skyfield = ">=1.13.0,<2.0.0"
tabulate = "*"
numpy = ">=1.17.0,<2.0.0"
termcolor = "*"
+latex = "*"
[requires]
python_version = "3"
diff --git a/Pipfile.lock b/Pipfile.lock
index 906ca02..9e0a149 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "fb530146420b5768bc25165302d947d11615aac375e7a63a9076fdddd0372d53"
+ "sha256": "789ae3ae412a3b57df763f776aa8ce0497d680de59fa09ad22a9b91a4e3d6b4e"
},
"pipfile-spec": 6,
"requires": {
@@ -16,12 +16,45 @@
]
},
"default": {
+ "data": {
+ "hashes": [
+ "sha256:2726a65da1af31e2345b6bba81ae4cee87dddf17f7c62f5c63ba7327a8480667"
+ ],
+ "version": "==0.4"
+ },
+ "decorator": {
+ "hashes": [
+ "sha256:54c38050039232e1db4ad7375cfce6748d7b41c29e95a081c8a6d2c30364a2ce",
+ "sha256:5d19b92a3c8f7f101c8dd86afd86b0f061a8ce4540ab8cd401fa2542756bce6d"
+ ],
+ "version": "==4.4.1"
+ },
+ "funcsigs": {
+ "hashes": [
+ "sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca",
+ "sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50"
+ ],
+ "version": "==1.0.2"
+ },
+ "future": {
+ "hashes": [
+ "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
+ ],
+ "version": "==0.18.2"
+ },
"jplephem": {
"hashes": [
"sha256:35a3b67444c7b03433e5ffff89fe10fd78d9bc88c12aafd001631227a1782023"
],
"version": "==2.12"
},
+ "latex": {
+ "hashes": [
+ "sha256:bf10c3fe27e9f3adccebc12e90ec239c86dcba101b89221f6775918211482a79"
+ ],
+ "index": "pypi",
+ "version": "==0.7.0"
+ },
"numpy": {
"hashes": [
"sha256:1786a08236f2c92ae0e70423c45e1e62788ed33028f94ca99c4df03f5be6b3c6",
@@ -94,6 +127,12 @@
"index": "pypi",
"version": "==0.8.6"
},
+ "tempdir": {
+ "hashes": [
+ "sha256:689680ed3ba4cc8347a70e67efc25086ce85b53b9d24a1420899c585bbf7ba8e"
+ ],
+ "version": "==0.7.1"
+ },
"termcolor": {
"hashes": [
"sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"
diff --git a/README.md b/README.md
index adcd4b6..0fda4a2 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# ![Kosmorro](assets/png/kosmorro-logo.png)
+# ![Kosmorro](kosmorrolib/assets/png/kosmorro-logo.png)
[![codecov](https://codecov.io/gh/Deuchnord/kosmorro/branch/master/graph/badge.svg)](https://codecov.io/gh/Deuchnord/kosmorro) [![Version on PyPI](https://img.shields.io/pypi/v/kosmorro)](https://pypi.org/project/kosmorro) [![Discord](https://img.shields.io/discord/650237632533757965?logo=discord&label=%23kosmorro)](https://discord.gg/nyemBqE)
## About the project
diff --git a/kosmorrolib/assets/moonphases/png/first-quarter.png b/kosmorrolib/assets/moonphases/png/first-quarter.png
new file mode 100644
index 0000000..c9ec338
Binary files /dev/null and b/kosmorrolib/assets/moonphases/png/first-quarter.png differ
diff --git a/kosmorrolib/assets/moonphases/png/full-moon.png b/kosmorrolib/assets/moonphases/png/full-moon.png
new file mode 100644
index 0000000..54beb67
Binary files /dev/null and b/kosmorrolib/assets/moonphases/png/full-moon.png differ
diff --git a/kosmorrolib/assets/moonphases/png/last-quarter.png b/kosmorrolib/assets/moonphases/png/last-quarter.png
new file mode 100644
index 0000000..86ebc38
Binary files /dev/null and b/kosmorrolib/assets/moonphases/png/last-quarter.png differ
diff --git a/kosmorrolib/assets/moonphases/png/new-moon.png b/kosmorrolib/assets/moonphases/png/new-moon.png
new file mode 100644
index 0000000..ff0cdb4
Binary files /dev/null and b/kosmorrolib/assets/moonphases/png/new-moon.png differ
diff --git a/kosmorrolib/assets/moonphases/png/waning-crescent.png b/kosmorrolib/assets/moonphases/png/waning-crescent.png
new file mode 100644
index 0000000..697fab9
Binary files /dev/null and b/kosmorrolib/assets/moonphases/png/waning-crescent.png differ
diff --git a/kosmorrolib/assets/moonphases/png/waning-gibbous.png b/kosmorrolib/assets/moonphases/png/waning-gibbous.png
new file mode 100644
index 0000000..6303cc0
Binary files /dev/null and b/kosmorrolib/assets/moonphases/png/waning-gibbous.png differ
diff --git a/kosmorrolib/assets/moonphases/png/waxing-crescent.png b/kosmorrolib/assets/moonphases/png/waxing-crescent.png
new file mode 100644
index 0000000..2fb768d
Binary files /dev/null and b/kosmorrolib/assets/moonphases/png/waxing-crescent.png differ
diff --git a/kosmorrolib/assets/moonphases/png/waxing-gibbous.png b/kosmorrolib/assets/moonphases/png/waxing-gibbous.png
new file mode 100644
index 0000000..093b674
Binary files /dev/null and b/kosmorrolib/assets/moonphases/png/waxing-gibbous.png differ
diff --git a/kosmorrolib/assets/moonphases/svg/first-quarter.svg b/kosmorrolib/assets/moonphases/svg/first-quarter.svg
new file mode 100644
index 0000000..c3b79d4
--- /dev/null
+++ b/kosmorrolib/assets/moonphases/svg/first-quarter.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/kosmorrolib/assets/moonphases/svg/full-moon.svg b/kosmorrolib/assets/moonphases/svg/full-moon.svg
new file mode 100644
index 0000000..0ad1088
--- /dev/null
+++ b/kosmorrolib/assets/moonphases/svg/full-moon.svg
@@ -0,0 +1,74 @@
+
+
diff --git a/kosmorrolib/assets/moonphases/svg/last-quarter.svg b/kosmorrolib/assets/moonphases/svg/last-quarter.svg
new file mode 100644
index 0000000..62f0559
--- /dev/null
+++ b/kosmorrolib/assets/moonphases/svg/last-quarter.svg
@@ -0,0 +1,74 @@
+
+
diff --git a/kosmorrolib/assets/moonphases/svg/new-moon.svg b/kosmorrolib/assets/moonphases/svg/new-moon.svg
new file mode 100644
index 0000000..3e962ef
--- /dev/null
+++ b/kosmorrolib/assets/moonphases/svg/new-moon.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/kosmorrolib/assets/moonphases/svg/waning-crescent.svg b/kosmorrolib/assets/moonphases/svg/waning-crescent.svg
new file mode 100644
index 0000000..e5775b1
--- /dev/null
+++ b/kosmorrolib/assets/moonphases/svg/waning-crescent.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/kosmorrolib/assets/moonphases/svg/waning-gibbous.svg b/kosmorrolib/assets/moonphases/svg/waning-gibbous.svg
new file mode 100644
index 0000000..eda8eb7
--- /dev/null
+++ b/kosmorrolib/assets/moonphases/svg/waning-gibbous.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/kosmorrolib/assets/moonphases/svg/waxing-crescent.svg b/kosmorrolib/assets/moonphases/svg/waxing-crescent.svg
new file mode 100644
index 0000000..6c6775e
--- /dev/null
+++ b/kosmorrolib/assets/moonphases/svg/waxing-crescent.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/kosmorrolib/assets/moonphases/svg/waxing-gibbous.svg b/kosmorrolib/assets/moonphases/svg/waxing-gibbous.svg
new file mode 100644
index 0000000..7450f15
--- /dev/null
+++ b/kosmorrolib/assets/moonphases/svg/waxing-gibbous.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/kosmorrolib/assets/pdf/template.tex b/kosmorrolib/assets/pdf/template.tex
new file mode 100644
index 0000000..6cb87ed
--- /dev/null
+++ b/kosmorrolib/assets/pdf/template.tex
@@ -0,0 +1,90 @@
+\documentclass[a4paper,12pt]{article}
+
+\usepackage[utf8]{inputenc}
+\usepackage[T1]{fontenc}
+\usepackage[margin=25mm]{geometry}
+\usepackage{graphicx}
+\usepackage{hyperref}
+
+% Fix non-break spaces issues
+\DeclareUnicodeCharacter{202F}{~}
+
+\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}
+
+ \newcommand{\object}[4]{
+ \hline
+ \textbf{#1} & {#2} & {#3} & {#4}\\
+ }
+
+ \newcommand{\moonphase}[2]{
+ \begin{center}
+ \begin{minipage}{2cm}
+ \includegraphics[width=\linewidth]{#1}
+ \end{minipage}
+ \hspace{5mm}
+ \begin{minipage}{7cm}
+ \textbf{+++CURRENT-MOON-PHASE-TITLE+++}\\#2
+ \end{minipage}
+ \end{center}
+}
+
+ \newenvironment{ephemerides}{
+ \begin{table}[h]
+ \centering
+ \begin{tabular}{lccc}
+ \textbf{+++EPHEMERIDES-OBJECT+++} &
+ \textbf{+++EPHEMERIDES-RISE-TIME+++} &
+ \textbf{+++EPHEMERIDES-CULMINATION-TIME+++} &
+ \textbf{+++EPHEMERIDES-SET-TIME+++}\\
+ \hline
+ }{
+ \end{tabular}
+ \end{table}
+ }
+
+ \newcommand{\event}[2]{
+ \textbf{#1} & {#2}\\
+ }
+
+ \newenvironment{events}{
+ \begin{table}[h]
+ \begin{tabular}{ll}
+ }{
+ \end{tabular}
+ \end{table}
+ }
+
+ \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}
diff --git a/assets/png/kosmorro-icon-white.png b/kosmorrolib/assets/png/kosmorro-icon-white.png
similarity index 100%
rename from assets/png/kosmorro-icon-white.png
rename to kosmorrolib/assets/png/kosmorro-icon-white.png
diff --git a/assets/png/kosmorro-icon.png b/kosmorrolib/assets/png/kosmorro-icon.png
similarity index 100%
rename from assets/png/kosmorro-icon.png
rename to kosmorrolib/assets/png/kosmorro-icon.png
diff --git a/assets/png/kosmorro-logo-white.png b/kosmorrolib/assets/png/kosmorro-logo-white.png
similarity index 100%
rename from assets/png/kosmorro-logo-white.png
rename to kosmorrolib/assets/png/kosmorro-logo-white.png
diff --git a/assets/png/kosmorro-logo.png b/kosmorrolib/assets/png/kosmorro-logo.png
similarity index 100%
rename from assets/png/kosmorro-logo.png
rename to kosmorrolib/assets/png/kosmorro-logo.png
diff --git a/assets/svg/kosmorro-icon-white.svg b/kosmorrolib/assets/svg/kosmorro-icon-white.svg
similarity index 100%
rename from assets/svg/kosmorro-icon-white.svg
rename to kosmorrolib/assets/svg/kosmorro-icon-white.svg
diff --git a/assets/svg/kosmorro-icon.svg b/kosmorrolib/assets/svg/kosmorro-icon.svg
similarity index 100%
rename from assets/svg/kosmorro-icon.svg
rename to kosmorrolib/assets/svg/kosmorro-icon.svg
diff --git a/assets/svg/kosmorro-logo-white.svg b/kosmorrolib/assets/svg/kosmorro-logo-white.svg
similarity index 100%
rename from assets/svg/kosmorro-logo-white.svg
rename to kosmorrolib/assets/svg/kosmorro-logo-white.svg
diff --git a/assets/svg/kosmorro-logo.svg b/kosmorrolib/assets/svg/kosmorro-logo.svg
similarity index 100%
rename from assets/svg/kosmorro-logo.svg
rename to kosmorrolib/assets/svg/kosmorro-logo.svg
diff --git a/kosmorrolib/dumper.py b/kosmorrolib/dumper.py
index 92b3649..b7fe4c2 100644
--- a/kosmorrolib/dumper.py
+++ b/kosmorrolib/dumper.py
@@ -19,12 +19,19 @@
from abc import ABC, abstractmethod
import datetime
import json
+import os
from tabulate import tabulate
from skyfield.timelib import Time
from numpy import int64
from termcolor import colored
from .data import Object, AsterEphemerides, MoonPhase, Event
from .i18n import _
+from .version import VERSION
+from .exceptions import UnavailableFeatureError
+try:
+ from latex import build_pdf
+except ImportError:
+ build_pdf = None
FULL_DATE_FORMAT = _('{day_of_week} {month} {day_number}, {year}').format(day_of_week='%A', month='%B',
day_number='%d', year='%Y')
@@ -39,10 +46,22 @@ class Dumper(ABC):
self.date = date
self.with_colors = with_colors
+ def get_date_as_string(self, capitalized: bool = False) -> str:
+ date = self.date.strftime(FULL_DATE_FORMAT)
+
+ if capitalized:
+ return ''.join([date[0].upper(), date[1:]])
+
+ return date
+
@abstractmethod
def to_string(self):
pass
+ @staticmethod
+ def is_file_output_needed() -> bool:
+ return False
+
class JsonDumper(Dumper):
def to_string(self):
@@ -83,7 +102,7 @@ class JsonDumper(Dumper):
class TextDumper(Dumper):
def to_string(self):
- text = [self.style(self.get_date(), 'h1')]
+ text = [self.style(self.get_date_as_string(capitalized=True), 'h1')]
if len(self.ephemeris['details']) > 0:
text.append(self.get_asters(self.ephemeris['details']))
@@ -112,11 +131,6 @@ class TextDumper(Dumper):
return styles[tag](text)
- def get_date(self) -> str:
- date = self.date.strftime(FULL_DATE_FORMAT)
-
- return ''.join([date[0].upper(), date[1:]])
-
def get_asters(self, asters: [Object]) -> str:
data = []
@@ -164,3 +178,132 @@ class TextDumper(Dumper):
)
return '\n'.join([current_moon_phase, new_moon_phase])
+
+
+class _LatexDumper(Dumper):
+ def to_string(self):
+ template_path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
+ 'assets', 'pdf', 'template.tex')
+
+ with open(template_path, mode='r') as file:
+ template = file.read()
+
+ return self._make_document(template)
+
+ def _make_document(self, template: str) -> str:
+ kosmorro_logo_path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
+ 'assets', 'png', 'kosmorro-logo.png')
+ moon_phase_graphics = os.path.join(os.path.abspath(os.path.dirname(__file__)),
+ 'assets', 'moonphases', 'png',
+ '.'.join([self.ephemeris['moon_phase'].identifier.lower().replace('_', '-'),
+ 'png']))
+
+ document = template
+
+ if len(self.ephemeris['details']) == 0:
+ document = self._remove_section(document, 'ephemerides')
+
+ if len(self.events) == 0:
+ document = self._remove_section(document, 'events')
+
+ document = document \
+ .replace('+++KOSMORRO-VERSION+++', VERSION) \
+ .replace('+++KOSMORRO-LOGO+++', kosmorro_logo_path) \
+ .replace('+++DOCUMENT-TITLE+++', _('A Summary of your Sky')) \
+ .replace('+++DOCUMENT-DATE+++', self.get_date_as_string(capitalized=True)) \
+ .replace('+++INTRODUCTION+++',
+ '\n\n'.join([
+ _("This document summarizes the ephemerides and the events of {date}. "
+ "It aims to help you to prepare your observation session.").format(
+ date=self.get_date_as_string()),
+ _("Don't forget to check the weather forecast before you go out with your material.")
+ ])) \
+ .replace('+++SECTION-EPHEMERIDES+++', _('Ephemerides of the day')) \
+ .replace('+++EPHEMERIDES-OBJECT+++', _('Object')) \
+ .replace('+++EPHEMERIDES-RISE-TIME+++', _('Rise time')) \
+ .replace('+++EPHEMERIDES-CULMINATION-TIME+++', _('Culmination time')) \
+ .replace('+++EPHEMERIDES-SET-TIME+++', _('Set time')) \
+ .replace('+++EPHEMERIDES+++', self._make_ephemerides()) \
+ .replace('+++MOON-PHASE-GRAPHICS+++', moon_phase_graphics) \
+ .replace('+++CURRENT-MOON-PHASE-TITLE+++', _('Moon phase:')) \
+ .replace('+++CURRENT-MOON-PHASE+++', self.ephemeris['moon_phase'].get_phase()) \
+ .replace('+++SECTION-EVENTS+++', _('Expected events')) \
+ .replace('+++EVENTS+++', self._make_events())
+
+ return document
+
+ def _make_ephemerides(self) -> str:
+ latex = []
+
+ for aster in self.ephemeris['details']:
+ if aster.ephemerides.rise_time is not None:
+ aster_rise = aster.ephemerides.rise_time.utc_strftime(TIME_FORMAT)
+ else:
+ aster_rise = '-'
+
+ if aster.ephemerides.culmination_time is not None:
+ aster_culmination = aster.ephemerides.culmination_time.utc_strftime(TIME_FORMAT)
+ else:
+ aster_culmination = '-'
+
+ if aster.ephemerides.set_time is not None:
+ aster_set = aster.ephemerides.set_time.utc_strftime(TIME_FORMAT)
+ else:
+ aster_set = '-'
+
+ latex.append(r'\object{%s}{%s}{%s}{%s}' % (aster.name,
+ aster_rise,
+ aster_culmination,
+ aster_set))
+
+ return ''.join(latex)
+
+ def _make_events(self) -> str:
+ latex = []
+
+ for event in self.events:
+ latex.append(r'\event{%s}{%s}' % (event.start_time.utc_strftime(TIME_FORMAT),
+ event.get_description()))
+
+ return ''.join(latex)
+
+ @staticmethod
+ def _remove_section(document: str, section: str):
+ begin_section_tag = '%%%%%% BEGIN-%s-SECTION' % section.upper()
+ end_section_tag = '%%%%%% END-%s-SECTION' % section.upper()
+
+ document = document.split('\n')
+ new_document = []
+
+ ignore_line = False
+ for line in document:
+ if begin_section_tag in line or end_section_tag in line:
+ ignore_line = not ignore_line
+ continue
+ if ignore_line:
+ continue
+ new_document.append(line)
+
+ return '\n'.join(new_document)
+
+
+class PdfDumper(Dumper):
+ def to_string(self):
+ try:
+ latex_dumper = _LatexDumper(self.ephemeris, self.events, self.date, self.with_colors)
+ return self._compile(latex_dumper.to_string())
+ except RuntimeError:
+ raise UnavailableFeatureError(_("Building PDFs was not possible, because some dependencies are not"
+ " installed.\nPlease look at the documentation at http://kosmorro.space "
+ "for more information."))
+
+ @staticmethod
+ def is_file_output_needed() -> bool:
+ return True
+
+ @staticmethod
+ def _compile(latex_input) -> bytes:
+ if build_pdf is None:
+ raise RuntimeError('Python latex module not found')
+
+ return bytes(build_pdf(latex_input))
diff --git a/kosmorrolib/exceptions.py b/kosmorrolib/exceptions.py
new file mode 100644
index 0000000..d6a87d8
--- /dev/null
+++ b/kosmorrolib/exceptions.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python3
+
+# Kosmorro - Compute The Next Ephemerides
+# Copyright (C) 2019 Jérôme Deuchnord
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+
+class UnavailableFeatureError(RuntimeError):
+ def __init__(self, msg: str):
+ super(UnavailableFeatureError, self).__init__()
+ self.msg = msg
diff --git a/kosmorrolib/locales/messages.pot b/kosmorrolib/locales/messages.pot
index 3893d2b..e67c57b 100644
--- a/kosmorrolib/locales/messages.pot
+++ b/kosmorrolib/locales/messages.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: kosmorro 0.5.1\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2020-02-03 13:19+0100\n"
+"POT-Creation-Date: 2020-02-04 13:29+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -99,111 +99,170 @@ msgstr ""
msgid "%s and %s are in conjunction"
msgstr ""
-#: kosmorrolib/dumper.py:29
+#: kosmorrolib/dumper.py:36
msgid "{day_of_week} {month} {day_number}, {year}"
msgstr ""
-#: kosmorrolib/dumper.py:31
+#: kosmorrolib/dumper.py:38
msgid "{hours}:{minutes}"
msgstr ""
-#: kosmorrolib/dumper.py:94
+#: kosmorrolib/dumper.py:113
msgid "Expected events:"
msgstr ""
-#: kosmorrolib/dumper.py:97
+#: kosmorrolib/dumper.py:116
msgid "Note: All the hours are given in UTC."
msgstr ""
-#: kosmorrolib/dumper.py:143
+#: kosmorrolib/dumper.py:157 kosmorrolib/dumper.py:222
msgid "Object"
msgstr ""
-#: kosmorrolib/dumper.py:144
+#: kosmorrolib/dumper.py:158 kosmorrolib/dumper.py:223
msgid "Rise time"
msgstr ""
-#: kosmorrolib/dumper.py:145
+#: kosmorrolib/dumper.py:159 kosmorrolib/dumper.py:224
msgid "Culmination time"
msgstr ""
-#: kosmorrolib/dumper.py:146
+#: kosmorrolib/dumper.py:160 kosmorrolib/dumper.py:225
msgid "Set time"
msgstr ""
-#: kosmorrolib/dumper.py:159
+#: kosmorrolib/dumper.py:173 kosmorrolib/dumper.py:228
msgid "Moon phase:"
msgstr ""
-#: kosmorrolib/dumper.py:160
+#: kosmorrolib/dumper.py:174
msgid "{next_moon_phase} on {next_moon_phase_date} at {next_moon_phase_time}"
msgstr ""
-#: kosmorrolib/main.py:76
-msgid "Running on Python {python_version}"
+#: kosmorrolib/dumper.py:212
+msgid "A Summary of your Sky"
+msgstr ""
+
+#: kosmorrolib/dumper.py:216
+msgid ""
+"This document summarizes the ephemerides and the events of {date}. It "
+"aims to help you to prepare your observation session."
+msgstr ""
+
+#: kosmorrolib/dumper.py:219
+msgid ""
+"Don't forget to check the weather forecast before you go out with your "
+"material."
+msgstr ""
+
+#: kosmorrolib/dumper.py:221
+msgid "Ephemerides of the day"
+msgstr ""
+
+#: kosmorrolib/dumper.py:230
+msgid "Expected events"
+msgstr ""
+
+#: kosmorrolib/dumper.py:296
+msgid ""
+"Building PDFs was not possible, because some dependencies are not "
+"installed.\n"
+"Please look at the documentation at http://kosmorro.space for more "
+"information."
+msgstr ""
+
+#: kosmorrolib/main.py:58
+msgid ""
+"Save the planet and paper!\n"
+"Consider printing you PDF document only if really necessary, and use the "
+"other side of the sheet."
+msgstr ""
+
+#: kosmorrolib/main.py:62
+msgid ""
+"PDF output will not contain the ephemerides, because you didn't provide "
+"the observation coordinate."
msgstr ""
#: kosmorrolib/main.py:82
+msgid "Could not save the output in \"{path}\": {error}"
+msgstr ""
+
+#: kosmorrolib/main.py:87
+msgid "Selected output format needs an output file (--output)."
+msgstr ""
+
+#: kosmorrolib/main.py:104
+msgid "Running on Python {python_version}"
+msgstr ""
+
+#: kosmorrolib/main.py:110
msgid "Do you really want to clear Kosmorro's cache? [yN] "
msgstr ""
-#: kosmorrolib/main.py:89
+#: kosmorrolib/main.py:117
msgid "Answer did not match expected options, cache not cleared."
msgstr ""
-#: kosmorrolib/main.py:98
+#: kosmorrolib/main.py:126
msgid ""
"Compute the ephemerides and the events for a given date, at a given "
"position on Earth."
msgstr ""
-#: kosmorrolib/main.py:100
+#: kosmorrolib/main.py:128
msgid ""
"By default, only the events will be computed for today ({date}).\n"
"To compute also the ephemerides, latitude and longitude arguments are "
"needed."
msgstr ""
-#: kosmorrolib/main.py:105
+#: kosmorrolib/main.py:133
msgid "Show the program version"
msgstr ""
-#: kosmorrolib/main.py:107
+#: kosmorrolib/main.py:135
msgid "Delete all the files Kosmorro stored in the cache."
msgstr ""
-#: kosmorrolib/main.py:109
+#: kosmorrolib/main.py:137
msgid "The format under which the information have to be output"
msgstr ""
-#: kosmorrolib/main.py:111
+#: kosmorrolib/main.py:139
msgid "The observer's latitude on Earth"
msgstr ""
-#: kosmorrolib/main.py:113
+#: kosmorrolib/main.py:141
msgid "The observer's longitude on Earth"
msgstr ""
-#: kosmorrolib/main.py:115
+#: kosmorrolib/main.py:143
msgid ""
"A number between 1 and 28, 29, 30 or 31 (depending on the month). The day"
" you want to compute the ephemerides for. Defaults to {default_day} (the"
" current day)."
msgstr ""
-#: kosmorrolib/main.py:119
+#: kosmorrolib/main.py:147
msgid ""
"A number between 1 and 12. The month you want to compute the ephemerides "
"for. Defaults to {default_month} (the current month)."
msgstr ""
-#: kosmorrolib/main.py:122
+#: kosmorrolib/main.py:150
msgid ""
"The year you want to compute the ephemerides for. Defaults to "
"{default_year} (the current year)."
msgstr ""
-#: kosmorrolib/main.py:125
+#: kosmorrolib/main.py:153
msgid "Disable the colors in the console."
msgstr ""
+#: kosmorrolib/main.py:155
+msgid ""
+"A file to export the output to. If not given, the standard output is "
+"used. This argument is needed for PDF format."
+msgstr ""
+
diff --git a/kosmorrolib/main.py b/kosmorrolib/main.py
index 6f27447..16788a0 100644
--- a/kosmorrolib/main.py
+++ b/kosmorrolib/main.py
@@ -22,6 +22,7 @@ import re
import sys
from datetime import date
+from termcolor import colored
from kosmorrolib.version import VERSION
from kosmorrolib import dumper
@@ -29,6 +30,7 @@ from kosmorrolib import core
from kosmorrolib import events
from kosmorrolib.i18n import _
from .ephemerides import EphemeridesComputer, Position
+from .exceptions import UnavailableFeatureError
def main():
@@ -52,13 +54,38 @@ def main():
else:
position = Position(args.latitude, args.longitude)
- ephemeris = EphemeridesComputer(position)
- ephemerides = ephemeris.compute_ephemerides(year, month, day)
+ if args.format == 'pdf':
+ print(_('Save the planet and paper!\n'
+ 'Consider printing you PDF document only if really necessary, and use the other side of the sheet.'))
+ if position is None:
+ print()
+ print(colored(_("PDF output will not contain the ephemerides, because you didn't provide the observation "
+ "coordinate."), 'yellow'))
- events_list = events.search_events(compute_date)
+ try:
+ ephemeris = EphemeridesComputer(position)
+ ephemerides = ephemeris.compute_ephemerides(year, month, day)
- dump = output_formats[args.format](ephemerides, events_list, compute_date, args.colors)
- print(dump.to_string())
+ events_list = events.search_events(compute_date)
+
+ selected_dumper = output_formats[args.format](ephemerides, events_list, compute_date, args.colors)
+ output = selected_dumper.to_string()
+ except UnavailableFeatureError as error:
+ print(colored(error.msg, 'red'))
+ return 2
+
+ if args.output is not None:
+ try:
+ with open(args.output, 'wb') as output_file:
+ output_file.write(output)
+ except OSError as error:
+ print(_('Could not save the output in "{path}": {error}').format(path=args.output,
+ error=error.strerror))
+ elif not selected_dumper.is_file_output_needed():
+ print(output)
+ else:
+ print(_('Selected output format needs an output file (--output).'))
+ return 1
return 0
@@ -66,7 +93,8 @@ def main():
def get_dumpers() -> {str: dumper.Dumper}:
return {
'text': dumper.TextDumper,
- 'json': dumper.JsonDumper
+ 'json': dumper.JsonDumper,
+ 'pdf': dumper.PdfDumper
}
@@ -123,5 +151,8 @@ def get_args(output_formats: [str]):
' Defaults to {default_year} (the current year).').format(default_year=today.year))
parser.add_argument('--no-colors', dest='colors', action='store_false',
help=_('Disable the colors in the console.'))
+ parser.add_argument('--output', '-o', type=str, default=None,
+ help=_('A file to export the output to. If not given, the standard output is used. '
+ 'This argument is needed for PDF format.'))
return parser.parse_args()
diff --git a/test/dumper.py b/test/dumper.py
index 523d878..c1daeb7 100644
--- a/test/dumper.py
+++ b/test/dumper.py
@@ -2,7 +2,7 @@ import unittest
from datetime import date
from kosmorrolib.data import AsterEphemerides, Planet, MoonPhase, Event
-from kosmorrolib.dumper import JsonDumper, TextDumper
+from kosmorrolib.dumper import JsonDumper, TextDumper, _LatexDumper
from kosmorrolib.core import get_timescale
@@ -39,8 +39,7 @@ class DumperTestCase(unittest.TestCase):
' }\n'
' ]\n'
'}', JsonDumper(data,
- [Event('OPPOSITION', [Planet('Mars', 'MARS')],
- get_timescale().utc(2018, 7, 27, 5, 12))]
+ self._get_events()
).to_string())
def test_text_dumper_without_events(self):
@@ -65,10 +64,7 @@ class DumperTestCase(unittest.TestCase):
'Expected events:\n'
'05:12 Mars is in opposition\n\n'
'Note: All the hours are given in UTC.',
- TextDumper(ephemerides, [Event('OPPOSITION',
- [Planet('Mars', 'MARS')],
- get_timescale().utc(2018, 7, 27, 5, 12))
- ], date=date(2019, 10, 14), with_colors=False).to_string())
+ TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string())
def test_text_dumper_without_ephemerides_and_with_events(self):
ephemerides = self._get_data(False)
@@ -78,18 +74,59 @@ class DumperTestCase(unittest.TestCase):
'Expected events:\n'
'05:12 Mars is in opposition\n\n'
'Note: All the hours are given in UTC.',
- TextDumper(ephemerides, [Event('OPPOSITION',
- [Planet('Mars', 'MARS')],
- get_timescale().utc(2018, 7, 27, 5, 12))
- ], date=date(2019, 10, 14), with_colors=False).to_string())
+ TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string())
+
+ def test_latex_dumper(self):
+ latex = _LatexDumper(self._get_data(), self._get_events(), date=date(2019, 10, 14)).to_string()
+ self.assertRegex(latex, 'Monday October 14, 2019')
+ self.assertRegex(latex, 'Full Moon')
+ self.assertRegex(latex, r'\\section{\\sffamily Expected events}')
+ self.assertRegex(latex, r'\\section{\\sffamily Ephemerides of the day}')
+ self.assertRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}')
+ self.assertRegex(latex, r'\\event\{05:12\}\{Mars is in opposition\}')
+
+ latex = _LatexDumper(self._get_data(aster_rise_set=True),
+ self._get_events(), date=date(2019, 10, 14)).to_string()
+ self.assertRegex(latex, r'\\object\{Mars\}\{08:00\}\{13:00\}\{23:00\}')
+
+ def test_latex_dumper_without_ephemerides(self):
+ latex = _LatexDumper(self._get_data(False), self._get_events(), date=date(2019, 10, 14)).to_string()
+ self.assertRegex(latex, 'Monday October 14, 2019')
+ self.assertRegex(latex, 'Full Moon')
+ self.assertRegex(latex, r'\\section{\\sffamily Expected events}')
+ self.assertRegex(latex, r'\\event\{05:12\}\{Mars is in opposition\}')
+
+ self.assertNotRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}')
+ self.assertNotRegex(latex, r'\\section{\\sffamily Ephemerides of the day}')
+
+ def test_latex_dumper_without_events(self):
+ latex = _LatexDumper(self._get_data(), [], date=date(2019, 10, 14)).to_string()
+ self.assertRegex(latex, 'Monday October 14, 2019')
+ self.assertRegex(latex, 'Full Moon')
+ self.assertRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}')
+ self.assertRegex(latex, r'\\section{\\sffamily Ephemerides of the day}')
+
+ self.assertNotRegex(latex, r'\\section{\\sffamily Expected events}')
@staticmethod
- def _get_data(has_ephemerides: bool = True):
+ def _get_data(has_ephemerides: bool = True, aster_rise_set=False):
+ rise_time = get_timescale().utc(2019, 10, 14, 8) if aster_rise_set else None
+ culmination_time = get_timescale().utc(2019, 10, 14, 13) if aster_rise_set else None
+ set_time = get_timescale().utc(2019, 10, 14, 23) if aster_rise_set else None
+
return {
'moon_phase': MoonPhase('FULL_MOON', get_timescale().utc(2019, 10, 14), get_timescale().utc(2019, 10, 21)),
- 'details': [Planet('Mars', 'MARS', AsterEphemerides(None, None, None))] if has_ephemerides else []
+ 'details': [Planet('Mars', 'MARS',
+ AsterEphemerides(rise_time, culmination_time, set_time))] if has_ephemerides else []
}
+ @staticmethod
+ def _get_events():
+ return [Event('OPPOSITION',
+ [Planet('Mars', 'MARS')],
+ get_timescale().utc(2018, 7, 27, 5, 12))
+ ]
+
if __name__ == '__main__':
unittest.main()