<commit_before>import os
import tkinter
import functools
import threading

from aiotkinter.loop import TkinterEventLoopPolicy


def run_in_thread(function, max_ignored=1):
    tkinter.NoDefaultRoot()

    quit_r, quit_w = os.pipe()

    ignored = 0
    keyboard_interrupt = None

    def sigint_handler(loop, cb=None):
        def quit_readable():
            os.read(quit_r, 1)
            if cb is None:
                raise KeyboardInterrupt() from keyboard_interrupt
            cb()

        loop.add_reader(quit_r, quit_readable)

    uncaught_exception = None

    def wrapper():
        try:
            function(sigint_handler)
        except Exception as exn:
            nonlocal uncaught_exception
            uncaught_exception = exn
        # Run GC collection to ensure that tkinter objects are collected in
        # this thread and not the main thread.
        try:
            import gc
            gc.collect()
        except ImportError:
            pass

    # Set daemon=True to let the interpreter kill an un-cooperative thread
    thread = threading.Thread(None, wrapper, daemon=True)
    thread.start()
    while True:
        try:
            thread.join()
            break
        except KeyboardInterrupt as exn:
            if keyboard_interrupt is not None:
                ignored += 1
                if max_ignored and ignored >= max_ignored:
                    raise
            keyboard_interrupt = exn
            os.write(quit_w, b'x')
    if uncaught_exception is not None:
        raise uncaught_exception


def threaded_sigint_wrapper(fn):
    return lambda: run_in_thread(fn)


def wrapper(fn):
    @functools.wraps(fn)
    @threaded_sigint_wrapper
    def wrapped(sigint_handler):
        loop = TkinterEventLoopPolicy().new_event_loop()
        root = fn(loop)  # type: tkinter.Tk
        sigint_handler(loop, loop.stop)
        loop.run_forever()
        root.destroy()

    return wrapped
<commit_msg>Always call destroy and catch errors in destroy<commit_after>import os
import tkinter
import functools
import threading

from aiotkinter.loop import TkinterEventLoopPolicy


def run_in_thread(function, max_ignored=1):
    tkinter.NoDefaultRoot()

    quit_r, quit_w = os.pipe()

    ignored = 0
    keyboard_interrupt = None

    def sigint_handler(loop, cb=None):
        def quit_readable():
            os.read(quit_r, 1)
            if cb is None:
                raise KeyboardInterrupt() from keyboard_interrupt
            cb()

        loop.add_reader(quit_r, quit_readable)

    uncaught_exception = None

    def wrapper():
        try:
            function(sigint_handler)
        except Exception as exn:
            nonlocal uncaught_exception
            uncaught_exception = exn
        # Run GC collection to ensure that tkinter objects are collected in
        # this thread and not the main thread.
        try:
            import gc
            gc.collect()
        except ImportError:
            pass

    # Set daemon=True to let the interpreter kill an un-cooperative thread
    thread = threading.Thread(None, wrapper, daemon=True)
    thread.start()
    while True:
        try:
            thread.join()
            break
        except KeyboardInterrupt as exn:
            if keyboard_interrupt is not None:
                ignored += 1
                if max_ignored and ignored >= max_ignored:
                    raise
            keyboard_interrupt = exn
            os.write(quit_w, b'x')
    if uncaught_exception is not None:
        raise uncaught_exception


def threaded_sigint_wrapper(fn):
    return lambda: run_in_thread(fn)


def wrapper(fn):
    @functools.wraps(fn)
    @threaded_sigint_wrapper
    def wrapped(sigint_handler):
        loop = TkinterEventLoopPolicy().new_event_loop()
        root = fn(loop)  # type: tkinter.Tk
        sigint_handler(loop, loop.stop)
        try:
            loop.run_forever()
        finally:
            try:
                root.destroy()
            except tkinter.TclError:
                # Already destroyed?
                pass

    return wrapped

{'fraction_non_alphanumeric': 0.06485560450318159, 'fraction_numerical': 0.0019579050416054823, 'mean_word_length': 1.9919472913616398, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '6776915', 'n_tokens_mistral': 1189, 'n_tokens_neox': 1138, 'n_words': 317}