<commit_before># Copyright 2016 Google Inc. All Rights Reserved.
#
# 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.

"""Actions for sysprep-related activities."""

import logging
import re
from glazier.lib import timezone
from glazier.lib.actions.base import ActionError
from glazier.lib.actions.base import BaseAction
from gwinpy.net import dhcp

class SetUnattendTimeZone(BaseAction):
  """Configure the TimeZone entries in unattend.xml."""

  def _EditUnattend(self,
                    zone,
                    unattend_path=r'C:\Windows\Panther\unattend.xml'):
    """Edit the unattend.xml to replace the timezone entry.

    Args:
      zone: The timezone string to insert into <TimeZone></TimeZone>
      unattend_path: Path to the unattend.xml file.
    """
    lines = []
    try:
      with open(unattend_path) as unattend:
        lines = unattend.readlines()
      lines = [
          re.sub('<TimeZone>.*?</TimeZone>', '<TimeZone>%s</TimeZone>' % zone,
                 l) for l in lines
      ]
      with open(unattend_path, 'w') as unattend:
        unattend.write(''.join(lines))
    except IOError as e:
      raise ActionError('Unable to set time zone in unattend.xml (%s)' % str(e))

  def Run(self):
    """Sets the timezone inside unattend.xml."""
    local_tz = 'Pacific Standard Time'
    from_dhcp = False
    retries = 0
    while not from_dhcp and retries < 5:
      for intf in self._build_info.NetInterfaces():
        if intf.ip_address and intf.mac_address:
          servers = ['255.255.255.255']
          if intf.dhcp_server:
            servers.insert(0, intf.dhcp_server)
          logging.debug(
              'Attempting to get timezone from interface with IP %s and MAC %s',
              intf.ip_address, intf.mac_address)
          for dhcp_server in servers:
            from_dhcp = dhcp.GetDhcpOption(
                client_addr=intf.ip_address,
                client_mac=intf.mac_address,
                option=101, server_addr=dhcp_server).decode('UTF-8')
            logging.debug('DHCP server %s returned: %s', dhcp_server, from_dhcp)
            if from_dhcp:
              break
          if from_dhcp:
            break
      logging.debug('No result from DHCP.  Retrying...')
      retries += 1

    if from_dhcp:
      logging.debug('Got timezone %s from DHCP.', from_dhcp)
      tz = timezone.Timezone(load_map=True)
      translated = tz.TranslateZone(from_dhcp)
      if translated:
        local_tz = translated
        logging.debug('Successfully translated timezone to %s.', local_tz)
      else:
        logging.error('Could not translate DHCP timezone.')
    else:
      logging.error('Could not find timezone from DHCP.')
    logging.debug('Finalized timezone is %s.', local_tz)
    self._EditUnattend(local_tz)
<commit_msg>only decode things that exist<commit_after># Copyright 2016 Google Inc. All Rights Reserved.
#
# 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.

"""Actions for sysprep-related activities."""

import logging
import re
from glazier.lib import timezone
from glazier.lib.actions.base import ActionError
from glazier.lib.actions.base import BaseAction
from gwinpy.net import dhcp

class SetUnattendTimeZone(BaseAction):
  """Configure the TimeZone entries in unattend.xml."""

  def _EditUnattend(self,
                    zone,
                    unattend_path=r'C:\Windows\Panther\unattend.xml'):
    """Edit the unattend.xml to replace the timezone entry.

    Args:
      zone: The timezone string to insert into <TimeZone></TimeZone>
      unattend_path: Path to the unattend.xml file.
    """
    lines = []
    try:
      with open(unattend_path) as unattend:
        lines = unattend.readlines()
      lines = [
          re.sub('<TimeZone>.*?</TimeZone>', '<TimeZone>%s</TimeZone>' % zone,
                 l) for l in lines
      ]
      with open(unattend_path, 'w') as unattend:
        unattend.write(''.join(lines))
    except IOError as e:
      raise ActionError('Unable to set time zone in unattend.xml (%s)' % str(e))

  def Run(self):
    """Sets the timezone inside unattend.xml."""
    local_tz = 'Pacific Standard Time'
    from_dhcp = False
    retries = 0
    while not from_dhcp and retries < 5:
      for intf in self._build_info.NetInterfaces():
        if intf.ip_address and intf.mac_address:
          servers = ['255.255.255.255']
          if intf.dhcp_server:
            servers.insert(0, intf.dhcp_server)
          logging.debug(
              'Attempting to get timezone from interface with IP %s and MAC %s',
              intf.ip_address, intf.mac_address)
          for dhcp_server in servers:
            dhcp_response = dhcp.GetDhcpOption(
                client_addr=intf.ip_address,
                client_mac=intf.mac_address,
                option=101, server_addr=dhcp_server)
            try:
              from_dhcp = dhcp_response.decode('utf-8')
            except AttributeError:
              logging.warning('could not decode dhcp response %s',
                              dhcp_response)
              from_dhcp = None
            logging.debug('DHCP server %s returned: %s', dhcp_server, from_dhcp)
            if from_dhcp:
              break
          if from_dhcp:
            break
      logging.debug('No result from DHCP.  Retrying...')
      retries += 1

    if from_dhcp:
      logging.debug('Got timezone %s from DHCP.', from_dhcp)
      tz = timezone.Timezone(load_map=True)
      translated = tz.TranslateZone(from_dhcp)
      if translated:
        local_tz = translated
        logging.debug('Successfully translated timezone to %s.', local_tz)
      else:
        logging.error('Could not translate DHCP timezone.')
    else:
      logging.error('Could not find timezone from DHCP.')
    logging.debug('Finalized timezone is %s.', local_tz)
    self._EditUnattend(local_tz)
<|endoftext|>


<commit_before>#!/usr/bin/env python
# coding: utf8

"""
Renderer for the keyboard and the text box used to display
the current text.
"""

import os.path as osp
import pygame  # pylint: disable=import-error

from . import vkeys

def fit_font(font_name, max_height):
    """Set the size of the font to fit the given height.

    This function uses the binary search algorithm to go faster
    than a one-by-one try.

    Parameters
    ----------
    font_name:
        Path to font file for rendering key.
    max_height:
        Height to fit.
    """
    font = pygame.font.Font(font_name, 1)

    # Ensure a large panel of characters heights
    text = "?/|!()§&@0123456789azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN"  # noqa

    start = 1
    end = max_height * 2

    while start < end:
        k = (start + end) // 2
        font = pygame.font.Font(font_name, k)
        height = font.size(text)[1]
        if height > max_height:
            end = k
        else:
            start = k + 1

    return font

def draw_round_rect(surface, color, rect, radius=0.1, width=0):
    """Draw a rounded rectangle.

    Parameters
    ----------
    surface:
        Surface to draw on.
    color:
        RGBA tuple color to draw with, the alpha value is optional.
    rect:
        Rectangle to draw, position and dimensions.
    radius:
        Used for drawing rectangle with rounded corners. The supported range is
        [0, 1] with 0 representing a rectangle without rounded corners.
    width:
        Line thickness (0 to fill the rectangle).
    """
    rect = pygame.Rect(rect)
    if len(color) == 4:
        alpha = color[-1]
        color = color[:3] + (0,)
    else:
        alpha = 255
        color += (0,)

    shape = pygame.Surface(rect.size, pygame.SRCALPHA)

    circle = pygame.Surface([min(rect.size) * 3] * 2, pygame.SRCALPHA)
    if width > 0:
        pygame.draw.arc(circle, (0, 0, 0), circle.get_rect(),
                        1.571, 3.1415, width * 8)
    else:
        pygame.draw.ellipse(circle, (0, 0, 0), circle.get_rect(), 0)
    circle = pygame.transform.smoothscale(circle,
                                          [int(min(rect.size) * radius)] * 2)

    i = 1
    shape_rect = shape.get_rect()
    for pos in ('topleft', 'topright', 'bottomleft', 'bottomright'):
        r = circle.get_rect(**{pos: getattr(shape_rect, pos)})
        shape.blit(circle, r)
        if width > 0:
            circle = pygame.transform.rotate(circle, -i * 90)
        i += 1

    hrect = shape_rect.inflate(0, -circle.get_height() + 1)
    vrect = shape_rect.inflate(-circle.get_width() + 1, 0)
    if width > 0:
        hrect.width = width
        vrect.height = width
        shape.fill((0, 0, 0), hrect)
        shape.fill((0, 0, 0), vrect)
        hrect.right = shape_rect.right
        vrect.bottom = shape_rect.bottom
        shape.fill((0, 0, 0), hrect)
        shape.fill((0, 0, 0), vrect)
    else:
        shape.fill((0, 0, 0), hrect)
        shape.fill((0, 0, 0), vrect)

    shape.fill(color, special_flags=pygame.BLEND_RGBA_MAX)
    shape.fill((255, 255, 255, alpha), special_flags=pygame.BLEND_RGBA_MIN)

    return surface.blit(shape, rect)

class VKeyboardRenderer(object):
    """
    A VKeyboardRenderer is in charge of keyboard rendering.

    It handles keyboard rendering properties such as color or padding,
    and provides several rendering methods.

    .. note::
        A DEFAULT and DARK styles are available as class attribute.
    """

    DEFAULT = None
    DARK = None

    def __init__(self,
                 font_name,
                 text_color,
                 cursor_color,
                 selection_color,
                 background_color,
                 background_key_color,
                 background_input_color,
                 text_special_key_color=None,
                 background_special_key_color=None):
        """VKeyboardStyle default constructor.

        Some parameters take a list of color tuples, one per state.
        The states are: (released, pressed)

        Parameters
        ----------
        font_name:
            Path to font file for rendering key.
        text_color:
            List of RGB tuples for text color (one tuple per state).
        cursor_color:
            RGB tuple for cursor color of text input.
        selection_color:
            RGB tuple for selected key color.
        background_color:
            RGB tuple for background colo   r for text.
        background_key_color:
            List of RGB tuples for key background color (one tuple per state).
        background_input_color:
            RGB tuple for background color of the text input.
        text_special_key_color:
            List of RGB tuples for special key text color (one tuple per state).
        background_special_key_color:
            List of RGB tuples for special key background color (one tuple per
            state).
        """
        self.font = None
        self.font_height = None
        self.font_input = None
        self.font_input_height = None
        self.font_name = font_name
        self.text_color = text_color
        self.cursor_color = cursor_color
        self.selection_color = selection_color
        self.background_color = background_color
        self.background_key_color = background_key_color
        self.background_input_color = background_input_color

        self.text_special_key_color = text_special_key_color
        self.background_special_key_color = background_special_key_color

    def get_text_width(self, text):
        """Return the width of the given text in the text input box.

        Parameters
        ----------
        text:
            Text to evaluate.
        """
        return self.font_input.size(text)[0]

    def truncate(self, text, max_width, start=0, nearest=False):
        """Truncate the given text in order to fit the maximum
        given width.

        This function uses the binary search algorithm to go faster
        than a one-by-one try.

        Parameters
        ----------
        text:
            Text to split.
        max_width:
            Maximum authorized width of the text (according to font).
        start:
            Index for searching the text part with correct width.
        nearest:
            If True, the returned text can have a width higher than
            the ``max_width`` to reduce abs(max_width - width).

        Returns
        -------
        (part, width):
            Truncated text and its rendered width.
        """
        width = 0
        end = len(text)

        if end < start:
            return text, self.get_text_width(text)

        while start < end:
            k = (start + end) // 2
            new_width = self.get_text_width(text[:k+1])
            if new_width > max_width:
                end = k
            else:
                width = new_width
                start = k + 1

        if nearest:
            next_width = self.get_text_width(text[:start+1])
            if abs(max_width - next_width) < abs(max_width - width):
                return text[:start+1], next_width

        return text[:start], width

    def draw_background(self, surface):
        """Default drawing method for background.

        Background is drawn as a simple rectangle filled using this
        style background color attribute.

        Parameters
        ----------
        surface:
            Surface background should be drawn in.
        """
        surface.fill(self.background_color)

    def draw_cursor(self, surface, cursor):
        """Default drawing method for cursor of the text input box.

        Cursor is drawn as a simple rectangle filled using the
        cursor color attribute.

        Parameters
        ----------
        surface:
            Surface representing the cursor.
        cursor:
            Cursor object.
        """
        if cursor.selected:
            surface.fill(self.selection_color)
        else:
            surface.fill(self.cursor_color)

    def draw_text(self, surface, text):
        """Default drawing method for text input box.

        Draw the text.

        Parameters
        ----------
        surface:
            Surface on which the text is drawn.
        text:
            Target text to be drawn.
        """
        if self.font_input_height != surface.get_height():
            # Resize font to fit the surface
            self.font_input = fit_font(self.font_name, surface.get_height())
            self.font_input_height = surface.get_height()

        surface.fill(self.background_input_color)
        surface.blit(self.font_input.render(text, 1,
                                            self.text_color[0]), (0, 0))

    def draw_key(self, surface, key):
        """Default drawing method for key.

        Draw the key accordingly to it type.

        Parameters
        ----------
        surface:
            Surface background should be drawn in.
        key:
            Target key to be drawn.
        """
        if isinstance(key, vkeys.VSpaceKey):
            self.draw_space_key(surface, key)
        elif isinstance(key, vkeys.VBackKey):
            self.draw_back_key(surface, key)
        elif isinstance(key, vkeys.VUppercaseKey):
            self.draw_uppercase_key(surface, key)
        elif isinstance(key, vkeys.VSpecialCharKey):
            self.draw_special_char_key(surface, key)
        else:
            self.draw_character_key(surface, key)

    def draw_character_key(self, surface, key, special=False):
        """Default drawing method for key.

        Key is drawn as a simple rectangle filled using this
        cell style background color attribute. Key value is printed
        into drawn cell using internal font.

        Parameters
        ----------
        surface:
            Surface key background should be drawn in.
        key:
            Target key to be drawn.
        special:
            Boolean flag that indicates if the drawn key should use
            special background color if available.
        """
        rect = surface.get_rect().inflate(-2, -2)
        if self.font_height != rect.height:
            # Resize font to fit the surface
            self.font = fit_font(self.font_name, rect.height)
            self.font_height = rect.height

        background_color = self.background_key_color[key.pressed]
        if special and self.background_special_key_color:
            background_color = self.background_special_key_color[key.pressed]

        text_color = self.text_color[key.pressed]
        if special and self.text_special_key_color and not key.pressed:
            # Key is not pressed, color according to activated state
            state = getattr(key, 'activated', key.pressed)
            text_color = self.text_special_key_color[state]

        surface.fill(self.background_color)
        draw_round_rect(surface, background_color, rect, 0.4)
        if key.selected:
            draw_round_rect(surface, self.selection_color, surface.get_rect(), 0.4, 1)

        text = self.font.render(str(key), 1, text_color)
        x = (key.rect.width - text.get_width()) // 2
        y = (key.rect.height - text.get_height()) // 2
        surface.blit(text, (x, y))

    def draw_space_key(self, surface, key):
        """Default drawing method space key.

        Key is drawn as a simple rectangle filled using this
        cell style background color attribute. Key value is printed
        into drawn cell using internal font.

        Parameters
        ----------
        surface:
            Surface background should be drawn in.
        key:
            Target key to be drawn.
        """
        self.draw_character_key(surface, key, False)

    def draw_back_key(self, surface, key):
        """Default drawing method for back key. Drawn as character key.

        Parameters
        ----------
        surface:
            Surface background should be drawn in.
        key:
            Target key to be drawn.
        """
        self.draw_character_key(surface, key, True)

    def draw_uppercase_key(self, surface, key):
        """Default drawing method for uppercase key. Drawn as character key.

        Parameters
        ----------
        surface:
            Surface background should be drawn in.
        key:
            Target key to be drawn.
        """
        self.draw_character_key(surface, key, True)

    def draw_special_char_key(self, surface, key):
        """Default drawing method for special char key.
        Drawn as character key.

        Parameters
        ----------
        surface:
            Surface background should be drawn in.
        key:
            Target key to be drawn.
        """
        self.draw_character_key(surface, key, True)

# Default keyboard renderer
VKeyboardRenderer.DEFAULT = VKeyboardRenderer(
    osp.join(osp.dirname(__file__), 'DejaVuSans.ttf'),
    text_color=((0, 0, 0), (255, 255, 255)),
    cursor_color=(0, 0, 0),
    selection_color=(0, 0, 200),
    background_color=(255, 255, 255),
    background_key_color=((255, 255, 255), (0, 0, 0)),
    background_input_color=(220, 220, 220),
    background_special_key_color=((180, 180, 180), (0, 0, 0))
)

VKeyboardRenderer.DARK = VKeyboardRenderer(
    osp.join(osp.dirname(__file__), 'DejaVuSans.ttf'),
    text_color=((182, 183, 184), (255, 255, 255)),
    cursor_color=(255, 255, 255),
    selection_color=(124, 183, 62),
    background_color=(0, 0, 0),
    background_key_color=((59, 56, 54), (47, 48, 51)),
    background_input_color=(80, 80, 80),
    text_special_key_color=((182, 183, 184), (124, 183, 62)),
    background_special_key_color=((35, 33, 30), (47, 48, 51))
)
<commit_msg>Buffer to avoid reaching the limit of opened Font files<commit_after>#!/usr/bin/env python
# coding: utf8

"""
Renderer for the keyboard and the text box used to display
the current text.
"""

import os.path as osp
import pygame  # pylint: disable=import-error

from . import vkeys

def get_font(font_name, size):
    """Get font object from font name and size.

    This method is used to optimize the number of opened font files
    and avoid reaching the limit of the system (each call to Font()
    class will open the font file, and let it opened).
    """
    if osp.isfile(font_name):
        if not hasattr(pygame.font, 'loaded'):
            setattr(pygame.font, 'loaded', {})
        return pygame.font.loaded.setdefault((font_name, size), pygame.font.Font(font_name, size))
    else:
        return pygame.font.Font(font_name, size)

def fit_font(font_name, max_height):
    """Set the size of the font to fit the given height.

    This function uses the binary search algorithm to go faster
    than a one-by-one try.

    Parameters
    ----------
    font_name:
        Path to font file for rendering key.
    max_height:
        Height to fit.
    """
    font = get_font(font_name, 1)

    # Ensure a large panel of characters heights
    text = "?/|!()§&@0123456789azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN"  # noqa

    start = 1
    end = max_height * 2

    while start < end:
        k = (start + end) // 2
        font = get_font(font_name, k)
        height = font.size(text)[1]
        if height > max_height:
            end = k
        else:
            start = k + 1

    return font

def draw_round_rect(surface, color, rect, radius=0.1, width=0):
    """Draw a rounded rectangle.

    Parameters
    ----------
    surface:
        Surface to draw on.
    color:
        RGBA tuple color to draw with, the alpha value is optional.
    rect:
        Rectangle to draw, position and dimensions.
    radius:
        Used for drawing rectangle with rounded corners. The supported range is
        [0, 1] with 0 representing a rectangle without rounded corners.
    width:
        Line thickness (0 to fill the rectangle).
    """
    rect = pygame.Rect(rect)
    if len(color) == 4:
        alpha = color[-1]
        color = color[:3] + (0,)
    else:
        alpha = 255
        color += (0,)

    shape = pygame.Surface(rect.size, pygame.SRCALPHA)

    circle = pygame.Surface([min(rect.size) * 3] * 2, pygame.SRCALPHA)
    if width > 0:
        pygame.draw.arc(circle, (0, 0, 0), circle.get_rect(),
                        1.571, 3.1415, width * 8)
    else:
        pygame.draw.ellipse(circle, (0, 0, 0), circle.get_rect(), 0)
    circle = pygame.transform.smoothscale(circle,
                                          [int(min(rect.size) * radius)] * 2)

    i = 1
    shape_rect = shape.get_rect()
    for pos in ('topleft', 'topright', 'bottomleft', 'bottomright'):
        r = circle.get_rect(**{pos: getattr(shape_rect, pos)})
        shape.blit(circle, r)
        if width > 0:
            circle = pygame.transform.rotate(circle, -i * 90)
        i += 1

    hrect = shape_rect.inflate(0, -circle.get_height() + 1)
    vrect = shape_rect.inflate(-circle.get_width() + 1, 0)
    if width > 0:
        hrect.width = width
        vrect.height = width
        shape.fill((0, 0, 0), hrect)
        shape.fill((0, 0, 0), vrect)
        hrect.right = shape_rect.right
        vrect.bottom = shape_rect.bottom
        shape.fill((0, 0, 0), hrect)
        shape.fill((0, 0, 0), vrect)
    else:
        shape.fill((0, 0, 0), hrect)
        shape.fill((0, 0, 0), vrect)

    shape.fill(color, special_flags=pygame.BLEND_RGBA_MAX)
    shape.fill((255, 255, 255, alpha), special_flags=pygame.BLEND_RGBA_MIN)

    return surface.blit(shape, rect)

class VKeyboardRenderer(object):
    """
    A VKeyboardRenderer is in charge of keyboard rendering.

    It handles keyboard rendering properties such as color or padding,
    and provides several rendering methods.

    .. note::
        A DEFAULT and DARK styles are available as class attribute.
    """

    DEFAULT = None
    DARK = None

    def __init__(self,
                 font_name,
                 text_color,
                 cursor_color,
                 selection_color,
                 background_color,
                 background_key_color,
                 background_input_color,
                 text_special_key_color=None,
                 background_special_key_color=None):
        """VKeyboardStyle default constructor.

        Some parameters take a list of color tuples, one per state.
        The states are: (released, pressed)

        Parameters
        ----------
        font_name:
            Path to font file for rendering key.
        text_color:
            List of RGB tuples for text color (one tuple per state).
        cursor_color:
            RGB tuple for cursor color of text input.
        selection_color:
            RGB tuple for selected key color.
        background_color:
            RGB tuple for background colo   r for text.
        background_key_color:
            List of RGB tuples for key background color (one tuple per state).
        background_input_color:
            RGB tuple for background color of the text input.
        text_special_key_color:
            List of RGB tuples for special key text color (one tuple per state).
        background_special_key_color:
            List of RGB tuples for special key background color (one tuple per
            state).
        """
        self.font = None
        self.font_height = None
        self.font_input = None
        self.font_input_height = None
        self.font_name = font_name
        self.text_color = text_color
        self.cursor_color = cursor_color
        self.selection_color = selection_color
        self.background_color = background_color
        self.background_key_color = background_key_color
        self.background_input_color = background_input_color

        self.text_special_key_color = text_special_key_color
        self.background_special_key_color = background_special_key_color

    def get_text_width(self, text):
        """Return the width of the given text in the text input box.

        Parameters
        ----------
        text:
            Text to evaluate.
        """
        return self.font_input.size(text)[0]

    def truncate(self, text, max_width, start=0, nearest=False):
        """Truncate the given text in order to fit the maximum
        given width.

        This function uses the binary search algorithm to go faster
        than a one-by-one try.

        Parameters
        ----------
        text:
            Text to split.
        max_width:
            Maximum authorized width of the text (according to font).
        start:
            Index for searching the text part with correct width.
        nearest:
            If True, the returned text can have a width higher than
            the ``max_width`` to reduce abs(max_width - width).

        Returns
        -------
        (part, width):
            Truncated text and its rendered width.
        """
        width = 0
        end = len(text)

        if end < start:
            return text, self.get_text_width(text)

        while start < end:
            k = (start + end) // 2
            new_width = self.get_text_width(text[:k+1])
            if new_width > max_width:
                end = k
            else:
                width = new_width
                start = k + 1

        if nearest:
            next_width = self.get_text_width(text[:start+1])
            if abs(max_width - next_width) < abs(max_width - width):
                return text[:start+1], next_width

        return text[:start], width

    def draw_background(self, surface):
        """Default drawing method for background.

        Background is drawn as a simple rectangle filled using this
        style background color attribute.

        Parameters
        ----------
        surface:
            Surface background should be drawn in.
        """
        surface.fill(self.background_color)

    def draw_cursor(self, surface, cursor):
        """Default drawing method for cursor of the text input box.

        Cursor is drawn as a simple rectangle filled using the
        cursor color attribute.

        Parameters
        ----------
        surface:
            Surface representing the cursor.
        cursor:
            Cursor object.
        """
        if cursor.selected:
            surface.fill(self.selection_color)
        else:
            surface.fill(self.cursor_color)

    def draw_text(self, surface, text):
        """Default drawing method for text input box.

        Draw the text.

        Parameters
        ----------
        surface:
            Surface on which the text is drawn.
        text:
            Target text to be drawn.
        """
        if self.font_input_height != surface.get_height():
            # Resize font to fit the surface
            self.font_input = fit_font(self.font_name, surface.get_height())
            self.font_input_height = surface.get_height()

        surface.fill(self.background_input_color)
        surface.blit(self.font_input.render(text, 1,
                                            self.text_color[0]), (0, 0))

    def draw_key(self, surface, key):
        """Default drawing method for key.

        Draw the key accordingly to it type.

        Parameters
        ----------
        surface:
            Surface background should be drawn in.
        key:
            Target key to be drawn.
        """
        if isinstance(key, vkeys.VSpaceKey):
            self.draw_space_key(surface, key)
        elif isinstance(key, vkeys.VBackKey):
            self.draw_back_key(surface, key)
        elif isinstance(key, vkeys.VUppercaseKey):
            self.draw_uppercase_key(surface, key)
        elif isinstance(key, vkeys.VSpecialCharKey):
            self.draw_special_char_key(surface, key)
        else:
            self.draw_character_key(surface, key)

    def draw_character_key(self, surface, key, special=False):
        """Default drawing method for key.

        Key is drawn as a simple rectangle filled using this
        cell style background color attribute. Key value is printed
        into drawn cell using internal font.

        Parameters
        ----------
        surface:
            Surface key background should be drawn in.
        key:
            Target key to be drawn.
        special:
            Boolean flag that indicates if the drawn key should use
            special background color if available.
        """
        rect = surface.get_rect().inflate(-2, -2)
        if self.font_height != rect.height:
            # Resize font to fit the surface
            self.font = fit_font(self.font_name, rect.height)
            self.font_height = rect.height

        background_color = self.background_key_color[key.pressed]
        if special and self.background_special_key_color:
            background_color = self.background_special_key_color[key.pressed]

        text_color = self.text_color[key.pressed]
        if special and self.text_special_key_color and not key.pressed:
            # Key is not pressed, color according to activated state
            state = getattr(key, 'activated', key.pressed)
            text_color = self.text_special_key_color[state]

        surface.fill(self.background_color)
        draw_round_rect(surface, background_color, rect, 0.4)
        if key.selected:
            draw_round_rect(surface, self.selection_color, surface.get_rect(), 0.4, 1)

        text = self.font.render(str(key), 1, text_color)
        x = (key.rect.width - text.get_width()) // 2
        y = (key.rect.height - text.get_height()) // 2
        surface.blit(text, (x, y))

    def draw_space_key(self, surface, key):
        """Default drawing method space key.

        Key is drawn as a simple rectangle filled using this
        cell style background color attribute. Key value is printed
        into drawn cell using internal font.

        Parameters
        ----------
        surface:
            Surface background should be drawn in.
        key:
            Target key to be drawn.
        """
        self.draw_character_key(surface, key, False)

    def draw_back_key(self, surface, key):
        """Default drawing method for back key. Drawn as character key.

        Parameters
        ----------
        surface:
            Surface background should be drawn in.
        key:
            Target key to be drawn.
        """
        self.draw_character_key(surface, key, True)

    def draw_uppercase_key(self, surface, key):
        """Default drawing method for uppercase key. Drawn as character key.

        Parameters
        ----------
        surface:
            Surface background should be drawn in.
        key:
            Target key to be drawn.
        """
        self.draw_character_key(surface, key, True)

    def draw_special_char_key(self, surface, key):
        """Default drawing method for special char key.
        Drawn as character key.

        Parameters
        ----------
        surface:
            Surface background should be drawn in.
        key:
            Target key to be drawn.
        """
        self.draw_character_key(surface, key, True)

# Default keyboard renderer
VKeyboardRenderer.DEFAULT = VKeyboardRenderer(
    osp.join(osp.dirname(__file__), 'DejaVuSans.ttf'),
    text_color=((0, 0, 0), (255, 255, 255)),
    cursor_color=(0, 0, 0),
    selection_color=(0, 0, 200),
    background_color=(255, 255, 255),
    background_key_color=((255, 255, 255), (0, 0, 0)),
    background_input_color=(220, 220, 220),
    background_special_key_color=((180, 180, 180), (0, 0, 0))
)

VKeyboardRenderer.DARK = VKeyboardRenderer(
    osp.join(osp.dirname(__file__), 'DejaVuSans.ttf'),
    text_color=((182, 183, 184), (255, 255, 255)),
    cursor_color=(255, 255, 255),
    selection_color=(124, 183, 62),
    background_color=(0, 0, 0),
    background_key_color=((59, 56, 54), (47, 48, 51)),
    background_input_color=(80, 80, 80),
    text_special_key_color=((182, 183, 184), (124, 183, 62)),
    background_special_key_color=((35, 33, 30), (47, 48, 51))
)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
Base HTTP client handler class.  This wraps a HTTP client library in a
consistent interface to make processing and handling of requests more
convenient and to aid portability of pyhaystack.
"""

import re
try:
    from urllib.parse import quote_plus
except ImportError:
    from urllib import quote_plus

try:
    from urllib.parse import urljoin
except ImportError:
    from urllib import basejoin as urljoin

from .auth import AuthenticationCredentials

class HTTPClient(object):
    """
    The base HTTP client interface.  This class defines methods for making
    HTTP requests in a unified manner.  The interface presented is an
    asynchronous one, even for synchronous implementations.
    """

    PROTO_RE    = re.compile(r'^[a-z]+://')

    def __init__(self, uri=None, params=None, headers=None, cookies=None,
            auth=None, timeout=None, proxies=None, tls_verify=None,
            tls_cert=None, log=None):
        """
        Instantiate a HTTP client instance with some default parameters.
        These parameters are made accessible as properties to be modified at
        will by the caller as needed.

        :param uri:     Base URI for all requests.  If given, this string will
                        be pre-pended to all requests passed through this
                        client.
        :param params:  A dictionary of key-value pairs to be passed as URI
                        query parameters.
        :param headers: A dictionary of key-value pairs to be passed as HTTP
                        headers.
        :param cookies: A dictionary of key-value pairs to be passed as cookies.
        :param auth:    An instance of a HttpAuth object.
        :param timeout: An integer or float giving the default maximum time
                        duration for requests before timing out.
        :param proxies: A dictionary mapping the hostname and protocol to a
                        proxy server URI.
        :param tls_verify:
                        For TLS servers, this determines whether the server
                        is validated or not.  It should be the path to the
                        CA certificate file for this server, or alternatively
                        can be set to 'True' to verify against CAs known to
                        the client. (e.g. OS certificate store)
        :param tls_cert:
                        For TLS servers, this specifies the certificate used
                        by the client to authenticate itself with the server.
        :param log:     If not None, then it's a logging object that will be
                        used for debugging HTTP operations.
        """

        # Stash these defaults for later.  These can be modified at any time
        # by the caller.
        self.uri = uri
        self.params = params
        self.headers = headers
        self.cookies = cookies
        self.auth = auth
        self.timeout = timeout
        self.proxies = proxies
        self.tls_verify = tls_verify
        self.tls_cert = tls_cert
        self.log = log

    def request(self, method, uri, callback, body=None, params=None,
            headers=None, cookies=None, auth=None, timeout=None, proxies=None,
            tls_verify=None, tls_cert=None, exclude_params=None,
            exclude_headers=None, exclude_cookies=True, exclude_proxies=True):
        """
        Perform a request with this client.  Most parameters here exist to either
        add to or override the defaults given by the client attributes.  The
        parameters exclude_... serve to allow selective removal of defaults.

        :param method:  The HTTP method to request.
        :param uri:     URL for this request.  If this is a relative URL, it
                        will be relative to the URL given by the 'uri'
                        attribute.
        :param callback:
                        A callback function that will be presented with the
                        result of this request.
        :param body:    An optional body for the request.
        :param params:  A dictionary of key-value pairs to be passed as URI
                        query parameters.
        :param headers: A dictionary of key-value pairs to be passed as HTTP
                        headers.
        :param cookies: A dictionary of key-value pairs to be passed as cookies.
        :param auth:    An instance of a HttpAuth object.
        :param timeout: An integer or float giving the default maximum time
                        duration for requests before timing out.
        :param proxies: A dictionary mapping the hostname and protocol to a
                        proxy server URI.
        :param tls_verify:
                        For TLS servers, this determines whether the server
                        is validated or not.  It should be the path to the
                        CA certificate file for this server, or alternatively
                        can be set to 'True' to verify against CAs known to
                        the client. (e.g. OS certificate store)
        :param tls_cert:
                        For TLS servers, this specifies the certificate used
                        by the client to authenticate itself with the server.
        :param exclude_params:
                        If True, exclude all default parameters and use only
                        the parameters given.  Otherwise, this is an iterable
                        of parameter names to be excluded.
        :param exclude_headers:
                        If True, exclude all default headers and use only
                        the headers given.  Otherwise, this is an iterable
                        of header names to be excluded.
        :param exclude_cookies:
                        If True, exclude all default cookies and use only
                        the cookies given.  Otherwise, this is an iterable
                        of cookie names to be excluded.
        :param exclude_proxies:
                        If True, exclude all default proxies and use only
                        the proxies given.  Otherwise, this is an iterable
                        of proxy names to be excluded.
        """
        # Is this an absolute URL?
        if not self.PROTO_RE.match(uri):
            # Do we have a base URL?
            if self.uri is None:
                raise ValueError('uri must be absolute or base '\
                        'set in uri attribute')
            # Prepend our base URL
            uri = urljoin(self.uri, uri)

        def _merge(given, defaults, exclude):
            if exclude is True:
                result = {}
            else:
                result = (defaults or {}).copy()
                if exclude is not None:
                    for param in exclude:
                        result.pop(param, None)

            if given is not None:
                result.update(given)
            return result

        # Merge our parameters, headers and cookies together
        params = _merge(params, self.params, exclude_params)
        headers = _merge(headers, self.headers, exclude_headers)
        cookies = _merge(cookies, self.cookies, exclude_cookies)
        proxies = _merge(proxies, self.proxies, exclude_proxies)
        auth = auth or self.auth or None
        timeout = timeout or self.timeout or None

        if not ((auth is None) or isinstance(auth, AuthenticationCredentials)):
            raise TypeError('%s is not a subclass of the '\
                    'AuthenticationCredentials class.' \
                    % auth.__class__.__name__)

        if tls_verify is None:
            tls_verify = self.tls_verify
            if (tls_verify is None) and uri.startswith('https://'):
                # If we're dealing with a https:// URL, turn on verification
                # by default for user safety.
                tls_verify = True
        tls_cert = tls_cert or self.tls_cert or None

        # Convert parameters to a query string
        query_str = u'&'.join([
            '%s=%s' % (key, quote_plus(value))
            for key, value in params.items()
        ])

        # Tack query string onto URL
        if query_str:
            uri += u'?' + query_str

        # Perform the actual request.
        if self.log is not None:
            self.log.debug( 'Performing operation %s of %s, headers: %r, '\
                            'cookies: %r, body: %r', method, uri, headers,
                            cookies, body)
        self._request(method, uri, callback, body = body,
                headers = headers, cookies = cookies, auth = auth, timeout = timeout, proxies = proxies,
                tls_verify = tls_verify, tls_cert = tls_cert)

    def get(self, uri, callback, **kwargs):
        """
        Convenience function: perform a HTTP GET operation.  Arguments are the
        same as for request.
        """
        kwargs.pop('body',None)
        self.request('GET', uri, callback, **kwargs)

    def post(self, uri, callback, body = None, body_type=None, body_size=None,
            headers=None, **kwargs):
        """
        Convenience function: perform a HTTP POST operation.  Arguments are the
        same as for request.

        :param body:        Body data to be posted in this request as a string.
        :param body_type:   Body MIME data type.  This is a convenience for setting
                            the Content-Type header.
        :param body_size:   Length of the body to be sent.  If None, the length
                            is autodetected.  Set to False to avoid this.
        """
        if body:
            if body_size is None:
                body_size = len(body)

        if headers is None:
            headers = {}

        if body_size is not False:
            headers['Content-Length'] = body_size

        if body_type is not None:
            headers['Content-Type'] = body_type
        self.request('POST', uri, callback, **kwargs)

    def _request(self, method, uri, callback, body,
            headers, cookies, auth, timeout, proxies,
            tls_verify, tls_cert):
        """
        Perform a HTTP request using the underlying implementation.  This is
        expected to take the arguments given, perform a query, then return the
        result via a callback.
        """
        raise NotImplementedError('TODO: implement in %s' \
                % self.__class__.__name__)

class HTTPResponse(object):
    """
    A class that represents the raw response from a HTTP request.
    """
    def __init__(self, status_code, headers, body, cookies=None, text=''):
        self.status_code = status_code
        self.headers = headers
        self.body = body
        self.text = text
        self.cookies = cookies
<commit_msg>client.http.base: Ensure _request args are given as keywords.<commit_after># -*- coding: utf-8 -*-
"""
Base HTTP client handler class.  This wraps a HTTP client library in a
consistent interface to make processing and handling of requests more
convenient and to aid portability of pyhaystack.
"""

import re
try:
    from urllib.parse import quote_plus
except ImportError:
    from urllib import quote_plus

try:
    from urllib.parse import urljoin
except ImportError:
    from urllib import basejoin as urljoin

from .auth import AuthenticationCredentials

class HTTPClient(object):
    """
    The base HTTP client interface.  This class defines methods for making
    HTTP requests in a unified manner.  The interface presented is an
    asynchronous one, even for synchronous implementations.
    """

    PROTO_RE    = re.compile(r'^[a-z]+://')

    def __init__(self, uri=None, params=None, headers=None, cookies=None,
            auth=None, timeout=None, proxies=None, tls_verify=None,
            tls_cert=None, log=None):
        """
        Instantiate a HTTP client instance with some default parameters.
        These parameters are made accessible as properties to be modified at
        will by the caller as needed.

        :param uri:     Base URI for all requests.  If given, this string will
                        be pre-pended to all requests passed through this
                        client.
        :param params:  A dictionary of key-value pairs to be passed as URI
                        query parameters.
        :param headers: A dictionary of key-value pairs to be passed as HTTP
                        headers.
        :param cookies: A dictionary of key-value pairs to be passed as cookies.
        :param auth:    An instance of a HttpAuth object.
        :param timeout: An integer or float giving the default maximum time
                        duration for requests before timing out.
        :param proxies: A dictionary mapping the hostname and protocol to a
                        proxy server URI.
        :param tls_verify:
                        For TLS servers, this determines whether the server
                        is validated or not.  It should be the path to the
                        CA certificate file for this server, or alternatively
                        can be set to 'True' to verify against CAs known to
                        the client. (e.g. OS certificate store)
        :param tls_cert:
                        For TLS servers, this specifies the certificate used
                        by the client to authenticate itself with the server.
        :param log:     If not None, then it's a logging object that will be
                        used for debugging HTTP operations.
        """

        # Stash these defaults for later.  These can be modified at any time
        # by the caller.
        self.uri = uri
        self.params = params
        self.headers = headers
        self.cookies = cookies
        self.auth = auth
        self.timeout = timeout
        self.proxies = proxies
        self.tls_verify = tls_verify
        self.tls_cert = tls_cert
        self.log = log

    def request(self, method, uri, callback, body=None, params=None,
            headers=None, cookies=None, auth=None, timeout=None, proxies=None,
            tls_verify=None, tls_cert=None, exclude_params=None,
            exclude_headers=None, exclude_cookies=True, exclude_proxies=True):
        """
        Perform a request with this client.  Most parameters here exist to either
        add to or override the defaults given by the client attributes.  The
        parameters exclude_... serve to allow selective removal of defaults.

        :param method:  The HTTP method to request.
        :param uri:     URL for this request.  If this is a relative URL, it
                        will be relative to the URL given by the 'uri'
                        attribute.
        :param callback:
                        A callback function that will be presented with the
                        result of this request.
        :param body:    An optional body for the request.
        :param params:  A dictionary of key-value pairs to be passed as URI
                        query parameters.
        :param headers: A dictionary of key-value pairs to be passed as HTTP
                        headers.
        :param cookies: A dictionary of key-value pairs to be passed as cookies.
        :param auth:    An instance of a HttpAuth object.
        :param timeout: An integer or float giving the default maximum time
                        duration for requests before timing out.
        :param proxies: A dictionary mapping the hostname and protocol to a
                        proxy server URI.
        :param tls_verify:
                        For TLS servers, this determines whether the server
                        is validated or not.  It should be the path to the
                        CA certificate file for this server, or alternatively
                        can be set to 'True' to verify against CAs known to
                        the client. (e.g. OS certificate store)
        :param tls_cert:
                        For TLS servers, this specifies the certificate used
                        by the client to authenticate itself with the server.
        :param exclude_params:
                        If True, exclude all default parameters and use only
                        the parameters given.  Otherwise, this is an iterable
                        of parameter names to be excluded.
        :param exclude_headers:
                        If True, exclude all default headers and use only
                        the headers given.  Otherwise, this is an iterable
                        of header names to be excluded.
        :param exclude_cookies:
                        If True, exclude all default cookies and use only
                        the cookies given.  Otherwise, this is an iterable
                        of cookie names to be excluded.
        :param exclude_proxies:
                        If True, exclude all default proxies and use only
                        the proxies given.  Otherwise, this is an iterable
                        of proxy names to be excluded.
        """
        # Is this an absolute URL?
        if not self.PROTO_RE.match(uri):
            # Do we have a base URL?
            if self.uri is None:
                raise ValueError('uri must be absolute or base '\
                        'set in uri attribute')
            # Prepend our base URL
            uri = urljoin(self.uri, uri)

        def _merge(given, defaults, exclude):
            if exclude is True:
                result = {}
            else:
                result = (defaults or {}).copy()
                if exclude is not None:
                    for param in exclude:
                        result.pop(param, None)

            if given is not None:
                result.update(given)
            return result

        # Merge our parameters, headers and cookies together
        params = _merge(params, self.params, exclude_params)
        headers = _merge(headers, self.headers, exclude_headers)
        cookies = _merge(cookies, self.cookies, exclude_cookies)
        proxies = _merge(proxies, self.proxies, exclude_proxies)
        auth = auth or self.auth or None
        timeout = timeout or self.timeout or None

        if not ((auth is None) or isinstance(auth, AuthenticationCredentials)):
            raise TypeError('%s is not a subclass of the '\
                    'AuthenticationCredentials class.' \
                    % auth.__class__.__name__)

        if tls_verify is None:
            tls_verify = self.tls_verify
            if (tls_verify is None) and uri.startswith('https://'):
                # If we're dealing with a https:// URL, turn on verification
                # by default for user safety.
                tls_verify = True
        tls_cert = tls_cert or self.tls_cert or None

        # Convert parameters to a query string
        query_str = u'&'.join([
            '%s=%s' % (key, quote_plus(value))
            for key, value in params.items()
        ])

        # Tack query string onto URL
        if query_str:
            uri += u'?' + query_str

        # Perform the actual request.
        if self.log is not None:
            self.log.debug( 'Performing operation %s of %s, headers: %r, '\
                            'cookies: %r, body: %r', method, uri, headers,
                            cookies, body)
        self._request(method=method, uri=uri, callback=callback, body=body,
                headers=headers, cookies=cookies, auth=auth,
                timeout=timeout, proxies=proxies, tls_verify=tls_verify,
                tls_cert=tls_cert)

    def get(self, uri, callback, **kwargs):
        """
        Convenience function: perform a HTTP GET operation.  Arguments are the
        same as for request.
        """
        kwargs.pop('body',None)
        self.request('GET', uri, callback, **kwargs)

    def post(self, uri, callback, body = None, body_type=None, body_size=None,
            headers=None, **kwargs):
        """
        Convenience function: perform a HTTP POST operation.  Arguments are the
        same as for request.

        :param body:        Body data to be posted in this request as a string.
        :param body_type:   Body MIME data type.  This is a convenience for setting
                            the Content-Type header.
        :param body_size:   Length of the body to be sent.  If None, the length
                            is autodetected.  Set to False to avoid this.
        """
        if body:
            if body_size is None:
                body_size = len(body)

        if headers is None:
            headers = {}

        if body_size is not False:
            headers['Content-Length'] = body_size

        if body_type is not None:
            headers['Content-Type'] = body_type
        self.request('POST', uri, callback, **kwargs)

    def _request(self, method, uri, callback, body,
            headers, cookies, auth, timeout, proxies,
            tls_verify, tls_cert):
        """
        Perform a HTTP request using the underlying implementation.  This is
        expected to take the arguments given, perform a query, then return the
        result via a callback.
        """
        raise NotImplementedError('TODO: implement in %s' \
                % self.__class__.__name__)

class HTTPResponse(object):
    """
    A class that represents the raw response from a HTTP request.
    """
    def __init__(self, status_code, headers, body, cookies=None, text=''):
        self.status_code = status_code
        self.headers = headers
        self.body = body
        self.text = text
        self.cookies = cookies
<|endoftext|>


<commit_before># jsonrpc.py
#   original code: http://trac.pyworks.org/pyjamas/wiki/DjangoWithPyJamas
#   also from: http://www.pimentech.fr/technologies/outils
from django.utils import simplejson
from django.http import HttpResponse
import sys

from pyjs.jsonrpc import JSONRPCServiceBase
# JSONRPCService and jsonremote are used in combination to drastically
# simplify the provision of JSONRPC services.  use as follows:
#
# jsonservice = JSONRPCService()
#
# @jsonremote(jsonservice)
# def test(request, echo_param):
#     return "echoing the param back: %s" % echo_param
#
# dump jsonservice into urlpatterns:
#  (r'^service1/$', 'djangoapp.views.jsonservice'),

class JSONRPCService(JSONRPCServiceBase):

    def __call__(self, request, extra=None):
        return self.process(request.raw_post_data)

def jsonremote(service):
    """Make JSONRPCService a decorator so that you can write :

    from jsonrpc import JSONRPCService
    chatservice = JSONRPCService()

    @jsonremote(chatservice)
    def login(request, user_name):
        (...)
    """
    def remotify(func):
        if isinstance(service, JSONRPCService):
            service.add_method(func.__name__, func)
        else:
            emsg = 'Service "%s" not found' % str(service.__name__)
            raise NotImplementedError, emsg
        return func
    return remotify

# FormProcessor provides a mechanism for turning Django Forms into JSONRPC
# Services.  If you have an existing Django app which makes prevalent
# use of Django Forms it will save you rewriting the app.
# use as follows.  in djangoapp/views.py :
#
# class SimpleForm(forms.Form):
#     testfield = forms.CharField(max_length=100)
#
# class SimpleForm2(forms.Form):
#     testfield = forms.CharField(max_length=20)
#
# processor = FormProcessor({'processsimpleform': SimpleForm,
#                            'processsimpleform2': SimpleForm2})
#
# this will result in a JSONRPC service being created with two
# RPC functions.  dump "processor" into urlpatterns to make it
# part of the app:
#  (r'^formsservice/$', 'djangoapp.views.processor'),

from django import forms

def builderrors(form):
    d = {}
    for error in form.errors.keys():
        if error not in d:
            d[error] = []
        for errorval in form.errors[error]:
            d[error].append(unicode(errorval))
    return d

class FormProcessor(JSONRPCService):
    def __init__(self, forms, _formcls=None):

        if _formcls is None:
            JSONRPCService.__init__(self)
            for k in forms.keys():
                s  = FormProcessor({}, forms[k])
                self.add_method(k, s.__process)
        else:
            JSONRPCService.__init__(self, forms)
            self.formcls = _formcls

    def __process(self, request, params, command=None):

        f = self.formcls(params)

        if command is None: # just validate
            if not f.is_valid():
                return {'success':False, 'errors': builderrors(f)}
            return {'success':True}
        if command.has_key('html'):
            return {'success': True, 'html': f.as_table()}
        return "unrecognised command"

# The following is incredibly convenient for saving vast amounts of
# coding, avoiding doing silly things like this:
#     jsonresult = {'field1': djangoobject.field1,
#                   'field2': djangoobject.date.strftime('%Y.%M'),
#                    ..... }
#
# The date/time flatten function is there because JSONRPC doesn't
# support date/time objects or formats, so conversion to a string
# is the most logical choice.  pyjamas, being python, can easily
# be used to parse the string result at the other end.
#
# use as follows:
#
# jsonservice = JSONRPCService()
#
# @jsonremote(jsonservice)
# def list_some_model(request, start=0, count=10):
#     l = SomeDjangoModelClass.objects.filter()
#     res = json_convert(l[start:end])
#
# @jsonremote(jsonservice)
# def list_another_model(request, start=0, count=10):
#     l = AnotherDjangoModelClass.objects.filter()
#     res = json_convert(l[start:end])
#
# dump jsonservice into urlpatterns to make the two RPC functions,
# list_some_model and list_another_model part of the django app:
#  (r'^service1/$', 'djangoapp.views.jsonservice'),

from django.core.serializers import serialize
import datetime
from datetime import date

def dict_datetimeflatten(item):
    d = {}
    for k, v in item.items():
        k = str(k)
        if isinstance(v, datetime.date):
            d[k] = str(v)
        elif isinstance(v, dict):
            d[k] = dict_datetimeflatten(v)
        else:
            d[k] = v
    return d

def json_convert(l, fields=None):
    res = []
    for item in serialize('python', l, fields=fields):
        res.append(dict_datetimeflatten(item))
    return res

<commit_msg>add form save command<commit_after># jsonrpc.py
#   original code: http://trac.pyworks.org/pyjamas/wiki/DjangoWithPyJamas
#   also from: http://www.pimentech.fr/technologies/outils
from django.utils import simplejson
from django.http import HttpResponse
import sys

from pyjs.jsonrpc import JSONRPCServiceBase
# JSONRPCService and jsonremote are used in combination to drastically
# simplify the provision of JSONRPC services.  use as follows:
#
# jsonservice = JSONRPCService()
#
# @jsonremote(jsonservice)
# def test(request, echo_param):
#     return "echoing the param back: %s" % echo_param
#
# dump jsonservice into urlpatterns:
#  (r'^service1/$', 'djangoapp.views.jsonservice'),

class JSONRPCService(JSONRPCServiceBase):

    def __call__(self, request, extra=None):
        return self.process(request.raw_post_data)

def jsonremote(service):
    """Make JSONRPCService a decorator so that you can write :

    from jsonrpc import JSONRPCService
    chatservice = JSONRPCService()

    @jsonremote(chatservice)
    def login(request, user_name):
        (...)
    """
    def remotify(func):
        if isinstance(service, JSONRPCService):
            service.add_method(func.__name__, func)
        else:
            emsg = 'Service "%s" not found' % str(service.__name__)
            raise NotImplementedError, emsg
        return func
    return remotify

# FormProcessor provides a mechanism for turning Django Forms into JSONRPC
# Services.  If you have an existing Django app which makes prevalent
# use of Django Forms it will save you rewriting the app.
# use as follows.  in djangoapp/views.py :
#
# class SimpleForm(forms.Form):
#     testfield = forms.CharField(max_length=100)
#
# class SimpleForm2(forms.Form):
#     testfield = forms.CharField(max_length=20)
#
# processor = FormProcessor({'processsimpleform': SimpleForm,
#                            'processsimpleform2': SimpleForm2})
#
# this will result in a JSONRPC service being created with two
# RPC functions.  dump "processor" into urlpatterns to make it
# part of the app:
#  (r'^formsservice/$', 'djangoapp.views.processor'),

from django import forms

def builderrors(form):
    d = {}
    for error in form.errors.keys():
        if error not in d:
            d[error] = []
        for errorval in form.errors[error]:
            d[error].append(unicode(errorval))
    return d

class FormProcessor(JSONRPCService):
    def __init__(self, forms, _formcls=None):

        if _formcls is None:
            JSONRPCService.__init__(self)
            for k in forms.keys():
                s  = FormProcessor({}, forms[k])
                self.add_method(k, s.__process)
        else:
            JSONRPCService.__init__(self, forms)
            self.formcls = _formcls

    def __process(self, request, params, command=None):

        f = self.formcls(params) # create instance of form, with input params

        if command is None: # just validate
            if not f.is_valid():
                return {'success':False, 'errors': builderrors(f)}
            return {'success':True}

        elif command.has_key('save'):
            if not f.is_valid():
                return {'success':False, 'errors': builderrors(f)}
            instance = f.save() # XXX: if you want more, over-ride save.
            return {'success': True, 'instance': json_convert(instance) }

        elif command.has_key('html'):
            return {'success': True, 'html': f.as_table()}
        return "unrecognised command"

# The following is incredibly convenient for saving vast amounts of
# coding, avoiding doing silly things like this:
#     jsonresult = {'field1': djangoobject.field1,
#                   'field2': djangoobject.date.strftime('%Y.%M'),
#                    ..... }
#
# The date/time flatten function is there because JSONRPC doesn't
# support date/time objects or formats, so conversion to a string
# is the most logical choice.  pyjamas, being python, can easily
# be used to parse the string result at the other end.
#
# use as follows:
#
# jsonservice = JSONRPCService()
#
# @jsonremote(jsonservice)
# def list_some_model(request, start=0, count=10):
#     l = SomeDjangoModelClass.objects.filter()
#     res = json_convert(l[start:end])
#
# @jsonremote(jsonservice)
# def list_another_model(request, start=0, count=10):
#     l = AnotherDjangoModelClass.objects.filter()
#     res = json_convert(l[start:end])
#
# dump jsonservice into urlpatterns to make the two RPC functions,
# list_some_model and list_another_model part of the django app:
#  (r'^service1/$', 'djangoapp.views.jsonservice'),

from django.core.serializers import serialize
import datetime
from datetime import date

def dict_datetimeflatten(item):
    d = {}
    for k, v in item.items():
        k = str(k)
        if isinstance(v, datetime.date):
            d[k] = str(v)
        elif isinstance(v, dict):
            d[k] = dict_datetimeflatten(v)
        else:
            d[k] = v
    return d

def json_convert(l, fields=None):
    res = []
    for item in serialize('python', l, fields=fields):
        res.append(dict_datetimeflatten(item))
    return res

<|endoftext|>


<commit_before>"""

Test helpers for metric classes.

Essentially, all you need to do is:

- Define a small set of queries along with expected metric values (for testing
  evaluate())
- Define a larger set of queries for testing other methods, using evaluate() as
  ground truth.

"""

import numpy as np

from numpy.testing import assert_approx_equal, assert_array_almost_equal_nulp

class TestMetric(object):
    def get_metric(self):
        """Metric class instance to test."""
        raise NotImplementedError()

    def get_queries_with_values(self):
        """Queries to test for evaluate()."""
        raise NotImplementedError()

    def get_queries(self):
        """Queries to test for methods except evaluate()."""
        raise NotImplementedError()

    def get_nulp(self):
        """NULP value for assertions."""
        return 99

    def test_evaluate(self):
        m = self.get_metric()
        for id, (q, v) in enumerate(self.get_queries_with_values()):
            # Test twice to ensure caching doesn't break things.
            assert_approx_equal(v, m.evaluate(id, q))
            assert_approx_equal(v, m.evaluate(id, q))

    def test_calc_swap_deltas(self):
        m = self.get_metric()
        for id, q in enumerate(self.get_queries()):
            n = len(q)
            q_cpy = np.copy(q)
            expected_deltas = np.zeros((n, n))
            deltas = m.calc_swap_deltas(id, q)
            orig = m.evaluate(id, q)

            for i in range(n):
                for j in range(n):
                    q_cpy[[i, j]] = q[[j, i]]
                    expected_deltas[i, j] = m.evaluate(id, q_cpy) - orig
                    q_cpy[[i, j]] = q[[i, j]]

            # Test that diagonal is 0.
            assert_array_almost_equal_nulp(
                0.0, np.diagonal(expected_deltas), nulp=self.get_nulp())

            # Test that the expected deltas are symmetric.
            assert_array_almost_equal_nulp(
                expected_deltas.transpose(), expected_deltas,
                nulp=self.get_nulp())

            # Test that deltas computed by the metric match the deltas from
            # evaluate().
            assert_array_almost_equal_nulp(
                np.triu(expected_deltas), deltas,
                nulp=self.get_nulp())

            # Test that max_k() works.
            assert_array_almost_equal_nulp(
                0.0, expected_deltas[m.max_k():, m.max_k():],
                nulp=self.get_nulp())
<commit_msg>Tests should not check for max_k behavior when max_k is None<commit_after>"""

Test helpers for metric classes.

Essentially, all you need to do is:

- Define a small set of queries along with expected metric values (for testing
  evaluate())
- Define a larger set of queries for testing other methods, using evaluate() as
  ground truth.

"""

import numpy as np

from numpy.testing import assert_approx_equal, assert_array_almost_equal_nulp

class TestMetric(object):
    def get_metric(self):
        """Metric class instance to test."""
        raise NotImplementedError()

    def get_queries_with_values(self):
        """Queries to test for evaluate()."""
        raise NotImplementedError()

    def get_queries(self):
        """Queries to test for methods except evaluate()."""
        raise NotImplementedError()

    def get_nulp(self):
        """NULP value for assertions."""
        return 99

    def test_evaluate(self):
        m = self.get_metric()
        for id, (q, v) in enumerate(self.get_queries_with_values()):
            # Test twice to ensure caching doesn't break things.
            assert_approx_equal(v, m.evaluate(id, q))
            assert_approx_equal(v, m.evaluate(id, q))

    def test_calc_swap_deltas(self):
        m = self.get_metric()
        for id, q in enumerate(self.get_queries()):
            n = len(q)
            q_cpy = np.copy(q)
            expected_deltas = np.zeros((n, n))
            deltas = m.calc_swap_deltas(id, q)
            orig = m.evaluate(id, q)

            for i in range(n):
                for j in range(n):
                    q_cpy[[i, j]] = q[[j, i]]
                    expected_deltas[i, j] = m.evaluate(id, q_cpy) - orig
                    q_cpy[[i, j]] = q[[i, j]]

            # Test that diagonal is 0.
            assert_array_almost_equal_nulp(
                0.0, np.diagonal(expected_deltas), nulp=self.get_nulp())

            # Test that the expected deltas are symmetric.
            assert_array_almost_equal_nulp(
                expected_deltas.transpose(), expected_deltas,
                nulp=self.get_nulp())

            # Test that deltas computed by the metric match the deltas from
            # evaluate().
            assert_array_almost_equal_nulp(
                np.triu(expected_deltas), deltas,
                nulp=self.get_nulp())

            # Test that max_k() works.
            if m.max_k() is not None:
                assert_array_almost_equal_nulp(
                    0.0, expected_deltas[m.max_k():, m.max_k():],
                    nulp=self.get_nulp())
<|endoftext|>


<commit_before>#
# This file is part of the PyMeasure package.
#
# Copyright (c) 2013-2015 Colin Jermain, Graham Rowlands
#
# 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.
#

from .qt_variant import QtCore

import zmq
from msgpack import loads
from time import sleep
from multiprocessing import Event

from .thread import StoppableQThread
from ..experiment.procedure import Procedure

class QListener(StoppableQThread):
    """Base class for QThreads that need to listen for messages
    on a ZMQ channel and can be stopped by a thread- and process-safe
    method call
    """

    def __init__(self, channel, topic=''):
        """ Constructs the Listener object with a subscriber channel
        over which to listen for messages

        :param channel: Channel to listen on
        """
        self.context = zmq.Context()
        self.subscriber = self.context.socket(zmq.SUB)
        self.subscriber.connect(subscriber_channel)
        self.subscriber.setsocketopt(zmq.SUBSCRIBE, topic.encode())
        super(Listener, self).__init__()

    def receive(self):
        topic, raw_data = self.subscriber.recv()
        return topic, loads(raw_data)

    def __repr__(self):
        return "<%s(channel=%s,topic=%s,should_stop=%s)>" % (
            self.__class__.__name__, channel, topic, self.should_stop())

class ProcedureMonitor(QListener):
    """ ProcedureMonitor listens for status and progress messages
    on a ZMQ channel and routes them to signals and slots
    """

    status = QtCore.QSignal(int)
    progress = QtCore.QSignal(float)
    running = QtCore.QSignal()
    failed = QtCore.QSignal()
    finished = QtCore.QSignal()

    def __init__(self, channel):
        super(QListener, self).__init__(channel, '')

    def run(self):
        while not self.should_stop():
            topic, data = self.receive()
            if topic == 'status':
                self.status.emit(data)
                if data == Procedure.FAILED:
                    self.failed.emit()
                elif data == Procedure.FINISHED:
                    self.finished.emit()
            elif topic == 'progress':
                self.progress.emit(data)
            sleep(0.01)

<commit_msg>Inheretance fixes for QListeners<commit_after>#
# This file is part of the PyMeasure package.
#
# Copyright (c) 2013-2015 Colin Jermain, Graham Rowlands
#
# 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.
#

from .qt_variant import QtCore

import zmq
from msgpack import loads
from time import sleep
from multiprocessing import Event

from .thread import StoppableQThread
from ..experiment.procedure import Procedure

class QListener(StoppableQThread):
    """Base class for QThreads that need to listen for messages
    on a ZMQ channel and can be stopped by a thread- and process-safe
    method call
    """

    def __init__(self, channel, topic=''):
        """ Constructs the Listener object with a subscriber channel
        over which to listen for messages

        :param channel: Channel to listen on
        """
        self.context = zmq.Context()
        self.subscriber = self.context.socket(zmq.SUB)
        self.subscriber.connect(subscriber_channel)
        self.subscriber.setsocketopt(zmq.SUBSCRIBE, topic.encode())
        super(QListener, self).__init__()

    def receive(self):
        topic, raw_data = self.subscriber.recv()
        return topic, loads(raw_data)

    def __repr__(self):
        return "<%s(channel=%s,topic=%s,should_stop=%s)>" % (
            self.__class__.__name__, channel, topic, self.should_stop())

class ProcedureMonitor(QListener):
    """ ProcedureMonitor listens for status and progress messages
    on a ZMQ channel and routes them to signals and slots
    """

    status = QtCore.QSignal(int)
    progress = QtCore.QSignal(float)
    running = QtCore.QSignal()
    failed = QtCore.QSignal()
    finished = QtCore.QSignal()

    def __init__(self, channel):
        super(QListener, self).__init__(channel, topic='')

    def run(self):
        while not self.should_stop():
            topic, data = self.receive()
            if topic == 'status':
                self.status.emit(data)
                if data == Procedure.FAILED:
                    self.failed.emit()
                elif data == Procedure.FINISHED:
                    self.finished.emit()
            elif topic == 'progress':
                self.progress.emit(data)
            sleep(0.01)

<|endoftext|>


<commit_before>'''
    Allows you to launch a pynetworktables2js server without copying
    any python code. Just install, and do::

        python -m pynetworktables2js

    Or on Windows:

        py -m pynetworktables2js
'''

from __future__ import print_function

import os
from os.path import abspath, dirname, exists, join
from optparse import OptionParser

import tornado.web
from tornado.ioloop import IOLoop

from networktables import NetworkTables
from . import get_handlers, NonCachingStaticFileHandler

try:
    from .version import __version__
except ImportError:
    __version__ = '__master__'

import logging
logger = logging.getLogger('dashboard')

log_datefmt = "%H:%M:%S"
log_format = "%(asctime)s:%(msecs)03d %(levelname)-8s: %(name)-20s: %(message)s"

def init_networktables(options):

    if options.dashboard:
        logger.info("Connecting to networktables in Dashboard mode")
        NetworkTables.setDashboardMode()
    else:
        logger.info("Connecting to networktables at %s", options.robot)
        NetworkTables.setIPAddress(options.robot)
        NetworkTables.setClientMode()

    NetworkTables.setNetworkIdentity(options.identity)
    NetworkTables.initialize()
    logger.info("Networktables Initialized")

def main():

    # Setup options here
    parser = OptionParser()

    parser.add_option('-p', '--port', default=8888,
                      help='Port to run web server on')

    parser.add_option('-v', '--verbose', default=False, action='store_true',
                      help='Enable verbose logging')

    parser.add_option('--robot', default='127.0.0.1',
                      help="Robot's IP address")

    #parser.add_option('--dashboard', default=False, action='store_true',
    #                  help='Use this instead of --robot to receive the IP from the driver station. WARNING: It will not work if you are not on the same host as the DS!')

    parser.add_option('--identity', default='pynetworktables2js %s' % __version__,
                      help='Identity to broadcast to remote NT clients')

    options, args = parser.parse_args()

    # Setup logging
    logging.basicConfig(datefmt=log_datefmt,
                        format=log_format,
                        level=logging.DEBUG if options.verbose else logging.INFO)

    #if options.dashboard and options.robot != '127.0.0.1':
    #    parser.error("Cannot specify --robot and --dashboard")

    # Setup NetworkTables
    init_networktables(options)

    # setup tornado application with static handler + networktables support
    www_dir = abspath(os.getcwd())
    index_html = join(www_dir, 'index.html')

    if not exists(www_dir):
        logger.error("Directory '%s' does not exist!", www_dir)
        exit(1)

    if not exists(index_html):
        logger.warn("%s not found", index_html)

    app = tornado.web.Application(
        get_handlers() + [
            (r"/()", NonCachingStaticFileHandler, {"path": index_html}),
            (r"/(.*)", NonCachingStaticFileHandler, {"path": www_dir})
        ]
    )

    # Start the app
    logger.info("Listening on http://localhost:%s/", options.port)

    app.listen(options.port)
    IOLoop.current().start()

if __name__ == '__main__':
    main()<commit_msg>remove check for dashboard option because dashboard is not an option anymore<commit_after>'''
    Allows you to launch a pynetworktables2js server without copying
    any python code. Just install, and do::

        python -m pynetworktables2js

    Or on Windows:

        py -m pynetworktables2js
'''

from __future__ import print_function

import os
from os.path import abspath, dirname, exists, join
from optparse import OptionParser

import tornado.web
from tornado.ioloop import IOLoop

from networktables import NetworkTables
from . import get_handlers, NonCachingStaticFileHandler

try:
    from .version import __version__
except ImportError:
    __version__ = '__master__'

import logging
logger = logging.getLogger('dashboard')

log_datefmt = "%H:%M:%S"
log_format = "%(asctime)s:%(msecs)03d %(levelname)-8s: %(name)-20s: %(message)s"

def init_networktables(options):

    #if options.dashboard:
    #    logger.info("Connecting to networktables in Dashboard mode")
    #    NetworkTables.setDashboardMode()
    #else:
    logger.info("Connecting to networktables at %s", options.robot)
    NetworkTables.setIPAddress(options.robot)
    NetworkTables.setClientMode()

    NetworkTables.setNetworkIdentity(options.identity)
    NetworkTables.initialize()
    logger.info("Networktables Initialized")

def main():

    # Setup options here
    parser = OptionParser()

    parser.add_option('-p', '--port', default=8888,
                      help='Port to run web server on')

    parser.add_option('-v', '--verbose', default=False, action='store_true',
                      help='Enable verbose logging')

    parser.add_option('--robot', default='127.0.0.1',
                      help="Robot's IP address")

    #parser.add_option('--dashboard', default=False, action='store_true',
    #                  help='Use this instead of --robot to receive the IP from the driver station. WARNING: It will not work if you are not on the same host as the DS!')

    parser.add_option('--identity', default='pynetworktables2js %s' % __version__,
                      help='Identity to broadcast to remote NT clients')

    options, args = parser.parse_args()

    # Setup logging
    logging.basicConfig(datefmt=log_datefmt,
                        format=log_format,
                        level=logging.DEBUG if options.verbose else logging.INFO)

    #if options.dashboard and options.robot != '127.0.0.1':
    #    parser.error("Cannot specify --robot and --dashboard")

    # Setup NetworkTables
    init_networktables(options)

    # setup tornado application with static handler + networktables support
    www_dir = abspath(os.getcwd())
    index_html = join(www_dir, 'index.html')

    if not exists(www_dir):
        logger.error("Directory '%s' does not exist!", www_dir)
        exit(1)

    if not exists(index_html):
        logger.warn("%s not found", index_html)

    app = tornado.web.Application(
        get_handlers() + [
            (r"/()", NonCachingStaticFileHandler, {"path": index_html}),
            (r"/(.*)", NonCachingStaticFileHandler, {"path": www_dir})
        ]
    )

    # Start the app
    logger.info("Listening on http://localhost:%s/", options.port)

    app.listen(options.port)
    IOLoop.current().start()

if __name__ == '__main__':
    main()
<|endoftext|>