From 38fc06657fb7452e35e81e61fb2b8990bf341f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Sat, 18 Jan 2020 14:13:55 +0100 Subject: [PATCH] feat: add colors in the text return Colors can be disabled with the new `--no-colors` argument. --- Pipfile | 1 + Pipfile.lock | 81 +++++++++++++++++--------------- kosmorrolib/dumper.py | 69 ++++++++++++++++----------- kosmorrolib/locales/messages.pot | 28 ++++++----- kosmorrolib/main.py | 4 +- test/dumper.py | 10 ++-- 6 files changed, 110 insertions(+), 83 deletions(-) diff --git a/Pipfile b/Pipfile index d6b8427..e716458 100644 --- a/Pipfile +++ b/Pipfile @@ -13,6 +13,7 @@ babel = "*" skyfield = ">=1.13.0,<2.0.0" tabulate = "*" numpy = ">=1.17.0,<2.0.0" +termcolor = "*" [requires] python_version = "3" diff --git a/Pipfile.lock b/Pipfile.lock index ed65f39..d330ec2 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "d5c2451a4f189a6d10a9205879f066fd9b595723f2e1077416aa3f48cdcbfb9f" + "sha256": "fb530146420b5768bc25165302d947d11615aac375e7a63a9076fdddd0372d53" }, "pipfile-spec": 6, "requires": { @@ -68,6 +68,13 @@ ], "index": "pypi", "version": "==0.8.6" + }, + "termcolor": { + "hashes": [ + "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b" + ], + "index": "pypi", + "version": "==1.1.0" } }, "develop": { @@ -110,39 +117,39 @@ }, "coverage": { "hashes": [ - "sha256:189aac76d6e0d7af15572c51892e7326ee451c076c5a50a9d266406cd6c49708", - "sha256:1bf7ba2af1d373a1750888724f84cffdfc697738f29a353c98195f98fc011509", - "sha256:1f4ee8e2e4243971618bc16fcc4478317405205f135e95226c2496e2a3b8dbbf", - "sha256:225e79a5d485bc1642cb7ba02281419c633c216cdc6b26c26494ba959f09e69f", - "sha256:23688ff75adfa8bfa2a67254d889f9bdf9302c27241d746e17547c42c732d3f4", - "sha256:28f7f73b34a05e23758e860a89a7f649b85c6749e252eff60ebb05532d180e86", - "sha256:2d0cb9b1fe6ad0d915d45ad3d87f03a38e979093a98597e755930db1f897afae", - "sha256:47874b4711c5aeb295c31b228a758ce3d096be83dc37bd56da48ed99efb8813b", - "sha256:511ec0c00840e12fb4e852e4db58fa6a01ca4da72f36a9766fae344c3d502033", - "sha256:53e7438fef0c97bc248f88ba1edd10268cd94d5609970aaf87abbe493691af87", - "sha256:569f9ee3025682afda6e9b0f5bb14897c0db03f1a1dc088b083dd36e743f92bb", - "sha256:593853aa1ac6dcc6405324d877544c596c9d948ef20d2e9512a0f5d2d3202356", - "sha256:5b0a07158360d22492f9abd02a0f2ee7981b33f0646bf796598b7673f6bbab14", - "sha256:7ca3db38a61f3655a2613ee2c190d63639215a7a736d3c64cc7bbdb002ce6310", - "sha256:7d1cc7acc9ce55179616cf72154f9e648136ea55987edf84addbcd9886ffeba2", - "sha256:88b51153657612aea68fa684a5b88037597925260392b7bb4509d4f9b0bdd889", - "sha256:955ec084f549128fa2702f0b2dc696392001d986b71acd8fd47424f28289a9c3", - "sha256:b251c7092cbb6d789d62dc9c9e7c4fb448c9138b51285c36aeb72462cad3600e", - "sha256:bd82b684bb498c60ef47bb1541a50e6d006dde8579934dcbdbc61d67d1ea70d9", - "sha256:bfe102659e2ec13b86c7f3b1db6c9a4e7beea4255058d006351339e6b342d5d2", - "sha256:c1e4e39e43057396a5e9d069bfbb6ffeee892e40c5d2effbd8cd71f34ee66c4d", - "sha256:cb2b74c123f65e8166f7e1265829a6c8ed755c3cd16d7f50e75a83456a5f3fd7", - "sha256:cca38ded59105f7705ef6ffe1e960b8db6c7d8279c1e71654a4775ab4454ca15", - "sha256:cf908840896f7aa62d0ec693beb53264b154f972eb8226fb864ac38975590c4f", - "sha256:d095a7b473f8a95f7efe821f92058c8a2ecfb18f8db6677ae3819e15dc11aaae", - "sha256:d22b4297e7e4225ccf01f1aa55e7a96412ea0796b532dd614c3fcbafa341128e", - "sha256:d4a2b578a7a70e0c71f662705262f87a456f1e6c1e40ada7ea699abaf070a76d", - "sha256:ddeb42a3d5419434742bf4cc71c9eaa22df3b76808e23a82bd0b0bd360f1a9f1", - "sha256:e65a5aa1670db6263f19fdc03daee1d7dbbadb5cb67fd0a1f16033659db13c1d", - "sha256:eaad65bd20955131bcdb3967a4dea66b4e4d4ca488efed7c00d91ee0173387e8", - "sha256:f45fba420b94165c17896861bb0e8b27fb7abdcedfeb154895d8553df90b7b00" - ], - "version": "==5.0.2" + "sha256:15cf13a6896048d6d947bf7d222f36e4809ab926894beb748fc9caa14605d9c3", + "sha256:1daa3eceed220f9fdb80d5ff950dd95112cd27f70d004c7918ca6dfc6c47054c", + "sha256:1e44a022500d944d42f94df76727ba3fc0a5c0b672c358b61067abb88caee7a0", + "sha256:25dbf1110d70bab68a74b4b9d74f30e99b177cde3388e07cc7272f2168bd1477", + "sha256:3230d1003eec018ad4a472d254991e34241e0bbd513e97a29727c7c2f637bd2a", + "sha256:3dbb72eaeea5763676a1a1efd9b427a048c97c39ed92e13336e726117d0b72bf", + "sha256:5012d3b8d5a500834783689a5d2292fe06ec75dc86ee1ccdad04b6f5bf231691", + "sha256:51bc7710b13a2ae0c726f69756cf7ffd4362f4ac36546e243136187cfcc8aa73", + "sha256:527b4f316e6bf7755082a783726da20671a0cc388b786a64417780b90565b987", + "sha256:722e4557c8039aad9592c6a4213db75da08c2cd9945320220634f637251c3894", + "sha256:76e2057e8ffba5472fd28a3a010431fd9e928885ff480cb278877c6e9943cc2e", + "sha256:77afca04240c40450c331fa796b3eab6f1e15c5ecf8bf2b8bee9706cd5452fef", + "sha256:7afad9835e7a651d3551eab18cbc0fdb888f0a6136169fbef0662d9cdc9987cf", + "sha256:9bea19ac2f08672636350f203db89382121c9c2ade85d945953ef3c8cf9d2a68", + "sha256:a8b8ac7876bc3598e43e2603f772d2353d9931709345ad6c1149009fd1bc81b8", + "sha256:b0840b45187699affd4c6588286d429cd79a99d509fe3de0f209594669bb0954", + "sha256:b26aaf69713e5674efbde4d728fb7124e429c9466aeaf5f4a7e9e699b12c9fe2", + "sha256:b63dd43f455ba878e5e9f80ba4f748c0a2156dde6e0e6e690310e24d6e8caf40", + "sha256:be18f4ae5a9e46edae3f329de2191747966a34a3d93046dbdf897319923923bc", + "sha256:c312e57847db2526bc92b9bfa78266bfbaabac3fdcd751df4d062cd4c23e46dc", + "sha256:c60097190fe9dc2b329a0eb03393e2e0829156a589bd732e70794c0dd804258e", + "sha256:c62a2143e1313944bf4a5ab34fd3b4be15367a02e9478b0ce800cb510e3bbb9d", + "sha256:cc1109f54a14d940b8512ee9f1c3975c181bbb200306c6d8b87d93376538782f", + "sha256:cd60f507c125ac0ad83f05803063bed27e50fa903b9c2cfee3f8a6867ca600fc", + "sha256:d513cc3db248e566e07a0da99c230aca3556d9b09ed02f420664e2da97eac301", + "sha256:d649dc0bcace6fcdb446ae02b98798a856593b19b637c1b9af8edadf2b150bea", + "sha256:d7008a6796095a79544f4da1ee49418901961c97ca9e9d44904205ff7d6aa8cb", + "sha256:da93027835164b8223e8e5af2cf902a4c80ed93cb0909417234f4a9df3bcd9af", + "sha256:e69215621707119c6baf99bda014a45b999d37602cb7043d943c76a59b05bf52", + "sha256:ea9525e0fef2de9208250d6c5aeeee0138921057cd67fcef90fbed49c4d62d37", + "sha256:fca1669d464f0c9831fd10be2eef6b86f5ebd76c724d1e0706ebdff86bb4adf0" + ], + "version": "==5.0.3" }, "idna": { "hashes": [ @@ -223,10 +230,10 @@ }, "six": { "hashes": [ - "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", - "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66" + "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", + "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c" ], - "version": "==1.13.0" + "version": "==1.14.0" }, "urllib3": { "hashes": [ diff --git a/kosmorrolib/dumper.py b/kosmorrolib/dumper.py index c631408..92b3649 100644 --- a/kosmorrolib/dumper.py +++ b/kosmorrolib/dumper.py @@ -22,6 +22,7 @@ import json 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 _ @@ -31,10 +32,12 @@ TIME_FORMAT = _('{hours}:{minutes}').format(hours='%H', minutes='%M') class Dumper(ABC): - def __init__(self, ephemeris: dict, events: [Event], date: datetime.date = datetime.date.today()): + def __init__(self, ephemeris: dict, events: [Event], date: datetime.date = datetime.date.today(), + with_colors: bool = True): self.ephemeris = ephemeris self.events = events self.date = date + self.with_colors = with_colors @abstractmethod def to_string(self): @@ -80,35 +83,45 @@ class JsonDumper(Dumper): class TextDumper(Dumper): def to_string(self): - text = self.date.strftime(FULL_DATE_FORMAT) - # Always capitalize the first character - text = ''.join([text[0].upper(), text[1:]]) + text = [self.style(self.get_date(), 'h1')] if len(self.ephemeris['details']) > 0: - text = '\n\n'.join([text, - self.get_asters(self.ephemeris['details']) - ]) + text.append(self.get_asters(self.ephemeris['details'])) - text = '\n\n'.join([text, - self.get_moon(self.ephemeris['moon_phase']) - ]) + text.append(self.get_moon(self.ephemeris['moon_phase'])) if len(self.events) > 0: - text = '\n\n'.join([text, - _('Expected events:'), - self.get_events(self.events) - ]) + text.append('\n'.join([self.style(_('Expected events:'), 'h2'), + self.get_events(self.events)])) - text = '\n\n'.join([text, _('Note: All the hours are given in UTC.')]) + text.append(self.style(_('Note: All the hours are given in UTC.'), 'em')) - return text + return '\n\n'.join(text) - @staticmethod - def get_asters(asters: [Object]) -> str: + def style(self, text: str, tag: str) -> str: + if not self.with_colors: + return text + + styles = { + 'h1': lambda t: colored(t, 'yellow', attrs=['bold']), + 'h2': lambda t: colored(t, 'magenta', attrs=['bold']), + 'th': lambda t: colored(t, 'white', attrs=['bold']), + 'strong': lambda t: colored(t, attrs=['bold']), + 'em': lambda t: colored(t, attrs=['dark']) + } + + 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 = [] for aster in asters: - name = aster.name + name = self.style(aster.name, 'th') if aster.ephemerides.rise_time is not None: planet_rise = aster.ephemerides.rise_time.utc_strftime(TIME_FORMAT) @@ -127,23 +140,23 @@ class TextDumper(Dumper): data.append([name, planet_rise, planet_culmination, planet_set]) - return tabulate(data, headers=[_('Object'), _('Rise time'), _('Culmination time'), _('Set time')], + return tabulate(data, headers=[self.style(_('Object'), 'th'), + self.style(_('Rise time'), 'th'), + self.style(_('Culmination time'), 'th'), + self.style(_('Set time'), 'th')], tablefmt='simple', stralign='center', colalign=('left',)) - @staticmethod - def get_events(events: [Event]) -> str: + def get_events(self, events: [Event]) -> str: data = [] for event in events: - data.append([event.start_time.utc_strftime(TIME_FORMAT), event.get_description()]) + data.append([self.style(event.start_time.utc_strftime(TIME_FORMAT), 'th'), + event.get_description()]) return tabulate(data, tablefmt='plain', stralign='left') - @staticmethod - def get_moon(moon_phase: MoonPhase) -> str: - current_moon_phase = _('Moon phase: {current_moon_phase}').format( - current_moon_phase=moon_phase.get_phase() - ) + def get_moon(self, moon_phase: MoonPhase) -> str: + current_moon_phase = ' '.join([self.style(_('Moon phase:'), 'strong'), moon_phase.get_phase()]) new_moon_phase = _('{next_moon_phase} on {next_moon_phase_date} at {next_moon_phase_time}').format( next_moon_phase=moon_phase.get_next_phase(), next_moon_phase_date=moon_phase.next_phase_date.utc_strftime(FULL_DATE_FORMAT), diff --git a/kosmorrolib/locales/messages.pot b/kosmorrolib/locales/messages.pot index ceb68b1..db653cc 100644 --- a/kosmorrolib/locales/messages.pot +++ b/kosmorrolib/locales/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: kosmorro 0.4.0\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-01-02 14:05+0100\n" +"POT-Creation-Date: 2020-01-19 10:39+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -99,43 +99,43 @@ msgstr "" msgid "%s and %s are in conjunction" msgstr "" -#: kosmorrolib/dumper.py:28 +#: kosmorrolib/dumper.py:29 msgid "{day_of_week} {month} {day_number}, {year}" msgstr "" -#: kosmorrolib/dumper.py:30 +#: kosmorrolib/dumper.py:31 msgid "{hours}:{minutes}" msgstr "" -#: kosmorrolib/dumper.py:98 +#: kosmorrolib/dumper.py:94 msgid "Expected events:" msgstr "" -#: kosmorrolib/dumper.py:102 +#: kosmorrolib/dumper.py:97 msgid "Note: All the hours are given in UTC." msgstr "" -#: kosmorrolib/dumper.py:130 +#: kosmorrolib/dumper.py:143 msgid "Object" msgstr "" -#: kosmorrolib/dumper.py:130 +#: kosmorrolib/dumper.py:144 msgid "Rise time" msgstr "" -#: kosmorrolib/dumper.py:130 +#: kosmorrolib/dumper.py:145 msgid "Culmination time" msgstr "" -#: kosmorrolib/dumper.py:130 +#: kosmorrolib/dumper.py:146 msgid "Set time" msgstr "" -#: kosmorrolib/dumper.py:144 -msgid "Moon phase: {current_moon_phase}" +#: kosmorrolib/dumper.py:159 +msgid "Moon phase:" msgstr "" -#: kosmorrolib/dumper.py:147 +#: kosmorrolib/dumper.py:160 msgid "{next_moon_phase} on {next_moon_phase_date} at {next_moon_phase_time}" msgstr "" @@ -203,3 +203,7 @@ msgid "" "{default_year} (the current year)." msgstr "" +#: kosmorrolib/main.py:125 +msgid "Disable the colors in the console." +msgstr "" + diff --git a/kosmorrolib/main.py b/kosmorrolib/main.py index 2cd1d71..6f27447 100644 --- a/kosmorrolib/main.py +++ b/kosmorrolib/main.py @@ -57,7 +57,7 @@ def main(): events_list = events.search_events(compute_date) - dump = output_formats[args.format](ephemerides, events_list, compute_date) + dump = output_formats[args.format](ephemerides, events_list, compute_date, args.colors) print(dump.to_string()) return 0 @@ -121,5 +121,7 @@ def get_args(output_formats: [str]): parser.add_argument('--year', '-y', type=int, default=today.year, help=_('The year you want to compute the ephemerides for.' ' 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.')) return parser.parse_args() diff --git a/test/dumper.py b/test/dumper.py index 5e5cfc4..523d878 100644 --- a/test/dumper.py +++ b/test/dumper.py @@ -52,7 +52,7 @@ class DumperTestCase(unittest.TestCase): 'Moon phase: Full Moon\n' 'Last Quarter on Monday October 21, 2019 at 00:00\n\n' 'Note: All the hours are given in UTC.', - TextDumper(ephemerides, [], date=date(2019, 10, 14)).to_string()) + TextDumper(ephemerides, [], date=date(2019, 10, 14), with_colors=False).to_string()) def test_text_dumper_with_events(self): ephemerides = self._get_data() @@ -62,26 +62,26 @@ class DumperTestCase(unittest.TestCase): 'Mars - - -\n\n' 'Moon phase: Full Moon\n' 'Last Quarter on Monday October 21, 2019 at 00:00\n\n' - 'Expected events:\n\n' + '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)).to_string()) + ], 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) self.assertEqual('Monday October 14, 2019\n\n' 'Moon phase: Full Moon\n' 'Last Quarter on Monday October 21, 2019 at 00:00\n\n' - 'Expected events:\n\n' + '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)).to_string()) + ], date=date(2019, 10, 14), with_colors=False).to_string()) @staticmethod def _get_data(has_ephemerides: bool = True):