<commit_before># pylint: disable=function-redefined
from __future__ import unicode_literals

from prompt_toolkit.enums import DEFAULT_BUFFER
from prompt_toolkit.filters import CLIFilter, Always, HasSelection, Condition
from prompt_toolkit.keys import Keys
from prompt_toolkit.layout.screen import Point
from prompt_toolkit.mouse_events import MouseEventTypes, MouseEvent
from prompt_toolkit.renderer import HeightIsUnknownError
from prompt_toolkit.utils import suspend_to_background_supported, is_windows

from .utils import create_handle_decorator

__all__ = (
    'load_basic_bindings',
    'load_abort_and_exit_bindings',
    'load_basic_system_bindings',
    'load_auto_suggestion_bindings',
)

def if_no_repeat(event):
    """ Callable that returns True when the previous event was delivered to
    another handler. """
    return not event.is_repeat

def load_basic_bindings(registry, filter=Always()):
    assert isinstance(filter, CLIFilter)

    handle = create_handle_decorator(registry, filter)
    has_selection = HasSelection()

    @handle(Keys.ControlA)
    @handle(Keys.ControlB)
    @handle(Keys.ControlC)
    @handle(Keys.ControlD)
    @handle(Keys.ControlE)
    @handle(Keys.ControlF)
    @handle(Keys.ControlG)
    @handle(Keys.ControlH)
    @handle(Keys.ControlI)
    @handle(Keys.ControlJ)
    @handle(Keys.ControlK)
    @handle(Keys.ControlL)
    @handle(Keys.ControlM)
    @handle(Keys.ControlN)
    @handle(Keys.ControlO)
    @handle(Keys.ControlP)
    @handle(Keys.ControlQ)
    @handle(Keys.ControlR)
    @handle(Keys.ControlS)
    @handle(Keys.ControlT)
    @handle(Keys.ControlU)
    @handle(Keys.ControlV)
    @handle(Keys.ControlW)
    @handle(Keys.ControlX)
    @handle(Keys.ControlY)
    @handle(Keys.ControlZ)
    @handle(Keys.F1)
    @handle(Keys.F2)
    @handle(Keys.F3)
    @handle(Keys.F4)
    @handle(Keys.F5)
    @handle(Keys.F6)
    @handle(Keys.F7)
    @handle(Keys.F8)
    @handle(Keys.F9)
    @handle(Keys.F10)
    @handle(Keys.F11)
    @handle(Keys.F12)
    @handle(Keys.F13)
    @handle(Keys.F14)
    @handle(Keys.F15)
    @handle(Keys.F16)
    @handle(Keys.F17)
    @handle(Keys.F18)
    @handle(Keys.F19)
    @handle(Keys.F20)
    @handle(Keys.ControlSpace)
    @handle(Keys.ControlBackslash)
    @handle(Keys.ControlSquareClose)
    @handle(Keys.ControlCircumflex)
    @handle(Keys.ControlUnderscore)
    @handle(Keys.Backspace)
    @handle(Keys.Up)
    @handle(Keys.Down)
    @handle(Keys.Right)
    @handle(Keys.Left)
    @handle(Keys.Home)
    @handle(Keys.End)
    @handle(Keys.Delete)
    @handle(Keys.ShiftDelete)
    @handle(Keys.PageUp)
    @handle(Keys.PageDown)
    @handle(Keys.BackTab)
    @handle(Keys.Tab)
    @handle(Keys.ControlLeft)
    @handle(Keys.ControlRight)
    @handle(Keys.ControlUp)
    @handle(Keys.ControlDown)
    @handle(Keys.Insert)
    def _(event):
        """
        First, for any of these keys, Don't do anything by default. Also don't
        catch them in the 'Any' handler which will insert them as data.

        If people want to insert these characters as a literal, they can always
        do by doing a quoted insert. (ControlQ in emacs mode, ControlV in Vi
        mode.)
        """
        pass

    @handle(Keys.Home)
    def _(event):
        b = event.current_buffer
        b.cursor_position += b.document.get_start_of_line_position()

    @handle(Keys.End)
    def _(event):
        b = event.current_buffer
        b.cursor_position += b.document.get_end_of_line_position()

    # CTRL keys.

    @handle(Keys.ControlD, filter=Condition(lambda cli: cli.current_buffer.text))
    def _(event):
        """
        Delete text before cursor.
        """
        event.current_buffer.delete(event.arg)

    @handle(Keys.ControlI, filter= ~has_selection)
    def _(event):
        r"""
        Ctrl-I is identical to "\t"

        Traditional tab-completion, where the first tab completes the common
        suffix and the second tab lists all the completions.
        """
        b = event.current_buffer

        def second_tab():
            if b.complete_state:
                b.complete_next()
            else:
                event.cli.start_completion(select_first=True)

        # On the second tab-press, or when already navigating through
        # completions.
        if event.is_repeat or b.complete_state:
            second_tab()
        else:
            event.cli.start_completion(insert_common_part=True)

    @handle(Keys.BackTab, filter= ~has_selection)
    def _(event):
        """
        Shift+Tab: go to previous completion.
        """
        event.current_buffer.complete_previous()

    @handle(Keys.ControlJ, filter= ~has_selection)
    def _(event):
        """
        Newline/Enter. (Or return input.)
        """
        b = event.current_buffer

        if b.is_multiline():
            b.newline(copy_margin=not event.cli.in_paste_mode)
        else:
            if b.accept_action.is_returnable:
                b.accept_action.validate_and_handle(event.cli, b)

    @handle(Keys.ControlK, filter= ~has_selection)
    def _(event):
        buffer = event.current_buffer
        deleted = buffer.delete(count=buffer.document.get_end_of_line_position())
        event.cli.clipboard.set_text(deleted)

    @handle(Keys.ControlT, filter= ~has_selection)
    def _(event):
        """
        Emulate Emacs transpose-char behavior: at the beginning of the buffer,
        do nothing.  At the end of a line or buffer, swap the characters before
        the cursor.  Otherwise, move the cursor right, and then swap the
        characters before the cursor.
        """
        b = event.current_buffer
        p = b.cursor_position
        if p == 0:
            return
        elif p == len(b.text) or b.text[p] == '\n':
            b.swap_characters_before_cursor()
        else:
            b.cursor_position += b.document.get_cursor_right_position()
            b.swap_characters_before_cursor()

    @handle(Keys.ControlU, filter= ~has_selection)
    def _(event):
        """
        Clears the line before the cursor position. If you are at the end of
        the line, clears the entire line.
        """
        buffer = event.current_buffer
        deleted = buffer.delete_before_cursor(count=-buffer.document.get_start_of_line_position())
        event.cli.clipboard.set_text(deleted)

    @handle(Keys.ControlW, filter= ~has_selection)
    def _(event):
        """
        Delete the word before the cursor.
        """
        buffer = event.current_buffer
        pos = buffer.document.find_start_of_previous_word(count=event.arg)

        if pos is None:
            # Nothing found? delete until the start of the document.  (The
            # input starts with whitespace and no words were found before the
            # cursor.)
            pos = - buffer.cursor_position

        if pos:
            deleted = buffer.delete_before_cursor(count=-pos)

            # If the previous key press was also Control-W, concatenate deleted
            # text.
            if event.is_repeat:
                deleted += event.cli.clipboard.get_data().text

            event.cli.clipboard.set_text(deleted)

    @handle(Keys.PageUp, filter= ~has_selection)
    def _(event):
        event.current_buffer.history_backward()

    @handle(Keys.PageDown, filter= ~has_selection)
    def _(event):
        event.current_buffer.history_forward()

    @handle(Keys.Left)
    def _(event):
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.get_cursor_left_position(count=event.arg)

    @handle(Keys.Right)
    def _(event):
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.get_cursor_right_position(count=event.arg)

    @handle(Keys.Up, filter= ~has_selection)
    def _(event):
        event.current_buffer.auto_up(count=event.arg)

    @handle(Keys.Up, filter=has_selection)
    def _(event):
        event.current_buffer.cursor_up(count=event.arg)

    @handle(Keys.Down, filter= ~has_selection)
    def _(event):
        event.current_buffer.auto_down(count=event.arg)

    @handle(Keys.Down, filter=has_selection)
    def _(event):
        event.current_buffer.cursor_down(count=event.arg)

    @handle(Keys.ControlH, filter= ~has_selection, save_before=if_no_repeat)
    def _(event):
        " Backspace: delete before cursor. "
        event.current_buffer.delete_before_cursor(count=event.arg)

    @handle(Keys.Delete, filter= ~has_selection, save_before=if_no_repeat)
    @handle(Keys.ShiftDelete, filter= ~has_selection, save_before=if_no_repeat)
    def _(event):
        event.current_buffer.delete(count=event.arg)

    @handle(Keys.Delete, filter=has_selection)
    def _(event):
        data = event.current_buffer.cut_selection()
        event.cli.clipboard.set_data(data)

    @handle(Keys.Any, filter= ~has_selection, save_before=if_no_repeat)
    def _(event):
        """
        Insert data at cursor position.
        """
        event.current_buffer.insert_text(event.data * event.arg)

    # Global bindings. These are never disabled and don't include the default filter.

    @handle(Keys.ControlL)
    def _(event):
        " Clear whole screen and redraw. "
        event.cli.renderer.clear()

    @handle(Keys.ControlZ)
    def _(event):
        """
        By default, control-Z should literally insert Ctrl-Z.
        (Ansi Ctrl-Z, code 26 in MSDOS means End-Of-File.
        In a Python REPL for instance, it's possible to type
        Control-Z followed by enter to quit.)

        When the system bindings are loaded and suspend-to-background is
        supported, that will override this binding.
        """
        event.current_buffer.insert_text(event.data)

    @registry.add_binding(Keys.CPRResponse)
    def _(event):
        """
        Handle incoming Cursor-Position-Request response.
        """
        # The incoming data looks like u'\x1b[35;1R'
        # Parse row/col information.
        row, col = map(int, event.data[2:-1].split(';'))

        # Report absolute cursor position to the renderer.
        event.cli.renderer.report_absolute_cursor_row(row)

    @registry.add_binding(Keys.Vt100MouseEvent)
    def _(event):
        """
        Handling of incoming mouse event.
        """
        # Typical:   "Esc[MaB*"
        # Urxvt:     "Esc[96;14;13M"
        # Xterm SGR: "Esc[<64;85;12M"

        # Parse incoming packet.
        if event.data[2] == 'M':
            # Typical.
            mouse_event, x, y = map(ord, event.data[3:])
            mouse_event = {
                32: MouseEventTypes.MOUSE_DOWN,
                35: MouseEventTypes.MOUSE_UP,
                96: MouseEventTypes.SCROLL_UP,
                97: MouseEventTypes.SCROLL_DOWN,
            }.get(mouse_event)
            x -= 32
            y -= 32
        else:
            # Urxvt and Xterm SGR.
            # When the '<' is not present, we are not using the Xterm SGR mode,
            # but Urxvt instead.
            data = event.data[2:]
            if data[:1] == '<':
                sgr = True
                data = data[1:]
            else:
                sgr = False

            # Extract coordinates.
            mouse_event, x, y = map(int, data[:-1].split(';'))
            m = data[-1]

            # Parse event type.
            if sgr:
                mouse_event = {
                    (0, 'M'): MouseEventTypes.MOUSE_DOWN,
                    (0, 'm'): MouseEventTypes.MOUSE_UP,
                    (64, 'M'): MouseEventTypes.SCROLL_UP,
                    (65, 'M'): MouseEventTypes.SCROLL_DOWN,
                }.get((mouse_event, m))
            else:
                mouse_event = {
                    32: MouseEventTypes.MOUSE_DOWN,
                    35: MouseEventTypes.MOUSE_UP,
                    96: MouseEventTypes.SCROLL_UP,
                    97: MouseEventTypes.SCROLL_DOWN,
                    }.get(mouse_event)

        x -= 1
        y -= 1

        # Only handle mouse events when we know the window height.
        if event.cli.renderer.height_is_known:
            # Take region above the layout into account. The reported
            # coordinates are absolute to the visible part of the terminal.
            try:
                y -= event.cli.renderer.rows_above_layout
            except HeightIsUnknownError:
                return

            # Call the mouse handler from the renderer.
            handler = event.cli.renderer.mouse_handlers.mouse_handlers[x,y]
            handler(event.cli, MouseEvent(position=Point(x=x, y=y),
                                          event_type=mouse_event))

    @registry.add_binding(Keys.WindowsMouseEvent)
    def _(event):
        """
        Handling of mouse events for Windows.
        """
        assert is_windows()  # This key binding should only exist for Windows.

        # Parse data.
        event_type, x, y = event.data.split(';')
        x = int(x)
        y = int(y)

        # Make coordinates absolute to the visible part of the terminal.
        screen_buffer_info = event.cli.renderer.output.get_win32_screen_buffer_info()
        rows_above_cursor = screen_buffer_info.dwCursorPosition.Y - event.cli.renderer._cursor_pos.y
        y -= rows_above_cursor

        # Call the mouse event handler.
        handler = event.cli.renderer.mouse_handlers.mouse_handlers[x,y]
        handler(event.cli, MouseEvent(position=Point(x=x, y=y),
                                      event_type=event_type))

def load_abort_and_exit_bindings(registry, filter=Always()):
    """
    Basic bindings for abort (Ctrl-C) and exit (Ctrl-D).
    """
    assert isinstance(filter, CLIFilter)
    handle = create_handle_decorator(registry, filter)

    @handle(Keys.ControlC)
    def _(event):
        " Abort when Control-C has been pressed. "
        event.cli.set_abort()

    @Condition
    def ctrl_d_condition(cli):
        """ Ctrl-D binding is only active when the default buffer is selected
        and empty. """
        return (cli.current_buffer_name == DEFAULT_BUFFER and
                not cli.current_buffer.text)

    @handle(Keys.ControlD, filter=ctrl_d_condition)
    def _(event):
        " Exit on Control-D when the input is empty. "
        event.cli.set_exit()

def load_basic_system_bindings(registry, filter=Always()):
    """
    Basic system bindings (For both Emacs and Vi mode.)
    """
    assert isinstance(filter, CLIFilter)
    handle = create_handle_decorator(registry, filter)

    suspend_supported = Condition(
        lambda cli: suspend_to_background_supported())

    @handle(Keys.ControlZ, filter=suspend_supported)
    def _(event):
        """
        Suspend process to background.
        """
        event.cli.suspend_to_background()

def load_auto_suggestion_bindings(registry, filter=Always()):
    """
    Key bindings for accepting auto suggestion text.
    """
    assert isinstance(filter, CLIFilter)
    handle = create_handle_decorator(registry, filter)

    suggestion_available = Condition(
        lambda cli:
            cli.current_buffer.suggestion is not None and
            cli.current_buffer.document.is_cursor_at_the_end)

    @handle(Keys.ControlF, filter=suggestion_available)
    @handle(Keys.ControlE, filter=suggestion_available)
    @handle(Keys.Right, filter=suggestion_available)
    def _(event):
        " Accept suggestion. "
        b = event.current_buffer
        suggestion = b.suggestion

        if suggestion:
            b.insert_text(suggestion.text)
<commit_msg>Only handle mouse events for known keys.<commit_after># pylint: disable=function-redefined
from __future__ import unicode_literals

from prompt_toolkit.enums import DEFAULT_BUFFER
from prompt_toolkit.filters import CLIFilter, Always, HasSelection, Condition
from prompt_toolkit.keys import Keys
from prompt_toolkit.layout.screen import Point
from prompt_toolkit.mouse_events import MouseEventTypes, MouseEvent
from prompt_toolkit.renderer import HeightIsUnknownError
from prompt_toolkit.utils import suspend_to_background_supported, is_windows

from .utils import create_handle_decorator

__all__ = (
    'load_basic_bindings',
    'load_abort_and_exit_bindings',
    'load_basic_system_bindings',
    'load_auto_suggestion_bindings',
)

def if_no_repeat(event):
    """ Callable that returns True when the previous event was delivered to
    another handler. """
    return not event.is_repeat

def load_basic_bindings(registry, filter=Always()):
    assert isinstance(filter, CLIFilter)

    handle = create_handle_decorator(registry, filter)
    has_selection = HasSelection()

    @handle(Keys.ControlA)
    @handle(Keys.ControlB)
    @handle(Keys.ControlC)
    @handle(Keys.ControlD)
    @handle(Keys.ControlE)
    @handle(Keys.ControlF)
    @handle(Keys.ControlG)
    @handle(Keys.ControlH)
    @handle(Keys.ControlI)
    @handle(Keys.ControlJ)
    @handle(Keys.ControlK)
    @handle(Keys.ControlL)
    @handle(Keys.ControlM)
    @handle(Keys.ControlN)
    @handle(Keys.ControlO)
    @handle(Keys.ControlP)
    @handle(Keys.ControlQ)
    @handle(Keys.ControlR)
    @handle(Keys.ControlS)
    @handle(Keys.ControlT)
    @handle(Keys.ControlU)
    @handle(Keys.ControlV)
    @handle(Keys.ControlW)
    @handle(Keys.ControlX)
    @handle(Keys.ControlY)
    @handle(Keys.ControlZ)
    @handle(Keys.F1)
    @handle(Keys.F2)
    @handle(Keys.F3)
    @handle(Keys.F4)
    @handle(Keys.F5)
    @handle(Keys.F6)
    @handle(Keys.F7)
    @handle(Keys.F8)
    @handle(Keys.F9)
    @handle(Keys.F10)
    @handle(Keys.F11)
    @handle(Keys.F12)
    @handle(Keys.F13)
    @handle(Keys.F14)
    @handle(Keys.F15)
    @handle(Keys.F16)
    @handle(Keys.F17)
    @handle(Keys.F18)
    @handle(Keys.F19)
    @handle(Keys.F20)
    @handle(Keys.ControlSpace)
    @handle(Keys.ControlBackslash)
    @handle(Keys.ControlSquareClose)
    @handle(Keys.ControlCircumflex)
    @handle(Keys.ControlUnderscore)
    @handle(Keys.Backspace)
    @handle(Keys.Up)
    @handle(Keys.Down)
    @handle(Keys.Right)
    @handle(Keys.Left)
    @handle(Keys.Home)
    @handle(Keys.End)
    @handle(Keys.Delete)
    @handle(Keys.ShiftDelete)
    @handle(Keys.PageUp)
    @handle(Keys.PageDown)
    @handle(Keys.BackTab)
    @handle(Keys.Tab)
    @handle(Keys.ControlLeft)
    @handle(Keys.ControlRight)
    @handle(Keys.ControlUp)
    @handle(Keys.ControlDown)
    @handle(Keys.Insert)
    def _(event):
        """
        First, for any of these keys, Don't do anything by default. Also don't
        catch them in the 'Any' handler which will insert them as data.

        If people want to insert these characters as a literal, they can always
        do by doing a quoted insert. (ControlQ in emacs mode, ControlV in Vi
        mode.)
        """
        pass

    @handle(Keys.Home)
    def _(event):
        b = event.current_buffer
        b.cursor_position += b.document.get_start_of_line_position()

    @handle(Keys.End)
    def _(event):
        b = event.current_buffer
        b.cursor_position += b.document.get_end_of_line_position()

    # CTRL keys.

    @handle(Keys.ControlD, filter=Condition(lambda cli: cli.current_buffer.text))
    def _(event):
        """
        Delete text before cursor.
        """
        event.current_buffer.delete(event.arg)

    @handle(Keys.ControlI, filter= ~has_selection)
    def _(event):
        r"""
        Ctrl-I is identical to "\t"

        Traditional tab-completion, where the first tab completes the common
        suffix and the second tab lists all the completions.
        """
        b = event.current_buffer

        def second_tab():
            if b.complete_state:
                b.complete_next()
            else:
                event.cli.start_completion(select_first=True)

        # On the second tab-press, or when already navigating through
        # completions.
        if event.is_repeat or b.complete_state:
            second_tab()
        else:
            event.cli.start_completion(insert_common_part=True)

    @handle(Keys.BackTab, filter= ~has_selection)
    def _(event):
        """
        Shift+Tab: go to previous completion.
        """
        event.current_buffer.complete_previous()

    @handle(Keys.ControlJ, filter= ~has_selection)
    def _(event):
        """
        Newline/Enter. (Or return input.)
        """
        b = event.current_buffer

        if b.is_multiline():
            b.newline(copy_margin=not event.cli.in_paste_mode)
        else:
            if b.accept_action.is_returnable:
                b.accept_action.validate_and_handle(event.cli, b)

    @handle(Keys.ControlK, filter= ~has_selection)
    def _(event):
        buffer = event.current_buffer
        deleted = buffer.delete(count=buffer.document.get_end_of_line_position())
        event.cli.clipboard.set_text(deleted)

    @handle(Keys.ControlT, filter= ~has_selection)
    def _(event):
        """
        Emulate Emacs transpose-char behavior: at the beginning of the buffer,
        do nothing.  At the end of a line or buffer, swap the characters before
        the cursor.  Otherwise, move the cursor right, and then swap the
        characters before the cursor.
        """
        b = event.current_buffer
        p = b.cursor_position
        if p == 0:
            return
        elif p == len(b.text) or b.text[p] == '\n':
            b.swap_characters_before_cursor()
        else:
            b.cursor_position += b.document.get_cursor_right_position()
            b.swap_characters_before_cursor()

    @handle(Keys.ControlU, filter= ~has_selection)
    def _(event):
        """
        Clears the line before the cursor position. If you are at the end of
        the line, clears the entire line.
        """
        buffer = event.current_buffer
        deleted = buffer.delete_before_cursor(count=-buffer.document.get_start_of_line_position())
        event.cli.clipboard.set_text(deleted)

    @handle(Keys.ControlW, filter= ~has_selection)
    def _(event):
        """
        Delete the word before the cursor.
        """
        buffer = event.current_buffer
        pos = buffer.document.find_start_of_previous_word(count=event.arg)

        if pos is None:
            # Nothing found? delete until the start of the document.  (The
            # input starts with whitespace and no words were found before the
            # cursor.)
            pos = - buffer.cursor_position

        if pos:
            deleted = buffer.delete_before_cursor(count=-pos)

            # If the previous key press was also Control-W, concatenate deleted
            # text.
            if event.is_repeat:
                deleted += event.cli.clipboard.get_data().text

            event.cli.clipboard.set_text(deleted)

    @handle(Keys.PageUp, filter= ~has_selection)
    def _(event):
        event.current_buffer.history_backward()

    @handle(Keys.PageDown, filter= ~has_selection)
    def _(event):
        event.current_buffer.history_forward()

    @handle(Keys.Left)
    def _(event):
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.get_cursor_left_position(count=event.arg)

    @handle(Keys.Right)
    def _(event):
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.get_cursor_right_position(count=event.arg)

    @handle(Keys.Up, filter= ~has_selection)
    def _(event):
        event.current_buffer.auto_up(count=event.arg)

    @handle(Keys.Up, filter=has_selection)
    def _(event):
        event.current_buffer.cursor_up(count=event.arg)

    @handle(Keys.Down, filter= ~has_selection)
    def _(event):
        event.current_buffer.auto_down(count=event.arg)

    @handle(Keys.Down, filter=has_selection)
    def _(event):
        event.current_buffer.cursor_down(count=event.arg)

    @handle(Keys.ControlH, filter= ~has_selection, save_before=if_no_repeat)
    def _(event):
        " Backspace: delete before cursor. "
        event.current_buffer.delete_before_cursor(count=event.arg)

    @handle(Keys.Delete, filter= ~has_selection, save_before=if_no_repeat)
    @handle(Keys.ShiftDelete, filter= ~has_selection, save_before=if_no_repeat)
    def _(event):
        event.current_buffer.delete(count=event.arg)

    @handle(Keys.Delete, filter=has_selection)
    def _(event):
        data = event.current_buffer.cut_selection()
        event.cli.clipboard.set_data(data)

    @handle(Keys.Any, filter= ~has_selection, save_before=if_no_repeat)
    def _(event):
        """
        Insert data at cursor position.
        """
        event.current_buffer.insert_text(event.data * event.arg)

    # Global bindings. These are never disabled and don't include the default filter.

    @handle(Keys.ControlL)
    def _(event):
        " Clear whole screen and redraw. "
        event.cli.renderer.clear()

    @handle(Keys.ControlZ)
    def _(event):
        """
        By default, control-Z should literally insert Ctrl-Z.
        (Ansi Ctrl-Z, code 26 in MSDOS means End-Of-File.
        In a Python REPL for instance, it's possible to type
        Control-Z followed by enter to quit.)

        When the system bindings are loaded and suspend-to-background is
        supported, that will override this binding.
        """
        event.current_buffer.insert_text(event.data)

    @registry.add_binding(Keys.CPRResponse)
    def _(event):
        """
        Handle incoming Cursor-Position-Request response.
        """
        # The incoming data looks like u'\x1b[35;1R'
        # Parse row/col information.
        row, col = map(int, event.data[2:-1].split(';'))

        # Report absolute cursor position to the renderer.
        event.cli.renderer.report_absolute_cursor_row(row)

    @registry.add_binding(Keys.Vt100MouseEvent)
    def _(event):
        """
        Handling of incoming mouse event.
        """
        # Typical:   "Esc[MaB*"
        # Urxvt:     "Esc[96;14;13M"
        # Xterm SGR: "Esc[<64;85;12M"

        # Parse incoming packet.
        if event.data[2] == 'M':
            # Typical.
            mouse_event, x, y = map(ord, event.data[3:])
            mouse_event = {
                32: MouseEventTypes.MOUSE_DOWN,
                35: MouseEventTypes.MOUSE_UP,
                96: MouseEventTypes.SCROLL_UP,
                97: MouseEventTypes.SCROLL_DOWN,
            }.get(mouse_event)
            x -= 32
            y -= 32
        else:
            # Urxvt and Xterm SGR.
            # When the '<' is not present, we are not using the Xterm SGR mode,
            # but Urxvt instead.
            data = event.data[2:]
            if data[:1] == '<':
                sgr = True
                data = data[1:]
            else:
                sgr = False

            # Extract coordinates.
            mouse_event, x, y = map(int, data[:-1].split(';'))
            m = data[-1]

            # Parse event type.
            if sgr:
                mouse_event = {
                    (0, 'M'): MouseEventTypes.MOUSE_DOWN,
                    (0, 'm'): MouseEventTypes.MOUSE_UP,
                    (64, 'M'): MouseEventTypes.SCROLL_UP,
                    (65, 'M'): MouseEventTypes.SCROLL_DOWN,
                }.get((mouse_event, m))
            else:
                mouse_event = {
                    32: MouseEventTypes.MOUSE_DOWN,
                    35: MouseEventTypes.MOUSE_UP,
                    96: MouseEventTypes.SCROLL_UP,
                    97: MouseEventTypes.SCROLL_DOWN,
                    }.get(mouse_event)

        x -= 1
        y -= 1

        # Only handle mouse events when we know the window height.
        if event.cli.renderer.height_is_known and mouse_event is not None:
            # Take region above the layout into account. The reported
            # coordinates are absolute to the visible part of the terminal.
            try:
                y -= event.cli.renderer.rows_above_layout
            except HeightIsUnknownError:
                return

            # Call the mouse handler from the renderer.
            handler = event.cli.renderer.mouse_handlers.mouse_handlers[x,y]
            handler(event.cli, MouseEvent(position=Point(x=x, y=y),
                                          event_type=mouse_event))

    @registry.add_binding(Keys.WindowsMouseEvent)
    def _(event):
        """
        Handling of mouse events for Windows.
        """
        assert is_windows()  # This key binding should only exist for Windows.

        # Parse data.
        event_type, x, y = event.data.split(';')
        x = int(x)
        y = int(y)

        # Make coordinates absolute to the visible part of the terminal.
        screen_buffer_info = event.cli.renderer.output.get_win32_screen_buffer_info()
        rows_above_cursor = screen_buffer_info.dwCursorPosition.Y - event.cli.renderer._cursor_pos.y
        y -= rows_above_cursor

        # Call the mouse event handler.
        handler = event.cli.renderer.mouse_handlers.mouse_handlers[x,y]
        handler(event.cli, MouseEvent(position=Point(x=x, y=y),
                                      event_type=event_type))

def load_abort_and_exit_bindings(registry, filter=Always()):
    """
    Basic bindings for abort (Ctrl-C) and exit (Ctrl-D).
    """
    assert isinstance(filter, CLIFilter)
    handle = create_handle_decorator(registry, filter)

    @handle(Keys.ControlC)
    def _(event):
        " Abort when Control-C has been pressed. "
        event.cli.set_abort()

    @Condition
    def ctrl_d_condition(cli):
        """ Ctrl-D binding is only active when the default buffer is selected
        and empty. """
        return (cli.current_buffer_name == DEFAULT_BUFFER and
                not cli.current_buffer.text)

    @handle(Keys.ControlD, filter=ctrl_d_condition)
    def _(event):
        " Exit on Control-D when the input is empty. "
        event.cli.set_exit()

def load_basic_system_bindings(registry, filter=Always()):
    """
    Basic system bindings (For both Emacs and Vi mode.)
    """
    assert isinstance(filter, CLIFilter)
    handle = create_handle_decorator(registry, filter)

    suspend_supported = Condition(
        lambda cli: suspend_to_background_supported())

    @handle(Keys.ControlZ, filter=suspend_supported)
    def _(event):
        """
        Suspend process to background.
        """
        event.cli.suspend_to_background()

def load_auto_suggestion_bindings(registry, filter=Always()):
    """
    Key bindings for accepting auto suggestion text.
    """
    assert isinstance(filter, CLIFilter)
    handle = create_handle_decorator(registry, filter)

    suggestion_available = Condition(
        lambda cli:
            cli.current_buffer.suggestion is not None and
            cli.current_buffer.document.is_cursor_at_the_end)

    @handle(Keys.ControlF, filter=suggestion_available)
    @handle(Keys.ControlE, filter=suggestion_available)
    @handle(Keys.Right, filter=suggestion_available)
    def _(event):
        " Accept suggestion. "
        b = event.current_buffer
        suggestion = b.suggestion

        if suggestion:
            b.insert_text(suggestion.text)
<|endoftext|>


<commit_before># Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from django.conf import settings
from django.core import urlresolvers
from django.utils.translation import ugettext_lazy as _

from horizon import tables

class ProvidingApplicationsTable(tables.DataTable):
    name = tables.Column('name', verbose_name=_('Name'))
    url = tables.Column(lambda obj: getattr(obj, 'url', None))
    avatar = tables.Column(lambda obj: settings.MEDIA_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/app.png'))
    default_avatar = tables.Column(lambda obj: settings.STATIC_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/app.png'))

    clickable = True
    # show_avatar = True

    class Meta:
        name = "providing_table"
        verbose_name = _("Providing Applications")
        multi_select = False

class PurchasedApplicationsTable(tables.DataTable):
    name = tables.Column('name', verbose_name=_('Name'))
    url = tables.Column(lambda obj: getattr(obj, 'url', None))
    avatar = tables.Column(lambda obj: settings.MEDIA_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/app.png'))
    default_avatar = tables.Column(lambda obj: settings.STATIC_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/app.png'))

    clickable = True
    # show_avatar = True

    class Meta:
        name = "purchased_table"
        verbose_name = _("Purchased Applications")
        multi_select = False

class ManageAuthorizedMembersLink(tables.LinkAction):
    name = "manage_application_members"
    verbose_name = _("Manage your applications' members")
    url = "horizon:idm:myApplications:members"
    classes = ("ajax-modal",)

    def allowed(self, request, user):
        # TODO(garcianavalon)
        return True

    def get_link_url(self, datum=None):
        app_id = self.table.kwargs['application_id']
        return  urlresolvers.reverse(self.url, args=(app_id,))

class MembersTable(tables.DataTable):
    name = tables.Column('name', verbose_name=_('Members'))
    avatar = tables.Column(lambda obj: settings.MEDIA_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/user.png'))
    default_avatar = tables.Column(lambda obj: settings.STATIC_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/user.png'))

    # show_avatar = True
    clickable = True

    class Meta:
        name = "members"
        verbose_name = _("Authorized Members")
        table_actions = (ManageAuthorizedMembersLink, )
        multi_select = False

class ManageAuthorizedOrganizationsLink(tables.LinkAction):
    name = "manage_application_organizations"
    verbose_name = _("Manage authorized organizations")
    url = "horizon:idm:myApplications:organizations"
    classes = ("ajax-modal",)

    def allowed(self, request, user):
        # TODO(garcianavalon)
        return True

    def get_link_url(self, datum=None):
        app_id = self.table.kwargs['application_id']
        return  urlresolvers.reverse(self.url, args=(app_id,))

class AuthorizedOrganizationsTable(tables.DataTable):
    name = tables.Column('name')
    avatar = tables.Column(lambda obj: settings.MEDIA_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/organization.png'))
    default_avatar = tables.Column(lambda obj: settings.STATIC_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/organization.png'))

    # show_avatar = True
    clickable = True

    class Meta:
        name = "organizations"
        verbose_name = _("Authorized Organizations")
        table_actions = (ManageAuthorizedOrganizationsLink, )
        multi_select = False<commit_msg>correctly showing authorized organization avatar<commit_after># Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from django.conf import settings
from django.core import urlresolvers
from django.utils.translation import ugettext_lazy as _

from horizon import tables

class ProvidingApplicationsTable(tables.DataTable):
    name = tables.Column('name', verbose_name=_('Name'))
    url = tables.Column(lambda obj: getattr(obj, 'url', None))
    avatar = tables.Column(lambda obj: settings.MEDIA_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/app.png'))
    default_avatar = tables.Column(lambda obj: settings.STATIC_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/app.png'))

    clickable = True
    # show_avatar = True

    class Meta:
        name = "providing_table"
        verbose_name = _("Providing Applications")
        multi_select = False

class PurchasedApplicationsTable(tables.DataTable):
    name = tables.Column('name', verbose_name=_('Name'))
    url = tables.Column(lambda obj: getattr(obj, 'url', None))
    avatar = tables.Column(lambda obj: settings.MEDIA_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/app.png'))
    default_avatar = tables.Column(lambda obj: settings.STATIC_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/app.png'))

    clickable = True
    # show_avatar = True

    class Meta:
        name = "purchased_table"
        verbose_name = _("Purchased Applications")
        multi_select = False

class ManageAuthorizedMembersLink(tables.LinkAction):
    name = "manage_application_members"
    verbose_name = _("Manage your applications' members")
    url = "horizon:idm:myApplications:members"
    classes = ("ajax-modal",)

    def allowed(self, request, user):
        # TODO(garcianavalon)
        return True

    def get_link_url(self, datum=None):
        app_id = self.table.kwargs['application_id']
        return  urlresolvers.reverse(self.url, args=(app_id,))

class MembersTable(tables.DataTable):
    name = tables.Column('name', verbose_name=_('Members'))
    avatar = tables.Column(lambda obj: settings.MEDIA_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/user.png'))
    default_avatar = tables.Column(lambda obj: settings.STATIC_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/user.png'))

    # show_avatar = True
    clickable = True

    class Meta:
        name = "members"
        verbose_name = _("Authorized Members")
        table_actions = (ManageAuthorizedMembersLink, )
        multi_select = False

class ManageAuthorizedOrganizationsLink(tables.LinkAction):
    name = "manage_application_organizations"
    verbose_name = _("Manage authorized organizations")
    url = "horizon:idm:myApplications:organizations"
    classes = ("ajax-modal",)

    def allowed(self, request, user):
        # TODO(garcianavalon)
        return True

    def get_link_url(self, datum=None):
        app_id = self.table.kwargs['application_id']
        return  urlresolvers.reverse(self.url, args=(app_id,))

class AuthorizedOrganizationsTable(tables.DataTable):
    name = tables.Column('name', verbose_name=_('Applications'))
    url = tables.Column(lambda obj: getattr(obj, 'url', None))
    avatar = tables.Column(lambda obj: settings.MEDIA_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/app.png'))
    default_avatar = tables.Column(lambda obj: settings.STATIC_URL + getattr(
        obj, 'img_medium', 'dashboard/img/logos/medium/app.png'))

    # show_avatar = True
    clickable = True

    class Meta:
        name = "organizations"
        verbose_name = _("Authorized Organizations")
        table_actions = (ManageAuthorizedOrganizationsLink, )
        multi_select = False<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import scrapy
import json
import re

from locations.items import GeojsonPointItem

class LoblawsSpider(scrapy.Spider):

    name = "loblaws"
    allowed_domains = ["www.loblaws.ca"]
    start_urls = (
        'https://www.loblaws.ca/store-locator/locations/all?showNonShoppable=true&_=1513445413276',
    )

    def store_hours(self, store_hours):
        if "24 hours" in store_hours:
            return "24/7"
        day_groups = []
        this_day_group = None
        days = ('Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su')

        for day in days:
            hour_intervals = []
            (f_time, t_time) = store_hours.split('-')
            if len(f_time) > 0 and len(t_time)> 0:
                f_ampm = f_time[-2:]
                f_hr = re.search(r'([0-9]{1,2}):', f_time).group(1)
                t_ampm = t_time[-2:]
                t_hr = re.search(r'([0-9]{1,2}):', t_time).group(1)
                f_min = re.search(r':([0-9]{1,2})', f_time).group(1)
                t_min = re.search(r':([0-9]{1,2})', t_time).group(1)

                f_hr = int(f_hr)
                t_hr = int(t_hr)
                if f_ampm == 'pm':
                    f_hr += 12
                if f_ampm == 'am' and f_hr == 12:
                    f_hr -= 12

                if t_ampm == 'pm':
                    t_hr += 12
                if t_ampm == 'am' and t_hr == 12:
                    t_hr -= 12

                hour_intervals.append('{}:{}-{}:{}'.format(
                    f_hr,
                    f_min,
                    t_hr,
                    t_min,
                ))
            hours = ','.join(hour_intervals)
            if not this_day_group:
                this_day_group = {
                    'from_day': day,
                    'to_day': day,
                    'hours': hours
                }
            elif this_day_group['hours'] != hours:
                day_groups.append(this_day_group)
                this_day_group = {
                    'from_day': day,
                    'to_day': day,
                    'hours': hours
                }
            elif this_day_group['hours'] == hours:
                this_day_group['to_day'] = day

        day_groups.append(this_day_group)

        opening_hours = ""
        if len(day_groups) == 1 and day_groups[0]['hours'] in ('00:00-23:59', '00:00-00:00'):
            opening_hours = '24/7'
        else:
            for day_group in day_groups:
                if day_group['from_day'] == day_group['to_day']:
                    opening_hours += '{from_day} {hours}; '.format(**day_group)
                elif day_group['from_day'] == 'Su' and day_group['to_day'] == 'Sa':
                    opening_hours += '{hours}; '.format(**day_group)
                else:
                    opening_hours += '{from_day}-{to_day} {hours}; '.format(**day_group)
            opening_hours = opening_hours[:-2]

        return opening_hours

    def parse(self, response):
        results = json.loads(response.body_as_unicode())
        for data in results['searchResult']:
            properties = {
                'ref': data['details']['storeID'],
                'name': data['details']['storeName'],
                'lat': data['lat'],
                'lon': data['lng'],
                'addr_full': data['details']['streetAddress'],
                'city': data['details']['city'],
                'state': data['details']['province'],
                'postcode': data['details']['postalCode'],
                'website': data['details']['url'],
            }

            if 'todaysHours' in data['details']:
                properties['opening_hours'] = self.store_hours(data['details']['todaysHours']),

            yield GeojsonPointItem(**properties)
<commit_msg>Fix hours<commit_after># -*- coding: utf-8 -*-
import scrapy
import json
import re

from locations.items import GeojsonPointItem

class LoblawsSpider(scrapy.Spider):

    name = "loblaws"
    allowed_domains = ["www.loblaws.ca"]
    start_urls = (
        'https://www.loblaws.ca/store-locator/locations/all?showNonShoppable=true&_=1513445413276',
    )

    def store_hours(self, store_hours):
        if "24 hours" in store_hours:
            return "24/7"
        day_groups = []
        this_day_group = None
        days = ('Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su')

        for day in days:
            hour_intervals = []
            (f_time, t_time) = store_hours.split('-')
            if len(f_time) > 0 and len(t_time)> 0:
                f_ampm = f_time[-2:]
                f_hr = re.search(r'([0-9]{1,2}):', f_time).group(1)
                t_ampm = t_time[-2:]
                t_hr = re.search(r'([0-9]{1,2}):', t_time).group(1)
                f_min = re.search(r':([0-9]{1,2})', f_time).group(1)
                t_min = re.search(r':([0-9]{1,2})', t_time).group(1)

                f_hr = int(f_hr)
                t_hr = int(t_hr)
                if f_ampm == 'pm':
                    f_hr += 12
                if f_ampm == 'am' and f_hr == 12:
                    f_hr -= 12

                if t_ampm == 'pm':
                    t_hr += 12
                if t_ampm == 'am' and t_hr == 12:
                    t_hr -= 12

                hour_intervals.append('{}:{}-{}:{}'.format(
                    f_hr,
                    f_min,
                    t_hr,
                    t_min,
                ))
            hours = ','.join(hour_intervals)
            if not this_day_group:
                this_day_group = {
                    'from_day': day,
                    'to_day': day,
                    'hours': hours
                }
            elif this_day_group['hours'] != hours:
                day_groups.append(this_day_group)
                this_day_group = {
                    'from_day': day,
                    'to_day': day,
                    'hours': hours
                }
            elif this_day_group['hours'] == hours:
                this_day_group['to_day'] = day

        day_groups.append(this_day_group)

        opening_hours = ""
        if len(day_groups) == 1 and day_groups[0]['hours'] in ('00:00-23:59', '00:00-00:00'):
            opening_hours = '24/7'
        else:
            for day_group in day_groups:
                if day_group['from_day'] == day_group['to_day']:
                    opening_hours += '{from_day} {hours}; '.format(**day_group)
                elif day_group['from_day'] == 'Su' and day_group['to_day'] == 'Sa':
                    opening_hours += '{hours}; '.format(**day_group)
                else:
                    opening_hours += '{from_day}-{to_day} {hours}; '.format(**day_group)
            opening_hours = opening_hours[:-2]

        return opening_hours

    def parse(self, response):
        results = json.loads(response.body_as_unicode())
        for data in results['searchResult']:
            properties = {
                'ref': data['details']['storeID'],
                'name': data['details']['storeName'],
                'lat': data['lat'],
                'lon': data['lng'],
                'addr_full': data['details']['streetAddress'],
                'city': data['details']['city'],
                'state': data['details']['province'],
                'postcode': data['details']['postalCode'],
                'website': data['details']['url'],
            }

            if 'todaysHours' in data['details']:
                properties['opening_hours'] = self.store_hours(data['details']['todaysHours'])

            yield GeojsonPointItem(**properties)
<|endoftext|>


<commit_before># Copyright 2022 Google.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

r"""Recreate a checkpoint from earlier in prompt tuning training.

When training using prompt tuning we generally set the number of checkpoints to
1. This gives us a checkpoint that has the right shape (the prompt variable, the
lack of optimizer state for the main model, etc) that can be used to restart
after a preemption. But because prompt tuning only updates ~0.003% of the
parameters for a T5 XXL model, it would be wasteful to save many checkpoints as
so much of the model is frozen. Instead, we emit a numpy checkpoint of just the
prompt.

The problem with the above is you always end up with the /last/ checkpoint
instead of the /best/ checkpoint. This binary is a tool to do checkpoint
surgery to splice the prompts numpy value for some given checkpoint into the
final checkpoint. A common usecase being the recreation the best performing
checkpoint to be used in things like the t5x `eval.py` script.

"""

import os
from typing import List, Sequence
from unittest import mock
from absl import app
from absl import flags
from absl import logging
import flax
from flax import optim
from flax import traverse_util
import jax.numpy as jnp
import numpy as np
from t5x import checkpoints
from t5x import partitioning
from t5x import state_utils
from t5x import train_state as train_state_lib
from tensorflow.io import gfile

FLAGS = flags.FLAGS

flags.DEFINE_string(
    "model_dir",
    None,
    "The model directory where the checkpoints were written.")
flags.DEFINE_integer(
    "step", None, "The step number of the prompt to load.")
flags.DEFINE_string("output_dir", None, "The output location.")
flags.DEFINE_integer(
    "concurrent_gb",
    16,
    "Maximum amount of memory to use at once, can use up to 4x in some cases.")
flags.DEFINE_enum(
    "save_dtype",
    "float32",
    ["float32", "bfloat16"],
    "The data type to use while saving.")
flags.DEFINE_enum(
    "restore_dtype",
    "float32",
    ["float32", "bfloat16"],
    "The datatype used while restoring.")
flags.mark_flag_as_required("model_dir")
flags.mark_flag_as_required("step")

def find_numpy_checkpoints(model_dir: str, step: int) -> List[str]:
  """Find all numpy files for saved at `step` in `model_dir`."""
  checkpoint_dir = os.path.join(
      model_dir, "numpy_checkpoints", f"checkpoint_{step}")
  return [os.path.join(checkpoint_dir, f)
          for f in gfile.listdir(checkpoint_dir)]

def remove_suffix(s: str, suffix: str) -> str:
  """Remove `suffix` from the end of `s` if it exists."""
  if suffix and s.endswith(suffix):
    return s[:-len(suffix)]
  return s[:]

def file_name_to_variable_path(file_name: str) -> str:
  """Convert the "." separated checkpoint naming to "/" nesting."""
  variable_name = remove_suffix(os.path.basename(file_name), ".npy")
  return variable_name.replace(".", "/")

def build_optimizer(state_dict) -> optim.Optimizer:
  """Create an (Adafactor) optimizer that matches `state_dict`."""
  flat_state = state_utils.flatten_state_dict(
      state_dict["state"]["param_states"])
  none_keys = {f"/{k}" for k, v in flat_state.items() if v is None}

  def filter_fn(path, _):
    return path not in none_keys

  optimizer_def = optim.MultiOptimizer(
      (optim.ModelParamTraversal(filter_fn), optim.Adafactor()))
  with mock.patch.object(flax.optim.base, "isinstance") as is_instance_mock:
    is_instance_mock.side_effect = (
        lambda x, y: True if y == jnp.ndarray else isinstance(x, y))
    optimizer = optimizer_def.create(state_dict["target"])
  return optimizer.restore_state(state_dict)

def main(argv: Sequence[str]) -> None:
  """Add numpy checkpoint values at some step to a prompt tuning checkpoint."""
  if len(argv) > 1:
    raise app.UsageError("Too many command-line-arguments.")

  output_dir = FLAGS.output_dir
  if output_dir is None:
    output_dir = FLAGS.model_dir

  # Find the latest checkpoint
  latest_step = checkpoints.latest_step(FLAGS.model_dir)
  if latest_step is None:
    raise ValueError(f"Cannot find checkpoint directory in {FLAGS.model_dir}")
  logging.info("Loading checkpoint at step %d", latest_step)
  checkpoint_directory = checkpoints.get_checkpoint_dir(
      FLAGS.model_dir, latest_step)
  logging.info("Loading checkpoint from %s", checkpoint_directory)
  # Load the latest checkpoint
  checkpoint = checkpoints.load_t5x_checkpoint(
      checkpoint_directory,
      restore_dtype=FLAGS.restore_dtype,
      lazy_parameters=True)

  flat_checkpoint = state_utils.flatten_state_dict(
      checkpoint, keep_empty_nodes=True)

  # Find the numpy files for the given step
  # TODO: Abstract this step to allow for more control of the
  # over-writing, i.e. given associated lists of variable overwrite paths and
  # paths to numpy files, overwrite several variables without being tied to
  # prompts produced by this training run.
  numpy_files = find_numpy_checkpoints(FLAGS.model_dir, FLAGS.step)
  if not numpy_files:
    raise ValueError(f"Cannot find any number checkpoints in {FLAGS.model_dir} "
                     f"with step {FLAGS.step}")
  for numpy_file in numpy_files:
    logging.info("Loading numpy variable from %s", numpy_file)
    # Load the numpy variable
    with gfile.GFile(numpy_file, "rb") as f:
      numpy_value = np.load(f).astype(FLAGS.restore_dtype)
    # Figure out where the variable goes in the pytree
    variable_path = file_name_to_variable_path(numpy_file)
    logging.info("Overwriting the variable at %s with the value loaded from %s",
                 variable_path, numpy_file)
    # Update the variable in the pytree
    flat_checkpoint[f"target/{variable_path}"] = numpy_value
  # Set the step to the given step.
  logging.info("Setting step to %d", FLAGS.step)
  flat_checkpoint["state/step"] = np.asarray(
      FLAGS.step, dtype=flat_checkpoint["state/step"].dtype)

  # Save the checkpoint with the given step prompt included.
  checkpoint = traverse_util.unflatten_dict(
      {tuple(k.split("/")): v for k, v in flat_checkpoint.items()})
  partitioner = partitioning.PjitPartitioner(
      num_partitions=1, params_on_devices=False)
  # TODO: Add option to configure what optimizer to use.
  optimizer = build_optimizer(checkpoint)
  # Turn the optimizer into the train_state object
  train_state = train_state_lib.FlaxOptimTrainState(optimizer)
  train_state = train_state.restore_state(checkpoint)
  checkpointer = checkpoints.Checkpointer(
      train_state,
      partitioner,
      output_dir,
      save_dtype=FLAGS.save_dtype,
      restore_dtype=FLAGS.restore_dtype)
  logging.info("Saving result to %s", output_dir)
  # Actually save the new checkpoint.
  checkpointer.save(train_state, concurrent_gb=FLAGS.concurrent_gb)

if __name__ == "__main__":
  app.run(main)
<commit_msg>Update the `recreate_checkpoint` script to use Gin.<commit_after># Copyright 2022 Google.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

r"""Recreate a checkpoint from earlier in prompt tuning training.

When training using prompt tuning we generally set the number of checkpoints to
1. This gives us a checkpoint that has the right shape (the prompt variable, the
lack of optimizer state for the main model, etc) that can be used to restart
after a preemption. But because prompt tuning only updates ~0.003% of the
parameters for a T5 XXL model, it would be wasteful to save many checkpoints as
so much of the model is frozen. Instead, we emit a numpy checkpoint of just the
prompt.

The problem with the above is you always end up with the /last/ checkpoint
instead of the /best/ checkpoint. This binary is a tool to do checkpoint
surgery to splice the prompts numpy value for some given checkpoint into the
final checkpoint. A common usecase being the recreation the best performing
checkpoint to be used in things like the t5x `eval.py` script.

Note:
  This script only recreates the model *parameters* at some given step, the
  optimizer state for the prompt variable at some step are not saved, thus the
  optimizer state in the final checkpoint are not rewound like the parameters
  are. This means this script can't be used to recreating an earlier
  checkpoint and restart training from a previous step.

"""

import os
from typing import List, Optional
from absl import logging
from flax import traverse_util
import jax
import jax.numpy as jnp
import numpy as np
from t5x import checkpoints
from t5x import models
from t5x import partitioning
from t5x import train_state as train_state_lib
from tensorflow.io import gfile

def find_numpy_checkpoints(model_dir: str, step: int) -> List[str]:
  """Find all numpy files for saved at `step` in `model_dir`."""
  checkpoint_dir = os.path.join(
      model_dir, "numpy_checkpoints", f"checkpoint_{step}")
  return [os.path.join(checkpoint_dir, f)
          for f in gfile.listdir(checkpoint_dir)]

def remove_suffix(s: str, suffix: str) -> str:
  """Remove `suffix` from the end of `s` if it exists."""
  if suffix and s.endswith(suffix):
    return s[:-len(suffix)]
  return s[:]

def file_name_to_variable_path(file_name: str) -> str:
  """Convert the "." separated checkpoint naming to "/" nesting."""
  variable_name = remove_suffix(os.path.basename(file_name), ".npy")
  return variable_name.replace(".", "/")

def recreate_checkpoint(model: models.BaseModel,
                        model_dir: str,
                        step: int,
                        concurrent_gb: int = 16,
                        save_dtype: jnp.dtype = jnp.float32,
                        output_dir: Optional[str] = None) -> None:
  """Add numpy checkpoint values at some step to a prompt tuning checkpoint."""
  # We are going to save the checkpoint with a new step number so if they don't
  # give a new place to put it, just use the same dir.
  if output_dir is None:
    output_dir = model_dir

  save_dtype = jnp.dtype(save_dtype)

  # Find the latest checkpoint
  latest_step = checkpoints.latest_step(model_dir)
  if latest_step is None:
    raise ValueError(f"Cannot find checkpoint directory in {model_dir}")
  logging.info("Loading checkpoint at step %d", latest_step)
  checkpoint_directory = checkpoints.get_checkpoint_dir(
      model_dir, latest_step)
  logging.info("Loading checkpoint from %s", checkpoint_directory)

  # Initialize the training state from the model which was loaded via gin.
  def initialize_train_state(rng):
    initial_variables = model.get_initial_variables(
        rng=rng,
        input_shapes={
            "encoder_input_tokens": (1, 1),
            "decoder_input_tokens": (1, 1)
        })
    return train_state_lib.FlaxOptimTrainState.create(model.optimizer_def,
                                                      initial_variables)

  train_state = jax.eval_shape(initialize_train_state, jax.random.PRNGKey(0))
  # We are doing this conversion on a single host with capped memory usage
  # so only 1 partitioned and keep params off devices.
  partitioner = partitioning.PjitPartitioner(1, params_on_devices=False)
  checkpointer = checkpoints.Checkpointer(
      train_state, partitioner, output_dir, save_dtype=save_dtype)
  train_state = checkpointer.restore(latest_step, lazy_parameters=True)

  # Flatten the parameters so we can overwrite them.
  flat_params = traverse_util.flatten_dict(train_state.params, sep="/")

  # Find the numpy files for the given step
  # TODO: Abstract this step to allow for more control of the
  # over-writing, i.e. given associated lists of variable overwrite paths and
  # paths to numpy files, overwrite several variables without being tied to
  # prompts produced by this training run.
  numpy_files = find_numpy_checkpoints(model_dir, step)
  if not numpy_files:
    raise ValueError(f"Cannot find any number checkpoints in {model_dir} "
                     f"with step {step}")
  # The numpy files for a checkpoint could include multiple parameters so
  # loop through them.
  for numpy_file in numpy_files:
    logging.info("Loading numpy variable from %s", numpy_file)
    # Load the numpy variable
    with gfile.GFile(numpy_file, "rb") as f:
      numpy_value = np.load(f).astype(checkpointer.restore_dtype)
    # Figure out where the variable goes in the pytree
    variable_path = file_name_to_variable_path(numpy_file)
    logging.info("Overwriting the variable at %s with the value loaded from %s",
                 variable_path, numpy_file)
    # Update the variable in the pytree
    flat_params[variable_path] = numpy_value

  train_state = train_state.replace_params(
      traverse_util.unflatten_dict(flat_params, sep="/"))
  # Set the step to the given step.
  logging.info("Setting step to %d", step)
  # TODO: This conversion of the train step from an int to a numpy
  # scalar should be upstreamed to the train_state as it currently allows one
  # to save the step as a python integer which causes an error when reloading.
  train_state = train_state.replace_step(np.array(step, dtype=save_dtype))

  logging.info("Saving result to %s", output_dir)
  # # Actually save the new checkpoint.
  checkpointer.save(train_state, concurrent_gb=concurrent_gb)

if __name__ == "__main__":
  # pylint:disable=g-import-not-at-top
  from absl import flags
  import gin
  from t5x import gin_utils
  # pylint:disable=g-import-not-at-to

  FLAGS = flags.FLAGS

  jax.config.parse_flags_with_absl()

  flags.DEFINE_multi_string(
      "gin_file",
      default=None,
      help="Path to gin configuration file. Multiple paths may be passed and "
      "will be imported in the given order, with later configurations  "
      "overriding earlier ones.")

  flags.DEFINE_multi_string(
      "gin_bindings", default=[], help="Individual gin bindings")

  flags.DEFINE_list(
      "gin_search_paths",
      default=["third_party/py/t5x/configs",
               "prompt_tuning/configs"],
      help="Comma-separated list of gin config path prefixes to be prepended "
      "to suffixes given via `--gin_file`. If a file appears in. Only the "
      "first prefix that produces a valid path for each suffix will be "
      "used.")

  def main(_):
    """True main function."""
    recreate_checkpoint_using_gin = gin.configurable(recreate_checkpoint)

    gin_utils.parse_gin_flags(FLAGS.gin_search_paths, FLAGS.gin_file,
                              FLAGS.gin_bindings)
    # Get gin-configured version of `recreate_checkpoint`.
    recreate_checkpoint_using_gin()

  gin_utils.run(main)
<|endoftext|>


<commit_before>"""Models of the aps_purchasing app."""
from django.db import models
from django.utils.translation import ugettext_lazy as _

class AML(models.Model):
    """
    Approved Manufacturer List.

    List of IPNs that may only be purchased through approved manufacturers.

    :ipn: The IPN instance.
    :manufacturer: A manufacturer who is approved for the given IPN.

    """
    ipn = models.ForeignKey(
        'aps_bom.IPN',
        verbose_name=_('Internal Part Number'),
    )

    manufacturer = models.ForeignKey(
        'aps_purchasing.Manufacturer',
        verbose_name=('Manufacturer'),
    )

    class Meta:
        verbose_name = _('AML')
        verbose_name_plural = _('AMLs')

    def __unicode__(self):
        return u'{0} - {1}'.format(self.ipn, self.manufacturer)

class Currency(models.Model):
    """
    Currency.

    :iso_code: The ISO code of this currency.
    :name: The name of this currency.
    :sign: The sign of this currency.

    """
    iso_code = models.CharField(
        verbose_name=_('ISO code'),
        max_length=3,
    )

    name = models.CharField(
        verbose_name=_('Name'),
        max_length=128,
    )

    sign = models.CharField(
        verbose_name=_('Sign'),
        max_length=1,
    )

    class Meta:
        verbose_name = _('Currency')
        verbose_name_plural = _('Currencies')

    def __unicode__(self):
        return self.iso_code

class Distributor(models.Model):
    """
    Distributor.

    :name: Name of this distributor.
    :questionnaire_form: Name of the form that was used for this distributor.
    :supplier_form: TODO: Describe this field.
    :min_order_value: Minimum order value for this distributor.
    :currency: Default currency for this distributor.
    :payment_terms: Payment terms for this distributor.
    :is_approved: If ``True``, this distributor is approved for business.
    :is_active: If ``False``, this distributor cannot be used, even if it was
      approved before.

    """
    name = models.CharField(
        verbose_name=_('Name'),
        max_length=128,
    )

    questionnaire_form = models.CharField(
        verbose_name=_('Questionnaire form'),
        max_length=128,
    )

    supplier_form = models.CharField(
        verbose_name=_('Supplier form'),
        max_length=128,
    )

    min_order_value = models.DecimalField(
        verbose_name=_('Minimum order value'),
        max_digits=11,
        decimal_places=5,
    )

    currency = models.ForeignKey(
        'aps_purchasing.Currency',
        verbose_name=_('Currency'),
    )

    payment_terms = models.ForeignKey(
        'aps_purchasing.PaymentTerm',
        verbose_name=_('Payment terms'),
        related_name='distributors',
    )

    is_approved = models.BooleanField(
        verbose_name=_('Is approved'),
        default=False,
    )

    is_active = models.BooleanField(
        verbose_name=_('Is active'),
        default=True,
    )

    def __unicode__(self):
        return self.name

class DPN(models.Model):
    """
    Distributor Part Number.

    :code: The code of this DPN.
    :ipn: The internal part number this DPN is mapped to.
    :distributor: The distributor who sells this part.
    :name: The name of this part.
    :mpn: The manufacturer part number for this part.

    """
    code = models.CharField(
        verbose_name=_('Code'),
        max_length=50,
    )

    ipn = models.ForeignKey(
        'aps_bom.IPN',
        verbose_name=_('Internal Part Number'),
        related_name='DPNs',
        null=True, blank=True,
    )

    distributor = models.ForeignKey(
        'aps_purchasing.Distributor',
        verbose_name=_('Distributor'),
        related_name='DPNs',
    )

    name = models.CharField(
        verbose_name=_('Name'),
        max_length=128,
    )

    mpn = models.ForeignKey(
        'aps_purchasing.MPN',
        verbose_name=_('Manufacturer Part Number'),
        related_name='DPNs',
    )

    class Meta:
        verbose_name = _('DPN')
        verbose_name_plural = _('DPNs')

    def __unicode__(self):
        return self.code

class Manufacturer(models.Model):
    """
    Manufacturer.

    :code: Internal code for this manufacturer.
    :name: Name of this manufacturer.

    """
    code = models.CharField(
        verbose_name=_('Code'),
        max_length=50,
    )

    name = models.CharField(
        verbose_name=_('Name'),
        max_length=128,
    )

    def __unicode__(self):
        return self.name

class MPN(models.Model):
    """
    Manufacturer Part Number.

    :code: The code of this MPN.
    :manufacturer: The manufacturer of this part.
    :name: The name of this part.
    :pku: The amount of parts in one pacakge unit.
    :unit: The package unit of this part.

    """
    code = models.CharField(
        verbose_name=_('Code'),
        max_length=50,
    )

    manufacturer = models.ForeignKey(
        'aps_purchasing.Manufacturer',
        verbose_name=_('Manufacturer'),
    )

    name = models.CharField(
        verbose_name=_('Name'),
        max_length=128,
    )

    pku = models.FloatField(
        verbose_name=_('Amount per packaging unit'),
    )

    unit = models.ForeignKey(
        'aps_purchasing.PackagingUnit',
        verbose_name=_('PackagingUnit'),
    )

    class Meta:
        verbose_name = _('MPN')
        verbose_name_plural = _('MPNs')

    def __unicode__(self):
        return self.code

class PackagingUnit(models.Model):
    """
    Packaging Unit.

    :name: The name of this unit.

    """
    name = models.CharField(
        verbose_name=_('Name'),
        max_length=128,
    )

    def __unicode__(self):
        return self.name

class PaymentTerm(models.Model):
    """
    Payment term.

    :code: Internal code for this payment term.
    :description: Description of this payment term.

    """
    code = models.CharField(
        verbose_name=_('Code'),
        max_length=50,
    )

    description = models.CharField(
        verbose_name=_('Description'),
        max_length=128,
    )

    def __unicode__(self):
        return self.code

class Price(models.Model):
    """
    Price.

    :quotation_item: The quotation item this price belongs to.
    :moq: TODO: Describe this field
    :price: The price.
    :currency: The currency for this price.

    """
    quotation_item = models.ForeignKey(
        'aps_purchasing.QuotationItem',
        verbose_name=_('Quotation item'),
        related_name='prices',
    )

    moq = models.DecimalField(
        verbose_name=_('MOQ'),
        max_digits=11,
        decimal_places=5,
    )

    price = models.DecimalField(
        verbose_name=_('price'),
        max_digits=11,
        decimal_places=5,
    )

    currency = models.ForeignKey(
        Currency,
        verbose_name=_('Currency'),
        related_name='prices',
    )

    def __unicode__(self):
        return u'{0}: {1} {2}'.format(
            self.quotation_item, self.price, self.currency)

class Quotation(models.Model):
    """
    Quotation.

    :distributor: The distributor offering this quotation.
    :ref_number: Reference number for this quotation.
    :issuance_date: Issuance date of this quotation.
    :expiry_date: Expiry date for this quotation.
    :completed: TODO: Describe this field.

    """
    distributor = models.ForeignKey(
        Distributor,
        verbose_name=_('Distributor'),
        related_name='quotations',
    )

    ref_number = models.CharField(
        verbose_name=_('Reference number'),
        max_length=128
    )

    issuance_date = models.DateTimeField(
        verbose_name=_('Issuance date'),
    )

    expiry_date = models.DateTimeField(
        verbose_name=_('Expiry date'),
    )

    is_completed = models.BooleanField(
        verbose_name=_('Completed'),
    )

    def __unicode__(self):
        return self.ref_number

class QuotationItem(models.Model):
    """
    Quotation item.

    :quotation: The quotation this item belongs to.
    :manufacturer: The manufacturer mannufacturing this product.
    :mpn: The MPN this quotation belongs refers to.
    :min_lead_time: TODO: Describe this field.
    :max_lead_time: TODO: Describe this field.

    """
    quotation = models.ForeignKey(
        Quotation,
        verbose_name=_('Quotation'),
        related_name='quotation_items',
    )

    manufacturer = models.ForeignKey(
        Manufacturer,
        verbose_name=_('Manufacturer'),
        related_name='quotations',
        blank=True, null=True,
    )

    mpn = models.ForeignKey(
        MPN,
        verbose_name=_('Manufacturer Part Number'),
        related_name='quotation_items',
    )

    min_lead_time = models.PositiveIntegerField(
        verbose_name=_('Minimum lead time'),
    )

    max_lead_time = models.PositiveIntegerField(
        verbose_name=_('Maximum lead time'),
    )

    def __unicode__(self):
        return u'{0} - {1}'.format(self.quotation, self.mpn)
<commit_msg>Fixed related names<commit_after>"""Models of the aps_purchasing app."""
from django.db import models
from django.utils.translation import ugettext_lazy as _

class AML(models.Model):
    """
    Approved Manufacturer List.

    List of IPNs that may only be purchased through approved manufacturers.

    :ipn: The IPN instance.
    :manufacturer: A manufacturer who is approved for the given IPN.

    """
    ipn = models.ForeignKey(
        'aps_bom.IPN',
        verbose_name=_('Internal Part Number'),
    )

    manufacturer = models.ForeignKey(
        'aps_purchasing.Manufacturer',
        verbose_name=('Manufacturer'),
    )

    class Meta:
        verbose_name = _('AML')
        verbose_name_plural = _('AMLs')

    def __unicode__(self):
        return u'{0} - {1}'.format(self.ipn, self.manufacturer)

class Currency(models.Model):
    """
    Currency.

    :iso_code: The ISO code of this currency.
    :name: The name of this currency.
    :sign: The sign of this currency.

    """
    iso_code = models.CharField(
        verbose_name=_('ISO code'),
        max_length=3,
    )

    name = models.CharField(
        verbose_name=_('Name'),
        max_length=128,
    )

    sign = models.CharField(
        verbose_name=_('Sign'),
        max_length=1,
    )

    class Meta:
        verbose_name = _('Currency')
        verbose_name_plural = _('Currencies')

    def __unicode__(self):
        return self.iso_code

class Distributor(models.Model):
    """
    Distributor.

    :name: Name of this distributor.
    :questionnaire_form: Name of the form that was used for this distributor.
    :supplier_form: TODO: Describe this field.
    :min_order_value: Minimum order value for this distributor.
    :currency: Default currency for this distributor.
    :payment_terms: Payment terms for this distributor.
    :is_approved: If ``True``, this distributor is approved for business.
    :is_active: If ``False``, this distributor cannot be used, even if it was
      approved before.

    """
    name = models.CharField(
        verbose_name=_('Name'),
        max_length=128,
    )

    questionnaire_form = models.CharField(
        verbose_name=_('Questionnaire form'),
        max_length=128,
    )

    supplier_form = models.CharField(
        verbose_name=_('Supplier form'),
        max_length=128,
    )

    min_order_value = models.DecimalField(
        verbose_name=_('Minimum order value'),
        max_digits=11,
        decimal_places=5,
    )

    currency = models.ForeignKey(
        'aps_purchasing.Currency',
        verbose_name=_('Currency'),
    )

    payment_terms = models.ForeignKey(
        'aps_purchasing.PaymentTerm',
        verbose_name=_('Payment terms'),
        related_name='distributors',
    )

    is_approved = models.BooleanField(
        verbose_name=_('Is approved'),
        default=False,
    )

    is_active = models.BooleanField(
        verbose_name=_('Is active'),
        default=True,
    )

    def __unicode__(self):
        return self.name

class DPN(models.Model):
    """
    Distributor Part Number.

    :code: The code of this DPN.
    :ipn: The internal part number this DPN is mapped to.
    :distributor: The distributor who sells this part.
    :name: The name of this part.
    :mpn: The manufacturer part number for this part.

    """
    code = models.CharField(
        verbose_name=_('Code'),
        max_length=50,
    )

    ipn = models.ForeignKey(
        'aps_bom.IPN',
        verbose_name=_('Internal Part Number'),
        related_name='dpns',
        null=True, blank=True,
    )

    distributor = models.ForeignKey(
        'aps_purchasing.Distributor',
        verbose_name=_('Distributor'),
        related_name='dpns',
    )

    name = models.CharField(
        verbose_name=_('Name'),
        max_length=128,
    )

    mpn = models.ForeignKey(
        'aps_purchasing.MPN',
        verbose_name=_('Manufacturer Part Number'),
        related_name='dpns',
    )

    class Meta:
        verbose_name = _('DPN')
        verbose_name_plural = _('DPNs')

    def __unicode__(self):
        return self.code

class Manufacturer(models.Model):
    """
    Manufacturer.

    :code: Internal code for this manufacturer.
    :name: Name of this manufacturer.

    """
    code = models.CharField(
        verbose_name=_('Code'),
        max_length=50,
    )

    name = models.CharField(
        verbose_name=_('Name'),
        max_length=128,
    )

    def __unicode__(self):
        return self.name

class MPN(models.Model):
    """
    Manufacturer Part Number.

    :code: The code of this MPN.
    :manufacturer: The manufacturer of this part.
    :name: The name of this part.
    :pku: The amount of parts in one pacakge unit.
    :unit: The package unit of this part.

    """
    code = models.CharField(
        verbose_name=_('Code'),
        max_length=50,
    )

    manufacturer = models.ForeignKey(
        'aps_purchasing.Manufacturer',
        verbose_name=_('Manufacturer'),
    )

    name = models.CharField(
        verbose_name=_('Name'),
        max_length=128,
    )

    pku = models.FloatField(
        verbose_name=_('Amount per packaging unit'),
    )

    unit = models.ForeignKey(
        'aps_purchasing.PackagingUnit',
        verbose_name=_('PackagingUnit'),
    )

    class Meta:
        verbose_name = _('MPN')
        verbose_name_plural = _('MPNs')

    def __unicode__(self):
        return self.code

class PackagingUnit(models.Model):
    """
    Packaging Unit.

    :name: The name of this unit.

    """
    name = models.CharField(
        verbose_name=_('Name'),
        max_length=128,
    )

    def __unicode__(self):
        return self.name

class PaymentTerm(models.Model):
    """
    Payment term.

    :code: Internal code for this payment term.
    :description: Description of this payment term.

    """
    code = models.CharField(
        verbose_name=_('Code'),
        max_length=50,
    )

    description = models.CharField(
        verbose_name=_('Description'),
        max_length=128,
    )

    def __unicode__(self):
        return self.code

class Price(models.Model):
    """
    Price.

    :quotation_item: The quotation item this price belongs to.
    :moq: TODO: Describe this field
    :price: The price.
    :currency: The currency for this price.

    """
    quotation_item = models.ForeignKey(
        'aps_purchasing.QuotationItem',
        verbose_name=_('Quotation item'),
        related_name='prices',
    )

    moq = models.DecimalField(
        verbose_name=_('MOQ'),
        max_digits=11,
        decimal_places=5,
    )

    price = models.DecimalField(
        verbose_name=_('price'),
        max_digits=11,
        decimal_places=5,
    )

    currency = models.ForeignKey(
        Currency,
        verbose_name=_('Currency'),
        related_name='prices',
    )

    def __unicode__(self):
        return u'{0}: {1} {2}'.format(
            self.quotation_item, self.price, self.currency)

class Quotation(models.Model):
    """
    Quotation.

    :distributor: The distributor offering this quotation.
    :ref_number: Reference number for this quotation.
    :issuance_date: Issuance date of this quotation.
    :expiry_date: Expiry date for this quotation.
    :completed: TODO: Describe this field.

    """
    distributor = models.ForeignKey(
        Distributor,
        verbose_name=_('Distributor'),
        related_name='quotations',
    )

    ref_number = models.CharField(
        verbose_name=_('Reference number'),
        max_length=128
    )

    issuance_date = models.DateTimeField(
        verbose_name=_('Issuance date'),
    )

    expiry_date = models.DateTimeField(
        verbose_name=_('Expiry date'),
    )

    is_completed = models.BooleanField(
        verbose_name=_('Completed'),
    )

    def __unicode__(self):
        return self.ref_number

class QuotationItem(models.Model):
    """
    Quotation item.

    :quotation: The quotation this item belongs to.
    :manufacturer: The manufacturer mannufacturing this product.
    :mpn: The MPN this quotation belongs refers to.
    :min_lead_time: TODO: Describe this field.
    :max_lead_time: TODO: Describe this field.

    """
    quotation = models.ForeignKey(
        Quotation,
        verbose_name=_('Quotation'),
        related_name='quotation_items',
    )

    manufacturer = models.ForeignKey(
        Manufacturer,
        verbose_name=_('Manufacturer'),
        related_name='quotations',
        blank=True, null=True,
    )

    mpn = models.ForeignKey(
        MPN,
        verbose_name=_('Manufacturer Part Number'),
        related_name='quotation_items',
    )

    min_lead_time = models.PositiveIntegerField(
        verbose_name=_('Minimum lead time'),
    )

    max_lead_time = models.PositiveIntegerField(
        verbose_name=_('Maximum lead time'),
    )

    def __unicode__(self):
        return u'{0} - {1}'.format(self.quotation, self.mpn)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Generated by Django 1.11.11 on 2018-03-26 21:47
# flake8: noqa
from __future__ import unicode_literals

from django.db import migrations, models

class Migration(migrations.Migration):

    dependencies = [
        ('icds_reports', '0035_auto_20180317_0645'),
    ]

    operations = [
        migrations.AlterField(
            model_name='aggregateccsrecordpostnatalcareforms',
            name='counsel_methods',
            field=models.PositiveSmallIntegerField(help_text='Counseling about family planning methods has ever occurred', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='counsel_adequate_bf',
            field=models.PositiveSmallIntegerField(help_text='Counseling about adequate breastfeeding has ever occurred', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='counsel_breast',
            field=models.PositiveSmallIntegerField(help_text='Counseling on managing breast problems has ever been completed', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='counsel_exclusive_bf',
            field=models.PositiveSmallIntegerField(help_text='Counseling about exclusive breastfeeding has ever occurred', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='counsel_increase_food_bf',
            field=models.PositiveSmallIntegerField(help_text='Counseling on increasing food intake has ever been completed', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='counsel_only_milk',
            field=models.PositiveSmallIntegerField(help_text='Counseling about avoiding other than breast milk has ever occurred', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='eating',
            field=models.PositiveSmallIntegerField(help_text='Child given something to eat in the last form submitted this month', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='is_ebf',
            field=models.PositiveSmallIntegerField(help_text='is_ebf set in the last form submitted this month', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='not_breastfeeding',
            field=models.CharField(help_text='The reason the mother is not able to breastfeed', max_length=126, null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='other_milk_to_child',
            field=models.PositiveSmallIntegerField(help_text='Child given something other than milk in the last form submitted this month', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='skin_to_skin',
            field=models.PositiveSmallIntegerField(help_text='Counseling on skin to skin care has ever been completed', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='tea_other',
            field=models.PositiveSmallIntegerField(help_text='Child given tea or other liquid in the last form submitted this month', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='water_or_milk',
            field=models.PositiveSmallIntegerField(help_text='Child given water or milk in the last form submitted this month', null=True),
        ),
    ]
<commit_msg>add absolute_import<commit_after># -*- coding: utf-8 -*-
# Generated by Django 1.11.11 on 2018-03-26 21:47
# flake8: noqa
from __future__ import unicode_literals

from __future__ import absolute_import
from django.db import migrations, models

class Migration(migrations.Migration):

    dependencies = [
        ('icds_reports', '0035_auto_20180317_0645'),
    ]

    operations = [
        migrations.AlterField(
            model_name='aggregateccsrecordpostnatalcareforms',
            name='counsel_methods',
            field=models.PositiveSmallIntegerField(help_text='Counseling about family planning methods has ever occurred', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='counsel_adequate_bf',
            field=models.PositiveSmallIntegerField(help_text='Counseling about adequate breastfeeding has ever occurred', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='counsel_breast',
            field=models.PositiveSmallIntegerField(help_text='Counseling on managing breast problems has ever been completed', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='counsel_exclusive_bf',
            field=models.PositiveSmallIntegerField(help_text='Counseling about exclusive breastfeeding has ever occurred', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='counsel_increase_food_bf',
            field=models.PositiveSmallIntegerField(help_text='Counseling on increasing food intake has ever been completed', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='counsel_only_milk',
            field=models.PositiveSmallIntegerField(help_text='Counseling about avoiding other than breast milk has ever occurred', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='eating',
            field=models.PositiveSmallIntegerField(help_text='Child given something to eat in the last form submitted this month', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='is_ebf',
            field=models.PositiveSmallIntegerField(help_text='is_ebf set in the last form submitted this month', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='not_breastfeeding',
            field=models.CharField(help_text='The reason the mother is not able to breastfeed', max_length=126, null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='other_milk_to_child',
            field=models.PositiveSmallIntegerField(help_text='Child given something other than milk in the last form submitted this month', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='skin_to_skin',
            field=models.PositiveSmallIntegerField(help_text='Counseling on skin to skin care has ever been completed', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='tea_other',
            field=models.PositiveSmallIntegerField(help_text='Child given tea or other liquid in the last form submitted this month', null=True),
        ),
        migrations.AlterField(
            model_name='aggregatechildhealthpostnatalcareforms',
            name='water_or_milk',
            field=models.PositiveSmallIntegerField(help_text='Child given water or milk in the last form submitted this month', null=True),
        ),
    ]
<|endoftext|>