<commit_before>import re
import typing
from datetime import timedelta

from knowit.property import Property


class Duration(Property[timedelta]):
    """Duration property."""

    duration_re = re.compile(r'(?P<hours>\d{1,2}):'
                             r'(?P<minutes>\d{1,2}):'
                             r'(?P<seconds>\d{1,2})(?:\.'
                             r'(?P<millis>\d{3})'
                             r'(?P<micro>\d{3})?\d*)?')

    def __init__(self, name: str, resolution: float = 1, *args, **kwargs):
        """Initialize a Duration."""
        super().__init__(name, *args, **kwargs)
        self.resolution = resolution

    def handle(self, value, context: typing.MutableMapping):
        """Return duration as timedelta."""
        if isinstance(value, timedelta):
            return value
        elif isinstance(value, int):
            return timedelta(microseconds=value * self.resolution)
        try:
            return timedelta(microseconds=int(float(value) * self.resolution))
        except ValueError:
            pass

        try:
            h, m, s, ms, mc = self.duration_re.match(value).groups('0')
            return timedelta(hours=int(h), minutes=int(m), seconds=int(s), milliseconds=int(ms), microseconds=int(mc))
        except ValueError:
            pass

        self.report(value, context)<commit_msg>Refactor duration handling<commit_after>import re
import typing
from datetime import timedelta

from knowit.property import Property


class Duration(Property[timedelta]):
    """Duration property."""

    duration_re = re.compile(r'(?P<hours>\d{1,2}):'
                             r'(?P<minutes>\d{1,2}):'
                             r'(?P<seconds>\d{1,2})(?:\.'
                             r'(?P<milliseconds>\d{3})'
                             r'(?P<microseconds>\d{3})?\d*)?')

    def __init__(self, name: str, resolution: float = 1, *args, **kwargs):
        """Initialize a Duration."""
        super().__init__(name, *args, **kwargs)
        self.resolution = resolution

    def handle(self, value, context: typing.MutableMapping):
        """Return duration as timedelta."""
        if isinstance(value, timedelta):
            return value
        elif isinstance(value, int):
            return timedelta(microseconds=value * self.resolution)
        try:
            return timedelta(microseconds=int(float(value) * self.resolution))
        except ValueError:
            pass

        match = self.duration_re.match(value)
        if not match:
            self.report(value, context)
            return None

        params = {
            key: int(value)
            for key, value in match.groupdict().items()
            if value
        }
        return timedelta(**params)
{'fraction_non_alphanumeric': 0.13740458015267176, 'fraction_numerical': 0.0069065794256633955, 'mean_word_length': 2.0714285714285716, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, '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': '2108684', 'n_tokens_mistral': 802, 'n_tokens_neox': 752, 'n_words': 172}