From 8f1ca03d15b4f5edd999a59bcb70828339ce4654 Mon Sep 17 00:00:00 2001 From: Bjorn Pettersen Date: Sun, 12 Feb 2023 18:16:41 +0100 Subject: [PATCH 1/4] Format excessively long help text in jobs, and use rich to output tables of `runjob -l`. --- .../management/commands/runjob.py | 2 +- django_extensions/management/jobs.py | 46 +++++++++++-------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/django_extensions/management/commands/runjob.py b/django_extensions/management/commands/runjob.py index cf1163ec4..cf986892e 100644 --- a/django_extensions/management/commands/runjob.py +++ b/django_extensions/management/commands/runjob.py @@ -53,6 +53,6 @@ def handle(self, *args, **options): setup_logger(logger, self.stdout) if options['list_jobs']: - print_jobs(only_scheduled=False, show_when=True, show_appname=True) + print_jobs(only_scheduled=False, show_when=True, show_appname=True, verbose=options['verbosity'] >= 2) else: self.runjob(app_name, job_name, options) diff --git a/django_extensions/management/jobs.py b/django_extensions/management/jobs.py index e13a4f2ec..573411998 100644 --- a/django_extensions/management/jobs.py +++ b/django_extensions/management/jobs.py @@ -2,8 +2,11 @@ import os import sys import importlib +import textwrap from typing import Optional # NOQA from django.apps import apps +from rich.console import Console +from rich.table import Table, Column _jobs = None @@ -147,34 +150,41 @@ def get_job(app_name, job_name): raise KeyError("Job not found: %s" % job_name) -def print_jobs(when=None, only_scheduled=False, show_when=True, show_appname=False, show_header=True): +def format_help_text(txt: str, digest: bool=False, maxwidth: int=80) -> str: + """Return the help text properly formatted.""" + if digest: + return textwrap.shorten(txt, maxwidth) + paragraphs = txt.split('\n\n') + return '\n\n'.join(textwrap.fill(textwrap.dedent(p), width=maxwidth) for p in paragraphs) + + +def print_jobs(when=None, only_scheduled=False, show_when=True, show_appname=False, show_header=True, verbose=False): + console = Console() + jobmap = get_jobs(when, only_scheduled=only_scheduled) - print("Job List: %i jobs" % len(jobmap)) + console.print("Job List: %i jobs" % len(jobmap)) jlist = sorted(jobmap.keys()) if not jlist: return - appname_spacer = "%%-%is" % max(len(e[0]) for e in jlist) - name_spacer = "%%-%is" % max(len(e[1]) for e in jlist) - when_spacer = "%%-%is" % max(len(e.when) for e in jobmap.values() if e.when) + table = Table() + if show_header: - line = " " if show_appname: - line += appname_spacer % "appname" + " - " - line += name_spacer % "jobname" + table.add_column('appname') + table.add_column('jobname') if show_when: - line += " - " + when_spacer % "when" - line += " - help" - print(line) - print("-" * 80) + table.add_column('when') + table.add_column('help') for app_name, job_name in jlist: job = jobmap[(app_name, job_name)] - line = " " + row = [] if show_appname: - line += appname_spacer % app_name + " - " - line += name_spacer % job_name + row.append(app_name) + row.append(job_name) if show_when: - line += " - " + when_spacer % (job.when and job.when or "") - line += " - " + job.help - print(line) + row.append(job.when and job.when or "") + row.append(format_help_text(job.help, digest=not verbose)) + table.add_row(*row) + console.print(table) From d4497190659d49a76a54e4eba59f012cd6237216 Mon Sep 17 00:00:00 2001 From: Bjorn Pettersen Date: Sun, 12 Feb 2023 18:42:18 +0100 Subject: [PATCH 2/4] Fix tests. --- setup.py | 5 ++++- tests/management/commands/test_runjob.py | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 917433e33..690c02438 100644 --- a/setup.py +++ b/setup.py @@ -107,7 +107,10 @@ def fullsplit(path, result=None): cmdclass=cmdclasses, package_data=package_data, python_requires=">=3.6", - install_requires=["Django>=3.2"], + install_requires=[ + "Django>=3.2", + "rich" + ], extras_require={}, classifiers=[ 'Development Status :: 5 - Production/Stable', diff --git a/tests/management/commands/test_runjob.py b/tests/management/commands/test_runjob.py index 22d68ca64..1003f6e38 100644 --- a/tests/management/commands/test_runjob.py +++ b/tests/management/commands/test_runjob.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import logging import sys +stdout = sys.stdout from io import StringIO from django.core.management import call_command @@ -32,7 +33,7 @@ def test_sample_job(self): def test_list_jobs(self): call_command('runjob', '-l', verbosity=2) - self.assertRegex(sys.stdout.getvalue(), "tests.testapp +- sample_job +- +- My sample job.\n") + self.assertRegex(sys.stdout.getvalue(), r"tests.testapp[^\w]+sample_job[^\w]+My sample job.") def test_list_jobs_appconfig(self): with self.modify_settings(INSTALLED_APPS={ @@ -40,7 +41,7 @@ def test_list_jobs_appconfig(self): 'remove': 'tests.testapp', }): call_command('runjob', '-l', verbosity=2) - self.assertRegex(sys.stdout.getvalue(), "tests.testapp +- sample_job +- +- My sample job.\n") + self.assertRegex(sys.stdout.getvalue(), r"tests.testapp[^\w]+sample_job[^\w]+My sample job.") def test_runs_appconfig(self): with self.modify_settings(INSTALLED_APPS={ From f079c3d4e78434f81a3f45a3f4663787281d0659 Mon Sep 17 00:00:00 2001 From: Bjorn Pettersen Date: Sun, 12 Feb 2023 19:05:03 +0100 Subject: [PATCH 3/4] Let rich handle the line wrapping. --- django_extensions/management/jobs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/django_extensions/management/jobs.py b/django_extensions/management/jobs.py index 573411998..0e2f437ce 100644 --- a/django_extensions/management/jobs.py +++ b/django_extensions/management/jobs.py @@ -152,10 +152,10 @@ def get_job(app_name, job_name): def format_help_text(txt: str, digest: bool=False, maxwidth: int=80) -> str: """Return the help text properly formatted.""" - if digest: - return textwrap.shorten(txt, maxwidth) paragraphs = txt.split('\n\n') - return '\n\n'.join(textwrap.fill(textwrap.dedent(p), width=maxwidth) for p in paragraphs) + if digest: + return textwrap.shorten(paragraphs[0], maxwidth) + return '\n\n'.join(textwrap.dedent(p).replace('\n', ' ') for p in paragraphs) def print_jobs(when=None, only_scheduled=False, show_when=True, show_appname=False, show_header=True, verbose=False): From 9d5f0d9077ec16b6de47f84fb799497b6af3cac9 Mon Sep 17 00:00:00 2001 From: Bjorn Pettersen Date: Sun, 12 Feb 2023 19:09:16 +0100 Subject: [PATCH 4/4] Remove debugging line. --- tests/management/commands/test_runjob.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/management/commands/test_runjob.py b/tests/management/commands/test_runjob.py index 1003f6e38..23ad135f8 100644 --- a/tests/management/commands/test_runjob.py +++ b/tests/management/commands/test_runjob.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import logging import sys -stdout = sys.stdout from io import StringIO from django.core.management import call_command