<commit_before>from abc import abstractmethod

from django.core.management.base import BaseCommand


class TaskCommand(BaseCommand):
    def start_progress(self, *args, **options):
        # TODO: needs implementation
        pass

    def update_progress(self, *args, **options):
        # TODO: needs implementation
        pass

    @abstractmethod
    def handle_async(self, *args, **options):
        pass<commit_msg>Add a progress tracker to the async task command<commit_after>from abc import abstractmethod
from collections import namedtuple

from django.core.management.base import BaseCommand
from django.core.management.base import CommandError

Progress = namedtuple(
    'Progress',
    [
        'progress',
        'total',
        'fraction',
    ]
)


class TaskCommand(BaseCommand):
    def handle(self, *args, **options):
        self.progresstracker = None
        return self.handle_async(*args, **options)

    def start_progress(self, total):
        self.progresstracker = Progress(progress=0, total=total, fraction=0)

    def update_progress(self, increment):
        tracker = self.progresstracker
        progress = tracker.progress + increment
        if progress > tracker.total:
            raise CommandError("Progress reaches over 100%.")

        fraction = 1.0 * progress / tracker.total
        updated_tracker = tracker._replace(progress=progress, fraction=fraction)
        self.progresstracker = updated_tracker

    @abstractmethod
    def handle_async(self, *args, **options):
        pass
{'fraction_non_alphanumeric': 0.09019607843137255, 'fraction_numerical': 0.004575163398692811, 'mean_word_length': 3.1945205479452055, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6124347', 'n_tokens_mistral': 415, 'n_tokens_neox': 397, 'n_words': 110}