# -*- coding: utf-8 -*-

# Copyright (c) 2010-2017 Tuukka Turto
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

"""
Module defining classes related to inventory actions
"""
from pyherc.data import is_armour, is_weapon, is_boots
from pyherc.aspects import log_debug, log_info
from pyherc.events import new_unequip_event
from pyherc.rules.factory import SubActionFactory

class UnEquipFactory(SubActionFactory):
    """
    Factory for creating unequip actions

    .. versionadded:: 0.8
    """
    @log_debug
    def __init__(self):
        """
        Constructor for this factory
        """
        super().__init__()
        self.sub_action = 'unequip'

    @log_debug
    def can_handle(self, parameters):
        """
        Can this factory process these parameters

        :param parameters: parameters to check
        :returns: True if factory is capable of handling parameters
        :rtype: Boolean
        """
        return self.sub_action == parameters.sub_action

    @log_info
    def get_action(self, parameters):
        """
        Create an unequip action

        :param parameters: parameters used to control creation
        :type parameters: InventoryParameters
        """
        return UnEquipAction(parameters.character, parameters.item)

class UnEquipAction():
    """
    Action for unequiping an item

    .. versionadded:: 0.8
    """
    @log_debug
    def __init__(self, character, item):
        """
        Default constructor

        :param character: character wearing the item
        :type character: Character
        :param item: item to unequip
        :type item: Item
        """
        super().__init__()

        self.character = character
        self.item = item

    @log_info
    def execute(self):
        """
        Executes this action
        """
        if is_armour(self.item):
            self.character.inventory.armour = None
            self.character.raise_event(new_unequip_event(self.character,
                                                         self.item))
        if is_weapon(self.item):
            self.character.inventory.weapon = None
            self.character.raise_event(new_unequip_event(self.character,
                                                         self.item))

        if is_boots(self.item):
            self.character.inventory.boots = None
            self.character.raise_event(new_unequip_event(self.character,
                                                         self.item))

    @log_debug
    def is_legal(self):
        """
        Check if the action is possible to perform

        :returns: True if move is possible, false otherwise
        :rtype: Boolean
        """
        return True


# Copyright The PyTorch Lightning team.
#
# 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.
import pytest

from pytorch_lightning import Callback, Trainer
from tests.helpers.boring_model import BoringModel

@pytest.mark.parametrize("single_cb", [False, True])
def test_train_step_no_return(tmpdir, single_cb: bool):
    """
    Tests that only training_step can be used
    """

    class CB(Callback):
        def on_train_batch_end(self, trainer, pl_module, outputs, batch, batch_idx, dataloader_idx):
            assert "loss" in outputs

        def on_validation_batch_end(self, trainer, pl_module, outputs, batch, batch_idx, dataloader_idx):
            assert "x" in outputs

        def on_test_batch_end(self, trainer, pl_module, outputs, batch, batch_idx, dataloader_idx):
            assert "x" in outputs

    class TestModel(BoringModel):
        def on_train_batch_end(self, outputs, batch, batch_idx: int, dataloader_idx: int) -> None:
            assert "loss" in outputs

        def on_validation_batch_end(self, outputs, batch, batch_idx: int, dataloader_idx: int) -> None:
            assert "x" in outputs

        def on_test_batch_end(self, outputs, batch, batch_idx: int, dataloader_idx: int) -> None:
            assert "x" in outputs

        def training_epoch_end(self, outputs) -> None:
            assert len(outputs) == self.trainer.num_training_batches

    model = TestModel()

    trainer = Trainer(
        callbacks=CB() if single_cb else [CB()],
        default_root_dir=tmpdir,
        limit_train_batches=2,
        limit_val_batches=2,
        max_epochs=1,
        log_every_n_steps=1,
        weights_summary=None,
    )

    assert any(isinstance(c, CB) for c in trainer.callbacks)

    trainer.fit(model)

def test_free_memory_on_eval_outputs(tmpdir):
    class CB(Callback):
        def on_epoch_end(self, trainer, pl_module):
            assert len(trainer._evaluation_loop.outputs) == 0

    model = BoringModel()

    trainer = Trainer(
        callbacks=CB(),
        default_root_dir=tmpdir,
        limit_train_batches=2,
        limit_val_batches=2,
        max_epochs=1,
        weights_summary=None,
    )

    trainer.fit(model)


# pylint: disable=W0611
# coding: utf-8
'''
Window
======

Core class for creating the default Kivy window. Kivy supports only one window
per application: please don't try to create more than one.
'''

__all__ = ('Keyboard', 'WindowBase', 'Window')

from os.path import join, exists
from os import getcwd

from kivy.core import core_select_lib
from kivy.clock import Clock
from kivy.config import Config
from kivy.logger import Logger
from kivy.base import EventLoop, stopTouchApp
from kivy.modules import Modules
from kivy.event import EventDispatcher
from kivy.properties import ListProperty, ObjectProperty, AliasProperty, \
    NumericProperty, OptionProperty, StringProperty, BooleanProperty
from kivy.utils import platform, reify
from kivy.context import get_current_context
from kivy.uix.behaviors import FocusBehavior
from kivy.setupconfig import USE_SDL2
from kivy.graphics.transformation import Matrix

# late import
VKeyboard = None
android = None

class Keyboard(EventDispatcher):
    '''Keyboard interface that is returned by
    :meth:`WindowBase.request_keyboard`. When you request a keyboard,
    you'll get an instance of this class. Whatever the keyboard input is
    (system or virtual keyboard), you'll receive events through this
    instance.

    :Events:
        `on_key_down`: keycode, text, modifiers
            Fired when a new key is pressed down
        `on_key_up`: keycode
            Fired when a key is released (up)

    Here is an example of how to request a Keyboard in accordance with the
    current configuration:

    .. include:: ../../examples/widgets/keyboardlistener.py
        :literal:

    '''

    # Keycodes mapping, between str <-> int. These keycodes are
    # currently taken from pygame.key. But when a new provider will be
    # used, it must do the translation to these keycodes too.
    keycodes = {
        # specials keys
        'backspace': 8, 'tab': 9, 'enter': 13, 'rshift': 303, 'shift': 304,
        'alt': 308, 'rctrl': 306, 'lctrl': 305,
        'super': 309, 'alt-gr': 307, 'compose': 311, 'pipe': 310,
        'capslock': 301, 'escape': 27, 'spacebar': 32, 'pageup': 280,
        'pagedown': 281, 'end': 279, 'home': 278, 'left': 276, 'up':
        273, 'right': 275, 'down': 274, 'insert': 277, 'delete': 127,
        'numlock': 300, 'print': 144, 'screenlock': 145, 'pause': 19,

        # a-z keys
        'a': 97, 'b': 98, 'c': 99, 'd': 100, 'e': 101, 'f': 102, 'g': 103,
        'h': 104, 'i': 105, 'j': 106, 'k': 107, 'l': 108, 'm': 109, 'n': 110,
        'o': 111, 'p': 112, 'q': 113, 'r': 114, 's': 115, 't': 116, 'u': 117,
        'v': 118, 'w': 119, 'x': 120, 'y': 121, 'z': 122,

        # 0-9 keys
        '0': 48, '1': 49, '2': 50, '3': 51, '4': 52,
        '5': 53, '6': 54, '7': 55, '8': 56, '9': 57,

        # numpad
        'numpad0': 256, 'numpad1': 257, 'numpad2': 258, 'numpad3': 259,
        'numpad4': 260, 'numpad5': 261, 'numpad6': 262, 'numpad7': 263,
        'numpad8': 264, 'numpad9': 265, 'numpaddecimal': 266,
        'numpaddivide': 267, 'numpadmul': 268, 'numpadsubstract': 269,
        'numpadadd': 270, 'numpadenter': 271,

        # F1-15
        'f1': 282, 'f2': 283, 'f3': 284, 'f4': 285, 'f5': 286, 'f6': 287,
        'f7': 288, 'f8': 289, 'f9': 290, 'f10': 291, 'f11': 292, 'f12': 293,
        'f13': 294, 'f14': 295, 'f15': 296,

        # other keys
        '(': 40, ')': 41,
        '[': 91, ']': 93,
        '{': 123, '}': 125,
        ':': 59, ';': 59,
        '=': 61, '+': 43,
        '-': 45, '_': 95,
        '/': 47, '*': 42,
        '?': 47,
        '`': 96, '~': 126,
        '´': 180, '¦': 166,
        '\\': 92, '|': 124,
        '"': 34, "'": 39,
        ',': 44, '.': 46,
        '<': 60, '>': 62,
        '@': 64, '!': 33,
        '#': 35, '$': 36,
        '%': 37, '^': 94,
        '&': 38, '¬': 172,
        '¨': 168, '…': 8230,
        'ù': 249, 'à': 224,
        'é': 233, 'è': 232,
    }

    __events__ = ('on_key_down', 'on_key_up', 'on_textinput')

    def __init__(self, **kwargs):
        super(Keyboard, self).__init__()

        #: Window which the keyboard is attached too
        self.window = kwargs.get('window', None)

        #: Callback that will be called when the keyboard is released
        self.callback = kwargs.get('callback', None)

        #: Target that have requested the keyboard
        self.target = kwargs.get('target', None)

        #: VKeyboard widget, if allowed by the configuration
        self.widget = kwargs.get('widget', None)

    def on_key_down(self, keycode, text, modifiers):
        pass

    def on_key_up(self, keycode):
        pass

    def on_textinput(self, text):
        pass

    def release(self):
        '''Call this method to release the current keyboard.
        This will ensure that the keyboard is no longer attached to your
        callback.'''
        if self.window:
            self.window.release_keyboard(self.target)

    def _on_window_textinput(self, instance, text):
        return self.dispatch('on_textinput', text)

    def _on_window_key_down(self, instance, keycode, scancode, text,
                            modifiers):
        keycode = (keycode, self.keycode_to_string(keycode))
        if text == '\x04':
            Window.trigger_keyboard_height()
            return
        return self.dispatch('on_key_down', keycode, text, modifiers)

    def _on_window_key_up(self, instance, keycode, *largs):
        keycode = (keycode, self.keycode_to_string(keycode))
        return self.dispatch('on_key_up', keycode)

    def _on_vkeyboard_key_down(self, instance, keycode, text, modifiers):
        if keycode is None:
            keycode = text.lower()
        keycode = (self.string_to_keycode(keycode), keycode)
        return self.dispatch('on_key_down', keycode, text, modifiers)

    def _on_vkeyboard_key_up(self, instance, keycode, text, modifiers):
        if keycode is None:
            keycode = text
        keycode = (self.string_to_keycode(keycode), keycode)
        return self.dispatch('on_key_up', keycode)

    def _on_vkeyboard_textinput(self, instance, text):
        return self.dispatch('on_textinput', text)

    def string_to_keycode(self, value):
        '''Convert a string to a keycode number according to the
        :attr:`Keyboard.keycodes`. If the value is not found in the
        keycodes, it will return -1.
        '''
        return Keyboard.keycodes.get(value, -1)

    def keycode_to_string(self, value):
        '''Convert a keycode number to a string according to the
        :attr:`Keyboard.keycodes`. If the value is not found in the
        keycodes, it will return ''.
        '''
        keycodes = list(Keyboard.keycodes.values())
        if value in keycodes:
            return list(Keyboard.keycodes.keys())[keycodes.index(value)]
        return ''

class WindowBase(EventDispatcher):
    '''WindowBase is an abstract window widget for any window implementation.

    :Parameters:
        `borderless`: str, one of ('0', '1')
            Set the window border state. Check the
            :mod:`~kivy.config` documentation for a
            more detailed explanation on the values.
        `fullscreen`: str, one of ('0', '1', 'auto', 'fake')
            Make the window fullscreen. Check the
            :mod:`~kivy.config` documentation for a
            more detailed explanation on the values.
        `width`: int
            Width of the window.
        `height`: int
            Height of the window.

    :Events:
        `on_motion`: etype, motionevent
            Fired when a new :class:`~kivy.input.motionevent.MotionEvent` is
            dispatched
        `on_touch_down`:
            Fired when a new touch event is initiated.
        `on_touch_move`:
            Fired when an existing touch event changes location.
        `on_touch_up`:
            Fired when an existing touch event is terminated.
        `on_draw`:
            Fired when the :class:`Window` is being drawn.
        `on_flip`:
            Fired when the :class:`Window` GL surface is being flipped.
        `on_rotate`: rotation
            Fired when the :class:`Window` is being rotated.
        `on_close`:
            Fired when the :class:`Window` is closed.
        `on_request_close`:
            Fired when the event loop wants to close the window, or if the
            escape key is pressed and `exit_on_escape` is `True`. If a function
            bound to this event returns `True`, the window will not be closed.
            If the the event is triggered because of the keyboard escape key,
            the keyword argument `source` is dispatched along with a value of
            `keyboard` to the bound functions.

            .. versionadded:: 1.9.0

        `on_keyboard`: key, scancode, codepoint, modifier
            Fired when the keyboard is used for input.

            .. versionchanged:: 1.3.0
                The *unicode* parameter has been deprecated in favor of
                codepoint, and will be removed completely in future versions.

        `on_key_down`: key, scancode, codepoint
            Fired when a key pressed.

            .. versionchanged:: 1.3.0
                The *unicode* parameter has been deprecated in favor of
                codepoint, and will be removed completely in future versions.

        `on_key_up`: key, scancode, codepoint
            Fired when a key is released.

            .. versionchanged:: 1.3.0
                The *unicode* parameter has be deprecated in favor of
                codepoint, and will be removed completely in future versions.

        `on_dropfile`: str
            Fired when a file is dropped on the application.

    '''

    __instance = None
    __initialized = False
    _fake_fullscreen = False
    _density = 1

    # private properties
    _size = ListProperty([0, 0])
    _modifiers = ListProperty([])
    _rotation = NumericProperty(0)
    _clearcolor = ObjectProperty([0, 0, 0, 1])

    children = ListProperty([])
    '''List of the children of this window.

    :attr:`children` is a :class:`~kivy.properties.ListProperty` instance and
    defaults to an empty list.

    Use :meth:`add_widget` and :meth:`remove_widget` to manipulate the list of
    children. Don't manipulate the list directly unless you know what you are
    doing.
    '''

    parent = ObjectProperty(None, allownone=True)
    '''Parent of this window.

    :attr:`parent` is a :class:`~kivy.properties.ObjectProperty` instance and
    defaults to None. When created, the parent is set to the window itself.
    You must take care of it if you are doing a recursive check.
    '''

    icon = StringProperty()

    def _get_modifiers(self):
        return self._modifiers

    modifiers = AliasProperty(_get_modifiers, None)
    '''List of keyboard modifiers currently active.
    '''

    def _get_size(self):
        r = self._rotation
        w, h = self._size
        if self._density != 1:
            w, h = self._win._get_gl_size()
        if self.softinput_mode == 'resize':
            h -= self.keyboard_height
        if r in (0, 180):
            return w, h
        return h, w

    def _set_size(self, size):
        if self._size != size:
            r = self._rotation
            if r in (0, 180):
                self._size = size
            else:
                self._size = size[1], size[0]

            self.dispatch('on_resize', *size)
            return True
        else:
            return False

    size = AliasProperty(_get_size, _set_size, bind=('_size', ))
    '''Get the rotated size of the window. If :attr:`rotation` is set, then the
    size will change to reflect the rotation.
    '''

    def _get_clearcolor(self):
        return self._clearcolor

    def _set_clearcolor(self, value):
        if value is not None:
            if type(value) not in (list, tuple):
                raise Exception('Clearcolor must be a list or tuple')
            if len(value) != 4:
                raise Exception('Clearcolor must contain 4 values')
        self._clearcolor = value

    clearcolor = AliasProperty(_get_clearcolor, _set_clearcolor,
                               bind=('_clearcolor', ))
    '''Color used to clear the window.

    ::

        from kivy.core.window import Window

        # red background color
        Window.clearcolor = (1, 0, 0, 1)

        # don't clear background at all
        Window.clearcolor = None

    .. versionchanged:: 1.7.2
        The clearcolor default value is now: (0, 0, 0, 1).

    '''

    # make some property read-only
    def _get_width(self):
        _size = self._size
        if self._density != 1:
            _size = self._win._get_gl_size()
        r = self._rotation
        if r == 0 or r == 180:
            return _size[0]
        return _size[1]

    width = AliasProperty(_get_width, None, bind=('_rotation', '_size'))
    '''Rotated window width.

    :attr:`width` is a read-only :class:`~kivy.properties.AliasProperty`.
    '''

    def _get_height(self):
        '''Rotated window height'''
        r = self._rotation
        _size = self._size
        if self._density != 1:
            _size = self._win._get_gl_size()
        kb = self.keyboard_height if self.softinput_mode == 'resize' else 0
        if r == 0 or r == 180:
            return _size[1] - kb
        return _size[0] - kb

    height = AliasProperty(_get_height, None, bind=('_rotation', '_size'))
    '''Rotated window height.

    :attr:`height` is a read-only :class:`~kivy.properties.AliasProperty`.
    '''

    def _get_center(self):
        return self.width / 2., self.height / 2.

    center = AliasProperty(_get_center, None, bind=('width', 'height'))
    '''Center of the rotated window.

    :attr:`center` is a :class:`~kivy.properties.AliasProperty`.
    '''

    def _get_rotation(self):
        return self._rotation

    def _set_rotation(self, x):
        x = int(x % 360)
        if x == self._rotation:
            return
        if x not in (0, 90, 180, 270):
            raise ValueError('can rotate only 0, 90, 180, 270 degrees')
        self._rotation = x
        if self.initialized is False:
            return
        self.dispatch('on_resize', *self.size)
        self.dispatch('on_rotate', x)

    rotation = AliasProperty(_get_rotation, _set_rotation,
                             bind=('_rotation', ))
    '''Get/set the window content rotation. Can be one of 0, 90, 180, 270
    degrees.
    '''

    softinput_mode = OptionProperty('', options=('', 'pan', 'scale', 'resize'))
    '''This specifies the behavior of window contents on display of soft
    keyboard on mobile platform. Can be one of '', 'pan', 'scale', 'resize'.

    When '' The main window is left as it is allowing the user to use
    :attr:`keyboard_height` to manage the window contents the way they want.

    when 'pan' The main window pans moving the bottom part of the window to be
    always on top of the keyboard.

    when 'resize' The window is resized and the contents scaled to fit the
    remaining space.

    .. versionadded:: 1.9.0

    :attr:`softinput_mode` is a :class:`OptionProperty` defaults to None.

    '''

    _keyboard_changed = BooleanProperty(False)

    def _upd_kbd_height(self, *kargs):
        self._keyboard_changed = not self._keyboard_changed

    def _get_ios_kheight(self):
        return 0

    def _get_android_kheight(self):
        global android
        if not android:
            import android
        return android.get_keyboard_height()

    def _get_kheight(self):
        if platform == 'android':
            return self._get_android_kheight()
        if platform == 'ios':
            return self._get_ios_kheight()
        return 0

    keyboard_height = AliasProperty(_get_kheight, None,
                                    bind=('_keyboard_changed',))
    '''Rerturns the height of the softkeyboard/IME on mobile platforms.
    Will return 0 if not on mobile platform or if IME is not active.

    .. versionadded:: 1.9.0

    :attr:`keyboard_height` is a read-only :class:`AliasProperty` defaults to 0.
    '''

    def _set_system_size(self, size):
        self._size = size

    def _get_system_size(self):
        if self.softinput_mode == 'resize':
            return self._size[0], self._size[1] - self.keyboard_height
        return self._size

    system_size = AliasProperty(
        _get_system_size,
        _set_system_size,
        bind=('_size', ))
    '''Real size of the window ignoring rotation.
    '''

    borderless = BooleanProperty(False)
    '''When set to True, this property removes the window border/decoration.

    .. versionadded:: 1.9.0

    :attr:`borderless` is a :class:`BooleanProperty`, defaults to False.
    '''

    fullscreen = OptionProperty(False, options=(True, False, 'auto', 'fake'))
    '''This property sets the fullscreen mode of the window. Available options
    are: True, False, 'auto', 'fake'. Check the :mod:`~kivy.config`
    documentation for a more detailed explanation on the values.

    .. versionadded:: 1.2.0

    .. note::
        The 'fake' option has been deprecated, use the :attr:`borderless`
        property instead.
    '''

    mouse_pos = ObjectProperty([0, 0])
    '''2d position of the mouse within the window.

    .. versionadded:: 1.2.0
    '''

    @property
    def __self__(self):
        return self

    top = NumericProperty(None, allownone=True)
    left = NumericProperty(None, allownone=True)
    position = OptionProperty('auto', options=['auto', 'custom'])
    render_context = ObjectProperty(None)
    canvas = ObjectProperty(None)
    title = StringProperty('Kivy')

    __events__ = (
        'on_draw', 'on_flip', 'on_rotate', 'on_resize', 'on_close',
        'on_motion', 'on_touch_down', 'on_touch_move', 'on_touch_up',
        'on_mouse_down', 'on_mouse_move', 'on_mouse_up', 'on_keyboard',
        'on_key_down', 'on_key_up', 'on_textinput', 'on_dropfile',
        'on_request_close', 'on_joy_axis', 'on_joy_hat', 'on_joy_ball',
        'on_joy_button_down', "on_joy_button_up")

    def __new__(cls, **kwargs):
        if cls.__instance is None:
            cls.__instance = EventDispatcher.__new__(cls)
        return cls.__instance

    def __init__(self, **kwargs):

        force = kwargs.pop('force', False)

        # don't init window 2 times,
        # except if force is specified
        if WindowBase.__instance is not None and not force:
            return

        self.initialized = False
        self._is_desktop = Config.getboolean('kivy', 'desktop')

        # create a trigger for update/create the window when one of window
        # property changes
        self.trigger_create_window = Clock.create_trigger(
            self.create_window, -1)

        # Create a trigger for updating the keyboard height
        self.trigger_keyboard_height = Clock.create_trigger(
            self._upd_kbd_height, .5)

        # set the default window parameter according to the configuration
        if 'borderless' not in kwargs:
            kwargs['borderless'] = Config.getboolean('graphics', 'borderless')
        if 'fullscreen' not in kwargs:
            fullscreen = Config.get('graphics', 'fullscreen')
            if fullscreen not in ('auto', 'fake'):
                fullscreen = fullscreen.lower() in ('true', '1', 'yes', 'yup')
            kwargs['fullscreen'] = fullscreen
        if 'width' not in kwargs:
            kwargs['width'] = Config.getint('graphics', 'width')
        if 'height' not in kwargs:
            kwargs['height'] = Config.getint('graphics', 'height')
        if 'rotation' not in kwargs:
            kwargs['rotation'] = Config.getint('graphics', 'rotation')
        if 'position' not in kwargs:
            kwargs['position'] = Config.getdefault('graphics', 'position',
                                                   'auto')
        if 'top' in kwargs:
            kwargs['position'] = 'custom'
            kwargs['top'] = kwargs['top']
        else:
            kwargs['top'] = Config.getint('graphics', 'top')
        if 'left' in kwargs:
            kwargs['position'] = 'custom'
            kwargs['left'] = kwargs['left']
        else:
            kwargs['left'] = Config.getint('graphics', 'left')
        kwargs['_size'] = (kwargs.pop('width'), kwargs.pop('height'))

        super(WindowBase, self).__init__(**kwargs)

        # bind all the properties that need to recreate the window
        self._bind_create_window()
        self.bind(size=self.trigger_keyboard_height,
                  rotation=self.trigger_keyboard_height)

        self.bind(softinput_mode=lambda *dt: self.update_viewport(),
                  keyboard_height=lambda *dt: self.update_viewport())

        # init privates
        self._system_keyboard = Keyboard(window=self)
        self._keyboards = {'system': self._system_keyboard}
        self._vkeyboard_cls = None

        self.children = []
        self.parent = self

        # before creating the window
        import kivy.core.gl  # NOQA

        # configure the window
        self.create_window()

        # attach modules + listener event
        EventLoop.set_window(self)
        Modules.register_window(self)
        EventLoop.add_event_listener(self)

        # manage keyboard(s)
        self.configure_keyboards()

        # assign the default context of the widget creation
        if not hasattr(self, '_context'):
            self._context = get_current_context()

        # mark as initialized
        self.initialized = True

    def _bind_create_window(self):
        for prop in (
                'fullscreen', 'borderless', 'position', 'top',
                'left', '_size', 'system_size'):
            self.bind(**{prop: self.trigger_create_window})

    def _unbind_create_window(self):
        for prop in (
                'fullscreen', 'borderless', 'position', 'top',
                'left', '_size', 'system_size'):
            self.unbind(**{prop: self.trigger_create_window})

    def toggle_fullscreen(self):
        '''Toggle between fullscreen and windowed mode.

        .. deprecated:: 1.9.0
            Use :attr:`fullscreen` instead.
        '''
        pass

    def maximize(self):
        '''Maximizes the window. This method should be used on desktop
        platforms only.

        .. versionadded:: 1.9.0

        .. note::
            This feature requires a SDL2 window provider and is currently only
            supported on desktop platforms.

        .. warning::
            This code is still experimental, and its API may be subject to
            change in a future version.
        '''
        Logger.warning('Window: maximize() is not implemented in the current '
                        'window provider.')

    def minimize(self):
        '''Minimizes the window. This method should be used on desktop
        platforms only.

        .. versionadded:: 1.9.0

        .. note::
            This feature requires a SDL2 window provider and is currently only
            supported on desktop platforms.

        .. warning::
            This code is still experimental, and its API may be subject to
            change in a future version.
        '''
        Logger.warning('Window: minimize() is not implemented in the current '
                        'window provider.')

    def restore(self):
        '''Restores the size and position of a maximized or minimized window.
        This method should be used on desktop platforms only.

        .. versionadded:: 1.9.0

        .. note::
            This feature requires a SDL2 window provider and is currently only
            supported on desktop platforms.

        .. warning::
            This code is still experimental, and its API may be subject to
            change in a future version.
        '''
        Logger.warning('Window: restore() is not implemented in the current '
                        'window provider.')

    def hide(self):
        '''Hides the window. This method should be used on desktop
        platforms only.

        .. versionadded:: 1.9.0

        .. note::
            This feature requires a SDL2 window provider and is currently only
            supported on desktop platforms.

        .. warning::
            This code is still experimental, and its API may be subject to
            change in a future version.
        '''
        Logger.warning('Window: hide() is not implemented in the current '
                        'window provider.')

    def show(self):
        '''Shows the window. This method should be used on desktop
        platforms only.

        .. versionadded:: 1.9.0

        .. note::
            This feature requires a SDL2 window provider and is currently only
            supported on desktop platforms.

        .. warning::
            This code is still experimental, and its API may be subject to
            change in a future version.
        '''
        Logger.warning('Window: show() is not implemented in the current '
                        'window provider.')

    def close(self):
        '''Close the window'''
        pass

    def create_window(self, *largs):
        '''Will create the main window and configure it.

        .. warning::
            This method is called automatically at runtime. If you call it, it
            will recreate a RenderContext and Canvas. This means you'll have a
            new graphics tree, and the old one will be unusable.

            This method exist to permit the creation of a new OpenGL context
            AFTER closing the first one. (Like using runTouchApp() and
            stopTouchApp()).

            This method has only been tested in a unittest environment and
            is not suitable for Applications.

            Again, don't use this method unless you know exactly what you are
            doing!
        '''
        # just to be sure, if the trigger is set, and if this method is
        # manually called, unset the trigger
        Clock.unschedule(self.create_window)

        # ensure the window creation will not be called twice
        if platform in ('android', 'ios'):
            self._unbind_create_window()

        if not self.initialized:
            from kivy.core.gl import init_gl
            init_gl()

            # create the render context and canvas, only the first time.
            from kivy.graphics import RenderContext, Canvas
            self.render_context = RenderContext()
            self.canvas = Canvas()
            self.render_context.add(self.canvas)

        else:
            # if we get initialized more than once, then reload opengl state
            # after the second time.
            # XXX check how it's working on embed platform.
            if platform == 'linux' or Window.__class__.__name__ == 'WindowSDL':
                # on linux, it's safe for just sending a resize.
                self.dispatch('on_resize', *self.system_size)

            else:
                # on other platform, window are recreated, we need to reload.
                from kivy.graphics.context import get_context
                get_context().reload()
                Clock.schedule_once(lambda x: self.canvas.ask_update(), 0)
                self.dispatch('on_resize', *self.system_size)

        # ensure the gl viewport is correct
        self.update_viewport()

    def on_flip(self):
        '''Flip between buffers (event)'''
        self.flip()

    def flip(self):
        '''Flip between buffers'''
        pass

    def _update_childsize(self, instance, value):
        self.update_childsize([instance])

    def add_widget(self, widget, canvas=None):
        '''Add a widget to a window'''
        widget.parent = self
        self.children.insert(0, widget)
        canvas = self.canvas.before if canvas == 'before' else \
            self.canvas.after if canvas == 'after' else self.canvas
        canvas.add(widget.canvas)
        self.update_childsize([widget])
        widget.bind(
            pos_hint=self._update_childsize,
            size_hint=self._update_childsize,
            size=self._update_childsize,
            pos=self._update_childsize)

    def remove_widget(self, widget):
        '''Remove a widget from a window
        '''
        if not widget in self.children:
            return
        self.children.remove(widget)
        if widget.canvas in self.canvas.children:
            self.canvas.remove(widget.canvas)
        elif widget.canvas in self.canvas.after.children:
            self.canvas.after.remove(widget.canvas)
        elif widget.canvas in self.canvas.before.children:
            self.canvas.before.remove(widget.canvas)
        widget.parent = None
        widget.unbind(
            pos_hint=self._update_childsize,
            size_hint=self._update_childsize,
            size=self._update_childsize,
            pos=self._update_childsize)

    def clear(self):
        '''Clear the window with the background color'''
        # XXX FIXME use late binding
        from kivy.graphics.opengl import glClearColor, glClear, \
            GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT
        cc = self._clearcolor
        if cc is not None:
            glClearColor(*cc)
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
                    GL_STENCIL_BUFFER_BIT)

    def set_title(self, title):
        '''Set the window title.

        .. versionadded:: 1.0.5
        '''
        self.title = title

    def set_icon(self, filename):
        '''Set the icon of the window.

        .. versionadded:: 1.0.5
        '''
        self.icon = filename

    def to_widget(self, x, y, initial=True, relative=False):
        return (x, y)

    def to_window(self, x, y, initial=True, relative=False):
        return (x, y)

    def _apply_transform(self, m):
        return m

    def get_window_matrix(self, x=0, y=0):
        m = Matrix()
        m.translate(x, y, 0)
        return m

    def get_root_window(self):
        return self

    def get_parent_window(self):
        return self

    def get_parent_layout(self):
        return None

    def on_draw(self):
        self.clear()
        self.render_context.draw()

    def on_motion(self, etype, me):
        '''Event called when a Motion Event is received.

        :Parameters:
            `etype`: str
                One of 'begin', 'update', 'end'
            `me`: :class:`~kivy.input.motionevent.MotionEvent`
                The Motion Event currently dispatched.
        '''
        if me.is_touch:
            w, h = self.system_size
            if platform == 'ios' or self._density != 1:
                w, h = self.size
            me.scale_for_screen(w, h, rotation=self._rotation,
                                smode=self.softinput_mode,
                                kheight=self.keyboard_height)
            if etype == 'begin':
                self.dispatch('on_touch_down', me)
            elif etype == 'update':
                self.dispatch('on_touch_move', me)
            elif etype == 'end':
                self.dispatch('on_touch_up', me)
                FocusBehavior._handle_post_on_touch_up(me)

    def on_touch_down(self, touch):
        '''Event called when a touch down event is initiated.

        .. versionchanged:: 1.9.0
            The touch `pos` is now transformed to window coordinates before
            this method is called. Before, the touch `pos` coordinate would be
            `(0, 0)` when this method was called.
        '''
        for w in self.children[:]:
            if w.dispatch('on_touch_down', touch):
                return True

    def on_touch_move(self, touch):
        '''Event called when a touch event moves (changes location).

        .. versionchanged:: 1.9.0
            The touch `pos` is now transformed to window coordinates before
            this method is called. Before, the touch `pos` coordinate would be
            `(0, 0)` when this method was called.
        '''
        for w in self.children[:]:
            if w.dispatch('on_touch_move', touch):
                return True

    def on_touch_up(self, touch):
        '''Event called when a touch event is released (terminated).

        .. versionchanged:: 1.9.0
            The touch `pos` is now transformed to window coordinates before
            this method is called. Before, the touch `pos` coordinate would be
            `(0, 0)` when this method was called.
        '''
        for w in self.children[:]:
            if w.dispatch('on_touch_up', touch):
                return True

    def on_resize(self, width, height):
        '''Event called when the window is resized.'''
        self.update_viewport()

    def update_viewport(self):
        from kivy.graphics.opengl import glViewport
        from kivy.graphics.transformation import Matrix
        from math import radians

        w, h = self.system_size
        if self._density != 1:
            w, h = self.size

        smode = self.softinput_mode
        kheight = self.keyboard_height

        w2, h2 = w / 2., h / 2.
        r = radians(self.rotation)

        x, y = 0, 0
        _h = h
        if smode:
            y = kheight
        if smode == 'scale':
            _h -= kheight

        # prepare the viewport
        glViewport(x, y, w, _h)

        # do projection matrix
        projection_mat = Matrix()
        projection_mat.view_clip(0.0, w, 0.0, h, -1.0, 1.0, 0)
        self.render_context['projection_mat'] = projection_mat

        # do modelview matrix
        modelview_mat = Matrix().translate(w2, h2, 0)
        modelview_mat = modelview_mat.multiply(Matrix().rotate(r, 0, 0, 1))

        w, h = self.size
        w2, h2 = w / 2., h / 2.
        modelview_mat = modelview_mat.multiply(Matrix().translate(-w2, -h2, 0))
        self.render_context['modelview_mat'] = modelview_mat

        # redraw canvas
        self.canvas.ask_update()

        # and update childs
        self.update_childsize()

    def update_childsize(self, childs=None):
        width, height = self.size
        if childs is None:
            childs = self.children
        for w in childs:
            shw, shh = w.size_hint
            if shw and shh:
                w.size = shw * width, shh * height
            elif shw:
                w.width = shw * width
            elif shh:
                w.height = shh * height
            for key, value in w.pos_hint.items():
                if key == 'x':
                    w.x = value * width
                elif key == 'right':
                    w.right = value * width
                elif key == 'y':
                    w.y = value * height
                elif key == 'top':
                    w.top = value * height
                elif key == 'center_x':
                    w.center_x = value * width
                elif key == 'center_y':
                    w.center_y = value * height

    def screenshot(self, name='screenshot{:04d}.png'):
        '''Save the actual displayed image in a file
        '''
        i = 0
        path = None
        if name != 'screenshot{:04d}.png':
            _ext = name.split('.')[-1]
            name = ''.join((name[:-(len(_ext) + 1)], '{:04d}.', _ext))
        while True:
            i += 1
            path = join(getcwd(), name.format(i))
            if not exists(path):
                break
        return path

    def on_rotate(self, rotation):
        '''Event called when the screen has been rotated.
        '''
        pass

    def on_close(self, *largs):
        '''Event called when the window is closed'''
        Modules.unregister_window(self)
        EventLoop.remove_event_listener(self)

    def on_request_close(self, *largs, **kwargs):
        '''Event called before we close the window. If a bound function returns
        `True`, the window will not be closed. If the the event is triggered
        because of the keyboard escape key, the keyword argument `source` is
        dispatched along with a value of `keyboard` to the bound functions.

        .. warning::
            When the bound function returns True the window will not be closed,
            so use with care because the user would not be able to close the
            program, even if the red X is clicked.
        '''
        pass

    def on_mouse_down(self, x, y, button, modifiers):
        '''Event called when the mouse is used (pressed/released)'''
        pass

    def on_mouse_move(self, x, y, modifiers):
        '''Event called when the mouse is moved with buttons pressed'''
        pass

    def on_mouse_up(self, x, y, button, modifiers):
        '''Event called when the mouse is moved with buttons pressed'''
        pass

    def on_joy_axis(self, stickid, axisid, value):
        '''Event called when a joystick has a stick or other axis moved

        .. versionadded:: 1.9.0'''
        pass

    def on_joy_hat(self, stickid, hatid, value):
        '''Event called when a joystick has a hat/dpad moved

        .. versionadded:: 1.9.0'''
        pass

    def on_joy_ball(self, stickid, ballid, value):
        '''Event called when a joystick has a ball moved

        .. versionadded:: 1.9.0'''
        pass

    def on_joy_button_down(self, stickid, buttonid):
        '''Event called when a joystick has a button pressed

        .. versionadded:: 1.9.0'''
        pass

    def on_joy_button_up(self, stickid, buttonid):
        '''Event called when a joystick has a button released

        .. versionadded:: 1.9.0'''
        pass

    def on_keyboard(self, key, scancode=None, codepoint=None,
                    modifier=None, **kwargs):
        '''Event called when keyboard is used.

        .. warning::
            Some providers may omit `scancode`, `codepoint` and/or `modifier`.
        '''
        if 'unicode' in kwargs:
            Logger.warning("The use of the unicode parameter is deprecated, "
                           "and will be removed in future versions. Use "
                           "codepoint instead, which has identical "
                           "semantics.")

        # Quit if user presses ESC or the typical OSX shortcuts CMD+q or CMD+w
        # TODO If just CMD+w is pressed, only the window should be closed.
        is_osx = platform == 'darwin'
        if WindowBase.on_keyboard.exit_on_escape:
            if key == 27 or all([is_osx, key in [113, 119], modifier == 1024]):
                if not self.dispatch('on_request_close', source='keyboard'):
                    stopTouchApp()
                    self.close()
                    return True

    if Config:
        on_keyboard.exit_on_escape = Config.getboolean('kivy', 'exit_on_escape')

        def __exit(section, name, value):
            WindowBase.__dict__['on_keyboard'].exit_on_escape = \
                Config.getboolean('kivy', 'exit_on_escape')

        Config.add_callback(__exit, 'kivy', 'exit_on_escape')

    def on_key_down(self, key, scancode=None, codepoint=None,
                    modifier=None, **kwargs):
        '''Event called when a key is down (same arguments as on_keyboard)'''
        if 'unicode' in kwargs:
            Logger.warning("The use of the unicode parameter is deprecated, "
                           "and will be removed in future versions. Use "
                           "codepoint instead, which has identical "
                           "semantics.")

    def on_key_up(self, key, scancode=None, codepoint=None,
                  modifier=None, **kwargs):
        '''Event called when a key is released (same arguments as on_keyboard)
        '''
        if 'unicode' in kwargs:
            Logger.warning("The use of the unicode parameter is deprecated, "
                           "and will be removed in future versions. Use "
                           "codepoint instead, which has identical "
                           "semantics.")

    def on_textinput(self, text):
        '''Event called whem text: i.e. alpha numeric non control keys or set
        of keys is entered. As it is not gaurenteed whether we get one
        character or multiple ones, this event supports handling multiple
        characters.

        .. versionadded:: 1.9.0
        '''
        pass

    def on_dropfile(self, filename):
        '''Event called when a file is dropped on the application.

        .. warning::

            This event currently works with sdl2 window provider, on pygame
            window provider and MacOSX with a patched version of pygame.
            This event is left in place for further evolution
            (ios, android etc.)

        .. versionadded:: 1.2.0
        '''
        pass

    @reify
    def dpi(self):
        '''Return the DPI of the screen. If the implementation doesn't support
        any DPI lookup, it will just return 96.

        .. warning::

            This value is not cross-platform. Use
            :attr:`kivy.base.EventLoop.dpi` instead.
        '''
        return 96.

    def configure_keyboards(self):
        # Configure how to provide keyboards (virtual or not)

        # register system keyboard to listening keys from window
        sk = self._system_keyboard
        self.bind(
            on_key_down=sk._on_window_key_down,
            on_key_up=sk._on_window_key_up,
            on_textinput=sk._on_window_textinput)

        # use the device's real keyboard
        self.use_syskeyboard = True

        # use the device's real keyboard
        self.allow_vkeyboard = False

        # one single vkeyboard shared between all widgets
        self.single_vkeyboard = True

        # the single vkeyboard is always sitting at the same position
        self.docked_vkeyboard = False

        # now read the configuration
        mode = Config.get('kivy', 'keyboard_mode')
        if mode not in ('', 'system', 'dock', 'multi', 'systemanddock',
                        'systemandmulti'):
            Logger.critical('Window: unknown keyboard mode %r' % mode)

        # adapt mode according to the configuration
        if mode == 'system':
            self.use_syskeyboard = True
            self.allow_vkeyboard = False
            self.single_vkeyboard = True
            self.docked_vkeyboard = False
        elif mode == 'dock':
            self.use_syskeyboard = False
            self.allow_vkeyboard = True
            self.single_vkeyboard = True
            self.docked_vkeyboard = True
        elif mode == 'multi':
            self.use_syskeyboard = False
            self.allow_vkeyboard = True
            self.single_vkeyboard = False
            self.docked_vkeyboard = False
        elif mode == 'systemanddock':
            self.use_syskeyboard = True
            self.allow_vkeyboard = True
            self.single_vkeyboard = True
            self.docked_vkeyboard = True
        elif mode == 'systemandmulti':
            self.use_syskeyboard = True
            self.allow_vkeyboard = True
            self.single_vkeyboard = False
            self.docked_vkeyboard = False

        Logger.info(
            'Window: virtual keyboard %sallowed, %s, %s' % (
                '' if self.allow_vkeyboard else 'not ',
                'single mode' if self.single_vkeyboard else 'multiuser mode',
                'docked' if self.docked_vkeyboard else 'not docked'))

    def set_vkeyboard_class(self, cls):
        '''.. versionadded:: 1.0.8

        Set the VKeyboard class to use. If set to None, it will use the
        :class:`kivy.uix.vkeyboard.VKeyboard`.
        '''
        self._vkeyboard_cls = cls

    def release_all_keyboards(self):
        '''.. versionadded:: 1.0.8

        This will ensure that no virtual keyboard / system keyboard is
        requested. All instances will be closed.
        '''
        for key in list(self._keyboards.keys())[:]:
            keyboard = self._keyboards[key]
            if keyboard:
                keyboard.release()

    def request_keyboard(self, callback, target, input_type='text'):
        '''.. versionadded:: 1.0.4

        Internal widget method to request the keyboard. This method is rarely
        required by the end-user as it is handled automatically by the
        :class:`~kivy.uix.textinput.TextInput`. We expose it in case you want
        to handle the keyboard manually for unique input scenarios.

        A widget can request the keyboard, indicating a callback to call
        when the keyboard is released (or taken by another widget).

        :Parameters:
            `callback`: func
                Callback that will be called when the keyboard is
                closed. This can be because somebody else requested the
                keyboard or the user closed it.
            `target`: Widget
                Attach the keyboard to the specified `target`. This should be
                the widget that requested the keyboard. Ensure you have a
                different target attached to each keyboard if you're working in
                a multi user mode.

                .. versionadded:: 1.0.8

            `input_type`: string
                Choose the type of soft keyboard to request. Can be one of
                'text', 'number', 'url', 'mail', 'datetime', 'tel', 'address'.

                .. note::

                    `input_type` is currently only honored on mobile devices.

                .. versionadded:: 1.8.0

        :Return:
            An instance of :class:`Keyboard` containing the callback, target,
            and if the configuration allows it, a
            :class:`~kivy.uix.vkeyboard.VKeyboard` instance attached as a
            *.widget* property.

        .. note::

            The behavior of this function is heavily influenced by the current
            `keyboard_mode`. Please see the Config's
            :ref:`configuration tokens <configuration-tokens>` section for
            more information.

        '''

        # release any previous keyboard attached.
        self.release_keyboard(target)

        # if we can use virtual vkeyboard, activate it.
        if self.allow_vkeyboard:
            keyboard = None

            # late import
            global VKeyboard
            if VKeyboard is None and self._vkeyboard_cls is None:
                from kivy.uix.vkeyboard import VKeyboard
                self._vkeyboard_cls = VKeyboard

            # if the keyboard doesn't exist, create it.
            key = 'single' if self.single_vkeyboard else target
            if key not in self._keyboards:
                vkeyboard = self._vkeyboard_cls()
                keyboard = Keyboard(widget=vkeyboard, window=self)
                vkeyboard.bind(
                    on_key_down=keyboard._on_vkeyboard_key_down,
                    on_key_up=keyboard._on_vkeyboard_key_up,
                    on_textinput=keyboard._on_vkeyboard_textinput)
                self._keyboards[key] = keyboard
            else:
                keyboard = self._keyboards[key]

            # configure vkeyboard
            keyboard.target = keyboard.widget.target = target
            keyboard.callback = keyboard.widget.callback = callback

            # add to the window
            self.add_widget(keyboard.widget)

            # only after add, do dock mode
            keyboard.widget.docked = self.docked_vkeyboard
            keyboard.widget.setup_mode()

        else:
            # system keyboard, just register the callback.
            keyboard = self._system_keyboard
            keyboard.callback = callback
            keyboard.target = target

        # use system (hardware) keyboard according to flag
        if self.allow_vkeyboard and self.use_syskeyboard:
            self.unbind(
                on_key_down=keyboard._on_window_key_down,
                on_key_up=keyboard._on_window_key_up,
                on_textinput=keyboard._on_window_textinput)
            self.bind(
                on_key_down=keyboard._on_window_key_down,
                on_key_up=keyboard._on_window_key_up,
                on_textinput=keyboard._on_window_textinput)

        return keyboard

    def release_keyboard(self, target=None):
        '''.. versionadded:: 1.0.4

        Internal method for the widget to release the real-keyboard. Check
        :meth:`request_keyboard` to understand how it works.
        '''
        if self.allow_vkeyboard:
            key = 'single' if self.single_vkeyboard else target
            if key not in self._keyboards:
                return
            keyboard = self._keyboards[key]
            callback = keyboard.callback
            if callback:
                keyboard.callback = None
                callback()
            keyboard.target = None
            self.remove_widget(keyboard.widget)
            if key != 'single' and key in self._keyboards:
                del self._keyboards[key]
        elif self._system_keyboard.callback:
            # this way will prevent possible recursion.
            callback = self._system_keyboard.callback
            self._system_keyboard.callback = None
            callback()
            return True

#: Instance of a :class:`WindowBase` implementation
window_impl = []
if platform == 'linux':
    window_impl += [('egl_rpi', 'window_egl_rpi', 'WindowEglRpi')]
if USE_SDL2:
    window_impl += [('sdl2', 'window_sdl2', 'WindowSDL')]
else:
    window_impl += [
        ('pygame', 'window_pygame', 'WindowPygame')]
if platform == 'linux':
    window_impl += [('x11', 'window_x11', 'WindowX11')]
Window = core_select_lib('window', window_impl, True)


import pytest

from nmcli.data import Connection
from nmcli.dummy._connection import DummyConnectionControl

def test_call():
    result_call = [Connection('a', 'b', 'ethernet', 'eth0')]
    c = DummyConnectionControl(result_call)
    assert c() == result_call

def test_call_when_raise_error():
    c = DummyConnectionControl(raise_error=Exception)
    with pytest.raises(Exception):
        c()

def test_add():
    c = DummyConnectionControl()
    conn_type = 'ethernet'
    options = {
        'key': 'value'
    }
    ifname = 'eth0'
    name = 'MyHome'
    autoconnect = True
    c.add(conn_type, options, ifname, name, autoconnect)
    assert c.add_args[0] == (conn_type, options, ifname, name, autoconnect)

    c.add(conn_type, options, ifname, name, False)
    assert c.add_args[1] == (conn_type, options, ifname, name, False)

    c.add(conn_type, options, ifname, name)
    assert c.add_args[2] == (conn_type, options, ifname, name, None)

def test_add_when_raise_error():
    c = DummyConnectionControl(raise_error=Exception)
    with pytest.raises(Exception):
        c.add('ethernet')

def test_modify():
    c = DummyConnectionControl()
    options = {
        'key': 'value'
    }
    name = 'MyHome'
    c.modify(name, options)
    assert c.modify_args[0] == (name, options)

def test_modify_when_raise_error():
    c = DummyConnectionControl(raise_error=Exception)
    with pytest.raises(Exception):
        c.modify('ethernet', {'key': 'value'})

def test_delete():
    c = DummyConnectionControl()
    name = 'MyHome'
    c.delete(name)
    assert c.delete_args[0] == name

def test_delete_when_raise_error():
    c = DummyConnectionControl(raise_error=Exception)
    with pytest.raises(Exception):
        c.delete('ethernet')

def test_up():
    c = DummyConnectionControl()
    name = 'MyHome'
    c.up(name)
    assert c.up_args[0] == name

def test_up_when_raise_error():
    c = DummyConnectionControl(raise_error=Exception)
    with pytest.raises(Exception):
        c.up('ethernet')

def test_down():
    c = DummyConnectionControl()
    name = 'MyHome'
    c.down(name)
    assert c.down_args[0] == name

def test_down_when_raise_error():
    c = DummyConnectionControl(raise_error=Exception)
    with pytest.raises(Exception):
        c.down('ethernet')

def test_show():
    result_show = {
        'key': 'value'
    }
    c = DummyConnectionControl(result_show=result_show)
    name = 'MyHome'
    assert c.show(name) == result_show

def test_show_when_raise_error():
    c = DummyConnectionControl(raise_error=Exception)
    with pytest.raises(Exception):
        c.show('MyHome')

def test_show_when_no_arguments_are_passed():
    c = DummyConnectionControl()
    with pytest.raises(ValueError):
        c.show('MyHome')

def test_reload():
    c = DummyConnectionControl()
    c.reload()
    assert c.called_reload == 1

def test_reload_when_raise_error():
    c = DummyConnectionControl(raise_error=Exception)
    with pytest.raises(Exception):
        c.reload()


# Copyright 2017 Workonline Communications (Pty) Ltd. All rights reserved.
#
# The contents of this file are 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.
"""Method test classes for djangolg."""

from __future__ import print_function
from __future__ import unicode_literals

from django.test import TestCase

from djangolg import dialects, methods
from djangolg.methods.base import BaseMethod

class MethodTestCase(TestCase):
    """Test djangolg methods."""

    def test_available_methods(self):
        """Test available_methods helper."""
        methods_map = methods.available_methods("map")
        methods_list = methods.available_methods("list")
        assert isinstance(methods_map, dict)
        assert isinstance(methods_list, list)
        try:
            methods.available_methods("wrong")
        except Exception as e:
            assert isinstance(e, ValueError)
            assert "{}".format(e) == "invalid output type: wrong"

    def test_get_method(self):
        """Test get_method helper."""
        for method_name in methods.available_methods("list"):
            method = methods.get_method(name=method_name)
            assert isinstance(method, BaseMethod)
        try:
            methods.get_method()
        except Exception as e:
            assert isinstance(e, methods.MethodNotFound)
        try:
            methods.get_method(name=dict())
        except Exception as e:
            assert isinstance(e, methods.LookingGlassMethodError)

    def test_method_init_failure(self):
        """Test method initiation failure."""
        try:
            BaseMethod(dialect="string")
        except Exception as e:
            assert isinstance(e, TypeError)

    def test_method_dialect_functions(self):
        """Test method dialect getter and setter and other methods."""
        for method_name in methods.available_methods(output="list"):
            method = methods.get_method(name=method_name)
            assert method.dialect is None
            try:
                method.dialect = "wrong_type"
            except Exception as e:
                assert isinstance(e, TypeError)
            for dialect_name in dialects.available_dialects(output="list"):
                dialect = dialects.get_dialect(dialect_name)
                method.dialect = dialect
                assert method.dialect is dialect
                if method.options:
                    for index, option in method.option_choices():
                        assert method.get_command(target=method.test_target,
                                                  option_index=index)
                else:
                    assert method.get_command(target=method.test_target)


import numpy as np
import tensorflow as tf
from numbers import Number
import gym
import time
from spinup.algos.tf1.sac1 import core
from spinup.algos.tf1.sac1.core import get_vars
from spinup.utils.logx import EpochLogger
from gym.spaces import Box, Discrete
from spinup.utils.frame_stack import FrameStack
import os

class ReplayBuffer:
    """
    A simple FIFO experience replay buffer for SAC agents.
    """

    def __init__(self, obs_dim, act_dim, size):
        self.obs1_buf = np.zeros([size, obs_dim], dtype=np.float32)
        self.obs2_buf = np.zeros([size, obs_dim], dtype=np.float32)
        self.acts_buf = np.zeros([size, act_dim], dtype=np.float32)
        self.rews_buf = np.zeros(size, dtype=np.float32)
        self.done_buf = np.zeros(size, dtype=np.float32)
        self.ptr, self.size, self.max_size = 0, 0, size

    def store(self, obs, act, rew, next_obs, done):
        self.obs1_buf[self.ptr] = obs
        self.obs2_buf[self.ptr] = next_obs
        self.acts_buf[self.ptr] = act
        self.rews_buf[self.ptr] = rew
        self.done_buf[self.ptr] = done
        self.ptr = (self.ptr+1) % self.max_size
        self.size = min(self.size+1, self.max_size)

    def sample_batch(self, batch_size=32):
        idxs = np.random.randint(0, self.size, size=batch_size)
        return dict(obs1=self.obs1_buf[idxs],
                    obs2=self.obs2_buf[idxs],
                    acts=self.acts_buf[idxs],
                    rews=self.rews_buf[idxs],
                    done=self.done_buf[idxs])

"""

Soft Actor-Critic

(With slight variations that bring it closer to TD3)

"""
def sac1(args, env_fn, actor_critic=core.mlp_actor_critic, ac_kwargs=dict(), seed=0,
        steps_per_epoch=1000, epochs=100, replay_size=int(2e6), gamma=0.99, reward_scale=1.0,
        polyak=0.995, lr=5e-4, alpha=0.2, batch_size=200, start_steps=10000,
        max_ep_len_train=1000, max_ep_len_test=1000, logger_kwargs=dict(), save_freq=1):
    """

    Args:
        env_fn : A function which creates a copy of the environment.
            The environment must satisfy the OpenAI Gym API.

        actor_critic: A function which takes in placeholder symbols
            for state, ``x_ph``, and action, ``a_ph``, and returns the main
            outputs from the agent's Tensorflow computation graph:

            ===========  ================  ======================================
            Symbol       Shape             Description
            ===========  ================  ======================================
            ``mu``       (batch, act_dim)  | Computes mean actions from policy
                                           | given states.
            ``pi``       (batch, act_dim)  | Samples actions from policy given
                                           | states.
            ``logp_pi``  (batch,)          | Gives log probability, according to
                                           | the policy, of the action sampled by
                                           | ``pi``. Critical: must be differentiable
                                           | with respect to policy parameters all
                                           | the way through action sampling.
            ``q1``       (batch,)          | Gives one estimate of Q* for
                                           | states in ``x_ph`` and actions in
                                           | ``a_ph``.
            ``q2``       (batch,)          | Gives another estimate of Q* for
                                           | states in ``x_ph`` and actions in
                                           | ``a_ph``.
            ``q1_pi``    (batch,)          | Gives the composition of ``q1`` and
                                           | ``pi`` for states in ``x_ph``:
                                           | q1(x, pi(x)).
            ``q2_pi``    (batch,)          | Gives the composition of ``q2`` and
                                           | ``pi`` for states in ``x_ph``:
                                           | q2(x, pi(x)).
            ===========  ================  ======================================

        ac_kwargs (dict): Any kwargs appropriate for the actor_critic
            function you provided to SAC.

        seed (int): Seed for random number generators.

        steps_per_epoch (int): Number of steps of interaction (state-action pairs)
            for the agent and the environment in each epoch.

        epochs (int): Number of epochs to run and train agent.

        replay_size (int): Maximum length of replay buffer.

        gamma (float): Discount factor. (Always between 0 and 1.)

        polyak (float): Interpolation factor in polyak averaging for target
            networks. Target networks are updated towards main networks
            according to:

            .. math:: \\theta_{\\text{targ}} \\leftarrow
                \\rho \\theta_{\\text{targ}} + (1-\\rho) \\theta

            where :math:`\\rho` is polyak. (Always between 0 and 1, usually
            close to 1.)

        lr (float): Learning rate (used for policy/value/alpha learning).

        alpha (float/'auto'): Entropy regularization coefficient. (Equivalent to
            inverse of reward scale in the original SAC paper.) / 'auto': alpha is automated.

        batch_size (int): Minibatch size for SGD.

        start_steps (int): Number of steps for uniform-random action selection,
            before running real policy. Helps exploration.

        max_ep_len (int): Maximum length of trajectory / episode / rollout.

        logger_kwargs (dict): Keyword args for EpochLogger.

        save_freq (int): How often (in terms of gap between epochs) to save
            the current policy and value function.

    """
    if not args.is_test:
        logger = EpochLogger(**logger_kwargs)
        logger.save_config(locals())

    tf.set_random_seed(seed)
    np.random.seed(seed)

    env, test_env = env_fn(3), env_fn(1)
    obs_dim = env.observation_space.shape[0]
    act_dim = env.action_space.shape[0]

    # Action limit for clamping: critically, assumes all dimensions share the same bound!
    act_limit = env.action_space.high[0]

    # Share information about action space with policy architecture
    ac_kwargs['action_space'] = env.action_space

    # Inputs to computation graph
    x_ph, a_ph, x2_ph, r_ph, d_ph = core.placeholders(obs_dim, act_dim, obs_dim, None, None)

    # Main outputs from computation graph
    with tf.variable_scope('main'):
        mu, pi, logp_pi, logp_pi2, q1, q2, q1_pi, q2_pi = actor_critic(x_ph, x2_ph, a_ph, **ac_kwargs)

    # Target value network
    with tf.variable_scope('target'):
        _, _, logp_pi_, _, _, _,q1_pi_, q2_pi_= actor_critic(x2_ph, x2_ph, a_ph, **ac_kwargs)

    # Experience buffer
    replay_buffer = ReplayBuffer(obs_dim=obs_dim, act_dim=act_dim, size=replay_size)

    # Count variables
    var_counts = tuple(core.count_vars(scope) for scope in
                       ['main/pi', 'main/q1', 'main/q2', 'main'])
    print(('\nNumber of parameters: \t pi: %d, \t' + \
           'q1: %d, \t q2: %d, \t total: %d\n')%var_counts)

######
    if alpha == 'auto':
        target_entropy = (-np.prod(env.action_space.shape))

        log_alpha = tf.get_variable( 'log_alpha', dtype=tf.float32, initializer=0.0)
        alpha = tf.exp(log_alpha)

        alpha_loss = tf.reduce_mean(-log_alpha * tf.stop_gradient(logp_pi + target_entropy))

        alpha_optimizer = tf.train.AdamOptimizer(learning_rate=lr*0.1, name='alpha_optimizer')
        train_alpha_op = alpha_optimizer.minimize(loss=alpha_loss, var_list=[log_alpha])
######

    # Min Double-Q:
    min_q_pi = tf.minimum(q1_pi_, q2_pi_)

    # Targets for Q and V regression
    v_backup = tf.stop_gradient(min_q_pi - alpha * logp_pi2)
    q_backup = r_ph + gamma*(1-d_ph)*v_backup

    # Soft actor-critic losses
    pi_loss = tf.reduce_mean(alpha * logp_pi - q1_pi)
    q1_loss = 0.5 * tf.reduce_mean((q_backup - q1)**2)
    q2_loss = 0.5 * tf.reduce_mean((q_backup - q2)**2)
    value_loss = q1_loss + q2_loss

    # Policy train op
    # (has to be separate from value train op, because q1_pi appears in pi_loss)
    pi_optimizer = tf.train.AdamOptimizer(learning_rate=lr)
    train_pi_op = pi_optimizer.minimize(pi_loss, var_list=get_vars('main/pi'))

    # Value train op
    # (control dep of train_pi_op because sess.run otherwise evaluates in nondeterministic order)
    value_optimizer = tf.train.AdamOptimizer(learning_rate=lr)
    value_params = get_vars('main/q')
    with tf.control_dependencies([train_pi_op]):
        train_value_op = value_optimizer.minimize(value_loss, var_list=value_params)

    # Polyak averaging for target variables
    # (control flow because sess.run otherwise evaluates in nondeterministic order)
    with tf.control_dependencies([train_value_op]):
        target_update = tf.group([tf.assign(v_targ, polyak*v_targ + (1-polyak)*v_main)
                                  for v_main, v_targ in zip(get_vars('main'), get_vars('target'))])

    # All ops to call during one training step
    if isinstance(alpha, Number):
        step_ops = [pi_loss, q1_loss, q2_loss, q1, q2, logp_pi, tf.identity(alpha),
                train_pi_op, train_value_op, target_update]
    else:
        step_ops = [pi_loss, q1_loss, q2_loss, q1, q2, logp_pi, alpha,
                train_pi_op, train_value_op, target_update, train_alpha_op]

    # Initializing targets to match main variables
    target_init = tf.group([tf.assign(v_targ, v_main)
                              for v_main, v_targ in zip(get_vars('main'), get_vars('target'))])

    sess = tf.Session()
    sess.run(tf.global_variables_initializer())
    sess.run(target_init)

    ##############################  save and restore  ############################

    saver = tf.train.Saver()

    checkpoint_path = logger_kwargs['output_dir'] + '/checkpoints'
    if not os.path.exists(checkpoint_path):
        os.makedirs(checkpoint_path)

    if args.is_test or args.is_restore_train:
        ckpt = tf.train.get_checkpoint_state(checkpoint_path)
        if ckpt and ckpt.model_checkpoint_path:
            saver.restore(sess, ckpt.model_checkpoint_path)
            print("Model restored.")

    def get_action(o, deterministic=False):
        act_op = mu if deterministic else pi
        return sess.run(act_op, feed_dict={x_ph: o.reshape(1,-1)})[0]

    ##############################  test  ############################

    if args.is_test:
        test_env = gym.make(args.env)
        ave_ep_ret = 0
        for j in range(10000):
            o, r, d, ep_ret, ep_len = test_env.reset(), 0, False, 0, 0
            while not d: # (d or (ep_len == 2000)):
                o, r, d, _ = test_env.step(get_action(o, True))
                ep_ret += r
                ep_len += 1
                if args.test_render:
                    test_env.render()
            ave_ep_ret = (j*ave_ep_ret + ep_ret)/(j+1)
            print('ep_len', ep_len, 'ep_ret:', ep_ret, 'ave_ep_ret:',ave_ep_ret,'({}/10000)'.format(j+1) )
        return

    ##############################  train  ############################

    def test_agent(n=25):
        global sess, mu, pi, q1, q2, q1_pi, q2_pi
        for j in range(n):
            o, r, d, ep_ret, ep_len = test_env.reset(), 0, False, 0, 0
            while not(d or (ep_len == max_ep_len_test)):
                # Take deterministic actions at test time
                o, r, d, _ = test_env.step(get_action(o, True))
                ep_ret += r
                ep_len += 1
                # test_env.render()
            logger.store(TestEpRet=ep_ret, TestEpLen=ep_len)

    start_time = time.time()
    o, r, d, ep_ret, ep_len = env.reset(), 0, False, 0, 0
    total_steps = steps_per_epoch * epochs

    ep_index = 0
    test_ep_ret_best = test_ep_ret = -10000.0

    # Main loop: collect experience in env and update/log each epoch
    for t in range(total_steps):

        """
        Until start_steps have elapsed, randomly sample actions
        from a uniform distribution for better exploration. Afterwards,
        use the learned policy.
        """
        if t > start_steps:
            a = get_action(o)
        else:
            a = env.action_space.sample()

        # Step the env
        o2, r, d, _ = env.step(a)
        ep_ret += r
        ep_len += 1

        # Ignore the "done" signal if it comes from hitting the time
        # horizon (that is, when it's an artificial terminal signal
        # that isn't based on the agent's state)
        # d = False if ep_len==max_ep_len_train else d

        # Store experience to replay buffer
        replay_buffer.store(o, a, r, o2, d)

        # Super critical, easy to overlook step: make sure to update
        # most recent observation!
        o = o2

        # End of episode. Training (ep_len times).
        if d or (ep_len == max_ep_len_train):
            ep_index += 1
            print('episode: {}, ep_len: {}, reward: {}'.format(ep_index, ep_len, ep_ret/reward_scale))
            """
            Perform all SAC updates at the end of the trajectory.
            This is a slight difference from the SAC specified in the
            original paper.
            """
            for j in range(int(1.5*ep_len)):
                batch = replay_buffer.sample_batch(batch_size)
                feed_dict = {x_ph: batch['obs1'],
                             x2_ph: batch['obs2'],
                             a_ph: batch['acts'],
                             r_ph: batch['rews'],
                             d_ph: batch['done'],
                            }
                # step_ops = [pi_loss, q1_loss, q2_loss, q1, q2, logp_pi, alpha, train_pi_op, train_value_op, target_update]
                outs = sess.run(step_ops, feed_dict)
                logger.store(LossPi=outs[0], LossQ1=outs[1], LossQ2=outs[2],
                            Q1Vals=outs[3], Q2Vals=outs[4],
                            LogPi=outs[5], Alpha=outs[6])

            logger.store(EpRet=ep_ret/reward_scale, EpLen=ep_len)
            o, r, d, ep_ret, ep_len = env.reset(), 0, False, 0, 0

        # End of epoch wrap-up
        if t > 0 and t % steps_per_epoch == 0:
            epoch = t // steps_per_epoch

            test_agent(10)
                # test_ep_ret = logger.get_stats('TestEpRet')[0]
                # print('TestEpRet', test_ep_ret, 'Best:', test_ep_ret_best)
            if logger.get_stats('TestEpRet')[0] >= 180:
                print('Recalculating TestEpRet...')
                test_agent(100)
                test_ep_ret = logger.get_stats('TestEpRet')[0]
                # logger.epoch_dict['TestEpRet'] = []

                print('TestEpRet', test_ep_ret, 'Best:', test_ep_ret_best)

            # logger.store(): store the data; logger.log_tabular(): log the data; logger.dump_tabular(): write the data
            # Log info about epoch
            logger.log_tabular('Epoch', epoch)
            logger.log_tabular('Num_Ep', ep_index)
            logger.log_tabular('EpRet', with_min_and_max=True)
            logger.log_tabular('TestEpRet', with_min_and_max=False)
            logger.log_tabular('EpLen', average_only=True)
            logger.log_tabular('TestEpLen', average_only=True)
            logger.log_tabular('TotalEnvInteracts', t)
            logger.log_tabular('Alpha',average_only=True)
            logger.log_tabular('Q1Vals', with_min_and_max=True)
            logger.log_tabular('Q2Vals', with_min_and_max=True)
            # logger.log_tabular('VVals', with_min_and_max=True)
            logger.log_tabular('LogPi', with_min_and_max=True)
            logger.log_tabular('LossPi', average_only=True)
            logger.log_tabular('LossQ1', average_only=True)
            logger.log_tabular('LossQ2', average_only=True)
            # logger.log_tabular('LossV', average_only=True)
            logger.log_tabular('Time', time.time()-start_time)
            logger.dump_tabular()

            # Save model
            if ((epoch % save_freq == 0) or (epoch == epochs - 1)) and test_ep_ret > test_ep_ret_best:
                save_path = saver.save(sess, checkpoint_path+'/model.ckpt', t)
                print("Model saved in path: %s" % save_path)
                test_ep_ret_best = test_ep_ret

            if test_ep_ret >= 200:
                print("Model saved in path: %s" % save_path)

                print('\nEnvironment solved in {:d} episodes!\tAverage Score: {:.2f}'.format(ep_index, test_ep_ret))
                exit()

if __name__ == '__main__':
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('--env', type=str, default='LunarLanderContinuous-v2')  # 'Pendulum-v0'

    parser.add_argument('--is_restore_train', type=bool, default=False)

    parser.add_argument('--is_test', type=bool, default=False)
    parser.add_argument('--test_render', type=bool, default=False)

    parser.add_argument('--max_ep_len_test', type=int, default=2000) # 'BipedalWalkerHardcore-v2' max_ep_len is 2000
    parser.add_argument('--max_ep_len_train', type=int, default=1000)  # max_ep_len_train < 2000//3 # 'BipedalWalkerHardcore-v2' max_ep_len is 2000
    parser.add_argument('--start_steps', type=int, default=100)
    parser.add_argument('--hid', type=int, default=300)
    parser.add_argument('--l', type=int, default=1)
    parser.add_argument('--gamma', type=float, default=0.99)
    parser.add_argument('--lr', type=float, default=1e-3)
    parser.add_argument('--seed', '-s', type=int, default=np.random.random_integers(1000))
    parser.add_argument('--epochs', type=int, default=10000)
    parser.add_argument('--alpha', default='auto', help="alpha can be either 'auto' or float(e.g:0.2).")
    parser.add_argument('--reward_scale', type=float, default=1.0)
    parser.add_argument('--act_noise', type=float, default=0.3)
    parser.add_argument('--obs_noise', type=float, default=0.0)
    parser.add_argument('--exp_name', type=str, default='sac1_LunarLanderContinuous-v2_debug3')
    parser.add_argument('--stack_frames', type=int, default=4)
    args = parser.parse_args()

    from spinup.utils.run_utils import setup_logger_kwargs
    logger_kwargs = setup_logger_kwargs(args.exp_name, args.seed)

    class Wrapper(object):

        def __init__(self, env, action_repeat):
            self._env = env
            self.action_repeat = action_repeat

        def __getattr__(self, name):
            return getattr(self._env, name)

        def step(self, action):
            r = 0.0
            for _ in range(self.action_repeat):
                obs_, reward_, done_, info_ = self._env.step(action)
                reward_ = reward_ if reward_ > -99.0 else 0.0
                r = r + reward_
                if done_:
                    return obs_, r, done_, info_
            return obs_, r, done_, info_

    # env = FrameStack(env, args.stack_frames)

    env_lunar1 = gym.make(args.env)
    env_lunar3 = Wrapper(gym.make(args.env),3)

    sac1(args, lambda n : env_lunar3 if n==3 else env_lunar1, actor_critic=core.mlp_actor_critic,
        ac_kwargs=dict(hidden_sizes=[200,150]), start_steps = args.start_steps,
        gamma=args.gamma, seed=args.seed, epochs=args.epochs, alpha=args.alpha,
        logger_kwargs=logger_kwargs, lr = args.lr, reward_scale=args.reward_scale,
         max_ep_len_train = args.max_ep_len_train, max_ep_len_test=args.max_ep_len_test)


# -*- coding: utf-8 -*-
"""
hashing package.
"""

from pyrin.packaging.base import Package

class HashingPackage(Package):
    """
    hashing package class.
    """

    NAME = __name__
    DEPENDS = []
    COMPONENT_NAME = 'security.hashing.component'


"""1248. Count Number of Nice Subarrays
Medium"""

class Solution(object):
    def numberOfSubarrays(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        #########
        m = [0]*50001
        res = 0
        curr = 0
        m[0] = 1
        for i in range(len(nums)):
            curr += (nums[i]%2)
            if curr >= k:
                res += m[curr-k]
            m[curr] += 1

        return res

        #######
        return self.atMost(nums, k)-self.atMost(nums, k-1)
    def atMost(self, nums, k):
        res = 0
        count = 0
        left = 0
        right = 0
        while right < len(nums):
            n = nums[right]
            count += n%2
            while count >= k:
                c = nums[left]
                count -= c%2
                left += 1
            res += right - left + 1
            right += 1
        return res
#################
        def atMost(k):
            res = 0
            left = 0
            for right in range(len(nums)):
                k -= nums[right]%2
                while k < 0:
                    k += nums[left]%2
                    left += 1
                res += right -left + 1

            return res

        return atMost(k) - atMost(k-1)

#


import numpy as np
import pandas as pd

from bokeh.plotting import figure, output_file, show

# generate some synthetic time series for six different categories
cats = list("abcdef")
yy = np.random.randn(2000)
g = np.random.choice(cats, 2000)
for i, l in enumerate(cats):
    yy[g == l] += i // 2
df = pd.DataFrame(dict(score=yy, group=g))

# find the quartiles and IQR for each category
groups = df.groupby('group')
q1 = groups.quantile(q=0.25)
q2 = groups.quantile(q=0.5)
q3 = groups.quantile(q=0.75)
iqr = q3 - q1
upper = q3 + 1.5*iqr
lower = q1 - 1.5*iqr

# find the outliers for each category
def outliers(group):
    cat = group.name
    return group[(group.score > upper.loc[cat]['score']) | (group.score < lower.loc[cat]['score'])]['score']
out = groups.apply(outliers).dropna()

# prepare outlier data for plotting, we need coordinates for every outlier.
if not out.empty:
    outx = []
    outy = []
    for keys in out.index:
        outx.append(keys[0])
        outy.append(out.loc[keys[0]].loc[keys[1]])

p = figure(tools="", background_fill_color="#efefef", x_range=cats, toolbar_location=None)

# if no outliers, shrink lengths of stems to be no longer than the minimums or maximums
qmin = groups.quantile(q=0.00)
qmax = groups.quantile(q=1.00)
upper.score = [min([x,y]) for (x,y) in zip(list(qmax.loc[:,'score']),upper.score)]
lower.score = [max([x,y]) for (x,y) in zip(list(qmin.loc[:,'score']),lower.score)]

# stems
p.segment(cats, upper.score, cats, q3.score, line_color="black")
p.segment(cats, lower.score, cats, q1.score, line_color="black")

# boxes
p.vbar(cats, 0.7, q2.score, q3.score, fill_color="#E08E79", line_color="black")
p.vbar(cats, 0.7, q1.score, q2.score, fill_color="#3B8686", line_color="black")

# whiskers (almost-0 height rects simpler than segments)
p.rect(cats, lower.score, 0.2, 0.01, line_color="black")
p.rect(cats, upper.score, 0.2, 0.01, line_color="black")

# outliers
if not out.empty:
    p.circle(outx, outy, size=6, color="#F38630", fill_alpha=0.6)

p.xgrid.grid_line_color = None
p.ygrid.grid_line_color = "white"
p.grid.grid_line_width = 2
p.xaxis.major_label_text_font_size="16px"

output_file("boxplot.html", title="boxplot.py example")

show(p)


#!/usr/bin/env python
# coding=utf-8
"""

__created__ = '4/22/16'
__author__ = 'deling.ma'
"""
import multiprocessing

bind = '0.0.0.0:7777'
max_requests = 10000
keepalive = 5

proc_name = 'fitahol'

workers = multiprocessing.cpu_count() * 2 + 1
worker_class = 'gaiohttp'

loglevel = 'info'
errorlog = '-'

x_forwarded_for_header = 'X-FORWARDED-FOR'


import numpy as np
import tensorflow as tf
import tensorflow.compat.v1.keras as keras
import pickle
import os
from math import ceil

from utils import preprocess_flags, save_kernel, save_kernel_partial
from utils import load_data,load_model,load_model_json,load_kernel
from utils import data_folder,kernel_folder,arch_folder

def main(_):

    FLAGS = tf.compat.v1.app.flags.FLAGS.flag_values_dict()
    FLAGS = preprocess_flags(FLAGS)
    globals().update(FLAGS)

    if init_dist != "gaussian":
        raise NotImplementedError("Initialization distributions other than Gaussian are not implemented for computing kernels!")

    from mpi4py import MPI
    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()
    size = comm.Get_size()
    print(rank)

    if n_gpus>0:
        os.environ["CUDA_VISIBLE_DEVICES"]=str((rank)%n_gpus)
    config = tf.compat.v1.ConfigProto()
    config.gpu_options.allow_growth = True

    set_session = keras.backend.set_session
    config.log_device_placement = False  # to log device placement (on which device the operation ran)
    config.allow_soft_placement = True  # so that it uses any other existing and supported devices, if the requested GPU:0 isn't found
    sess = tf.compat.v1.Session(config=config)
    set_session(sess)  # set this TensorFlow session as the default session for Keras

    train_images,flat_train_images,_,test_images,_ = load_data(FLAGS)
    image_size = train_images.shape[1]
    number_channels = train_images.shape[-1]
    #print("image_size", image_size)
    X = train_images
    flat_X = flat_train_images
    if compute_for_GP_train:
        test_images = test_images[:1000]
        data = test_images
        tp_order = np.concatenate([[0,len(data.shape)-1], np.arange(1, len(data.shape)-1)])
        print(data.shape,tp_order)
        flat_data = np.transpose(data, tp_order)  # NHWC -> NCHW # this is because the cnn GP kernels assume this
        flat_test_images = np.array([test_image.flatten() for test_image in flat_data])
        Xfull =  np.concatenate([flat_train_images,flat_test_images])
        flat_X = Xfull
        X = np.concatenate([train_images,test_images])

    print("compute kernel", network, dataset)

    # COMPUTE KERNEL
    if use_empirical_NTK:
        from nngp_kernel.empirical_ntk import empirical_NTK
        print(ceil(int(X.shape[0])*n_samples_repeats))
        from tensorflow.keras.models import model_from_json
        model = load_model(FLAGS)
        K = empirical_NTK(model,X)#,sess=sess)
    elif use_empirical_K:
        from nngp_kernel.empirical_kernel import empirical_K
        print("n_samples_repeats",n_samples_repeats)
        print(ceil(int(X.shape[0])*n_samples_repeats))
        arch_json_string = load_model_json(FLAGS)
        K = empirical_K(arch_json_string,X,ceil(int(X.shape[0])*n_samples_repeats),sigmaw=sigmaw,sigmab=sigmab,n_gpus=n_gpus,empirical_kernel_batch_size=empirical_kernel_batch_size, sess=sess, truncated_init_dist=truncated_init_dist,data_parallelism=False,store_partial_kernel=store_partial_kernel,partial_kernel_n_proc=partial_kernel_n_proc,partial_kernel_index=partial_kernel_index)
    if rank == 0:
        if not (use_empirical_K or use_empirical_NTK):
            if network=="cnn":
                from nngp_kernel.cnn_kernel import kernel_matrix
                K = kernel_matrix(flat_X,image_size=image_size,number_channels=number_channels,filter_sizes=filter_sizes,padding=padding,strides=strides,sigmaw=sigmaw,sigmab=sigmab,n_gpus=n_gpus)

            elif network=="resnet":
                from nngp_kernel.resnet_kernel import kernel_matrix
                K = kernel_matrix(flat_X,depth=number_layers,image_size=image_size,number_channels=number_channels,n_blocks=3,sigmaw=sigmaw,sigmab=sigmab,n_gpus=n_gpus)

            elif network == "fc":
                from nngp_kernel.fc_kernel import kernel_matrix
                K = kernel_matrix(flat_X,number_layers=number_layers,sigmaw=sigmaw,sigmab=sigmab,n_gpus=n_gpus)

        print(K)

        '''SAVE KERNEL'''
        if store_partial_kernel:
            save_kernel_partial(K,FLAGS,partial_kernel_index)
        else:
            save_kernel(K,FLAGS)

if __name__ == '__main__':

    f = tf.compat.v1.app.flags

    from utils import define_default_flags

    define_default_flags(f)
    f.DEFINE_boolean('compute_for_GP_train', False, "Whether to add a bit of test set to kernel, to be able to use it for GP training")
    f.DEFINE_boolean('store_partial_kernel', False, "Whether to store the kernels partially on a file to free the processes")
    f.DEFINE_integer('empirical_kernel_batch_size', 256, "batch size to use when computing the empirical kernel, larger models need smaller values, but smaller models can use larger values")
    f.DEFINE_integer('partial_kernel_n_proc', 175, "number of processes over which we are parallelizing the when computing partial kernels and saving")
    f.DEFINE_integer('partial_kernel_index', 0, "index of the process when using partial_kernels method")

    tf.compat.v1.app.run()


"""
This namespace holds Inference decorators.
"""
from .inference import Inference

# --------------------------------------------------------------------------
def get(label):
    """
    This is an inference decorator which can be used to decorate
    a getter method.

    ..code-block:: python

        >>> import recollection
        >>>
        >>> class Foo(recollection.Inference):
        ...
        ...     def __init__(self):
        ...         super(Foo, self).__init__()
        ...
        ...         # -- Demonstrate a private attribute with getter
        ...         # -- and setter methods
        ...         self._letter = 1
        ...
        ...     # -- Declare that this is a memento getter
        ...     @recollection.infer.get('foobar')
        ...     def get_letter(self):
        ...         return self._letter

    :param label: You must specify a label to be used when storing
        this variable. For the registration to be processed there
        must be a correlating setter defined on the class with the same
        label.
    :type label: str

    :return:
    """
    def inner_decor(func):
        def inner(*args, **kwargs):
            return func(*args, **kwargs)

        # -- Assign our attributes
        inner.label = label
        inner.is_memento_getter = True
        inner.is_memento_setter = False

        return inner

    return inner_decor

# --------------------------------------------------------------------------
def store(label, copy_value=True, serialise=False):
    """
    This is an inference decorator which can be used to decorate
    a getter method.

    ..code-block:: python

        >>> import recollection
        >>>
        >>> class Foo(recollection.Inference):
        ...
        ...     def __init__(self):
        ...         super(Foo, self).__init__()
        ...
        ...         # -- Demonstrate a private attribute with getter
        ...         # -- and setter methods
        ...         self._letter = 1
        ...
        ...     # -- Declare that this is a memento getter
        ...     @recollection.infer.store('letter', serialise=True)
        ...     def set_letter(self):
        ...         return self._letter
        >>> foo = Foo()

    :param label: You must specify a label to be used when storing
        this variable. For the registration to be processed there
        must be a correlating setter defined on the class with the same
        label.
    :type label: str

    :param copy_value: Default is True, this defines whether the object
        being stored will be copied or referenced. Typically if this is
        likely to be left to True, however if you want a reference to an
        object to be stored in history rather than copies of the object you
        should set this to False.
    :type copy_value: bool

    :param serialise: If true this will perform a serialisation of the
        memento object each time the setter is called. This expects a
        serialiser to be registered. The default is False.
    :type serialise: bool

    :return:
    """

    def inner_decor(func):
        def inner(*args, **kwargs):
            result = func(*args, **kwargs)

            # -- Now store
            if isinstance(args[0], Inference):
                args[0].memento.store(serialise=serialise)

            return result

        # -- Assign our attributes
        inner.label = label
        inner.is_memento_getter = False
        inner.is_memento_setter = True
        inner.copy_value = copy_value

        return inner

    return inner_decor