<commit_before>import asyncio
import tkinter
from functools import partial


BUTTONS = {
    'abortretryignore': ('abort retry ignore'.split(), 'abort'),
    'ok': ('ok'.split(), 'ok'),
    'okcancel': ('ok cancel'.split(), 'cancel'),
    'retrycancel': ('retry cancel'.split(), 'cancel'),
    'yesno': ('yes no'.split(), 'no'),
    'yesnocancel': ('yes no cancel'.split(), 'cancel'),
}


class Dialog(tkinter.Toplevel):
    # Based on http://effbot.org/tkinterbook/tkinter-dialog-windows.htm
    def __init__(self, loop, parent, title, message, buttons):
        super().__init__(parent, {'class': 'Dialog'})
        self.wm_attributes('-type', 'dialog')
        self.transient(parent)
        self.title(title)
        self.parent = parent
        self.result = None
        body = tkinter.Frame(self)
        self.initial_focus = self.body(body, message)
        body.pack(side='top', fill='both', expand=1)
        self.buttonbox(buttons)
        self.grab_set()
        if not self.initial_focus:
            self.initial_focus = self
        self.protocol("WM_DELETE_WINDOW", self.wm_delete)

        # TODO we could also implement tk.tcl PlaceWindow...
        self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
                                  parent.winfo_rooty()+50))

        self.initial_focus.focus_set()
        self.result = asyncio.Future(loop=loop)

    def body(self, master, message, detail=None):
        bitmap = tkinter.Label(master, image='::tk::icons::question')
        bitmap.grid(row=0, column=0, sticky='nw', padx='2m', pady='2m')
        msg = tkinter.Label(master, text=message, font='TkCaptionFont',
                            anchor='nw', justify='left')
        msg.grid(row=0, column=1, sticky='news', padx='2m', pady='2m')
        master.columnconfigure(1, weight=1)
        if detail is not None:
            dtl = tkinter.Label(master, text=detail,
                                anchor='nw', justify='left')
            dtl.grid(sticky='news', padx='2m', pady=[0, '2m'])
            master.rowconfigure(1, weight=1)
        else:
            master.rowconfigure(0, weight=1)

    def buttonbox(self, button_spec):
        if isinstance(button_spec, str):
            names, self.cancel_button = BUTTONS[button_spec]
        else:
            names, self.cancel_button = button_spec
        self.ok_button = names[0]
        box = tkinter.Frame(self)
        buttons = []

        for i, name in enumerate(names):
            label = name[0].upper() + name[1:]
            default = i == 0
            kwargs = {'default': tkinter.ACTIVE if default else tkinter.NORMAL}
            buttons.append(
                tkinter.Button(box, text=label,
                               command=partial(self.command, name),
                               **kwargs))
            # buttons[-1].pack(side=tkinter.LEFT, padx=3, pady=2)
            buttons[-1].grid(row=0, column=i, padx='3m', pady='2m', sticky='ew')
            box.columnconfigure(i, uniform='buttons')

        self.bind("<Return>", self.key_return)
        self.bind("<Escape>", self.cancel)

        box.pack(side='bottom', fill='both')
        box.anchor(tkinter.CENTER)

    def wm_delete(self):
        self.set_result(None)

    def key_return(self, ev):
        self.command(self.ok_button)

    def cancel(self, ev):
        self.set_result(None)

    def set_result(self, value):
        self.withdraw()
        self.update_idletasks()
        self.parent.focus_set()
        self.destroy()
        self.result.set_result(value)

    def command(self, name, *args):
        try:
            method = getattr(self, 'button_' + name)
        except AttributeError:
            self.set_result(name)
        else:
            method()

    def __await__(self):
        return self.result.__await__()


async def askyesno(title, message, parent, loop):
    result = await Dialog(loop, parent, title, message, 'yesno')<commit_msg>Call set_result outside of try-except to remove AttributeError from traceback<commit_after>import asyncio
import tkinter
from functools import partial


BUTTONS = {
    'abortretryignore': ('abort retry ignore'.split(), 'abort'),
    'ok': ('ok'.split(), 'ok'),
    'okcancel': ('ok cancel'.split(), 'cancel'),
    'retrycancel': ('retry cancel'.split(), 'cancel'),
    'yesno': ('yes no'.split(), 'no'),
    'yesnocancel': ('yes no cancel'.split(), 'cancel'),
}


class Dialog(tkinter.Toplevel):
    # Based on http://effbot.org/tkinterbook/tkinter-dialog-windows.htm
    def __init__(self, loop, parent, title, message, buttons):
        super().__init__(parent, {'class': 'Dialog'})
        self.wm_attributes('-type', 'dialog')
        self.transient(parent)
        self.title(title)
        self.parent = parent
        self.result = None
        body = tkinter.Frame(self)
        self.initial_focus = self.body(body, message)
        body.pack(side='top', fill='both', expand=1)
        self.buttonbox(buttons)
        self.grab_set()
        if not self.initial_focus:
            self.initial_focus = self
        self.protocol("WM_DELETE_WINDOW", self.wm_delete)

        # TODO we could also implement tk.tcl PlaceWindow...
        self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
                                  parent.winfo_rooty()+50))

        self.initial_focus.focus_set()
        self.result = asyncio.Future(loop=loop)

    def body(self, master, message, detail=None):
        bitmap = tkinter.Label(master, image='::tk::icons::question')
        bitmap.grid(row=0, column=0, sticky='nw', padx='2m', pady='2m')
        msg = tkinter.Label(master, text=message, font='TkCaptionFont',
                            anchor='nw', justify='left')
        msg.grid(row=0, column=1, sticky='news', padx='2m', pady='2m')
        master.columnconfigure(1, weight=1)
        if detail is not None:
            dtl = tkinter.Label(master, text=detail,
                                anchor='nw', justify='left')
            dtl.grid(sticky='news', padx='2m', pady=[0, '2m'])
            master.rowconfigure(1, weight=1)
        else:
            master.rowconfigure(0, weight=1)

    def buttonbox(self, button_spec):
        if isinstance(button_spec, str):
            names, self.cancel_button = BUTTONS[button_spec]
        else:
            names, self.cancel_button = button_spec
        self.ok_button = names[0]
        box = tkinter.Frame(self)
        buttons = []

        for i, name in enumerate(names):
            label = name[0].upper() + name[1:]
            default = i == 0
            kwargs = {'default': tkinter.ACTIVE if default else tkinter.NORMAL}
            buttons.append(
                tkinter.Button(box, text=label,
                               command=partial(self.command, name),
                               **kwargs))
            # buttons[-1].pack(side=tkinter.LEFT, padx=3, pady=2)
            buttons[-1].grid(row=0, column=i, padx='3m', pady='2m', sticky='ew')
            box.columnconfigure(i, uniform='buttons')

        self.bind("<Return>", self.key_return)
        self.bind("<Escape>", self.cancel)

        box.pack(side='bottom', fill='both')
        box.anchor(tkinter.CENTER)

    def wm_delete(self):
        self.set_result(None)

    def key_return(self, ev):
        self.command(self.ok_button)

    def cancel(self, ev):
        self.set_result(None)

    def set_result(self, value):
        self.withdraw()
        self.update_idletasks()
        self.parent.focus_set()
        self.destroy()
        self.result.set_result(value)

    def command(self, name, *args):
        try:
            method = getattr(self, 'button_' + name)
        except AttributeError:
            pass
        else:
            return method()
        self.set_result(name)

    def __await__(self):
        return self.result.__await__()


async def askyesno(title, message, parent, loop):
    result = await Dialog(loop, parent, title, message, 'yesno')
{'fraction_non_alphanumeric': 0.14366658272475447, 'fraction_numerical': 0.008310249307479225, 'mean_word_length': 2.308204914618909, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '192740', 'n_tokens_mistral': 2466, 'n_tokens_neox': 2425, 'n_words': 492}