<commit_before>from __future__ import division

import re
import string

pipe_split_p = re.compile("\s*\|\s*")
func_and_arg_p = re.compile('(?P<func>\w+)\((?P<args>.*)\)', flags=re.DOTALL)
comma_sep_p = re.compile('\s*,\s*')

def get_func_and_arg_dict(s):
    """
    Parses the input string recursively, returning:
        * if the string has the format f(*args): a nested func_and_arg_dict
        * else returns the string itself, unchanged.
    A func_and_arg_dict is a dict of the format:
        {"func": FUNC_STRING, "args": ARG_STRING_LIST},
    where ARG_STRING_LIST elements are themselves strings or func_and_arg_dicts.

    The intended use is to parse string.Formatter() spec strings and carry out the instructions therein.
    :param s: a string
    :return: the same string, or a {func:, args:} dict if the string has the f(*args) pattern
    >>> get_func_and_arg_dict("foo")
    'foo'
    >>> get_func_and_arg_dict("foo()")
    {'args': [], 'func': 'foo'}
    >>> get_func_and_arg_dict("foo(bar)")
    {'args': ['bar'], 'func': 'foo'}
    >>> get_func_and_arg_dict("f(g(x), y)")
    {'args': [{'args': ['x'], 'func': 'g'}, 'y'], 'func': 'f'}
    >>> get_func_and_arg_dict('f(g(x), "two words", h(z))')
    {'args': [{'args': ['x'], 'func': 'g'}, '"two words"', {'args': ['z'], 'func': 'h'}], 'func': 'f'}
    """
    match = func_and_arg_p.match(s)
    if match:
        func_and_arg_dict = match.groupdict()
        if 'args' in func_and_arg_dict:
            args_list = comma_sep_p.split(func_and_arg_dict['args'])
            if args_list == ['']:
                args_list = []
            for i, arg in enumerate(args_list):
                arg_expanded = get_func_and_arg_dict(arg)
                args_list[i] = arg_expanded
            func_and_arg_dict['args'] = args_list
        return func_and_arg_dict
    else:
        return s

class PipelineTemplate(string.Formatter):
    def __init__(self, **key_to_action):
        """
        A string.Formatter that accepts a |-separated specification of a pipeline through which the input value should
        go through before being output (cast automatically to a str).
        This formatter is created by specifying what functions correspond to the  names that will be used in the spec
        of the string. Standard format specifications (such as 04.04f, d, etc) can be used as well, anywhere in the
        pipeline.
        :param key_to_action: key=action specifications. Action must be a callable which will be applied to input value
        >>> p = PipelineTemplate(plus_ten=lambda x: x + 10,
        ...                      times_ten=lambda x: x * 10
        ... )
        >>> p.format('{x:plus_ten}', x=1)  # plus_ten points to the function that does that job
        '11'
        >>> p.format('{x:plus_ten|times_ten}', x=1)  # you can pipeline the functions you've specified
        '110'
        >>> p.format('{x} + 10 = {x:plus_ten}, ({x} + 10) * 10 = {x:plus_ten|times_ten}', x=1)
        '1 + 10 = 11, (1 + 10) * 10 = 110'
        >>> p.format('x + 10 = {0:plus_ten}, (x + 10) * 10 = {0:plus_ten|times_ten}', 1)  # no name use
        'x + 10 = 11, (x + 10) * 10 = 110'
        >>> p.format('{x: times_ten  | plus_ten  }', x=1)  # can have spaces between pipes
        '20'
        >>> p.format('{x:04.02f}', x=2)  # you can also use standard formatting specs
        '2.00'
        >>> p.format('{x:times_ten | plus_ten | 04.0f}', x=2)  # even in a pipeline
        '0030'
        >>> p = {
        ...     'f_wrap': lambda x: map('f({})'.format, x),
        ...     'csv': lambda x: ', '.join(x),
        ... }
        >>>
        >>> p = PipelineTemplate(**p)
        >>>
        >>> p.format('this --> {alist:f_wrap|csv}', alist=['A'])
        'this --> f(A)'
        >>> p.format('that --> {alist:f_wrap|csv}', alist=['A', 'B', 'C'])
        'that --> f(A), f(B), f(C)'
        >>> # and if you didn't define what you needed in the constructor arguments, you can always write python code
        >>> s = '''This {x:
        ...         lambda x: x + 2
        ...         | lambda x: x * 10
        ...         | 3.02f} was obtained through python functions.'''
        >>> PipelineTemplate().format(s, x=1)
        'This 30.00 was obtained through python functions.'
        >>> # and you can even use functions that need to be imported!
        >>> p = {
        ...     'add_10': lambda x: x + 10
        ... }
        >>> s = '''{x:
        ...         lambda x: map(lambda xx: xx + 2, x)
        ...         | lambda x: __import__('numpy').array(x) * 10
        ...         | __import__('numpy').sum
        ...         | add_10}'''
        >>> PipelineTemplate(**p).format(s, x=[1, 2])
        '80'
        """
        self.key_to_action = key_to_action

    def format_field(self, value, spec):
        spec = spec.strip()
        spec_list = pipe_split_p.split(spec)
        for spec in spec_list:
            try:
                if spec in self.key_to_action:
                    value = self.key_to_action[spec](value)
                else:
                    try:
                        f = eval(spec)
                        value = eval("f(value)")  # TODO: evals are not secure. Put safety checks in place.
                    except Exception:
                        value = super(PipelineTemplate, self).format_field(value, spec)
            except ValueError as e:
                raise ValueError("{}: {}".format(spec, e.args[0]))
        return str(value)

def wrapper(prefix='', suffix=''):
    return "{prefix}{{}}{suffix}".format(prefix=prefix, suffix=suffix).format

def mapper(func):
    return lambda x: map(func, x)

def templater(template):
    template = template.replace("{{}}", "{}")
    return template.format

def joiner(join_str=','):
    return join_str.join<commit_msg>old stuff on hana procs (might not use anymore thought)<commit_after>from __future__ import division

import re
import string

pipe_split_p = re.compile("\s*\|\s*")
func_and_arg_p = re.compile('(?P<func>\w+)\((?P<args>.*)\)', flags=re.DOTALL)
comma_sep_p = re.compile('\s*,\s*')

def get_func_and_arg_dict(s):
    """
    Parses the input string recursively, returning:
        * if the string has the format f(*args): a nested func_and_arg_dict
        * else returns the string itself, unchanged.
    A func_and_arg_dict is a dict of the format:
        {"func": FUNC_STRING, "args": ARG_STRING_LIST},
    where ARG_STRING_LIST elements are themselves strings or func_and_arg_dicts.

    The intended use is to parse string.Formatter() spec strings and carry out the instructions therein.
    :param s: a string
    :return: the same string, or a {func:, args:} dict if the string has the f(*args) pattern
    >>> get_func_and_arg_dict("foo")
    'foo'
    >>> get_func_and_arg_dict("foo()")
    {'args': [], 'func': 'foo'}
    >>> get_func_and_arg_dict("foo(bar)")
    {'args': ['bar'], 'func': 'foo'}
    >>> get_func_and_arg_dict("f(g(x), y)")
    {'args': [{'args': ['x'], 'func': 'g'}, 'y'], 'func': 'f'}
    >>> get_func_and_arg_dict('f(g(x), "two words", h(z))')
    {'args': [{'args': ['x'], 'func': 'g'}, '"two words"', {'args': ['z'], 'func': 'h'}], 'func': 'f'}
    """
    match = func_and_arg_p.match(s)
    if match:
        func_and_arg_dict = match.groupdict()
        if 'args' in func_and_arg_dict:
            args_list = comma_sep_p.split(func_and_arg_dict['args'])
            if args_list == ['']:
                args_list = []
            for i, arg in enumerate(args_list):
                arg_expanded = get_func_and_arg_dict(arg)
                args_list[i] = arg_expanded
            func_and_arg_dict['args'] = args_list
        return func_and_arg_dict
    else:
        return s

class PipelineTemplate(string.Formatter):
    def __init__(self, **key_to_action):
        """
        A string.Formatter that accepts a |-separated specification of a pipeline through which the input value should
        go through before being output (cast automatically to a str).
        This formatter is created by specifying what functions correspond to the  names that will be used in the spec
        of the string. Standard format specifications (such as 04.04f, d, etc) can be used as well, anywhere in the
        pipeline.
        :param key_to_action: key=action specifications. Action must be a callable which will be applied to input value
        >>> p = PipelineTemplate(plus_ten=lambda x: x + 10,
        ...                      times_ten=lambda x: x * 10
        ... )
        >>> p.format('{x:plus_ten}', x=1)  # plus_ten points to the function that does that job
        '11'
        >>> p.format('{x:plus_ten|times_ten}', x=1)  # you can pipeline the functions you've specified
        '110'
        >>> p.format('{x} + 10 = {x:plus_ten}, ({x} + 10) * 10 = {x:plus_ten|times_ten}', x=1)
        '1 + 10 = 11, (1 + 10) * 10 = 110'
        >>> p.format('x + 10 = {0:plus_ten}, (x + 10) * 10 = {0:plus_ten|times_ten}', 1)  # no name use
        'x + 10 = 11, (x + 10) * 10 = 110'
        >>> p.format('{x: times_ten  | plus_ten  }', x=1)  # can have spaces between pipes
        '20'
        >>> p.format('{x:04.02f}', x=2)  # you can also use standard formatting specs
        '2.00'
        >>> p.format('{x:times_ten | plus_ten | 04.0f}', x=2)  # even in a pipeline
        '0030'
        >>> p = {
        ...     'f_wrap': lambda x: map('f({})'.format, x),
        ...     'csv': lambda x: ', '.join(x),
        ... }
        >>>
        >>> p = PipelineTemplate(**p)
        >>>
        >>> p.format('this --> {alist:f_wrap|csv}', alist=['A'])
        'this --> f(A)'
        >>> p.format('that --> {alist:f_wrap|csv}', alist=['A', 'B', 'C'])
        'that --> f(A), f(B), f(C)'
        >>> # and if you didn't define what you needed in the constructor arguments, you can always write python code
        >>> s = '''This {x:
        ...         lambda x: x + 2
        ...         | lambda x: x * 10
        ...         | 3.02f} was obtained through python functions.'''
        >>> PipelineTemplate().format(s, x=1)
        'This 30.00 was obtained through python functions.'
        >>> # and you can even use functions that need to be imported!
        >>> p = {
        ...     'add_10': lambda x: x + 10
        ... }
        >>> s = '''{x:
        ...         lambda x: map(lambda xx: xx + 2, x)
        ...         | lambda x: __import__('numpy').array(x) * 10
        ...         | __import__('numpy').sum
        ...         | add_10}'''
        >>> PipelineTemplate(**p).format(s, x=[1, 2])
        '80'
        """
        self.key_to_action = key_to_action

    def format_field(self, value, spec):
        spec = spec.strip()
        spec_list = pipe_split_p.split(spec)
        for spec in spec_list:
            try:
                if spec in self.key_to_action:
                    value = self.key_to_action[spec](value)
                else:
                    try:
                        f = eval(spec)
                        value = eval("f(value)")  # TODO: evals are not secure. Put safety checks in place.
                    except Exception:
                        value = super(PipelineTemplate, self).format_field(value, spec)
            except ValueError as e:
                raise ValueError("{}: {}".format(spec, e.args[0]))
        return str(value)

def wrapper(prefix='', suffix=''):
    return "{prefix}{{}}{suffix}".format(prefix=prefix, suffix=suffix).format

def mapper(func):
    return lambda x: map(func, x)

def templater(template):
    template = template.replace("{{}}", "{}")
    return template.format

<|endoftext|>


<commit_before># http://lividinstruments.com

from __future__ import with_statement
import Live
import math

""" _Framework files """
from _Framework.ButtonElement import ButtonElement # Class representing a button a the controller
from _Framework.ButtonMatrixElement import ButtonMatrixElement # Class representing a 2-dimensional set of buttons
from _Framework.ChannelStripComponent import ChannelStripComponent # Class attaching to the mixer of a given track
#from _Framework.ClipSlotComponent import ClipSlotComponent # Class representing a ClipSlot within Live
from _Framework.CompoundComponent import CompoundComponent # Base class for classes encompasing other components to form complex components
from _Framework.ControlElement import ControlElement # Base class for all classes representing control elements on a controller
from _Framework.ControlSurface import ControlSurface # Central base class for scripts based on the new Framework
from _Framework.ControlSurfaceComponent import ControlSurfaceComponent # Base class for all classes encapsulating functions in Live
from _Framework.DeviceComponent import DeviceComponent # Class representing a device in Live
from _Framework.EncoderElement import EncoderElement # Class representing a continuous control on the controller
from _Framework.InputControlElement import * # Base class for all classes representing control elements on a controller
from _Framework.MixerComponent import MixerComponent # Class encompassing several channel strips to form a mixer
from _Framework.ModeSelectorComponent import ModeSelectorComponent # Class for switching between modes, handle several functions with few controls
from _Framework.NotifyingControlElement import NotifyingControlElement # Class representing control elements that can send values
from _Framework.SceneComponent import SceneComponent # Class representing a scene in Live
from _Framework.SessionComponent import SessionComponent # Class encompassing several scene to cover a defined section of Live's session
from _Framework.SessionZoomingComponent import SessionZoomingComponent # Class using a matrix of buttons to choose blocks of clips in the session
from _Framework.SliderElement import SliderElement # Class representing a slider on the controller
from _Framework.TrackEQComponent import TrackEQComponent # Class representing a track's EQ, it attaches to the last EQ device in the track
from _Framework.TrackFilterComponent import TrackFilterComponent # Class representing a track's filter, attaches to the last filter in the track
from _Framework.TransportComponent import TransportComponent # Class encapsulating all functions in Live's transport section

""" Here we define some global variables """
CHANNEL = 0		#main channel (0 - 15)
BASE_PADS = [60, 61, 62, 63, 64, 65, 66, 67, 52, 53, 54, 55, 56, 57, 58, 59, 44, 45, 46, 47, 48, 49, 50, 51, 36, 37, 38, 39, 40, 41, 42, 43]	#there are 32 of these
BASE_TOUCHSTRIPS = [1, 2, 3, 4, 5, 6, 7, 8, 9]		#there are 9 of these
BASE_TOUCHPADS = [10, 11, 12, 13, 14, 15, 16, 17] #there are 8 of these
BASE_BUTTONS = [18, 19, 20, 21, 22, 23, 24, 25]		#there are 8 of these
BASE_RUNNERS = [68, 69, 70, 71, 72, 73, 74, 75]   #there are 8 of these top LEDS
BASE_SIDES = [26,27,28,29,30,31,32,33]   #there are 8 of these side LEDS
BASE_LCDS = [34, 35]

class LividBaseM4L(ControlSurface):
	__module__ = __name__
	__doc__ = " LividBaseM4L controller script "

	def __init__(self, c_instance):
		super(LividBaseM4L, self).__init__(c_instance)
		with self.component_guard():
			self._host_name = 'LividBaseM4L'
			self._color_type = 'Base'
			self.log_message("--------------= LividBaseM4L log BEGIN =--------------")
			self._setup_controls()

	"""script initialization methods"""

	def _setup_controls(self):
		is_momentary = True
		self._tfader = [None for index in range(9)]
		self._tfader_touch = [None for index in range(9)]
		self._pad = [None for index in range(32)]
		self._pad_cc = [None for index in range(32)]
		self._button = [None for index in range(8)]
		self._tbutton = [None for index in range(8)]
		self._runnerled = [None for index in range(8)]
		self._sideled = [None for index in range(8)]
		self._lcd = [None for index in range(2)]
		for index in range(9):
			self._tfader[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, BASE_TOUCHSTRIPS[index], Live.MidiMap.MapMode.absolute)
			self._tfader[index].name = 'Fader_' + str(index)
		for index in range(9):
			self._tfader_touch[index] = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, BASE_TOUCHSTRIPS[index])
			self._tfader_touch[index].name = 'FaderTouch_' + str(index)
		for index in range(32):
			self._pad[index] = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, BASE_PADS[index])
			self._pad[index].name = 'Pad_' + str(index)
		for index in range(32):
			self._pad_cc[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, BASE_PADS[index], Live.MidiMap.MapMode.absolute)
			self._pad_cc[index].name = 'PadCC_' + str(index)
		for index in range(8):
			self._button[index] = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, BASE_BUTTONS[index])
			self._button[index].name = 'Button_' + str(index)
		for index in range(8):
			self._tbutton[index] = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, BASE_TOUCHPADS[index])
			self._tbutton[index].name = 'Tbutton_' + str(index)
		for index in range(8):
			self._runnerled[index] = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, BASE_RUNNERS[index])
			self._runnerled[index].name = 'RunnerLED_' + str(index)
		for index in range(8):
			self._sideled[index] = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, BASE_SIDES[index])
			self._sideled[index].name = 'SideLED_' + str(index)
		for index in range(2):
			self._lcd[index] = ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, BASE_LCDS[index])
			self._lcd[index].name = 'LCD_' + str(index)

	def receive_value(self, value):
		self._value = value

	"""LividBaseM4L script disconnection"""
	def disconnect(self):
		self.log_message("--------------= LividBaseM4L log END =--------------")
		ControlSurface.disconnect(self)
		return None<commit_msg>Fixed some controls initialization, added slider color control<commit_after># http://lividinstruments.com

from __future__ import with_statement
import Live
import math

""" _Framework files """
from _Framework.ButtonElement import ButtonElement # Class representing a button a the controller
from _Framework.ButtonMatrixElement import ButtonMatrixElement # Class representing a 2-dimensional set of buttons
from _Framework.ChannelStripComponent import ChannelStripComponent # Class attaching to the mixer of a given track
#from _Framework.ClipSlotComponent import ClipSlotComponent # Class representing a ClipSlot within Live
from _Framework.CompoundComponent import CompoundComponent # Base class for classes encompasing other components to form complex components
from _Framework.ControlElement import ControlElement # Base class for all classes representing control elements on a controller
from _Framework.ControlSurface import ControlSurface # Central base class for scripts based on the new Framework
from _Framework.ControlSurfaceComponent import ControlSurfaceComponent # Base class for all classes encapsulating functions in Live
from _Framework.DeviceComponent import DeviceComponent # Class representing a device in Live
from _Framework.EncoderElement import EncoderElement # Class representing a continuous control on the controller
from _Framework.InputControlElement import * # Base class for all classes representing control elements on a controller
from _Framework.MixerComponent import MixerComponent # Class encompassing several channel strips to form a mixer
from _Framework.ModeSelectorComponent import ModeSelectorComponent # Class for switching between modes, handle several functions with few controls
from _Framework.NotifyingControlElement import NotifyingControlElement # Class representing control elements that can send values
from _Framework.SceneComponent import SceneComponent # Class representing a scene in Live
from _Framework.SessionComponent import SessionComponent # Class encompassing several scene to cover a defined section of Live's session
from _Framework.SessionZoomingComponent import SessionZoomingComponent # Class using a matrix of buttons to choose blocks of clips in the session
from _Framework.SliderElement import SliderElement # Class representing a slider on the controller
from _Framework.TrackEQComponent import TrackEQComponent # Class representing a track's EQ, it attaches to the last EQ device in the track
from _Framework.TrackFilterComponent import TrackFilterComponent # Class representing a track's filter, attaches to the last filter in the track
from _Framework.TransportComponent import TransportComponent # Class encapsulating all functions in Live's transport section

""" Here we define some global variables """
CHANNEL = 0   #main channel (0 - 15)
BASE_PADS = [60, 61, 62, 63, 64, 65, 66, 67, 52, 53, 54, 55, 56, 57, 58, 59, 44, 45, 46, 47, 48, 49, 50, 51, 36, 37, 38, 39, 40, 41, 42, 43]  #there are 32 of these
BASE_TOUCHSTRIPS = [1, 2, 3, 4, 5, 6, 7, 8, 9]    #there are 9 of these
BASE_TOUCHPADS = [10, 11, 12, 13, 14, 15, 16, 17] #there are 8 of these
BASE_BUTTONS = [18, 19, 20, 21, 22, 23, 24, 25]   #there are 8 of these
BASE_RUNNERS = [68, 69, 70, 71, 72, 73, 74, 75]   #there are 8 of these top LEDS
BASE_SIDES = [26,27,28,29,30,31,32,33]   #there are 8 of these side LEDS
BASE_LCDS = [34, 35]

class LividBaseM4L(ControlSurface):
  __module__ = __name__
  __doc__ = " LividBaseM4L controller script "

  def __init__(self, c_instance):
    super(LividBaseM4L, self).__init__(c_instance)
    with self.component_guard():
      self._host_name = 'LividBaseM4L'
      self._color_type = 'Base'
      self.log_message("--------------= LividBaseM4L log BEGIN SCRIPT =--------------")
      self._setup_controls()

  """script initialization methods"""

  def _setup_controls(self):
    is_momentary = True
    self._tfader = [None for index in range(9)]
    self._tfader_touch = [None for index in range(9)]
    self._pad = [None for index in range(32)]
    self._pad_cc = [None for index in range(32)]
    self._button = [None for index in range(8)]
    self._tbutton = [None for index in range(8)]
    self._runnerled = [None for index in range(8)]
    self._sideled = [None for index in range(8)]
    self._lcd = [None for index in range(2)]
    for index in range(9):
      self._tfader[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, BASE_TOUCHSTRIPS[index], Live.MidiMap.MapMode.absolute)
      self._tfader[index].name = 'Fader_' + str(index)
    for index in range(9):
      self._tfader_touch[index] = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, BASE_TOUCHSTRIPS[index])
      self._tfader_touch[index].name = 'FaderTouch_' + str(index)
    for index in range(32):
      self._pad[index] = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, BASE_PADS[index])
      self._pad[index].name = 'Pad_' + str(index)
    for index in range(32):
      self._pad_cc[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, BASE_PADS[index], Live.MidiMap.MapMode.absolute)
      self._pad_cc[index].name = 'PadCC_' + str(index)
    for index in range(8):
      self._button[index] = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, BASE_BUTTONS[index])
      self._button[index].name = 'Button_' + str(index)
    for index in range(8):
      self._tbutton[index] = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, BASE_TOUCHPADS[index])
      self._tbutton[index].name = 'Tbutton_' + str(index)
    for index in range(8):
      self._runnerled[index] = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, BASE_RUNNERS[index])
      self._runnerled[index].name = 'RunnerLED_' + str(index)
    for index in range(8):
      self._sideled[index] = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, BASE_SIDES[index])
      self._sideled[index].name = 'SideLED_' + str(index)
    for index in range(2):
      self._lcd[index] = ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, BASE_LCDS[index])
      self._lcd[index].name = 'LCD_' + str(index)

  def receive_value(self, value):
    self._value = value

  def slider_color(self, value):
    for index in range(9):
      self._send_midi((191,index+10,value))

  def aslider_color(self, sli, value):
    self._send_midi((191,sli+10,value))

  """LividBaseM4L script disconnection"""
  def disconnect(self):
    self.log_message("--------------= LividBaseM4L log END =--------------")
    ControlSurface.disconnect(self)
    return None<|endoftext|>


<commit_before>"""
Admin configuration for ``icekit`` app.
"""

# Define `list_display`, `list_filter` and `search_fields` for each model.
# These go a long way to making the admin more usable.
from django.conf import settings
from django.conf.urls import url, patterns
from django.contrib import admin
from django.contrib.contenttypes.models import ContentType
from django.http import JsonResponse
from django.utils.text import capfirst
from django.utils.translation import ugettext_lazy as _
from polymorphic.admin import PolymorphicParentModelAdmin

from icekit import models

# FILTERS #####################################################################

class ChildModelFilter(admin.SimpleListFilter):
    title = _('type')
    parameter_name = 'type'

    child_model_plugin_class = None

    def lookups(self, request, model_admin):
        lookups = [
            (p.content_type.pk, p.verbose_name.capitalize())
            for p in self.child_model_plugin_class.get_plugins()
        ]
        return lookups

    def queryset(self, request, queryset):
        value = self.value()
        if value:
            content_type = ContentType.objects.get_for_id(value)
            return queryset.filter(polymorphic_ctype=content_type)

# MIXINS ######################################################################

class ChildModelPluginPolymorphicParentModelAdmin(PolymorphicParentModelAdmin):
    """
    Get child models and choice labels from registered plugins.
    """

    child_model_plugin_class = None
    child_model_admin = None

    def get_child_models(self):
        """
        Get child models from registered plugins. Fallback to the child model
        admin and its base model if no plugins are registered.
        """
        child_models = []
        for plugin in self.child_model_plugin_class.get_plugins():
            child_models.append((plugin.model, plugin.model_admin))
        if not child_models:
            child_models.append((
                self.child_model_admin.base_model,
                self.child_model_admin,
            ))
        return child_models

    def get_child_type_choices(self, request, action):
        """
        Override choice labels with ``verbose_name`` from plugins and sort.
        """
        # Get choices from the super class to check permissions.
        choices = super(ChildModelPluginPolymorphicParentModelAdmin, self) \
            .get_child_type_choices(request, action)
        # Update label with verbose name from plugins.
        plugins = self.child_model_plugin_class.get_plugins()
        if plugins:
            labels = {
                plugin.content_type.pk: capfirst(plugin.verbose_name) for plugin in plugins
            }
            choices = [(ctype, labels[ctype]) for ctype, _ in choices]
            return sorted(choices, lambda a, b: cmp(a[1], b[1]))
        return choices

    def _child_model_dict(self):
        if not hasattr(self, "_child_model_dict_cache"):
            self._child_model_dict_cache = dict([
                (ContentType.objects.get_for_model(p.model, for_concrete_model=False).id, p.model) for p in
                self.child_model_plugin_class.get_plugins()
            ])
        return self._child_model_dict_cache

    def child_type_name(self, inst):
        """
        :param inst: a polymorphic parent instance
        :return: The name of the polymorphic model
        """
        return capfirst(self._child_model_dict()[inst.polymorphic_ctype_id]._meta.verbose_name)
    child_type_name.short_description = "Type"

# MODELS ######################################################################

class LayoutAdmin(admin.ModelAdmin):
    model = models.Layout

    def _get_ctypes(self):
        """
        Returns all related objects for this model.
        """
        ctypes = []
        for related_object in self.model._meta.get_all_related_objects():
            model = getattr(related_object, 'related_model', related_object.model)
            ctypes.append(ContentType.objects.get_for_model(model).pk)
            if model.__subclasses__():
                for child in model.__subclasses__():
                    ctypes.append(ContentType.objects.get_for_model(child).pk)
        return ctypes

    def placeholder_data_view(self, request, id):
        """
        Return placeholder data for the given layout's template.
        """
        # See: `fluent_pages.pagetypes.fluentpage.admin.FluentPageAdmin`.
        try:
            layout = models.Layout.objects.get(pk=id)
        except models.Layout.DoesNotExist:
            json = {'success': False, 'error': 'Layout not found'}
            status = 404
        else:
            placeholders = layout.get_placeholder_data()
            status = 200

            placeholders = [p.as_dict() for p in placeholders]

            # inject placeholder help text, if any is set
            for p in placeholders:
                try:
                    p['help_text'] = settings.FLUENT_CONTENTS_PLACEHOLDER_CONFIG.get(p['slot']).get('help_text')
                except AttributeError:
                    p['help_text'] = None

            json = {
                'id': layout.id,
                'title': layout.title,
                'placeholders': placeholders,
            }

        return JsonResponse(json, status=status)

    def get_urls(self):
        """
        Add ``layout_placeholder_data`` URL.
        """
        # See: `fluent_pages.pagetypes.fluentpage.admin.FluentPageAdmin`.
        urls = super(LayoutAdmin, self).get_urls()
        my_urls = patterns(
            '',
            url(
                r'^placeholder_data/(?P<id>\d+)/$',
                self.admin_site.admin_view(self.placeholder_data_view),
                name='layout_placeholder_data',
            )
        )
        return my_urls + urls

    def get_form(self, *args, **kwargs):
        ctypes = self._get_ctypes()

        class Form(super(LayoutAdmin, self).get_form(*args, **kwargs)):
            def __init__(self, *args, **kwargs):
                super(Form, self).__init__(*args, **kwargs)
                self.fields['content_types'].queryset = self.fields[
                    'content_types'].queryset.filter(
                    pk__in=ctypes,
                )

        return Form

class MediaCategoryAdmin(admin.ModelAdmin):
    pass

admin.site.register(models.Layout, LayoutAdmin)
admin.site.register(models.MediaCategory, MediaCategoryAdmin)
<commit_msg>Factor out and simplify child_type_name<commit_after>"""
Admin configuration for ``icekit`` app.
"""

# Define `list_display`, `list_filter` and `search_fields` for each model.
# These go a long way to making the admin more usable.
from django.conf import settings
from django.conf.urls import url, patterns
from django.contrib import admin
from django.contrib.contenttypes.models import ContentType
from django.http import JsonResponse
from django.utils.text import capfirst
from django.utils.translation import ugettext_lazy as _
from polymorphic.admin import PolymorphicParentModelAdmin

from icekit import models

# FILTERS #####################################################################

class ChildModelFilter(admin.SimpleListFilter):
    title = _('type')
    parameter_name = 'type'

    child_model_plugin_class = None

    def lookups(self, request, model_admin):
        lookups = [
            (p.content_type.pk, p.verbose_name.capitalize())
            for p in self.child_model_plugin_class.get_plugins()
        ]
        return lookups

    def queryset(self, request, queryset):
        value = self.value()
        if value:
            content_type = ContentType.objects.get_for_id(value)
            return queryset.filter(polymorphic_ctype=content_type)

# MIXINS ######################################################################

class PolymorphicAdminUtilsMixin(admin.ModelAdmin):
    """
    Utility methods for working with Polymorphic admins.
    """
    def child_type_name(self, inst):
        """
        e.g. for use in list_display
        :param inst: a polymorphic parent instance
        :return: The name of the polymorphic model
        """
        return capfirst(inst.polymorphic_ctype.name)
    child_type_name.short_description = "Type"

class ChildModelPluginPolymorphicParentModelAdmin(
    PolymorphicParentModelAdmin,
    PolymorphicAdminUtilsMixin
):
    """
    Get child models and choice labels from registered plugins.
    """

    child_model_plugin_class = None
    child_model_admin = None

    def get_child_type_choices(self, request, action):
        """
        Override choice labels with ``verbose_name`` from plugins and sort.
        """
        # Get choices from the super class to check permissions.
        choices = super(ChildModelPluginPolymorphicParentModelAdmin, self) \
            .get_child_type_choices(request, action)
        # Update label with verbose name from plugins.
        plugins = self.child_model_plugin_class.get_plugins()
        if plugins:
            labels = {
                plugin.content_type.pk: capfirst(plugin.verbose_name) for plugin in plugins
            }
            choices = [(ctype, labels[ctype]) for ctype, _ in choices]
            return sorted(choices, lambda a, b: cmp(a[1], b[1]))
        return choices

    def get_child_models(self):
        """
        Get child models from registered plugins. Fallback to the child model
        admin and its base model if no plugins are registered.
        """
        child_models = []
        for plugin in self.child_model_plugin_class.get_plugins():
            child_models.append((plugin.model, plugin.model_admin))
        if not child_models:
            child_models.append((
                self.child_model_admin.base_model,
                self.child_model_admin,
            ))
        return child_models

# MODELS ######################################################################

class LayoutAdmin(admin.ModelAdmin):
    model = models.Layout

    def _get_ctypes(self):
        """
        Returns all related objects for this model.
        """
        ctypes = []
        for related_object in self.model._meta.get_all_related_objects():
            model = getattr(related_object, 'related_model', related_object.model)
            ctypes.append(ContentType.objects.get_for_model(model).pk)
            if model.__subclasses__():
                for child in model.__subclasses__():
                    ctypes.append(ContentType.objects.get_for_model(child).pk)
        return ctypes

    def placeholder_data_view(self, request, id):
        """
        Return placeholder data for the given layout's template.
        """
        # See: `fluent_pages.pagetypes.fluentpage.admin.FluentPageAdmin`.
        try:
            layout = models.Layout.objects.get(pk=id)
        except models.Layout.DoesNotExist:
            json = {'success': False, 'error': 'Layout not found'}
            status = 404
        else:
            placeholders = layout.get_placeholder_data()
            status = 200

            placeholders = [p.as_dict() for p in placeholders]

            # inject placeholder help text, if any is set
            for p in placeholders:
                try:
                    p['help_text'] = settings.FLUENT_CONTENTS_PLACEHOLDER_CONFIG.get(p['slot']).get('help_text')
                except AttributeError:
                    p['help_text'] = None

            json = {
                'id': layout.id,
                'title': layout.title,
                'placeholders': placeholders,
            }

        return JsonResponse(json, status=status)

    def get_urls(self):
        """
        Add ``layout_placeholder_data`` URL.
        """
        # See: `fluent_pages.pagetypes.fluentpage.admin.FluentPageAdmin`.
        urls = super(LayoutAdmin, self).get_urls()
        my_urls = patterns(
            '',
            url(
                r'^placeholder_data/(?P<id>\d+)/$',
                self.admin_site.admin_view(self.placeholder_data_view),
                name='layout_placeholder_data',
            )
        )
        return my_urls + urls

    def get_form(self, *args, **kwargs):
        ctypes = self._get_ctypes()

        class Form(super(LayoutAdmin, self).get_form(*args, **kwargs)):
            def __init__(self, *args, **kwargs):
                super(Form, self).__init__(*args, **kwargs)
                self.fields['content_types'].queryset = self.fields[
                    'content_types'].queryset.filter(
                    pk__in=ctypes,
                )

        return Form

class MediaCategoryAdmin(admin.ModelAdmin):
    pass

admin.site.register(models.Layout, LayoutAdmin)
admin.site.register(models.MediaCategory, MediaCategoryAdmin)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    Copyright (C) 2015 Pexego All Rights Reserved
#    $Jesús Ventosinos Mayor <jesus@pexego.es>$
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import models, fields, api, _
from lxml import etree

class StockMove(models.Model):

    _inherit = 'stock.move'

    @api.model
    def _get_invoice_line_vals(self, move, partner, inv_type):
        res = super(StockMove, self)._get_invoice_line_vals(move, partner, inv_type)
        res['move_id'] = move.id
        return res

    @api.multi
    def unlink(self):
        for move in self:
            if move.state == "confirmed":
                move.state = "draft"
        return super(StockMove, self).unlink()

    @api.multi
    def action_done(self):
        res = super(StockMove, self).action_done()
        for move in self:
            if move.location_id.usage == "customer" and \
                    move.location_dest_id.usage == "internal":
                for quant in move.quant_ids:
                    quantS = self.sudo().env["stock.quant"].browse(quant.id)
                    quantS.cost = quant.product_id.standard_price

        return res

class ProductProduct(models.Model):

    _inherit = "product.product"

    @api.multi
    def action_view_sales(self):
        res = super(ProductProduct, self).action_view_sales()
        res['domain'] = "[('product_id','in',[" + \
            ','.join(map(str, self.ids)) + \
            "]),('state', 'not in', ['cancel', 'draft'])]"
        return res

    @api.multi
    def action_view_quotations(self):
        res = super(ProductProduct, self).action_view_sales()
        res['domain'] = "[('product_id','in',[" + \
            ','.join(map(str, self.ids)) + \
            "]),('state', '=', 'draft')]"
        return res

    default_code = fields.Char(required=True)

    _sql_constraints = [
        ('default_code_uniq', 'unique(default_code, active)',
         'The code of product must be unique.')
    ]

    def copy(self, cr, uid, id, default=None, context=None):
        if default is None: default = {}
        if not default.get('default_code', False):
            prod = self.browse(cr, uid, id, context=context)
            default['default_code'] = _("%s (copy)") % (prod.default_code)
        return super(ProductProduct, self).copy(cr, uid, id, default=default,
                                                context=context)

    @api.multi
    def name_get(self):
        partner_id = self.env.context.get('partner_id', False)
        result = []
        for record in self:
            sellers = [x.name.id for x in record.seller_ids]
            if partner_id and partner_id in sellers:
                result.extend(super(ProductProduct, self).name_get())
            else:
                result.append((record.id, "%s" % record.default_code))
        return result

    def _check_ean_key(self, cr, uid, ids, context=None):
        return True

    _constraints = [(_check_ean_key, 'You provided an invalid "EAN13 Barcode" reference. You may use the "Internal Reference" field instead.', ['ean13'])]

class ProductTemplate(models.Model):

    _inherit = "product.template"

    @api.multi
    def action_view_sales(self):
        res = super(ProductTemplate, self).action_view_sales()
        product_ids = []
        for template in self:
            product_ids += [x.id for x in template.product_variant_ids]
        res['domain'] = "[('product_id','in',[" + \
            ','.join(map(str, product_ids)) + \
            "]),('state', 'not in', ['draft', 'cancel'])]"
        return res

    @api.multi
    def action_view_quotations(self):
        res = super(ProductTemplate, self).action_view_sales()
        product_ids = []
        for template in self:
            product_ids += [x.id for x in template.product_variant_ids]
        res['domain'] = "[('product_id','in',[" + \
            ','.join(map(str, product_ids)) + \
            "]),('state', '=', 'draft')]"
        return res

    @api.multi
    def action_view_stock_moves(self):
        res = super(ProductTemplate, self).action_view_stock_moves()
        product_ids = []
        for template in self:
            product_ids += [x.id for x in template.product_variant_ids]
        res['domain'] = "[('product_id','in',[" + \
            ','.join(map(str, product_ids)) + \
            "]),('picking_type_code', '=', 'incoming')]"

        if len(product_ids) == 1:
            ctx = "{'tree_view_ref':'stock.view_move_tree', \
                  'default_product_id': %s, 'search_default_product_id': %s, 'search_default_ready': 1,'search_default_future': 1}" \
                  % (product_ids[0], product_ids[0])
            res['context'] = ctx
        else:
            res['context'] = "{'tree_view_ref':'stock.view_move_tree', 'search_default_ready': 1,'search_default_future': 1}"
        return res

class SaleOrder(models.Model):

    _inherit = "sale.order"

    _order = "date_confirm desc, date_order desc, id desc"

    state = fields.Selection(selection_add=[("history", "History")])
    internal_notes = fields.Text("Internal Notes")
    partner_tags = fields.Many2many('res.partner.category', id1='sale_id',
                                    id2='category_id', string='Tags')

    def fields_view_get(self, cr, uid, view_id=None, view_type='form',
                        context=None, toolbar=False, submenu=False):
        res = super(SaleOrder, self).\
            fields_view_get(cr, uid, view_id=view_id, view_type=view_type,
                            context=context, toolbar=toolbar, submenu=submenu)
        no_create = context.get('no_create', False)
        update = (no_create and view_type in ['form', 'tree']) or False
        if update:
            doc = etree.XML(res['arch'])
            if no_create:
                for t in doc.xpath("//"+view_type):
                    t.attrib['create'] = 'false'
            res['arch'] = etree.tostring(doc)

        return res

    _sql_constraints = [('customer_ref_uniq',
                         'unique(partner_id, client_order_ref)',
                         'Customer ref must be unique by partner')]

    def onchange_partner_id(self, cr, uid, ids, part, context=None):
        res = super(SaleOrder, self).onchange_partner_id(cr, uid, ids, part,
                                                         context=context)
        if part and res.get('value', False):
            partner = self.pool['res.partner'].browse(cr, uid, part)
            res['value']['partner_tags'] = [x.id for x in partner.category_id]

        return res

    def copy(self, cr, uid, id, default={}, context=None):
        sale = self.browse(cr, uid, id, context)
        if sale.client_order_ref:
            default['client_order_ref'] = sale.client_order_ref + _(" (copy)")
        result = super(SaleOrder, self).copy(cr, uid, id, default, context)

        return result

class SaleOrderLine(models.Model):

    _inherit = "sale.order.line"

    state = fields.Selection(selection_add=[("history", "History")])

class PurchaseOrder(models.Model):

    _inherit = "purchase.order"

    state = fields.Selection(selection_add=[("history", "History")])

class PurchaseOrderLine(models.Model):

    _inherit = "purchase.order.line"

    state = fields.Selection(selection_add=[("history", "History")])

class AccountInvoice(models.Model):

    _inherit = "account.invoice"

    state = fields.Selection(selection_add=[("history", "History")])

class StockQuant(models.Model):

    _inherit = "stock.quant"

    @api.model
    def _prepare_account_move_line(self, move, qty, cost, credit_account_id,
                                   debit_account_id):
        res = super(StockQuant, self).\
            _prepare_account_move_line(move, qty, cost, credit_account_id,
                                       debit_account_id)
        currency_obj = self.pool.get('res.currency')
        if not self.env.context.get('force_valuation_amount', False) and \
                move.product_id.cost_method == 'real' and \
                move.location_id.usage == "customer" and \
                move.location_dest_id.usage == "internal":
            valuation_amount = \
                currency_obj.round(self._cr, self._uid,
                                   move.company_id.currency_id,
                                   move.product_id.standard_price * qty)
            res[0][2]['debit'] = valuation_amount > 0 and valuation_amount \
                or 0
            res[0][2]['credit'] = valuation_amount < 0 and -valuation_amount \
                or 0
            res[1][2]['debit'] = valuation_amount < 0 and -valuation_amount \
                or 0
            res[1][2]['credit'] = valuation_amount > 0 and valuation_amount \
                or 0

        return res
<commit_msg>[IMP] custom_account: cambiamos la ordenación por defceto de pedidos de venta<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    Copyright (C) 2015 Pexego All Rights Reserved
#    $Jesús Ventosinos Mayor <jesus@pexego.es>$
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import models, fields, api, _
from lxml import etree

class StockMove(models.Model):

    _inherit = 'stock.move'

    @api.model
    def _get_invoice_line_vals(self, move, partner, inv_type):
        res = super(StockMove, self)._get_invoice_line_vals(move, partner, inv_type)
        res['move_id'] = move.id
        return res

    @api.multi
    def unlink(self):
        for move in self:
            if move.state == "confirmed":
                move.state = "draft"
        return super(StockMove, self).unlink()

    @api.multi
    def action_done(self):
        res = super(StockMove, self).action_done()
        for move in self:
            if move.location_id.usage == "customer" and \
                    move.location_dest_id.usage == "internal":
                for quant in move.quant_ids:
                    quantS = self.sudo().env["stock.quant"].browse(quant.id)
                    quantS.cost = quant.product_id.standard_price

        return res

class ProductProduct(models.Model):

    _inherit = "product.product"

    @api.multi
    def action_view_sales(self):
        res = super(ProductProduct, self).action_view_sales()
        res['domain'] = "[('product_id','in',[" + \
            ','.join(map(str, self.ids)) + \
            "]),('state', 'not in', ['cancel', 'draft'])]"
        return res

    @api.multi
    def action_view_quotations(self):
        res = super(ProductProduct, self).action_view_sales()
        res['domain'] = "[('product_id','in',[" + \
            ','.join(map(str, self.ids)) + \
            "]),('state', '=', 'draft')]"
        return res

    default_code = fields.Char(required=True)

    _sql_constraints = [
        ('default_code_uniq', 'unique(default_code, active)',
         'The code of product must be unique.')
    ]

    def copy(self, cr, uid, id, default=None, context=None):
        if default is None: default = {}
        if not default.get('default_code', False):
            prod = self.browse(cr, uid, id, context=context)
            default['default_code'] = _("%s (copy)") % (prod.default_code)
        return super(ProductProduct, self).copy(cr, uid, id, default=default,
                                                context=context)

    @api.multi
    def name_get(self):
        partner_id = self.env.context.get('partner_id', False)
        result = []
        for record in self:
            sellers = [x.name.id for x in record.seller_ids]
            if partner_id and partner_id in sellers:
                result.extend(super(ProductProduct, self).name_get())
            else:
                result.append((record.id, "%s" % record.default_code))
        return result

    def _check_ean_key(self, cr, uid, ids, context=None):
        return True

    _constraints = [(_check_ean_key, 'You provided an invalid "EAN13 Barcode" reference. You may use the "Internal Reference" field instead.', ['ean13'])]

class ProductTemplate(models.Model):

    _inherit = "product.template"

    @api.multi
    def action_view_sales(self):
        res = super(ProductTemplate, self).action_view_sales()
        product_ids = []
        for template in self:
            product_ids += [x.id for x in template.product_variant_ids]
        res['domain'] = "[('product_id','in',[" + \
            ','.join(map(str, product_ids)) + \
            "]),('state', 'not in', ['draft', 'cancel'])]"
        return res

    @api.multi
    def action_view_quotations(self):
        res = super(ProductTemplate, self).action_view_sales()
        product_ids = []
        for template in self:
            product_ids += [x.id for x in template.product_variant_ids]
        res['domain'] = "[('product_id','in',[" + \
            ','.join(map(str, product_ids)) + \
            "]),('state', '=', 'draft')]"
        return res

    @api.multi
    def action_view_stock_moves(self):
        res = super(ProductTemplate, self).action_view_stock_moves()
        product_ids = []
        for template in self:
            product_ids += [x.id for x in template.product_variant_ids]
        res['domain'] = "[('product_id','in',[" + \
            ','.join(map(str, product_ids)) + \
            "]),('picking_type_code', '=', 'incoming')]"

        if len(product_ids) == 1:
            ctx = "{'tree_view_ref':'stock.view_move_tree', \
                  'default_product_id': %s, 'search_default_product_id': %s, 'search_default_ready': 1,'search_default_future': 1}" \
                  % (product_ids[0], product_ids[0])
            res['context'] = ctx
        else:
            res['context'] = "{'tree_view_ref':'stock.view_move_tree', 'search_default_ready': 1,'search_default_future': 1}"
        return res

class SaleOrder(models.Model):

    _inherit = "sale.order"

    _order = "date_order desc, id desc"

    state = fields.Selection(selection_add=[("history", "History")])
    internal_notes = fields.Text("Internal Notes")
    partner_tags = fields.Many2many('res.partner.category', id1='sale_id',
                                    id2='category_id', string='Tags')

    def fields_view_get(self, cr, uid, view_id=None, view_type='form',
                        context=None, toolbar=False, submenu=False):
        res = super(SaleOrder, self).\
            fields_view_get(cr, uid, view_id=view_id, view_type=view_type,
                            context=context, toolbar=toolbar, submenu=submenu)
        no_create = context.get('no_create', False)
        update = (no_create and view_type in ['form', 'tree']) or False
        if update:
            doc = etree.XML(res['arch'])
            if no_create:
                for t in doc.xpath("//"+view_type):
                    t.attrib['create'] = 'false'
            res['arch'] = etree.tostring(doc)

        return res

    _sql_constraints = [('customer_ref_uniq',
                         'unique(partner_id, client_order_ref)',
                         'Customer ref must be unique by partner')]

    def onchange_partner_id(self, cr, uid, ids, part, context=None):
        res = super(SaleOrder, self).onchange_partner_id(cr, uid, ids, part,
                                                         context=context)
        if part and res.get('value', False):
            partner = self.pool['res.partner'].browse(cr, uid, part)
            res['value']['partner_tags'] = [x.id for x in partner.category_id]

        return res

    def copy(self, cr, uid, id, default={}, context=None):
        sale = self.browse(cr, uid, id, context)
        if sale.client_order_ref:
            default['client_order_ref'] = sale.client_order_ref + _(" (copy)")
        result = super(SaleOrder, self).copy(cr, uid, id, default, context)

        return result

class SaleOrderLine(models.Model):

    _inherit = "sale.order.line"

    state = fields.Selection(selection_add=[("history", "History")])

class PurchaseOrder(models.Model):

    _inherit = "purchase.order"

    state = fields.Selection(selection_add=[("history", "History")])

class PurchaseOrderLine(models.Model):

    _inherit = "purchase.order.line"

    state = fields.Selection(selection_add=[("history", "History")])

class AccountInvoice(models.Model):

    _inherit = "account.invoice"

    state = fields.Selection(selection_add=[("history", "History")])

class StockQuant(models.Model):

    _inherit = "stock.quant"

    @api.model
    def _prepare_account_move_line(self, move, qty, cost, credit_account_id,
                                   debit_account_id):
        res = super(StockQuant, self).\
            _prepare_account_move_line(move, qty, cost, credit_account_id,
                                       debit_account_id)
        currency_obj = self.pool.get('res.currency')
        if not self.env.context.get('force_valuation_amount', False) and \
                move.product_id.cost_method == 'real' and \
                move.location_id.usage == "customer" and \
                move.location_dest_id.usage == "internal":
            valuation_amount = \
                currency_obj.round(self._cr, self._uid,
                                   move.company_id.currency_id,
                                   move.product_id.standard_price * qty)
            res[0][2]['debit'] = valuation_amount > 0 and valuation_amount \
                or 0
            res[0][2]['credit'] = valuation_amount < 0 and -valuation_amount \
                or 0
            res[1][2]['debit'] = valuation_amount < 0 and -valuation_amount \
                or 0
            res[1][2]['credit'] = valuation_amount > 0 and valuation_amount \
                or 0

        return res
<|endoftext|>


<commit_before>'''
Create Packs, like Zicbee Pack (at http://pypi.python.org/zicbee).
Inspired by zicbee-workshop's manage.py
'''

import re
import os
import sys
import glob
import shutil
import platform

from pyg.log import logger
from pyg.req import Requirement
from pyg.web import highest_version
from pyg.inst import Bundler
from pyg.core import PygError
from pyg.utils import TempDir, ZipFile, call_setup, print_output, unpack, name_from_name

PY_RUN_CODE = '''
import re
p_re = re.compile('.*(python\d+[.\d]+[^/]*|lib-\w+|plat-\w+)$')
sys.path = [os.path.join(egg_path, mod) for mod in {modules!r}] + [x for x in sys.path if p_re.match(x)]

# run!
import {mod_name}
sys.exit({mod_name}.{callable}())
'''

RUN_PY = '''#!/usr/bin/env python
## Executable file auto-generated by Pyg

import os
import sys

exists = os.path.exists
j = os.path.join
# we don't care about order
paths = set(sys.path)
paths.add(os.getcwd())

my_dir = [p for p in paths if exists(j(p, {egg!r}))]
if not(my_dir):
    print "Unable to find {egg!r} file !"
    raise SystemExit()

# keep the first egg found
egg_path = os.path.join(my_dir[0], {egg!r})

''' + PY_RUN_CODE

## Now it is still a placeholder
def _gen_executable(eggname, code, modules):
    import_tok, func = map(str.strip, code.split(':'))
    return RUN_PY.format(
        egg = eggname,
        mod_name = import_tok,
        callable = func,
        modules = tuple(modules),
    )

class Packer(object):

    EMPTY, INI, CAT, SCAT, MERGE = range(5)
    REQ = 42

    EGG_FILES = {
        'dependency_links.txt': MERGE,
        'entry_points.txt': INI,
        'not-zip-safe': EMPTY,
        'PKG-INFO': REQ,
        'requires.txt': EMPTY,
        'SOURCES.txt': SCAT,
        'top_level.txt': SCAT,
        'spec/depend': """metadata_version = '1.1'
name = {req!r}
version = {req_version!r}
build = 1

arch = {arch}
platform = {platform!r}
osdist = None
python = {python_version!r}
packages = [
  {packages}
]
            """
    }

    def __init__(self, req, bundle_name, dest=None):
        self.req = req
        self.bundle_name = bundle_name
        self.pack_name = bundle_name
        if not self.pack_name.endswith('.zip'):
            self.pack_name = self.pack_name + '.zip'
        self.dest = dest
        self.bundled = {}
        ## For now this is a simple placeholder
        self.modules = []
        self.entry_points = {}

    def _bundle_callback(self, req, sdist):
        sdist._name, sdist._version = req.name, req.version
        self.bundled[sdist.name] = sdist
        self.modules.append('{0}-{1}'.format(sdist.name, sdist.version))

    def _fill_metadata(self):
        content = self.EGG_FILES['spec/depend']
        req_version = self.req.version
        try:
            if req_version is None:
                req_version = self.bundled[self.req.name].version
        except KeyError:
            pass
        if req_version is None:
            req_version = highest_version(self.req)

        self.EGG_FILES['spec/depend'] = content.format(
            req=self.req.name,
            req_version=req_version,
            arch=platform.machine(),
            platform=sys.platform,
            python_version='.'.join(map(str, sys.version_info[:2])),
            packages=',\n  '.join('{0.name} {0.version}'.format(dist) for dist in self.bundled.values())
        )

    def _safe_readlines(self, dist, filename):
        try:
            return dist.file(filename)
        except KeyError:
            return {}

    def _mk_egg_info(self):
        ## This function should return the EGG-INFO path

        logger.info('Generating EGG-INFO...')
        with TempDir(dont_remove=True) as tempdir:
            egg_info = os.path.join(tempdir, 'EGG-INFO')
            os.mkdir(egg_info)
            self._fill_metadata()
            for mfile, data in self.EGG_FILES.iteritems():
                deps = dict((name, self._safe_readlines(dist, mfile)) for name, dist in self.bundled.iteritems())
                if data == self.EMPTY:
                    content = ''
                elif data == self.INI:
                    ini_file = {}
                    for dep, content in deps.iteritems():
                        for section, options in content.iteritems():
                            if section in ini_file:
                                ini_file[section].update(options)
                            else:
                                ini_file[section] = options
                    result = []
                    for section in sorted(ini_file.iterkeys()):
                        result.append('[{0}]'.format(section))
                        for option, value in ini_file[section].iteritems():
                            result.append('{0} = {1}'.format(option, value))
                        result.append('\n')
                    content = '\n'.join(result)
                elif data in (self.CAT, self.SCAT):
                    lines = []
                    for dep, content in deps.iteritems():
                        lines.extend(content)
                    if data == self.SCAT:
                        lines.sort()
                    content = '\n'.join(lines)
                elif data == self.MERGE:
                    d = set()
                    for dep, content in deps.iteritems():
                        d.update(content)
                    content = '\n'.join(sorted(d))
                elif data == self.REQ:
                    content = '\n'.join('{0}: {1}'.format(opt, val) \
                        for opt, val in self._safe_readlines(self.bundled[self.req.name], mfile).iteritems())
                else:
                    content = data

                if '/' in mfile:
                    # Make it platform-indipendent
                    parts = mfile.split('/')
                    mfile = os.path.join(*mfile.split('/'))
                    os.makedirs(os.path.join(egg_info, *parts[:-1]))
                with open(os.path.join(egg_info, mfile), 'w') as f:
                    # FIXME: this is a bit ugly
                    if mfile == 'entry_points.txt':
                        try:
                            raw = content.split('[console_scripts]')[1].split('[', 1)[0].split('\n')
                        except IndexError:
                            raw = []
                        for line in raw:
                            line = line.strip()
                            if not line:
                                continue
                            cmd, code = (x.strip() for x in line.split('='))
                            self.entry_points[cmd] = code
                    f.write(content)

                # this is for Bundler._add_to_archive: it needs the temporary
                # directory length
                tempdir_len = len(tempdir)
            return egg_info, tempdir_len

    def _gen_eggs(self, source_dir, egg_dir):
        ## Old method
        r = re.compile(r'-py\d\.\d')
        def sep_egg_info(arch_path):
            arch = os.path.basename(arch_path)
            eggname = arch[:r.search(arch).start()]
            with ZipFile(arch_path) as z:
                z.extractall(os.path.join(egg_dir, eggname))

        ## New method
        def no_egg_info(arch_path):
            with ZipFile(arch_path) as z:
                z.extractall(egg_dir)

        with TempDir() as tempdir:
            for dist in os.listdir(source_dir):
                code, output = call_setup(os.path.join(source_dir, dist), ['bdist_egg', '-d', tempdir])
                if code != 0:
                    logger.fatal('Error: cannot generate egg for {0}', dist)
                    print_output(output, 'setup.py bdist_egg')
                    raise PygError('cannot generate egg for {0}'.format(dist))
                arch = os.path.join(tempdir, os.listdir(tempdir)[0])
                no_egg_info(arch)
                os.remove(arch)
        # Comment out this line if you want to use old method (see above)
        shutil.rmtree(os.path.join(egg_dir, 'EGG-INFO'))

    def gen_pack(self, exclude=[], use_develop=False):
        # This is where to download all packages
        # and where to build the pack
        with TempDir() as tempdir:
            # This is where to store the egg
            with TempDir() as bundle_dir:
                logger.info('Generating the bundle...')
                b = Bundler([self.req], self.bundle_name, exclude=exclude, \
                    callback=self._bundle_callback, use_develop=use_develop)

                # we download packages without creating the bundle to build
                # eggs
                b._download_all(tempdir)
                b._clean(tempdir)

                bundle = os.path.join(bundle_dir, self.req.name) + '.egg'
                with ZipFile(bundle, mode='w') as egg:
                    # Create a new directory to store unpacked eggs
                    with TempDir() as egg_dir:
                        self._gen_eggs(tempdir, egg_dir)
                        b._add_to_archive(egg, egg_dir, len(egg_dir))
                        egg_info, tl = self._mk_egg_info()
                        b._add_to_archive(egg, egg_info, tl)

                pack = os.path.join(tempdir, self.pack_name)
                self.modules = [name_from_name(mod) for mod in self.modules]

                eggname = self.req.name + '.egg'
                folder_name = '{0.name}-{0.version}'.format(self.bundled[self.req.name])
                with ZipFile(pack, mode='w') as z:
                    z.write(bundle, '/'.join([folder_name, eggname]))
                    # write executable files
                    for command_name, code in self.entry_points.iteritems():
                        z.add_executable('/'.join((folder_name, 'run_%s.py' % command_name)),
                            _gen_executable(eggname, code, self.modules)
                        )
                dest = os.path.join(self.dest, self.pack_name)
                if os.path.exists(dest):
                    os.remove(dest)
                shutil.move(pack, self.dest)
<commit_msg>pack: new generation method<commit_after>'''
Create Packs, like Zicbee Pack (at http://pypi.python.org/zicbee).
Inspired by zicbee-workshop's manage.py
'''

import re
import os
import sys
import glob
import shutil
import platform

from pyg.log import logger
from pyg.req import Requirement
from pyg.web import highest_version
from pyg.inst import Bundler
from pyg.core import PygError
from pyg.utils import TempDir, ZipFile, call_setup, print_output, unpack, name_from_name

PY_RUN_CODE = '''
import re
#p_re = re.compile('.*(python\d+[.\d]+[^/]*|lib-\w+|plat-\w+)$')
#sys.path = [os.path.join(egg_path, mod) for mod in {modules!r}] + [x for x in sys.path if p_re.match(x)]
sys.path.insert(0, egg_path)

# run!
import {mod_name}
sys.exit({mod_name}.{callable}())
'''

RUN_PY = '''#!/usr/bin/env python
## Executable file auto-generated by Pyg

import os
import sys

exists = os.path.exists
j = os.path.join
# we don't care about order
paths = set(sys.path)
paths.add(os.getcwd())

my_dir = [p for p in paths if exists(j(p, {egg!r}))]
if not(my_dir):
    print "Unable to find {egg!r} file !"
    raise SystemExit()

# keep the first egg found
egg_path = os.path.join(my_dir[0], {egg!r})

''' + PY_RUN_CODE

## Now it is still a placeholder
def _gen_executable(eggname, code, modules):
    import_tok, func = map(str.strip, code.split(':'))
    return RUN_PY.format(
        egg = eggname,
        mod_name = import_tok,
        callable = func,
        modules = tuple(modules),
    )

class Packer(object):

    EMPTY, INI, CAT, SCAT, MERGE = range(5)
    REQ = 42

    EGG_FILES = {
        'dependency_links.txt': MERGE,
        'entry_points.txt': INI,
        'not-zip-safe': EMPTY,
        'PKG-INFO': REQ,
        'requires.txt': EMPTY,
        'SOURCES.txt': SCAT,
        'top_level.txt': SCAT,
        'spec/depend': """metadata_version = '1.1'
name = {req!r}
version = {req_version!r}
build = 1

arch = {arch}
platform = {platform!r}
osdist = None
python = {python_version!r}
packages = [
  {packages}
]
            """
    }

    def __init__(self, req, bundle_name, dest=None):
        self.req = req
        self.bundle_name = bundle_name
        self.pack_name = bundle_name
        if not self.pack_name.endswith('.zip'):
            self.pack_name = self.pack_name + '.zip'
        self.dest = dest
        self.bundled = {}
        ## For now this is a simple placeholder
        self.modules = []
        self.entry_points = {}

    def _bundle_callback(self, req, sdist):
        sdist._name, sdist._version = req.name, req.version
        self.bundled[sdist.name] = sdist
        self.modules.append('{0}-{1}'.format(sdist.name, sdist.version))

    def _fill_metadata(self):
        content = self.EGG_FILES['spec/depend']
        req_version = self.req.version
        try:
            if req_version is None:
                req_version = self.bundled[self.req.name].version
        except KeyError:
            pass
        if req_version is None:
            req_version = highest_version(self.req)

        self.EGG_FILES['spec/depend'] = content.format(
            req=self.req.name,
            req_version=req_version,
            arch=platform.machine(),
            platform=sys.platform,
            python_version='.'.join(map(str, sys.version_info[:2])),
            packages=',\n  '.join('{0.name} {0.version}'.format(dist) for dist in self.bundled.values())
        )

    def _safe_readlines(self, dist, filename):
        try:
            return dist.file(filename)
        except KeyError:
            return {}

    def _mk_egg_info(self):
        ## This function should return the EGG-INFO path

        logger.info('Generating EGG-INFO...')
        with TempDir(dont_remove=True) as tempdir:
            egg_info = os.path.join(tempdir, 'EGG-INFO')
            os.mkdir(egg_info)
            self._fill_metadata()
            for mfile, data in self.EGG_FILES.iteritems():
                deps = dict((name, self._safe_readlines(dist, mfile)) for name, dist in self.bundled.iteritems())
                if data == self.EMPTY:
                    content = ''
                elif data == self.INI:
                    ini_file = {}
                    for dep, content in deps.iteritems():
                        for section, options in content.iteritems():
                            if section in ini_file:
                                ini_file[section].update(options)
                            else:
                                ini_file[section] = options
                    result = []
                    for section in sorted(ini_file.iterkeys()):
                        result.append('[{0}]'.format(section))
                        for option, value in ini_file[section].iteritems():
                            result.append('{0} = {1}'.format(option, value))
                        result.append('\n')
                    content = '\n'.join(result)
                elif data in (self.CAT, self.SCAT):
                    lines = []
                    for dep, content in deps.iteritems():
                        lines.extend(content)
                    if data == self.SCAT:
                        lines.sort()
                    content = '\n'.join(lines)
                elif data == self.MERGE:
                    d = set()
                    for dep, content in deps.iteritems():
                        d.update(content)
                    content = '\n'.join(sorted(d))
                elif data == self.REQ:
                    content = '\n'.join('{0}: {1}'.format(opt, val) \
                        for opt, val in self._safe_readlines(self.bundled[self.req.name], mfile).iteritems())
                else:
                    content = data

                if '/' in mfile:
                    # Make it platform-indipendent
                    parts = mfile.split('/')
                    mfile = os.path.join(*mfile.split('/'))
                    os.makedirs(os.path.join(egg_info, *parts[:-1]))
                with open(os.path.join(egg_info, mfile), 'w') as f:
                    # FIXME: this is a bit ugly
                    if mfile == 'entry_points.txt':
                        try:
                            raw = content.split('[console_scripts]')[1].split('[', 1)[0].split('\n')
                        except IndexError:
                            raw = []
                        for line in raw:
                            line = line.strip()
                            if not line:
                                continue
                            cmd, code = (x.strip() for x in line.split('='))
                            self.entry_points[cmd] = code
                    f.write(content)

                # this is for Bundler._add_to_archive: it needs the temporary
                # directory length
                tempdir_len = len(tempdir)
            return egg_info, tempdir_len

    def _gen_eggs(self, source_dir, egg_dir):
        ## Old method
        r = re.compile(r'-py\d\.\d')
        def sep_egg_info(arch_path):
            arch = os.path.basename(arch_path)
            eggname = arch[:r.search(arch).start()]
            with ZipFile(arch_path) as z:
                z.extractall(os.path.join(egg_dir, eggname))

        ## New method
        def no_egg_info(arch_path):
            with ZipFile(arch_path) as z:
                z.extractall(egg_dir)

        with TempDir() as tempdir:
            for dist in os.listdir(source_dir):
                code, output = call_setup(os.path.join(source_dir, dist), ['bdist_egg', '-d', tempdir])
                if code != 0:
                    logger.fatal('Error: cannot generate egg for {0}', dist)
                    print_output(output, 'setup.py bdist_egg')
                    raise PygError('cannot generate egg for {0}'.format(dist))
                arch = os.path.join(tempdir, os.listdir(tempdir)[0])
                no_egg_info(arch)
                os.remove(arch)
        # Comment out this line if you want to use old method (see above)
        shutil.rmtree(os.path.join(egg_dir, 'EGG-INFO'))

    def gen_pack(self, exclude=[], use_develop=False):
        # This is where to download all packages
        # and where to build the pack
        with TempDir() as tempdir:
            # This is where to store the egg
            with TempDir() as bundle_dir:
                logger.info('Generating the bundle...')
                b = Bundler([self.req], self.bundle_name, exclude=exclude, \
                    callback=self._bundle_callback, use_develop=use_develop)

                # we download packages without creating the bundle to build
                # eggs
                b._download_all(tempdir)
                b._clean(tempdir)

                bundle = os.path.join(bundle_dir, self.req.name) + '.egg'
                with ZipFile(bundle, mode='w') as egg:
                    # Create a new directory to store unpacked eggs
                    with TempDir() as egg_dir:
                        self._gen_eggs(tempdir, egg_dir)
                        b._add_to_archive(egg, egg_dir, len(egg_dir))
                        egg_info, tl = self._mk_egg_info()
                        b._add_to_archive(egg, egg_info, tl)

                pack = os.path.join(tempdir, self.pack_name)
                self.modules = [name_from_name(mod) for mod in self.modules]

                eggname = self.req.name + '.egg'
                folder_name = '{0.name}-{0.version}'.format(self.bundled[self.req.name])
                with ZipFile(pack, mode='w') as z:
                    z.write(bundle, '/'.join([folder_name, eggname]))
                    # write executable files
                    for command_name, code in self.entry_points.iteritems():
                        z.add_executable('/'.join((folder_name, 'run_%s.py' % command_name)),
                            _gen_executable(eggname, code, self.modules)
                        )
                dest = os.path.join(self.dest, self.pack_name)
                if os.path.exists(dest):
                    os.remove(dest)
                shutil.move(pack, self.dest)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import urwid
import webbrowser

class ItemWidget(urwid.WidgetWrap):

    def __init__(self, story):
        self.story = story
        self.number = story.number
        self.title = story.title
        self.url = story.URL
        self.submitter = story.submitter
        self.comment_count = story.commentCount
        self.score = story.score
        self.publishedTime = story.publishedTime
        self.item = [
            ('fixed', 4, urwid.Padding(urwid.AttrWrap(
                urwid.Text("%s:" % self.number, align="right"), 'body', 'focus'))),
            urwid.AttrWrap(urwid.Text('%s' % self.title), 'body', 'focus'),
            ('fixed', 5, urwid.Padding(urwid.AttrWrap(
                urwid.Text(str(self.score), align="right"), 'body','focus'))),
            ('fixed', 8, urwid.Padding(urwid.AttrWrap(
                urwid.Text(str(self.comment_count), align="right"), 'body','focus'))),
        ]
        w = urwid.Columns(self.item, focus_column=1, dividechars=1)
        self.__super.__init__(w)

    def selectable (self):
        return True

    def keypress(self, size, key):
        return key

class HNGui(object):
    def __init__(self, cache_manager):
        self.cache_manager = cache_manager
        self.already_build = False
        self.which = "top"

        self.palette = [
            ('body','default', '', 'standout'),
            ('focus','black', 'light green', 'underline'),
            ('footer','black', 'light gray'),
            ('header','dark gray,bold', 'white'),
            ('title','dark red,bold', 'light gray', ''),
            ('help','black,bold', 'light gray'),
        ]

    def main(self):
        self.ui = urwid.raw_display.Screen()
        self.ui.register_palette(self.palette)
        self.build_interface()
        self.ui.run_wrapper(self.run)

    def build_interface(self):
        if self.cache_manager.is_outdated():
            self.cache_manager.refresh()

        self.stories = self.cache_manager.get_stories()
        self.update_stories(self.stories)
        self.header_content = [
                ('fixed', 4, urwid.Padding(urwid.AttrWrap(
                    urwid.Text(' N°'), 'header'))),
                urwid.AttrWrap(urwid.Text('TOP STORIES', align="center"), 'title'),
                ('fixed', 5, urwid.Padding(urwid.AttrWrap(
                    urwid.Text('SCORE'), 'header'))),
                ('fixed', 8, urwid.Padding(urwid.AttrWrap(
                    urwid.Text('COMMENTS'), 'header'))),
            ]

        self.header = urwid.Columns(self.header_content, dividechars=1)
        self.footer = urwid.AttrMap(urwid.Text('Welcome in pyhn by socketubs (https://github.com/socketubs/pyhn)', align='center'), 'footer')

        self.view = urwid.Frame(urwid.AttrWrap(self.listbox, 'body'), header=self.header, footer=self.footer)
        self.loop = urwid.MainLoop(self.view, self.palette, screen=self.ui, unhandled_input=self.keystroke)
        self.already_build = True

    def set_help(self):
        msg = "J: Go next -- K: Go prev -- T: Top -- B: Best -- N: Newest -- R: Refresh -- Enter: Open link -- ?, H: Help -- Q: Quit"
        self.view.set_footer(urwid.AttrWrap(urwid.Text(msg, align="center"), 'help'))

    def set_footer(self, msg):
        self.view.set_footer(urwid.AttrWrap(urwid.Text(msg), 'footer'))

    def set_header(self, msg):
        self.header_content[1] = urwid.AttrWrap(urwid.Text(msg, align="center"), 'title')
        self.view.set_header(urwid.Columns(self.header_content, dividechars=1))

    def keystroke(self, input):
        if input in ('q', 'Q'):
            raise urwid.ExitMainLoop()

        elif input is 'enter':
            focus = self.listbox.get_focus()[0].title
            webbrowser.open(self.listbox.get_focus()[0].url, autoraise=False)

        elif input in ('n', 'N'):
            self.set_footer('Retrieving newest stories...')
            if self.cache_manager.is_outdated('newest'):
                self.cache_manager.refresh('newest')
            stories = self.cache_manager.get_stories('newest')
            self.update_stories(stories)
            self.set_header('NEWEST STORIES')
            self.which = "newest"

        elif input in ('t', 'T'):
            self.set_footer('Retrieving top stories...')
            if self.cache_manager.is_outdated('top'):
                self.cache_manager.refresh('top')
            stories = self.cache_manager.get_stories('top')
            self.update_stories(stories)
            self.set_header('TOP STORIES')
            self.which = "top"

        elif input in ('b', 'B'):
            self.set_footer('Retrieving best stories...')
            if self.cache_manager.is_outdated('best'):
                self.cache_manager.refresh('best')
            stories = self.cache_manager.get_stories('best')
            self.update_stories(stories)
            self.set_header('BEST STORIES')
            self.which = "best"

        elif input in ('r', 'R'):
            self.cache_manager.refresh(self.which)
            stories = self.cache_manager.get_stories(self.which)
            self.update_stories(stories)

        elif input in ('h', 'H', '?'):
            self.set_help()
        elif input is 'j':
            self.listbox.set_focus(self.listbox.focus_position - 1)
        elif input is 'k':
            self.listbox.set_focus(self.listbox.focus_position + 1)

    def update_stories(self, stories):
        items = []
        for story in stories:
            items.append(ItemWidget(story))

        if self.already_build:
            self.walker[:] = items
            self.update()
        else:
            self.walker = urwid.SimpleListWalker(items)
            self.listbox = urwid.ListBox(self.walker)

    def update(self):
        focus = self.listbox.get_focus()[0]
        self.set_footer('submitted %s by %s' % (focus.publishedTime, focus.submitter))

    def run(self):
        urwid.connect_signal(self.walker, 'modified', self.update)

        try:
            self.loop.run()
        except KeyboardInterrupt:
            urwid.ExitMainLoop()<commit_msg>Fix #2<commit_after># -*- coding: utf-8 -*-
import urwid
import webbrowser

class ItemWidget(urwid.WidgetWrap):

    def __init__(self, story):
        self.story = story
        self.number = story.number
        self.title = story.title
        self.url = story.URL
        self.submitter = story.submitter
        self.comment_count = story.commentCount
        self.score = story.score
        self.publishedTime = story.publishedTime
        self.item = [
            ('fixed', 4, urwid.Padding(urwid.AttrWrap(
                urwid.Text("%s:" % self.number, align="right"), 'body', 'focus'))),
            urwid.AttrWrap(urwid.Text('%s' % self.title), 'body', 'focus'),
            ('fixed', 5, urwid.Padding(urwid.AttrWrap(
                urwid.Text(str(self.score), align="right"), 'body','focus'))),
            ('fixed', 8, urwid.Padding(urwid.AttrWrap(
                urwid.Text(str(self.comment_count), align="right"), 'body','focus'))),
        ]
        w = urwid.Columns(self.item, focus_column=1, dividechars=1)
        self.__super.__init__(w)

    def selectable (self):
        return True

    def keypress(self, size, key):
        return key

class HNGui(object):
    def __init__(self, cache_manager):
        self.cache_manager = cache_manager
        self.already_build = False
        self.which = "top"

        self.palette = [
            ('body','default', '', 'standout'),
            ('focus','black', 'light green', 'underline'),
            ('footer','black', 'light gray'),
            ('header','dark gray,bold', 'white'),
            ('title','dark red,bold', 'light gray', ''),
            ('help','black,bold', 'light gray'),
        ]

    def main(self):
        self.ui = urwid.raw_display.Screen()
        self.ui.register_palette(self.palette)
        self.build_interface()
        self.ui.run_wrapper(self.run)

    def build_interface(self):
        if self.cache_manager.is_outdated():
            self.cache_manager.refresh()

        self.stories = self.cache_manager.get_stories()
        self.update_stories(self.stories)
        self.header_content = [
                ('fixed', 4, urwid.Padding(urwid.AttrWrap(
                    urwid.Text(' N°'), 'header'))),
                urwid.AttrWrap(urwid.Text('TOP STORIES', align="center"), 'title'),
                ('fixed', 5, urwid.Padding(urwid.AttrWrap(
                    urwid.Text('SCORE'), 'header'))),
                ('fixed', 8, urwid.Padding(urwid.AttrWrap(
                    urwid.Text('COMMENTS'), 'header'))),
            ]

        self.header = urwid.Columns(self.header_content, dividechars=1)
        self.footer = urwid.AttrMap(urwid.Text('Welcome in pyhn by socketubs (https://github.com/socketubs/pyhn)', align='center'), 'footer')

        self.view = urwid.Frame(urwid.AttrWrap(self.listbox, 'body'), header=self.header, footer=self.footer)
        self.loop = urwid.MainLoop(self.view, self.palette, screen=self.ui, unhandled_input=self.keystroke)
        self.already_build = True

    def set_help(self):
        msg = "J: Go next -- K: Go prev -- T: Top -- B: Best -- N: Newest -- R: Refresh -- Enter: Open link -- ?, H: Help -- Q: Quit"
        self.view.set_footer(urwid.AttrWrap(urwid.Text(msg, align="center"), 'help'))

    def set_footer(self, msg):
        self.view.set_footer(urwid.AttrWrap(urwid.Text(msg), 'footer'))

    def set_header(self, msg):
        self.header_content[1] = urwid.AttrWrap(urwid.Text(msg, align="center"), 'title')
        self.view.set_header(urwid.Columns(self.header_content, dividechars=1))

    def keystroke(self, input):
        if input in ('q', 'Q'):
            raise urwid.ExitMainLoop()

        elif input is 'enter':
            focus = self.listbox.get_focus()[0].title
            webbrowser.open(self.listbox.get_focus()[0].url, autoraise=False)

        elif input in ('n', 'N'):
            self.set_footer('Retrieving newest stories...')
            if self.cache_manager.is_outdated('newest'):
                self.cache_manager.refresh('newest')
            stories = self.cache_manager.get_stories('newest')
            self.update_stories(stories)
            self.set_header('NEWEST STORIES')
            self.which = "newest"

        elif input in ('t', 'T'):
            self.set_footer('Retrieving top stories...')
            if self.cache_manager.is_outdated('top'):
                self.cache_manager.refresh('top')
            stories = self.cache_manager.get_stories('top')
            self.update_stories(stories)
            self.set_header('TOP STORIES')
            self.which = "top"

        elif input in ('b', 'B'):
            self.set_footer('Retrieving best stories...')
            if self.cache_manager.is_outdated('best'):
                self.cache_manager.refresh('best')
            stories = self.cache_manager.get_stories('best')
            self.update_stories(stories)
            self.set_header('BEST STORIES')
            self.which = "best"

        elif input in ('r', 'R'):
            self.cache_manager.refresh(self.which)
            stories = self.cache_manager.get_stories(self.which)
            self.update_stories(stories)

        elif input in ('h', 'H', '?'):
            self.set_help()
        elif input is 'j':
            if self.listbox.focus_position - 1 in self.walker.positions():
                self.listbox.set_focus(self.walker.prev_position(self.listbox.focus_position))
        elif input is 'k':
            if self.listbox.focus_position + 1 in self.walker.positions():
                self.listbox.set_focus(self.walker.next_position(self.listbox.focus_position))

    def update_stories(self, stories):
        items = []
        for story in stories:
            items.append(ItemWidget(story))

        if self.already_build:
            self.walker[:] = items
            self.update()
        else:
            self.walker = urwid.SimpleListWalker(items)
            self.listbox = urwid.ListBox(self.walker)

    def update(self):
        focus = self.listbox.get_focus()[0]
        self.set_footer('submitted %s by %s' % (focus.publishedTime, focus.submitter))

    def run(self):
        urwid.connect_signal(self.walker, 'modified', self.update)

        try:
            self.loop.run()
        except KeyboardInterrupt:
            urwid.ExitMainLoop()<|endoftext|>