<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-

# feed works to get feed meta info into database
#
# @author Jin Yuan
# @contact jinyuan@baidu.com
# @created Jan 1, 2013

import sys
reload(sys)
sys.setdefaultencoding('UTF-8')
sys.path.append("..")

from administration.config import Collection
from administration.config import db
from administration.config import rclient
from BeautifulSoup import BeautifulStoneSoup
import entry
import feedparser
import task
import time

from administration.config import FEED_REGISTRAR
from administration.config import LANGUAGES

def create_language_collection(feed_info=None):
    ''''''
    if not feed_info:
        return None
    if feed_info['language'] not in db.collection_names():
        feed_id = db.create_collection(feed_info['language'])
        return feed_id
    return None

def register_source(feed_info=None):
    ''''''
    if not feed_info:
        return 1
    col = None
    if FEED_REGISTRAR not in db.collection_names():
        col = db.create_collection(FEED_REGISTRAR)
    else:
        col = Collection(db, FEED_REGISTRAR)
    # make a record in the feeds table
    item = col.find_one({'feed_link':feed_info['feed_link']})
    if not item:
        col.save(feed_info)
    return 0

def _read_source(d=None, feed_link=None, language=None, categories=None, weight_categories=10, weight_source=10):
    feed_info = {}
    if 'feed' in d:
        if 'title' in d.feed:
            feed_info['feed_name'] = d.feed.title.strip()
        else:
            feed_info['feed_name'] = raw_input('Cannot find name for %s, input new:\n' % feed_link).strip()
        if 'subtitle' in d.feed:
            feed_info['subtitle'] = d.feed.subtitle.strip()
        if 'rights' in d.feed:
            feed_info['rights'] = d.feed.rights.strip()
        #if 'image' in d.feed:
        #    feed_info['image'] = d.feed.image.href
    else:
        feed_info['feed_name'] = raw_input('Invalid format of %s, input name:\n' % feed_link).strip()
    # read in passed values
    feed_info['feed_link'] = feed_link
    feed_info['categories'] = categories
    feed_info['language'] = language
    feed_info['weight_categories'] = weight_categories
    feed_info['weight_source'] = weight_source
    return feed_info

def add(feed_link=None, language=None, categories=None):
    """
    read rss/atom meta information from a given feed
    """
    if not feed_link or not language:
        return 1
    feed_link = feed_link.strip()
    language = language.strip()
    categories = categories.strip()

    d = feedparser.parse(feed_link)
    if d:
        # feed level
        feed_info = _read_source(d, feed_link, language, categories, weight_categories, weight_source)
        register_source(feed_info)
        feed_id = create_language_collection(feed_info)
        print '1/4 .. created entry in database'
        # ToDos
        # add feed_id checking procedure

        # add entries of this feed
        entry.add_entries(feed_id, feed_info['feed_link'], feed_info['language'], feed_info['categories'])
        print '2/4 .. added all rss entries'

        # add weights to memory
        if not rclient.hexists('%s-weights' % feed_info['language'], feed_info['categories']):
            language_weights = {feed_info['categories']:feed_info['weight_categories']}
            rclient.hmset('%s-weights' % feed_info['language'], language_weights)
        if not rclient.hexists('%s-%s-weights' % (feed_info['language'], feed_info['categories']), feed_id):
            categories_weights = {feed_id:feed_info['weight_source']}
            rclient.hmset('%s-%s-weights' % (feed_info['language'], feed_info['categories']), categories_weights)
        print '3/4 .. updated memory structure'

        # add to update list
        task.add_task(feed_id, feed_info['feed_link'], feed_info['language'], feed_info['categories'])
        print '4/4 .. added to task list'
        return 0
    else:
        return 4
<commit_msg>removed memory writing part of feed.py<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-

# feed works to get feed meta info into database
#
# @author Jin Yuan
# @contact jinyuan@baidu.com
# @created Jan 1, 2013

import sys
reload(sys)
sys.setdefaultencoding('UTF-8')
sys.path.append("..")

from administration.config import Collection
from administration.config import db
from administration.config import rclient
from BeautifulSoup import BeautifulStoneSoup
import entry
import feedparser
import task
import time

from administration.config import FEED_REGISTRAR
from administration.config import LANGUAGES

def create_language_collection(feed_info=None):
    ''''''
    if not feed_info:
        return None
    if feed_info['language'] not in db.collection_names():
        feed_id = db.create_collection(feed_info['language'])
        return feed_id
    return None

def _register_source(feed_info=None):
    ''''''
    if not feed_info:
        return 1
    col = None
    if FEED_REGISTRAR not in db.collection_names():
        col = db.create_collection(FEED_REGISTRAR)
    else:
        col = Collection(db, FEED_REGISTRAR)
    # make a record in the feeds table
    item = col.find_one({'feed_link':feed_info['feed_link']})
    if not item:
        col.save(feed_info)
    return 0

def _read_source(d=None, feed_link=None, language=None, categories=None, weight_categories=10, weight_source=10):
    feed_info = {}
    if 'feed' in d:
        if 'title' in d.feed:
            feed_info['feed_name'] = d.feed.title.strip()
        else:
            feed_info['feed_name'] = raw_input('Cannot find name for %s, input new:\n' % feed_link).strip()
        if 'subtitle' in d.feed:
            feed_info['subtitle'] = d.feed.subtitle.strip()
        if 'rights' in d.feed:
            feed_info['rights'] = d.feed.rights.strip()
        #if 'image' in d.feed:
        #    feed_info['image'] = d.feed.image.href
    else:
        feed_info['feed_name'] = raw_input('Invalid format of %s, input name:\n' % feed_link).strip()
    # read in passed values
    feed_info['feed_link'] = feed_link
    feed_info['categories'] = categories
    feed_info['language'] = language
    feed_info['weight_categories'] = weight_categories
    feed_info['weight_source'] = weight_source
    return feed_info

def _link_cleaner(link):
    """
    remove unnecessary parameters and the like
    """
    pass

def add(feed_link=None, language=None, categories=None):
    """
    read rss/atom meta information from a given feed
    """
    if not feed_link or not language:
        raise Exception("ERROR: Method not well formed!")

    feed_link = feed_link.strip()
    language = language.strip()
    categories = categories.strip()

    d = feedparser.parse(feed_link)
    if d:
        # feed level
        feed_info = _read_source(d, feed_link, language, categories, weight_categories, weight_source)
        _register_source(feed_info)
        feed_id = create_language_collection(feed_info)
        print '1/4 .. created entry in database'
        # ToDos
        # add feed_id checking procedure

        # add entries of this feed
        entry.add_entries(feed_id, feed_info['feed_link'], feed_info['language'], feed_info['categories'])
        print '2/4 .. added all rss entries'

        # add to update list
        task.add_task(feed_id, feed_info['feed_link'], feed_info['language'], feed_info['categories'])
        print '4/4 .. added to task list'
        return 0
    else:
        return 4
<|endoftext|>


<commit_before>class Menu:
	"""docstring for Menu"""
	def __init__(self):
		self.option = 0
		self.suboption_menu = 0

	def welcome_message(self):
		print("""

        ---------------------------------------------------------
                            WELCOME TO TWEETSTAT
        ---------------------------------------------------------

                      Get Twitter user\'s profile info

           Remember: with great power comes great responsibility

		""")

	def print_main_menu(self):
		print("""

        ---------------------------------------------------------
                           TweetStat Main Menu
        ---------------------------------------------------------

        0 --> User stat\'s                 1 --> RT\'s zone
        2 --> Fav\'s zone                  3 --> Follower\'s zone
                            -1 --> Exit
		""")

	def print_user_menu(self):
		print("""
			User stat\'s zone menu

			0 --> ??
			1 --> ??

			More comming soon

			""")

	def print_rt_menu(self):
		print("""
        ---------------------------------------------------------
                           RT\'s zone menu
        ---------------------------------------------------------

               0 --> More rted users.
               1 --> User that make more rt\'s. (Comming soon)
               2 --> Top 10 rted\'s tweets. (Comming soon)
               3 --> Average rt per day. (Comming soon)

			""")

	def print_fav_menu(self):
		print("""
        ---------------------------------------------------------
                           Fav\'s zone menu
        ---------------------------------------------------------
               0 --> More fav users.
               1 --> User that make favorite you more. (Comming soon)
               2 --> Top 10 fav\'s tweets. (Comming soon)
               3 --> Average fav per day. (Comming soon)

			""")

	def print_follower_menu(self):

		print("""
        ---------------------------------------------------------
                           Follower\'s zone menu
        ---------------------------------------------------------
               0 --> Not follow back.
               1 --> New follower\'s. (Comming soon)
               2 --> Last unfollows. (Comming soon)
               -1 --> Back
			""")

	def print_exit_log(self):

		print("""

        ---------------------------------------------------------
                            Exiting of TweetStat
        ---------------------------------------------------------

                      Thank you for using TweetStat

               Remember what uncle Ben said once before die:

                With great power comes great responsibility

			""")

	def set_main_menu_opt(self):
		self.option = int(input("Choose a valid option: "))

		if self.option < -1 or self.option > 3:
			print("Oups! Something is wrong with your choice")

			while self.option < -1 or self.option > 3:
				self.option = int(input("Try to choose a valid option: "))

	def set_submenu_opt(self):
		self.suboption_menu = int(input("Choose a valid option: "))

		if self.suboption_menu < -1 or self.suboption_menu > 3:
			print("Oups! Something is wrong with your choice")

			while self.suboption_menu < -1 or self.suboption_menu > 3:
				self.option = int(input("Try to choose a valid option: "))

if __name__ == '__main__':
    menu = Menu()
    menu.welcome_message()
    menu.print_main_menu()

    menu.set_main_menu_opt()

    while menu.option != -1:
    	if menu.option == 0:
    		menu.print_user_menu()
    		menu.suboption_menu = int(input("Choose a valid submenu option: "))

    	elif menu.option == 1:
    		menu.print_rt_menu()
    		menu.suboption_menu = int(input("Choose a valid submenu option: "))

    	elif menu.option == 2:
    		menu.print_fav_menu()
    		menu.suboption_menu = int(input("Choose a valid submenu option: "))

    	elif menu.option == 3:
    		menu.print_follower_menu()
    		menu.suboption_menu = int(input("Choose a valid submenu option: "))

    if menu.option == -1:
    	menu.print_exit_log()
<commit_msg>intentando volver atrás<commit_after>class Menu:
	"""docstring for Menu"""
	def __init__(self):
		self.option = 0
		self.suboption_menu = 0

	def welcome_message(self):
		print("""

        ---------------------------------------------------------
                            WELCOME TO TWEETSTAT
        ---------------------------------------------------------

                      Get Twitter user\'s profile info

           Remember: with great power comes great responsibility

		""")

	def print_main_menu(self):
		print("""

        ---------------------------------------------------------
                           TweetStat Main Menu
        ---------------------------------------------------------

        0 --> User stat\'s                 1 --> RT\'s zone
        2 --> Fav\'s zone                  3 --> Follower\'s zone
                            -1 --> Exit
		""")

	def print_user_menu(self):
		print("""
      ---------------------------------------------------------
			                   User stat\'s zone menu
      ---------------------------------------------------------

			          0 --> ??
			          1 --> ??
               -1 --> Back

			More comming soon

			""")

	def print_rt_menu(self):
		print("""
        ---------------------------------------------------------
                           RT\'s zone menu
        ---------------------------------------------------------

                0 --> More rted users.
                1 --> User that make more rt\'s. (Comming soon)
                2 --> Top 10 rted\'s tweets. (Comming soon)
                3 --> Average rt per day. (Comming soon)
               -1 --> Back

			""")

	def print_fav_menu(self):
		print("""
        ---------------------------------------------------------
                           Fav\'s zone menu
        ---------------------------------------------------------
                0 --> More fav users.
                1 --> User that make favorite you more. (Comming soon)
                2 --> Top 10 fav\'s tweets. (Comming soon)
                3 --> Average fav per day. (Comming soon)
               -1 --> Back

			""")

	def print_follower_menu(self):

		print("""
        ---------------------------------------------------------
                           Follower\'s zone menu
        ---------------------------------------------------------
                0 --> Not follow back.
                1 --> New follower\'s. (Comming soon)
                2 --> Last unfollows. (Comming soon)
               -1 --> Back
			""")

	def print_exit_log(self):

		print("""

        ---------------------------------------------------------
                            Exiting of TweetStat
        ---------------------------------------------------------

                      Thank you for using TweetStat

               Remember what uncle Ben said once before die:

                With great power comes great responsibility

			""")

	def set_main_menu_opt(self):
		self.option = int(input("Choose a valid option: "))

		if self.option < -1 or self.option > 3:
			print("Oups! Something is wrong with your choice")

			while self.option < -1 or self.option > 3:
				self.option = int(input("Try to choose a valid option: "))

	def set_submenu_opt(self):
		self.suboption_menu = int(input("Choose a valid option: "))

		if self.suboption_menu < -1 or self.suboption_menu > 3:
			print("Oups! Something is wrong with your choice.")

			while self.suboption_menu < -1 or self.suboption_menu > 3:
				self.option = int(input("Try to choose a valid option: "))

if __name__ == '__main__':
    menu = Menu()
    menu.welcome_message()
    menu.print_main_menu()

    menu.set_main_menu_opt()

    while menu.option != -1:
    	if menu.option == 0:
    		menu.print_user_menu()
        menu.set_submenu_opt()

        while menu.suboption_menu != -1:
          if menu.suboption_menu == 0:
            print("Comming soon...")
            menu.print_user_menu()
            menu.set_submenu_opt()
          else if menu.suboption_menu == 1:
            print("Comming soon...")
            menu.print_user_menu()
            menu.set_submenu_opt()

        menu.print_main_menu()
        menu.set_main_menu_opt()

    	elif menu.option == 1:
    		menu.print_rt_menu()
    		menu.suboption_menu = int(input("Choose a valid submenu option: "))

    	elif menu.option == 2:
    		menu.print_fav_menu()
    		menu.suboption_menu = int(input("Choose a valid submenu option: "))

    	elif menu.option == 3:
    		menu.print_follower_menu()
    		menu.suboption_menu = int(input("Choose a valid submenu option: "))

    if menu.option == -1:
    	menu.print_exit_log()
<|endoftext|>


<commit_before>
"""
Test ContactInfo support.
"""

from servicetest import call_async, EventPattern
from gabbletest import exec_test, acknowledge_iq, make_result_iq
import constants as cs
import dbus

def test(q, bus, conn, stream):
    conn.Connect()
    _, event = q.expect_many(
        EventPattern('dbus-signal', signal='StatusChanged',
            args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]),
        EventPattern('stream-iq', to=None, query_ns='vcard-temp',
            query_name='vCard'))

    acknowledge_iq(stream, event.stanza)

    handle = conn.RequestHandles(1, ['bob@foo.com'])[0]
    call_async(q, conn.ContactInfo, 'GetContactInfo', [handle])

    event = q.expect('stream-iq', to='bob@foo.com', query_ns='vcard-temp',
        query_name='vCard')
    result = make_result_iq(stream, event.stanza)
    result.firstChildElement().addElement('FN', content='Bob')
    n = result.firstChildElement().addElement('N')
    n.addElement('GIVEN', content='Bob')
    result.firstChildElement().addElement('NICKNAME', content='bob')
    stream.send(result)

    q.expect('dbus-signal', signal='ContactInfoChanged')

    # A second request should be satisfied from the cache.
    assert conn.ContactInfo.GetContactInfo([handle]) == \
        {handle: [(u'fn', [], [u'Bob']),
                  (u'n', [], [u'', u'Bob', u'', u'', u'']),
                  (u'nickname', [], [u'bob'])]}

if __name__ == '__main__':
    exec_test(test)
<commit_msg>twisted tests: Improved test for getting contact info with plural nicknames.<commit_after>
"""
Test ContactInfo support.
"""

from servicetest import call_async, EventPattern
from gabbletest import exec_test, acknowledge_iq, make_result_iq
import constants as cs
import dbus

def test(q, bus, conn, stream):
    conn.Connect()
    _, event = q.expect_many(
        EventPattern('dbus-signal', signal='StatusChanged',
            args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]),
        EventPattern('stream-iq', to=None, query_ns='vcard-temp',
            query_name='vCard'))

    acknowledge_iq(stream, event.stanza)

    handle = conn.RequestHandles(1, ['bob@foo.com'])[0]
    call_async(q, conn.ContactInfo, 'GetContactInfo', [handle])

    event = q.expect('stream-iq', to='bob@foo.com', query_ns='vcard-temp',
        query_name='vCard')
    result = make_result_iq(stream, event.stanza)
    result.firstChildElement().addElement('FN', content='Bob')
    n = result.firstChildElement().addElement('N')
    n.addElement('GIVEN', content='Bob')
    result.firstChildElement().addElement('NICKNAME',
        content='bob,bob1\,,bob2,bob3\,bob4')
    stream.send(result)

    q.expect('dbus-signal', signal='ContactInfoChanged')

    # A second request should be satisfied from the cache.
    assert conn.ContactInfo.GetContactInfo([handle]) == \
        {handle: [(u'fn', [], [u'Bob']),
                  (u'n', [], [u'', u'Bob', u'', u'', u'']),
                  (u'nickname', [], [u'bob']),
                  (u'nickname', [], [u'bob1\,']),
                  (u'nickname', [], [u'bob2']),
                  (u'nickname', [], [u'bob3\,bob4'])]}

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


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

from setuptools import find_packages
from setuptools import setup

REQUIRED_PACKAGES = [
    'tensorflow==1.15.2',
    'scikit-learn>=0.20.2',
    'pandas==0.24.2',
    'cloudml-hypertune',
]

setup(
    name='trainer',
    version='0.1',
    install_requires=REQUIRED_PACKAGES,
    packages=find_packages(),
    include_package_data=True,
    description='AI Platform | Training | scikit-learn | Base'
)
<commit_msg>Bump tensorflow in /training/sklearn/structured/hp_tuning (#213)<commit_after>#!/usr/bin/env python
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================

from setuptools import find_packages
from setuptools import setup

REQUIRED_PACKAGES = [
    'tensorflow==1.15.4',
    'scikit-learn>=0.20.2',
    'pandas==0.24.2',
    'cloudml-hypertune',
]

setup(
    name='trainer',
    version='0.1',
    install_requires=REQUIRED_PACKAGES,
    packages=find_packages(),
    include_package_data=True,
    description='AI Platform | Training | scikit-learn | Base'
)
<|endoftext|>


<commit_before>"""
Complete implementation of the XDG Icon Spec Version 0.8
http://standards.freedesktop.org/icon-theme-spec/
"""

import os, sys, time

from xdg.IniFile import *
from xdg.BaseDirectory import *
from xdg.Exceptions import *

import xdg.Config

class IconTheme(IniFile):
    "Class to parse and validate IconThemes"
    def __init__(self):
        IniFile.__init__(self)

    def __repr__(self):
        return self.name

    def parse(self, file):
        IniFile.parse(self, file, ["Icon Theme", "KDE Icon Theme"])
        self.dir = os.path.dirname(file)
        (nil, self.name) = os.path.split(self.dir)

    def getDir(self):
        return self.dir

    # Standard Keys
    def getName(self):
        return self.get('Name', locale=True)
    def getComment(self):
        return self.get('Comment', locale=True)
    def getInherits(self):
        return self.get('Inherits', list=True)
    def getDirectories(self):
        return self.get('Directories', list=True)
    def getHidden(self):
        return self.get('Hidden', type="boolean")
    def getExample(self):
        return self.get('Example')

    # Per Directory Keys
    def getSize(self, directory):
        return self.get('Size', type="integer", group=directory)
    def getContext(self, directory):
        return self.get('Context', group=directory)
    def getType(self, directory):
        value = self.get('Type', group=directory)
        if value:
            return value
        else:
            return "Threshold"
    def getMaxSize(self, directory):
        value = self.get('MaxSize', type="integer", group=directory)
        if value or value == 0:
            return value
        else:
            return self.getSize(directory)
    def getMinSize(self, directory):
        value = self.get('MinSize', type="integer", group=directory)
        if value or value == 0:
            return value
        else:
            return self.getSize(directory)
    def getThreshold(self, directory):
        value = self.get('Threshold', type="integer", group=directory)
        if value or value == 0:
            return value
        else:
            return 2

    # validation stuff
    def checkExtras(self):
        # header
        if self.defaultGroup == "KDE Icon Theme":
            self.warnings.append('[KDE Icon Theme]-Header is deprecated')

        # file extension
        if self.fileExtension == ".theme":
            pass
        elif self.fileExtension == ".desktop":
            self.warnings.append('.desktop fileExtension is deprecated')
        else:
            self.warnings.append('Unknown File extension')

        # Check required keys
        # Name
        try:
            self.name = self.content[self.defaultGroup]["Name"]
        except KeyError:
            self.errors.append("Key 'Name' is missing")

        # Comment
        try:
            self.comment = self.content[self.defaultGroup]["Comment"]
        except KeyError:
            self.errors.append("Key 'Comment' is missing")

        # Directories
        try:
            self.directories = self.content[self.defaultGroup]["Directories"]
        except KeyError:
            self.errors.append("Key 'Directories' is missing")

    def checkGroup(self, group):
        # check if group header is valid
        if group == self.defaultGroup:
            pass
        elif group in self.getDirectories():
            try:
                self.type = self.content[group]["Type"]
            except KeyError:
                self.type = "Threshold"
            try:
                self.name = self.content[group]["Name"]
            except KeyError:
                self.errors.append("Key 'Name' in Group '%s' is missing" % group)
        elif not (re.match("^\[X-", group) and group.decode("utf-8", "ignore").encode("ascii", 'ignore') == group):
            self.errors.append("Invalid Group name: %s" % group)

    def checkKey(self, key, value, group):
        # standard keys
        if group == self.defaultGroup:
            if re.match("^Name"+xdg.Locale.regex+"$", key):
                pass
            elif re.match("^Comment"+xdg.Locale.regex+"$", key):
                pass
            elif key == "Inherits":
                self.checkValue(key, value, list=True)
            elif key == "Directories":
                self.checkValue(key, value, list=True)
            elif key == "Hidden":
                self.checkValue(key, value, type="boolean")
            elif key == "Example":
                self.checkValue(key, value)
            elif re.match("^X-[a-zA-Z0-9-]+", key):
                pass
            else:
                self.errors.append("Invalid key: %s" % key)
        elif group in self.getDirectories():
            if key == "Size":
                self.checkValue(key, value, type="integer")
            elif key == "Context":
                self.checkValue(key, value)
            elif key == "Type":
                self.checkValue(key, value)
                if value not in ["Fixed", "Scalable", "Threshold"]:
                    self.errors.append("Key 'Type' must be one out of 'Fixed','Scalable','Threshold', but is %s" % value)
            elif key == "MaxSize":
                self.checkValue(key, value, type="integer")
                if self.type != "Scalable":
                    self.errors.append("Key 'MaxSize' give, but Type is %s" % self.type)
            elif key == "MinSize":
                self.checkValue(key, value, type="integer")
                if self.type != "Scalable":
                    self.errors.append("Key 'MinSize' give, but Type is %s" % self.type)
            elif key == "Threshold":
                self.checkValue(key, value, type="integer")
                if self.type != "Threshold":
                    self.errors.append("Key 'Threshold' give, but Type is %s" % self.type)
            elif re.match("^X-[a-zA-Z0-9-]+", key):
                pass
            else:
                self.errors.append("Invalid key: %s" % key)

class IconData(IniFile):
    "Class to parse and validate IconData Files"
    def __init__(self):
        IniFile.__init__(self)

    def __repr__(self):
        return self.getDisplayName()

    def parse(self, file):
        IniFile.parse(self, file, ["Icon Data"])

    # Standard Keys
    def getDisplayName(self):
        return self.get('DisplayName', locale=True)
    def getEmbeddedTextRectangle(self):
        return self.get('EmbeddedTextRectangle', list=True)
    def getAttachPoints(self):
        return self.get('AttachPoints', type="point", list=True)

    # validation stuff
    def checkExtras(self):
        # file extension
        if self.fileExtension != ".icon":
            self.warnings.append('Unknown File extension')

    def checkGroup(self, group):
        # check if group header is valid
        if not (group == self.defaultGroup \
        or (re.match("^\[X-", group) and group.encode("ascii", 'ignore') == group)):
            self.errors.append("Invalid Group name: %s" % group.encode("ascii", "replace"))

    def checkKey(self, key, value, group):
        # standard keys
        if re.match("^DisplayName"+xdg.Locale.regex+"$", key):
            pass
        elif key == "EmbeddedTextRectangle":
            self.checkValue(key, value, type="integer", list=True)
        elif key == "AttachPoints":
            self.checkValue(key, value, type="point", list=True)
        elif re.match("^X-[a-zA-Z0-9-]+", key):
            pass
        else:
            self.errors.append("Invalid key: %s" % key)

icondirs = []
for basedir in xdg_data_dirs:
    icondirs.append(os.path.join(basedir, "icons"))
    icondirs.append(os.path.join(basedir, "pixmaps"))
icondirs.append(os.path.expanduser("~/.icons"))

# just cache variables, they give a 10x speed improvement
themes = []
cache = dict()
dache = dict()
eache = dict()

def getIconPath(iconname, size = None, theme = None, extensions = ["png", "svg", "xpm"]):
    global themes

    if size == None:
        size = xdg.Config.icon_size
    if theme == None:
        theme = xdg.Config.icon_theme

    # if we have an absolute path, just return it
    if os.path.isabs(iconname):
        return iconname

    # check if it has an extension and strip it
    if os.path.splitext(iconname)[1][1:] in extensions:
        iconname = os.path.splitext(iconname)[0]

    # parse theme files
    try:
        if themes[0].name != theme:
            themes = []
            __addTheme(theme)
    except IndexError:
        __addTheme(theme)

    # more caching (icon looked up in the last 5 seconds?)
    tmp = "".join([iconname, str(size), theme, "".join(extensions)])
    if tmp in eache:
        if int(time.time() - eache[tmp][0]) >= xdg.Config.cache_time:
            del eache[tmp]
        else:
            return eache[tmp][1]

    for thme in themes:
        icon = LookupIcon(iconname, size, thme, extensions)
        if icon:
            eache[tmp] = [time.time(), icon]
            return icon

    # cache stuff again (directories lookuped up in the last 5 seconds?)
    for directory in icondirs:
        if (directory not in dache \
            or (int(time.time() - dache[directory][1]) >= xdg.Config.cache_time \
            and dache[directory][2] < os.path.getmtime(directory))) \
            and os.path.isdir(directory):
            dache[directory] = [os.listdir(directory), time.time(), os.path.getmtime(directory)]

    for dir, values in dache.items():
        for extension in extensions:
            try:
                if iconname + "." + extension in values[0]:
                    icon = os.path.join(dir, iconname + "." + extension)
                    eache[tmp] = [time.time(), icon]
                    return icon
            except UnicodeDecodeError as e:
                if debug:
                    raise e
                else:
                    pass

    # we haven't found anything? "hicolor" is our fallback
    if theme != "hicolor":
        icon = getIconPath(iconname, size, "hicolor")
        eache[tmp] = [time.time(), icon]
        return icon

def getIconData(path):
    if os.path.isfile(path):
        dirname = os.path.dirname(path)
        basename = os.path.basename(path)
        if os.path.isfile(os.path.join(dirname, basename + ".icon")):
            data = IconData()
            data.parse(os.path.join(dirname, basename + ".icon"))
            return data

def __addTheme(theme):
    for dir in icondirs:
        if os.path.isfile(os.path.join(dir, theme, "index.theme")):
            __parseTheme(os.path.join(dir,theme, "index.theme"))
            break
        elif os.path.isfile(os.path.join(dir, theme, "index.desktop")):
            __parseTheme(os.path.join(dir,theme, "index.desktop"))
            break
    else:
        if debug:
            raise NoThemeError(theme)

def __parseTheme(file):
    theme = IconTheme()
    theme.parse(file)
    themes.append(theme)
    for subtheme in theme.getInherits():
        __addTheme(subtheme)

def LookupIcon(iconname, size, theme, extensions):
    # look for the cache
    if theme.name not in cache:
        cache[theme.name] = []
        cache[theme.name].append(time.time() - (xdg.Config.cache_time + 1)) # [0] last time of lookup
        cache[theme.name].append(0)               # [1] mtime
        cache[theme.name].append(dict())          # [2] dir: [subdir, [items]]

    # cache stuff (directory lookuped up the in the last 5 seconds?)
    if int(time.time() - cache[theme.name][0]) >= xdg.Config.cache_time:
        cache[theme.name][0] = time.time()
        for subdir in theme.getDirectories():
            for directory in icondirs:
                dir = os.path.join(directory,theme.name,subdir)
                if (cache not in ncache[theme.name][2] \
                or cache[theme.name][1] < os.path.getmtime(os.path.join(directory,theme.name))) \
                and subdir != "" \
                and os.path.isdir(dir):
                    cache[theme.name][2][dir] = [subdir, os.listdir(dir)]
                    cache[theme.name][1] = os.path.getmtime(os.path.join(directory,theme.name))

    for dir, values in cache[theme.name][2].items():
        if DirectoryMatchesSize(values[0], size, theme):
            for extension in extensions:
                if iconname + "." + extension in values[1]:
                    return os.path.join(dir, iconname + "." + extension)

    minimal_size = float("inf")
    closest_filename = ""
    for dir, values in cache[theme.name][2].items():
        distance = DirectorySizeDistance(values[0], size, theme)
        if distance < minimal_size:
            for extension in extensions:
                if iconname + "." + extension in values[1]:
                    closest_filename = os.path.join(dir, iconname + "." + extension)
                    minimal_size = distance

    return closest_filename

def DirectoryMatchesSize(subdir, iconsize, theme):
    Type = theme.getType(subdir)
    Size = theme.getSize(subdir)
    Threshold = theme.getThreshold(subdir)
    MinSize = theme.getMinSize(subdir)
    MaxSize = theme.getMaxSize(subdir)
    if Type == "Fixed":
        return Size == iconsize
    elif Type == "Scaleable":
        return MinSize <= iconsize <= MaxSize
    elif Type == "Threshold":
        return Size - Threshold <= iconsize <= Size + Threshold

def DirectorySizeDistance(subdir, iconsize, theme):
    Type = theme.getType(subdir)
    Size = theme.getSize(subdir)
    Threshold = theme.getThreshold(subdir)
    MinSize = theme.getMinSize(subdir)
    MaxSize = theme.getMaxSize(subdir)
    if Type == "Fixed":
        return abs(Size - iconsize)
    elif Type == "Scalable":
        if iconsize < MinSize:
            return MinSize - iconsize
        elif iconsize > MaxSize:
            return MaxSize - iconsize
        return 0
    elif Type == "Threshold":
        if iconsize < Size - Threshold:
            return MinSize - iconsize
        elif iconsize > Size + Threshold:
            return iconsize - MaxSize
        return 0
<commit_msg>Fix cache bug in IconTheme.py<commit_after>"""
Complete implementation of the XDG Icon Spec Version 0.8
http://standards.freedesktop.org/icon-theme-spec/
"""

import os, sys, time

from xdg.IniFile import *
from xdg.BaseDirectory import *
from xdg.Exceptions import *

import xdg.Config

class IconTheme(IniFile):
    "Class to parse and validate IconThemes"
    def __init__(self):
        IniFile.__init__(self)

    def __repr__(self):
        return self.name

    def parse(self, file):
        IniFile.parse(self, file, ["Icon Theme", "KDE Icon Theme"])
        self.dir = os.path.dirname(file)
        (nil, self.name) = os.path.split(self.dir)

    def getDir(self):
        return self.dir

    # Standard Keys
    def getName(self):
        return self.get('Name', locale=True)
    def getComment(self):
        return self.get('Comment', locale=True)
    def getInherits(self):
        return self.get('Inherits', list=True)
    def getDirectories(self):
        return self.get('Directories', list=True)
    def getHidden(self):
        return self.get('Hidden', type="boolean")
    def getExample(self):
        return self.get('Example')

    # Per Directory Keys
    def getSize(self, directory):
        return self.get('Size', type="integer", group=directory)
    def getContext(self, directory):
        return self.get('Context', group=directory)
    def getType(self, directory):
        value = self.get('Type', group=directory)
        if value:
            return value
        else:
            return "Threshold"
    def getMaxSize(self, directory):
        value = self.get('MaxSize', type="integer", group=directory)
        if value or value == 0:
            return value
        else:
            return self.getSize(directory)
    def getMinSize(self, directory):
        value = self.get('MinSize', type="integer", group=directory)
        if value or value == 0:
            return value
        else:
            return self.getSize(directory)
    def getThreshold(self, directory):
        value = self.get('Threshold', type="integer", group=directory)
        if value or value == 0:
            return value
        else:
            return 2

    # validation stuff
    def checkExtras(self):
        # header
        if self.defaultGroup == "KDE Icon Theme":
            self.warnings.append('[KDE Icon Theme]-Header is deprecated')

        # file extension
        if self.fileExtension == ".theme":
            pass
        elif self.fileExtension == ".desktop":
            self.warnings.append('.desktop fileExtension is deprecated')
        else:
            self.warnings.append('Unknown File extension')

        # Check required keys
        # Name
        try:
            self.name = self.content[self.defaultGroup]["Name"]
        except KeyError:
            self.errors.append("Key 'Name' is missing")

        # Comment
        try:
            self.comment = self.content[self.defaultGroup]["Comment"]
        except KeyError:
            self.errors.append("Key 'Comment' is missing")

        # Directories
        try:
            self.directories = self.content[self.defaultGroup]["Directories"]
        except KeyError:
            self.errors.append("Key 'Directories' is missing")

    def checkGroup(self, group):
        # check if group header is valid
        if group == self.defaultGroup:
            pass
        elif group in self.getDirectories():
            try:
                self.type = self.content[group]["Type"]
            except KeyError:
                self.type = "Threshold"
            try:
                self.name = self.content[group]["Name"]
            except KeyError:
                self.errors.append("Key 'Name' in Group '%s' is missing" % group)
        elif not (re.match("^\[X-", group) and group.decode("utf-8", "ignore").encode("ascii", 'ignore') == group):
            self.errors.append("Invalid Group name: %s" % group)

    def checkKey(self, key, value, group):
        # standard keys
        if group == self.defaultGroup:
            if re.match("^Name"+xdg.Locale.regex+"$", key):
                pass
            elif re.match("^Comment"+xdg.Locale.regex+"$", key):
                pass
            elif key == "Inherits":
                self.checkValue(key, value, list=True)
            elif key == "Directories":
                self.checkValue(key, value, list=True)
            elif key == "Hidden":
                self.checkValue(key, value, type="boolean")
            elif key == "Example":
                self.checkValue(key, value)
            elif re.match("^X-[a-zA-Z0-9-]+", key):
                pass
            else:
                self.errors.append("Invalid key: %s" % key)
        elif group in self.getDirectories():
            if key == "Size":
                self.checkValue(key, value, type="integer")
            elif key == "Context":
                self.checkValue(key, value)
            elif key == "Type":
                self.checkValue(key, value)
                if value not in ["Fixed", "Scalable", "Threshold"]:
                    self.errors.append("Key 'Type' must be one out of 'Fixed','Scalable','Threshold', but is %s" % value)
            elif key == "MaxSize":
                self.checkValue(key, value, type="integer")
                if self.type != "Scalable":
                    self.errors.append("Key 'MaxSize' give, but Type is %s" % self.type)
            elif key == "MinSize":
                self.checkValue(key, value, type="integer")
                if self.type != "Scalable":
                    self.errors.append("Key 'MinSize' give, but Type is %s" % self.type)
            elif key == "Threshold":
                self.checkValue(key, value, type="integer")
                if self.type != "Threshold":
                    self.errors.append("Key 'Threshold' give, but Type is %s" % self.type)
            elif re.match("^X-[a-zA-Z0-9-]+", key):
                pass
            else:
                self.errors.append("Invalid key: %s" % key)

class IconData(IniFile):
    "Class to parse and validate IconData Files"
    def __init__(self):
        IniFile.__init__(self)

    def __repr__(self):
        return self.getDisplayName()

    def parse(self, file):
        IniFile.parse(self, file, ["Icon Data"])

    # Standard Keys
    def getDisplayName(self):
        return self.get('DisplayName', locale=True)
    def getEmbeddedTextRectangle(self):
        return self.get('EmbeddedTextRectangle', list=True)
    def getAttachPoints(self):
        return self.get('AttachPoints', type="point", list=True)

    # validation stuff
    def checkExtras(self):
        # file extension
        if self.fileExtension != ".icon":
            self.warnings.append('Unknown File extension')

    def checkGroup(self, group):
        # check if group header is valid
        if not (group == self.defaultGroup \
        or (re.match("^\[X-", group) and group.encode("ascii", 'ignore') == group)):
            self.errors.append("Invalid Group name: %s" % group.encode("ascii", "replace"))

    def checkKey(self, key, value, group):
        # standard keys
        if re.match("^DisplayName"+xdg.Locale.regex+"$", key):
            pass
        elif key == "EmbeddedTextRectangle":
            self.checkValue(key, value, type="integer", list=True)
        elif key == "AttachPoints":
            self.checkValue(key, value, type="point", list=True)
        elif re.match("^X-[a-zA-Z0-9-]+", key):
            pass
        else:
            self.errors.append("Invalid key: %s" % key)

icondirs = []
for basedir in xdg_data_dirs:
    icondirs.append(os.path.join(basedir, "icons"))
    icondirs.append(os.path.join(basedir, "pixmaps"))
icondirs.append(os.path.expanduser("~/.icons"))

# just cache variables, they give a 10x speed improvement
themes = []
cache = dict()
dache = dict()
eache = dict()

def getIconPath(iconname, size = None, theme = None, extensions = ["png", "svg", "xpm"]):
    global themes

    if size == None:
        size = xdg.Config.icon_size
    if theme == None:
        theme = xdg.Config.icon_theme

    # if we have an absolute path, just return it
    if os.path.isabs(iconname):
        return iconname

    # check if it has an extension and strip it
    if os.path.splitext(iconname)[1][1:] in extensions:
        iconname = os.path.splitext(iconname)[0]

    # parse theme files
    try:
        if themes[0].name != theme:
            themes = []
            __addTheme(theme)
    except IndexError:
        __addTheme(theme)

    # more caching (icon looked up in the last 5 seconds?)
    tmp = "".join([iconname, str(size), theme, "".join(extensions)])
    if tmp in eache:
        if int(time.time() - eache[tmp][0]) >= xdg.Config.cache_time:
            del eache[tmp]
        else:
            return eache[tmp][1]

    for thme in themes:
        icon = LookupIcon(iconname, size, thme, extensions)
        if icon:
            eache[tmp] = [time.time(), icon]
            return icon

    # cache stuff again (directories lookuped up in the last 5 seconds?)
    for directory in icondirs:
        if (directory not in dache \
            or (int(time.time() - dache[directory][1]) >= xdg.Config.cache_time \
            and dache[directory][2] < os.path.getmtime(directory))) \
            and os.path.isdir(directory):
            dache[directory] = [os.listdir(directory), time.time(), os.path.getmtime(directory)]

    for dir, values in dache.items():
        for extension in extensions:
            try:
                if iconname + "." + extension in values[0]:
                    icon = os.path.join(dir, iconname + "." + extension)
                    eache[tmp] = [time.time(), icon]
                    return icon
            except UnicodeDecodeError as e:
                if debug:
                    raise e
                else:
                    pass

    # we haven't found anything? "hicolor" is our fallback
    if theme != "hicolor":
        icon = getIconPath(iconname, size, "hicolor")
        eache[tmp] = [time.time(), icon]
        return icon

def getIconData(path):
    if os.path.isfile(path):
        dirname = os.path.dirname(path)
        basename = os.path.basename(path)
        if os.path.isfile(os.path.join(dirname, basename + ".icon")):
            data = IconData()
            data.parse(os.path.join(dirname, basename + ".icon"))
            return data

def __addTheme(theme):
    for dir in icondirs:
        if os.path.isfile(os.path.join(dir, theme, "index.theme")):
            __parseTheme(os.path.join(dir,theme, "index.theme"))
            break
        elif os.path.isfile(os.path.join(dir, theme, "index.desktop")):
            __parseTheme(os.path.join(dir,theme, "index.desktop"))
            break
    else:
        if debug:
            raise NoThemeError(theme)

def __parseTheme(file):
    theme = IconTheme()
    theme.parse(file)
    themes.append(theme)
    for subtheme in theme.getInherits():
        __addTheme(subtheme)

def LookupIcon(iconname, size, theme, extensions):
    # look for the cache
    if theme.name not in cache:
        cache[theme.name] = []
        cache[theme.name].append(time.time() - (xdg.Config.cache_time + 1)) # [0] last time of lookup
        cache[theme.name].append(0)               # [1] mtime
        cache[theme.name].append(dict())          # [2] dir: [subdir, [items]]

    # cache stuff (directory lookuped up the in the last 5 seconds?)
    if int(time.time() - cache[theme.name][0]) >= xdg.Config.cache_time:
        cache[theme.name][0] = time.time()
        for subdir in theme.getDirectories():
            for directory in icondirs:
                dir = os.path.join(directory,theme.name,subdir)
                if (dir not in cache[theme.name][2] \
                or cache[theme.name][1] < os.path.getmtime(os.path.join(directory,theme.name))) \
                and subdir != "" \
                and os.path.isdir(dir):
                    cache[theme.name][2][dir] = [subdir, os.listdir(dir)]
                    cache[theme.name][1] = os.path.getmtime(os.path.join(directory,theme.name))

    for dir, values in cache[theme.name][2].items():
        if DirectoryMatchesSize(values[0], size, theme):
            for extension in extensions:
                if iconname + "." + extension in values[1]:
                    return os.path.join(dir, iconname + "." + extension)

    minimal_size = float("inf")
    closest_filename = ""
    for dir, values in cache[theme.name][2].items():
        distance = DirectorySizeDistance(values[0], size, theme)
        if distance < minimal_size:
            for extension in extensions:
                if iconname + "." + extension in values[1]:
                    closest_filename = os.path.join(dir, iconname + "." + extension)
                    minimal_size = distance

    return closest_filename

def DirectoryMatchesSize(subdir, iconsize, theme):
    Type = theme.getType(subdir)
    Size = theme.getSize(subdir)
    Threshold = theme.getThreshold(subdir)
    MinSize = theme.getMinSize(subdir)
    MaxSize = theme.getMaxSize(subdir)
    if Type == "Fixed":
        return Size == iconsize
    elif Type == "Scaleable":
        return MinSize <= iconsize <= MaxSize
    elif Type == "Threshold":
        return Size - Threshold <= iconsize <= Size + Threshold

def DirectorySizeDistance(subdir, iconsize, theme):
    Type = theme.getType(subdir)
    Size = theme.getSize(subdir)
    Threshold = theme.getThreshold(subdir)
    MinSize = theme.getMinSize(subdir)
    MaxSize = theme.getMaxSize(subdir)
    if Type == "Fixed":
        return abs(Size - iconsize)
    elif Type == "Scalable":
        if iconsize < MinSize:
            return MinSize - iconsize
        elif iconsize > MaxSize:
            return MaxSize - iconsize
        return 0
    elif Type == "Threshold":
        if iconsize < Size - Threshold:
            return MinSize - iconsize
        elif iconsize > Size + Threshold:
            return iconsize - MaxSize
        return 0
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
Created on Thu Apr 28 00:52:42 2016

@author: Gonçalo
"""

import numpy as np

class TunaDataFrame:
    _IdMask_ = 0x0FFF
    _SyncFlag_ = 0x8000
    _ButtonFlag_ = 0x4000
    _AlignedFlag_ = 0x2000
    _ErrorFlag_ = 0x1000
    _MessageLength_ = 80
    _NumSamples_ = 4
    _NumChannels_ = 9

    def __init__(self, message):
        messageId = message[1] | message[2] << 8
        self.id = messageId & self._IdMask_
        self.sync = (messageId & self._SyncFlag_) != 0;
        self.button = (messageId & self._ButtonFlag_) != 0;
        self.aligned = (messageId & self._AlignedFlag_) != 0;
        self.error = (messageId & self._ErrorFlag_) != 0;
        self.second = message[3] | message[4] << 8 |\
                      message[5] << 16 | message[6] << 24;
        self.counter = message[7]
        self.data = message[8:self._MessageLength_].view(dtype=np.int16)\
                    .reshape((self._NumSamples_,self._NumChannels_))

def fromfile(name):
    data = np.fromfile(name,dtype=np.uint8)
    return frombuffer(data)

def frombuffer(data):
    frames = []
    for i in range(0,len(data),TunaDataFrame._MessageLength_):
        message = data[i:]
        if len(message) < TunaDataFrame._MessageLength_:
            break
        frames.append(TunaDataFrame(message))
    return frames

def timeline(frames,freq=200):
    mintime = min(frames,key=lambda x:x.second).second
    maxtime = max(frames,key=lambda x:x.second).second
    ids = np.unique((f.id for f in frames))
    channelmap = dict(((x,i) for i,x in enumerate(ids)))
    nsamples = (maxtime - mintime + 1) * freq
    adc = np.full((nsamples,len(ids),TunaDataFrame._NumChannels_),np.NaN)
    state = np.full((nsamples // 4,len(ids),7),np.NaN)
    for frame in frames:
        i = channelmap[frame.id]
        t = (frame.second - mintime) * freq + frame.counter
        adc[t:t+TunaDataFrame._NumSamples_,i,:] = frame.data
        state[t//4,i,:] = [frame.id,
                          frame.sync,
                          frame.button,
                          frame.aligned,
                          frame.error,
                          frame.second,
                          frame.counter]
    return adc, state, channelmap
<commit_msg>Updated analysis script for forward numpy compatibility.<commit_after># -*- coding: utf-8 -*-
"""
Created on Thu Apr 28 00:52:42 2016

@author: Gonçalo
"""

import numpy as np

class TunaDataFrame:
    _IdMask_ = 0x0FFF
    _SyncFlag_ = 0x8000
    _ButtonFlag_ = 0x4000
    _AlignedFlag_ = 0x2000
    _ErrorFlag_ = 0x1000
    _MessageLength_ = 80
    _NumSamples_ = 4
    _NumChannels_ = 9

    def __init__(self, message):
        messageId = message[1] | message[2] << 8
        self.id = messageId & self._IdMask_
        self.sync = (messageId & self._SyncFlag_) != 0;
        self.button = (messageId & self._ButtonFlag_) != 0;
        self.aligned = (messageId & self._AlignedFlag_) != 0;
        self.error = (messageId & self._ErrorFlag_) != 0;
        self.second = message[3] | message[4] << 8 |\
                      message[5] << 16 | message[6] << 24;
        self.counter = message[7]
        self.data = message[8:self._MessageLength_].view(dtype=np.int16)\
                    .reshape((self._NumSamples_,self._NumChannels_))

def fromfile(name):
    data = np.fromfile(name,dtype=np.uint8)
    return frombuffer(data)

def frombuffer(data):
    frames = []
    for i in range(0,len(data),TunaDataFrame._MessageLength_):
        message = data[i:]
        if len(message) < TunaDataFrame._MessageLength_:
            break
        frames.append(TunaDataFrame(message))
    return frames

def timeline(frames,freq=200):
    mintime = min(frames,key=lambda x:x.second).second
    maxtime = max(frames,key=lambda x:x.second).second
    ids = np.unique([f.id for f in frames])
    channelmap = dict(((x,i) for i,x in enumerate(ids)))
    nsamples = (maxtime - mintime + 1) * freq
    adc = np.full((nsamples,len(ids),TunaDataFrame._NumChannels_),np.NaN)
    state = np.full((nsamples // 4,len(ids),7),np.NaN)
    for frame in frames:
        i = channelmap[frame.id]
        t = (frame.second - mintime) * freq + frame.counter
        adc[t:t+TunaDataFrame._NumSamples_,i,:] = frame.data
        state[t//4,i,:] = [frame.id,
                          frame.sync,
                          frame.button,
                          frame.aligned,
                          frame.error,
                          frame.second,
                          frame.counter]
    return adc, state, channelmap
<|endoftext|>


<commit_before>"""
Helper functions for creating Form classes from Django models
and database field objects.
"""

from warnings import warn

from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode
from django.utils.datastructures import SortedDict
from django.core.exceptions import ImproperlyConfigured

from util import ValidationError, ErrorList
from forms import BaseForm
from fields import Field, ChoiceField, EMPTY_VALUES
from widgets import Select, SelectMultiple, MultipleHiddenInput

__all__ = (
    'ModelForm', 'BaseModelForm', 'model_to_dict', 'fields_for_model',
    'save_instance', 'form_for_model', 'form_for_instance', 'form_for_fields',
    'ModelChoiceField', 'ModelMultipleChoiceField'
)

def save_instance(form, instance, fields=None, fail_message='saved',
                  commit=True):
    """
    Saves bound Form ``form``'s cleaned_data into model instance ``instance``.

    If commit=True, then the changes to ``instance`` will be saved to the
    database. Returns ``instance``.
    """
    from django.db import models
    opts = instance.__class__._meta
    if form.errors:
        raise ValueError("The %s could not be %s because the data didn't"
                         " validate." % (opts.object_name, fail_message))
    cleaned_data = form.cleaned_data
    for f in opts.fields:
        if not f.editable or isinstance(f, models.AutoField) \
                or not f.name in cleaned_data:
            continue
        if fields and f.name not in fields:
            continue
        f.save_form_data(instance, cleaned_data[f.name])
    # Wrap up the saving of m2m data as a function.
    def save_m2m():
        opts = instance.__class__._meta
        cleaned_data = form.cleaned_data
        for f in opts.many_to_many:
            if fields and f.name not in fields:
                continue
            if f.name in cleaned_data:
                f.save_form_data(instance, cleaned_data[f.name])
    if commit:
        # If we are committing, save the instance and the m2m data immediately.
        instance.save()
        save_m2m()
    else:
        # We're not committing. Add a method to the form to allow deferred
        # saving of m2m data.
        form.save_m2m = save_m2m
    return instance

def make_model_save(model, fields, fail_message):
    """Returns the save() method for a Form."""
    def save(self, commit=True):
        return save_instance(self, model(), fields, fail_message, commit)
    return save

def make_instance_save(instance, fields, fail_message):
    """Returns the save() method for a Form."""
    def save(self, commit=True):
        return save_instance(self, instance, fields, fail_message, commit)
    return save

def form_for_model(model, form=BaseForm, fields=None,
                   formfield_callback=lambda f: f.formfield()):
    """
    Returns a Form class for the given Django model class.

    Provide ``form`` if you want to use a custom BaseForm subclass.

    Provide ``formfield_callback`` if you want to define different logic for
    determining the formfield for a given database field. It's a callable that
    takes a database Field instance and returns a form Field instance.
    """
    warn("form_for_model is deprecated, use ModelForm instead.",
        PendingDeprecationWarning,
        stacklevel=3)
    opts = model._meta
    field_list = []
    for f in opts.fields + opts.many_to_many:
        if not f.editable:
            continue
        if fields and not f.name in fields:
            continue
        formfield = formfield_callback(f)
        if formfield:
            field_list.append((f.name, formfield))
    base_fields = SortedDict(field_list)
    return type(opts.object_name + 'Form', (form,),
        {'base_fields': base_fields, '_model': model,
         'save': make_model_save(model, fields, 'created')})

def form_for_instance(instance, form=BaseForm, fields=None,
                      formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):
    """
    Returns a Form class for the given Django model instance.

    Provide ``form`` if you want to use a custom BaseForm subclass.

    Provide ``formfield_callback`` if you want to define different logic for
    determining the formfield for a given database field. It's a callable that
    takes a database Field instance, plus **kwargs, and returns a form Field
    instance with the given kwargs (i.e. 'initial').
    """
    warn("form_for_instance is deprecated, use ModelForm instead.",
        PendingDeprecationWarning,
        stacklevel=3)
    model = instance.__class__
    opts = model._meta
    field_list = []
    for f in opts.fields + opts.many_to_many:
        if not f.editable:
            continue
        if fields and not f.name in fields:
            continue
        current_value = f.value_from_object(instance)
        formfield = formfield_callback(f, initial=current_value)
        if formfield:
            field_list.append((f.name, formfield))
    base_fields = SortedDict(field_list)
    return type(opts.object_name + 'InstanceForm', (form,),
        {'base_fields': base_fields, '_model': model,
         'save': make_instance_save(instance, fields, 'changed')})

def form_for_fields(field_list):
    """
    Returns a Form class for the given list of Django database field instances.
    """
    fields = SortedDict([(f.name, f.formfield())
                         for f in field_list if f.editable])
    return type('FormForFields', (BaseForm,), {'base_fields': fields})

# ModelForms #################################################################

def model_to_dict(instance, fields=None, exclude=None):
    """
    Returns a dict containing the data in ``instance`` suitable for passing as
    a Form's ``initial`` keyword argument.

    ``fields`` is an optional list of field names. If provided, only the named
    fields will be included in the returned dict.

    ``exclude`` is an optional list of field names. If provided, the named
    fields will be excluded from the returned dict, even if they are listed in
    the ``fields`` argument.
    """
    # avoid a circular import
    from django.db.models.fields.related import ManyToManyField
    opts = instance._meta
    data = {}
    for f in opts.fields + opts.many_to_many:
        if not f.editable:
            continue
        if fields and not f.name in fields:
            continue
        if exclude and f.name in exclude:
            continue
        if isinstance(f, ManyToManyField):
            # If the object doesn't have a primry key yet, just use an empty
            # list for its m2m fields. Calling f.value_from_object will raise
            # an exception.
            if instance.pk is None:
                data[f.name] = []
            else:
                # MultipleChoiceWidget needs a list of pks, not object instances.
                data[f.name] = [obj.pk for obj in f.value_from_object(instance)]
        else:
            data[f.name] = f.value_from_object(instance)
    return data

def fields_for_model(model, fields=None, exclude=None, formfield_callback=lambda f: f.formfield()):
    """
    Returns a ``SortedDict`` containing form fields for the given model.

    ``fields`` is an optional list of field names. If provided, only the named
    fields will be included in the returned fields.

    ``exclude`` is an optional list of field names. If provided, the named
    fields will be excluded from the returned fields, even if they are listed
    in the ``fields`` argument.
    """
    # TODO: if fields is provided, it would be nice to return fields in that order
    field_list = []
    opts = model._meta
    for f in opts.fields + opts.many_to_many:
        if not f.editable:
            continue
        if fields and not f.name in fields:
            continue
        if exclude and f.name in exclude:
            continue
        formfield = formfield_callback(f)
        if formfield:
            field_list.append((f.name, formfield))
    return SortedDict(field_list)

class ModelFormOptions(object):
    def __init__(self, options=None):
        self.model = getattr(options, 'model', None)
        self.fields = getattr(options, 'fields', None)
        self.exclude = getattr(options, 'exclude', None)

class ModelFormMetaclass(type):
    def __new__(cls, name, bases, attrs):
        # TODO: no way to specify formfield_callback yet, do we need one, or
        # should it be a special case for the admin?
        fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
        fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))

        # If this class is subclassing another Form, add that Form's fields.
        # Note that we loop over the bases in *reverse*. This is necessary in
        # order to preserve the correct order of fields.
        for base in bases[::-1]:
            if hasattr(base, 'base_fields'):
                fields = base.base_fields.items() + fields
        declared_fields = SortedDict(fields)

        opts = ModelFormOptions(attrs.get('Meta', None))
        attrs['_meta'] = opts

        # Don't allow more than one Meta model defenition in bases. The fields
        # would be generated correctly, but the save method won't deal with
        # more than one object.
        base_models = []
        for base in bases:
            base_opts = getattr(base, '_meta', None)
            base_model = getattr(base_opts, 'model', None)
            if base_model is not None:
                base_models.append(base_model)
        if len(base_models) > 1:
            raise ImproperlyConfigured("%s's base classes define more than one model." % name)

        # If a model is defined, extract form fields from it and add them to base_fields
        if attrs['_meta'].model is not None:
            # Don't allow a subclass to define a different Meta model than a
            # parent class has. Technically the right fields would be generated,
            # but the save method will not deal with more than one model.
            for base in bases:
                base_opts = getattr(base, '_meta', None)
                base_model = getattr(base_opts, 'model', None)
                if base_model and base_model is not opts.model:
                    raise ImproperlyConfigured('%s defines a different model than its parent.' % name)
            model_fields = fields_for_model(opts.model, opts.fields, opts.exclude)
            # fields declared in base classes override fields from the model
            model_fields.update(declared_fields)
            attrs['base_fields'] = model_fields
        else:
            attrs['base_fields'] = declared_fields
        return type.__new__(cls, name, bases, attrs)

class BaseModelForm(BaseForm):
    def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
                 initial=None, error_class=ErrorList, label_suffix=':', instance=None):
        opts = self._meta
        if instance is None:
            # if we didn't get an instance, instantiate a new one
            self.instance = opts.model()
            object_data = {}
        else:
            self.instance = instance
            object_data = model_to_dict(instance, opts.fields, opts.exclude)
        # if initial was provided, it should override the values from instance
        if initial is not None:
            object_data.update(initial)
        BaseForm.__init__(self, data, files, auto_id, prefix, object_data, error_class, label_suffix)

    def save(self, commit=True):
        """
        Saves this ``form``'s cleaned_data into model instance ``self.instance``.

        If commit=True, then the changes to ``instance`` will be saved to the
        database. Returns ``instance``.
        """
        if self.instance.pk is None:
            fail_message = 'created'
        else:
            fail_message = 'changed'
        return save_instance(self, self.instance, self._meta.fields, fail_message, commit)

class ModelForm(BaseModelForm):
    __metaclass__ = ModelFormMetaclass

# Fields #####################################################################

class QuerySetIterator(object):
    def __init__(self, queryset, empty_label, cache_choices):
        self.queryset = queryset
        self.empty_label = empty_label
        self.cache_choices = cache_choices

    def __iter__(self):
        if self.empty_label is not None:
            yield (u"", self.empty_label)
        for obj in self.queryset:
            yield (obj.pk, smart_unicode(obj))
        # Clear the QuerySet cache if required.
        if not self.cache_choices:
            self.queryset._result_cache = None

class ModelChoiceField(ChoiceField):
    """A ChoiceField whose choices are a model QuerySet."""
    # This class is a subclass of ChoiceField for purity, but it doesn't
    # actually use any of ChoiceField's implementation.
    default_error_messages = {
        'invalid_choice': _(u'Select a valid choice. That choice is not one of'
                            u' the available choices.'),
    }

    def __init__(self, queryset, empty_label=u"---------", cache_choices=False,
                 required=True, widget=Select, label=None, initial=None,
                 help_text=None, *args, **kwargs):
        self.empty_label = empty_label
        self.cache_choices = cache_choices
        # Call Field instead of ChoiceField __init__() because we don't need
        # ChoiceField.__init__().
        Field.__init__(self, required, widget, label, initial, help_text,
                       *args, **kwargs)
        self.queryset = queryset

    def _get_queryset(self):
        return self._queryset

    def _set_queryset(self, queryset):
        self._queryset = queryset
        self.widget.choices = self.choices

    queryset = property(_get_queryset, _set_queryset)

    def _get_choices(self):
        # If self._choices is set, then somebody must have manually set
        # the property self.choices. In this case, just return self._choices.
        if hasattr(self, '_choices'):
            return self._choices
        # Otherwise, execute the QuerySet in self.queryset to determine the
        # choices dynamically. Return a fresh QuerySetIterator that has not
        # been consumed. Note that we're instantiating a new QuerySetIterator
        # *each* time _get_choices() is called (and, thus, each time
        # self.choices is accessed) so that we can ensure the QuerySet has not
        # been consumed.
        return QuerySetIterator(self.queryset, self.empty_label,
                                self.cache_choices)

    def _set_choices(self, value):
        # This method is copied from ChoiceField._set_choices(). It's necessary
        # because property() doesn't allow a subclass to overwrite only
        # _get_choices without implementing _set_choices.
        self._choices = self.widget.choices = list(value)

    choices = property(_get_choices, _set_choices)

    def clean(self, value):
        Field.clean(self, value)
        if value in EMPTY_VALUES:
            return None
        try:
            value = self.queryset.get(pk=value)
        except self.queryset.model.DoesNotExist:
            raise ValidationError(self.error_messages['invalid_choice'])
        return value

class ModelMultipleChoiceField(ModelChoiceField):
    """A MultipleChoiceField whose choices are a model QuerySet."""
    hidden_widget = MultipleHiddenInput
    default_error_messages = {
        'list': _(u'Enter a list of values.'),
        'invalid_choice': _(u'Select a valid choice. %s is not one of the'
                            u' available choices.'),
    }

    def __init__(self, queryset, cache_choices=False, required=True,
                 widget=SelectMultiple, label=None, initial=None,
                 help_text=None, *args, **kwargs):
        super(ModelMultipleChoiceField, self).__init__(queryset, None,
            cache_choices, required, widget, label, initial, help_text,
            *args, **kwargs)

    def clean(self, value):
        if self.required and not value:
            raise ValidationError(self.error_messages['required'])
        elif not self.required and not value:
            return []
        if not isinstance(value, (list, tuple)):
            raise ValidationError(self.error_messages['list'])
        final_values = []
        for val in value:
            try:
                obj = self.queryset.get(pk=val)
            except self.queryset.model.DoesNotExist:
                raise ValidationError(self.error_messages['invalid_choice'] % val)
            else:
                final_values.append(obj)
        return final_values
<commit_msg>Fixed #6197 -- Added (optional) formfield_callback argument to ModelForms.__new__. Patch from guido@python.org.<commit_after>"""
Helper functions for creating Form classes from Django models
and database field objects.
"""

from warnings import warn

from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode
from django.utils.datastructures import SortedDict
from django.core.exceptions import ImproperlyConfigured

from util import ValidationError, ErrorList
from forms import BaseForm
from fields import Field, ChoiceField, EMPTY_VALUES
from widgets import Select, SelectMultiple, MultipleHiddenInput

__all__ = (
    'ModelForm', 'BaseModelForm', 'model_to_dict', 'fields_for_model',
    'save_instance', 'form_for_model', 'form_for_instance', 'form_for_fields',
    'ModelChoiceField', 'ModelMultipleChoiceField'
)

def save_instance(form, instance, fields=None, fail_message='saved',
                  commit=True):
    """
    Saves bound Form ``form``'s cleaned_data into model instance ``instance``.

    If commit=True, then the changes to ``instance`` will be saved to the
    database. Returns ``instance``.
    """
    from django.db import models
    opts = instance.__class__._meta
    if form.errors:
        raise ValueError("The %s could not be %s because the data didn't"
                         " validate." % (opts.object_name, fail_message))
    cleaned_data = form.cleaned_data
    for f in opts.fields:
        if not f.editable or isinstance(f, models.AutoField) \
                or not f.name in cleaned_data:
            continue
        if fields and f.name not in fields:
            continue
        f.save_form_data(instance, cleaned_data[f.name])
    # Wrap up the saving of m2m data as a function.
    def save_m2m():
        opts = instance.__class__._meta
        cleaned_data = form.cleaned_data
        for f in opts.many_to_many:
            if fields and f.name not in fields:
                continue
            if f.name in cleaned_data:
                f.save_form_data(instance, cleaned_data[f.name])
    if commit:
        # If we are committing, save the instance and the m2m data immediately.
        instance.save()
        save_m2m()
    else:
        # We're not committing. Add a method to the form to allow deferred
        # saving of m2m data.
        form.save_m2m = save_m2m
    return instance

def make_model_save(model, fields, fail_message):
    """Returns the save() method for a Form."""
    def save(self, commit=True):
        return save_instance(self, model(), fields, fail_message, commit)
    return save

def make_instance_save(instance, fields, fail_message):
    """Returns the save() method for a Form."""
    def save(self, commit=True):
        return save_instance(self, instance, fields, fail_message, commit)
    return save

def form_for_model(model, form=BaseForm, fields=None,
                   formfield_callback=lambda f: f.formfield()):
    """
    Returns a Form class for the given Django model class.

    Provide ``form`` if you want to use a custom BaseForm subclass.

    Provide ``formfield_callback`` if you want to define different logic for
    determining the formfield for a given database field. It's a callable that
    takes a database Field instance and returns a form Field instance.
    """
    warn("form_for_model is deprecated, use ModelForm instead.",
        PendingDeprecationWarning,
        stacklevel=3)
    opts = model._meta
    field_list = []
    for f in opts.fields + opts.many_to_many:
        if not f.editable:
            continue
        if fields and not f.name in fields:
            continue
        formfield = formfield_callback(f)
        if formfield:
            field_list.append((f.name, formfield))
    base_fields = SortedDict(field_list)
    return type(opts.object_name + 'Form', (form,),
        {'base_fields': base_fields, '_model': model,
         'save': make_model_save(model, fields, 'created')})

def form_for_instance(instance, form=BaseForm, fields=None,
                      formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):
    """
    Returns a Form class for the given Django model instance.

    Provide ``form`` if you want to use a custom BaseForm subclass.

    Provide ``formfield_callback`` if you want to define different logic for
    determining the formfield for a given database field. It's a callable that
    takes a database Field instance, plus **kwargs, and returns a form Field
    instance with the given kwargs (i.e. 'initial').
    """
    warn("form_for_instance is deprecated, use ModelForm instead.",
        PendingDeprecationWarning,
        stacklevel=3)
    model = instance.__class__
    opts = model._meta
    field_list = []
    for f in opts.fields + opts.many_to_many:
        if not f.editable:
            continue
        if fields and not f.name in fields:
            continue
        current_value = f.value_from_object(instance)
        formfield = formfield_callback(f, initial=current_value)
        if formfield:
            field_list.append((f.name, formfield))
    base_fields = SortedDict(field_list)
    return type(opts.object_name + 'InstanceForm', (form,),
        {'base_fields': base_fields, '_model': model,
         'save': make_instance_save(instance, fields, 'changed')})

def form_for_fields(field_list):
    """
    Returns a Form class for the given list of Django database field instances.
    """
    fields = SortedDict([(f.name, f.formfield())
                         for f in field_list if f.editable])
    return type('FormForFields', (BaseForm,), {'base_fields': fields})

# ModelForms #################################################################

def model_to_dict(instance, fields=None, exclude=None):
    """
    Returns a dict containing the data in ``instance`` suitable for passing as
    a Form's ``initial`` keyword argument.

    ``fields`` is an optional list of field names. If provided, only the named
    fields will be included in the returned dict.

    ``exclude`` is an optional list of field names. If provided, the named
    fields will be excluded from the returned dict, even if they are listed in
    the ``fields`` argument.
    """
    # avoid a circular import
    from django.db.models.fields.related import ManyToManyField
    opts = instance._meta
    data = {}
    for f in opts.fields + opts.many_to_many:
        if not f.editable:
            continue
        if fields and not f.name in fields:
            continue
        if exclude and f.name in exclude:
            continue
        if isinstance(f, ManyToManyField):
            # If the object doesn't have a primry key yet, just use an empty
            # list for its m2m fields. Calling f.value_from_object will raise
            # an exception.
            if instance.pk is None:
                data[f.name] = []
            else:
                # MultipleChoiceWidget needs a list of pks, not object instances.
                data[f.name] = [obj.pk for obj in f.value_from_object(instance)]
        else:
            data[f.name] = f.value_from_object(instance)
    return data

def fields_for_model(model, fields=None, exclude=None, formfield_callback=lambda f: f.formfield()):
    """
    Returns a ``SortedDict`` containing form fields for the given model.

    ``fields`` is an optional list of field names. If provided, only the named
    fields will be included in the returned fields.

    ``exclude`` is an optional list of field names. If provided, the named
    fields will be excluded from the returned fields, even if they are listed
    in the ``fields`` argument.
    """
    # TODO: if fields is provided, it would be nice to return fields in that order
    field_list = []
    opts = model._meta
    for f in opts.fields + opts.many_to_many:
        if not f.editable:
            continue
        if fields and not f.name in fields:
            continue
        if exclude and f.name in exclude:
            continue
        formfield = formfield_callback(f)
        if formfield:
            field_list.append((f.name, formfield))
    return SortedDict(field_list)

class ModelFormOptions(object):
    def __init__(self, options=None):
        self.model = getattr(options, 'model', None)
        self.fields = getattr(options, 'fields', None)
        self.exclude = getattr(options, 'exclude', None)

class ModelFormMetaclass(type):
    def __new__(cls, name, bases, attrs,
                formfield_callback=lambda f: f.formfield()):
        fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
        fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))

        # If this class is subclassing another Form, add that Form's fields.
        # Note that we loop over the bases in *reverse*. This is necessary in
        # order to preserve the correct order of fields.
        for base in bases[::-1]:
            if hasattr(base, 'base_fields'):
                fields = base.base_fields.items() + fields
        declared_fields = SortedDict(fields)

        opts = ModelFormOptions(attrs.get('Meta', None))
        attrs['_meta'] = opts

        # Don't allow more than one Meta model defenition in bases. The fields
        # would be generated correctly, but the save method won't deal with
        # more than one object.
        base_models = []
        for base in bases:
            base_opts = getattr(base, '_meta', None)
            base_model = getattr(base_opts, 'model', None)
            if base_model is not None:
                base_models.append(base_model)
        if len(base_models) > 1:
            raise ImproperlyConfigured("%s's base classes define more than one model." % name)

        # If a model is defined, extract form fields from it and add them to base_fields
        if attrs['_meta'].model is not None:
            # Don't allow a subclass to define a different Meta model than a
            # parent class has. Technically the right fields would be generated,
            # but the save method will not deal with more than one model.
            for base in bases:
                base_opts = getattr(base, '_meta', None)
                base_model = getattr(base_opts, 'model', None)
                if base_model and base_model is not opts.model:
                    raise ImproperlyConfigured('%s defines a different model than its parent.' % name)
            model_fields = fields_for_model(opts.model, opts.fields,
                    opts.exclude, formfield_callback)
            # fields declared in base classes override fields from the model
            model_fields.update(declared_fields)
            attrs['base_fields'] = model_fields
        else:
            attrs['base_fields'] = declared_fields
        return type.__new__(cls, name, bases, attrs)

class BaseModelForm(BaseForm):
    def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
                 initial=None, error_class=ErrorList, label_suffix=':', instance=None):
        opts = self._meta
        if instance is None:
            # if we didn't get an instance, instantiate a new one
            self.instance = opts.model()
            object_data = {}
        else:
            self.instance = instance
            object_data = model_to_dict(instance, opts.fields, opts.exclude)
        # if initial was provided, it should override the values from instance
        if initial is not None:
            object_data.update(initial)
        BaseForm.__init__(self, data, files, auto_id, prefix, object_data, error_class, label_suffix)

    def save(self, commit=True):
        """
        Saves this ``form``'s cleaned_data into model instance ``self.instance``.

        If commit=True, then the changes to ``instance`` will be saved to the
        database. Returns ``instance``.
        """
        if self.instance.pk is None:
            fail_message = 'created'
        else:
            fail_message = 'changed'
        return save_instance(self, self.instance, self._meta.fields, fail_message, commit)

class ModelForm(BaseModelForm):
    __metaclass__ = ModelFormMetaclass

# Fields #####################################################################

class QuerySetIterator(object):
    def __init__(self, queryset, empty_label, cache_choices):
        self.queryset = queryset
        self.empty_label = empty_label
        self.cache_choices = cache_choices

    def __iter__(self):
        if self.empty_label is not None:
            yield (u"", self.empty_label)
        for obj in self.queryset:
            yield (obj.pk, smart_unicode(obj))
        # Clear the QuerySet cache if required.
        if not self.cache_choices:
            self.queryset._result_cache = None

class ModelChoiceField(ChoiceField):
    """A ChoiceField whose choices are a model QuerySet."""
    # This class is a subclass of ChoiceField for purity, but it doesn't
    # actually use any of ChoiceField's implementation.
    default_error_messages = {
        'invalid_choice': _(u'Select a valid choice. That choice is not one of'
                            u' the available choices.'),
    }

    def __init__(self, queryset, empty_label=u"---------", cache_choices=False,
                 required=True, widget=Select, label=None, initial=None,
                 help_text=None, *args, **kwargs):
        self.empty_label = empty_label
        self.cache_choices = cache_choices
        # Call Field instead of ChoiceField __init__() because we don't need
        # ChoiceField.__init__().
        Field.__init__(self, required, widget, label, initial, help_text,
                       *args, **kwargs)
        self.queryset = queryset

    def _get_queryset(self):
        return self._queryset

    def _set_queryset(self, queryset):
        self._queryset = queryset
        self.widget.choices = self.choices

    queryset = property(_get_queryset, _set_queryset)

    def _get_choices(self):
        # If self._choices is set, then somebody must have manually set
        # the property self.choices. In this case, just return self._choices.
        if hasattr(self, '_choices'):
            return self._choices
        # Otherwise, execute the QuerySet in self.queryset to determine the
        # choices dynamically. Return a fresh QuerySetIterator that has not
        # been consumed. Note that we're instantiating a new QuerySetIterator
        # *each* time _get_choices() is called (and, thus, each time
        # self.choices is accessed) so that we can ensure the QuerySet has not
        # been consumed.
        return QuerySetIterator(self.queryset, self.empty_label,
                                self.cache_choices)

    def _set_choices(self, value):
        # This method is copied from ChoiceField._set_choices(). It's necessary
        # because property() doesn't allow a subclass to overwrite only
        # _get_choices without implementing _set_choices.
        self._choices = self.widget.choices = list(value)

    choices = property(_get_choices, _set_choices)

    def clean(self, value):
        Field.clean(self, value)
        if value in EMPTY_VALUES:
            return None
        try:
            value = self.queryset.get(pk=value)
        except self.queryset.model.DoesNotExist:
            raise ValidationError(self.error_messages['invalid_choice'])
        return value

class ModelMultipleChoiceField(ModelChoiceField):
    """A MultipleChoiceField whose choices are a model QuerySet."""
    hidden_widget = MultipleHiddenInput
    default_error_messages = {
        'list': _(u'Enter a list of values.'),
        'invalid_choice': _(u'Select a valid choice. %s is not one of the'
                            u' available choices.'),
    }

    def __init__(self, queryset, cache_choices=False, required=True,
                 widget=SelectMultiple, label=None, initial=None,
                 help_text=None, *args, **kwargs):
        super(ModelMultipleChoiceField, self).__init__(queryset, None,
            cache_choices, required, widget, label, initial, help_text,
            *args, **kwargs)

    def clean(self, value):
        if self.required and not value:
            raise ValidationError(self.error_messages['required'])
        elif not self.required and not value:
            return []
        if not isinstance(value, (list, tuple)):
            raise ValidationError(self.error_messages['list'])
        final_values = []
        for val in value:
            try:
                obj = self.queryset.get(pk=val)
            except self.queryset.model.DoesNotExist:
                raise ValidationError(self.error_messages['invalid_choice'] % val)
            else:
                final_values.append(obj)
        return final_values
<|endoftext|>


<commit_before>"""
Copyright 2015 Zalando SE

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
 language governing permissions and limitations under the License.
"""

from typing import Optional, List
from clickclick import warning
from urlpath import URL
import json
import requests
import time

FINAL_STATES = ["CF:CREATE_COMPLETE",
                "CF:CREATE_FAILED",
                "CF:DELETE_COMPLETE",
                "CF:DELETE_FAILED",
                "CF:DELETE_IN_PROGRESS"
                "CF:ROLLBACK_COMPLETE",
                "CF:ROLLBACK_FAILED",
                "CF:ROLLBACK_IN_PROGRESS",
                "LIZZY:ERROR",
                "LIZZY:REMOVED"]

TARGET_VERSION = '2016-01-14'

def make_header(access_token: str):
    headers = dict()
    headers['Authorization'] = 'Bearer {}'.format(access_token)
    headers['Content-type'] = 'application/json'
    return headers

class Lizzy:
    def __init__(self, base_url: str, access_token: str):
        self.base_url = URL(base_url)
        self.access_token = access_token

    @property
    def stacks_url(self) -> URL:
        return self.base_url / 'stacks'

    def delete(self, stack_id: str):
        url = self.stacks_url / stack_id

        header = make_header(self.access_token)
        request = url.delete(headers=header, verify=False)
        lizzy_version = request.headers.get('X-Lizzy-Version')
        if lizzy_version and lizzy_version != TARGET_VERSION:
            warning("Version Mismatch (Client: {}, Server: {})".format(TARGET_VERSION, lizzy_version))
        request.raise_for_status()

    def get_stack(self, stack_id: str) -> dict:
        header = make_header(self.access_token)
        url = self.stacks_url / stack_id
        request = url.get(headers=header, verify=False)
        lizzy_version = request.headers.get('X-Lizzy-Version')
        if lizzy_version and lizzy_version != TARGET_VERSION:
            warning("Version Mismatch (Client: {}, Server: {})".format(TARGET_VERSION, lizzy_version))
        request.raise_for_status()
        return request.json()

    def get_stacks(self) -> list:
        header = make_header(self.access_token)
        request = self.stacks_url.get(headers=header, verify=False)
        lizzy_version = request.headers.get('X-Lizzy-Version')
        if lizzy_version and lizzy_version != TARGET_VERSION:
            warning("Version Mismatch (Client: {}, Server: {})".format(TARGET_VERSION, lizzy_version))
        request.raise_for_status()
        return request.json()

    def new_stack(self, image_version: str, keep_stacks: str, new_traffic: int, senza_yaml_path: str,
                  application_version: Optional[str], parameters: List[str]) -> str:
        header = make_header(self.access_token)

        with open(senza_yaml_path) as senza_yaml_file:
            senza_yaml = senza_yaml_file.read()

        data = {'image_version': image_version,
                'keep_stacks': keep_stacks,
                'new_traffic': new_traffic,
                'parameters:': parameters,
                'senza_yaml': senza_yaml}

        if application_version:
            data['application_version'] = application_version

        request = self.stacks_url.post(data=json.dumps(data), headers=header, verify=False)
        lizzy_version = request.headers.get('X-Lizzy-Version')
        if lizzy_version and lizzy_version != TARGET_VERSION:
            warning("Version Mismatch (Client: {}, Server: {})".format(TARGET_VERSION, lizzy_version))
        request.raise_for_status()
        stack_info = request.json()
        return stack_info['stack_id']

    def traffic(self, stack_id: str, percentage: int):
        url = self.stacks_url / stack_id
        data = {"new_traffic": percentage}

        header = make_header(self.access_token)
        request = url.patch(data=json.dumps(data), headers=header, verify=False)
        lizzy_version = request.headers.get('X-Lizzy-Version')
        if lizzy_version and lizzy_version != TARGET_VERSION:
            warning("Version Mismatch (Client: {}, Server: {})".format(TARGET_VERSION, lizzy_version))
        try:
            request.raise_for_status()
        except requests.RequestException:
            warning('Data Json:')
            print(json.dumps(data, indent=4))
            raise

    def wait_for_deployment(self, stack_id: str) -> [str]:
        retries = 3
        while retries:
            try:
                stack = self.get_stack(stack_id)
                status = stack["status"]
                retries = 3  # reset the number of retries
                yield status
                if status in FINAL_STATES:
                    return status
            except Exception as e:
                retries -= 1
                yield 'Failed to get stack ({retries} retries left): {exception}.'.format(retries=retries,
                                                                                exception=repr(e))

            time.sleep(10)
<commit_msg>zalando/lizzy#37 Send the parameters correctly<commit_after>"""
Copyright 2015 Zalando SE

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
 language governing permissions and limitations under the License.
"""

from typing import Optional, List
from clickclick import warning
from urlpath import URL
import json
import requests
import time

FINAL_STATES = ["CF:CREATE_COMPLETE",
                "CF:CREATE_FAILED",
                "CF:DELETE_COMPLETE",
                "CF:DELETE_FAILED",
                "CF:DELETE_IN_PROGRESS"
                "CF:ROLLBACK_COMPLETE",
                "CF:ROLLBACK_FAILED",
                "CF:ROLLBACK_IN_PROGRESS",
                "LIZZY:ERROR",
                "LIZZY:REMOVED"]

TARGET_VERSION = '2016-01-14'

def make_header(access_token: str):
    headers = dict()
    headers['Authorization'] = 'Bearer {}'.format(access_token)
    headers['Content-type'] = 'application/json'
    return headers

class Lizzy:
    def __init__(self, base_url: str, access_token: str):
        self.base_url = URL(base_url)
        self.access_token = access_token

    @property
    def stacks_url(self) -> URL:
        return self.base_url / 'stacks'

    def delete(self, stack_id: str):
        url = self.stacks_url / stack_id

        header = make_header(self.access_token)
        request = url.delete(headers=header, verify=False)
        lizzy_version = request.headers.get('X-Lizzy-Version')
        if lizzy_version and lizzy_version != TARGET_VERSION:
            warning("Version Mismatch (Client: {}, Server: {})".format(TARGET_VERSION, lizzy_version))
        request.raise_for_status()

    def get_stack(self, stack_id: str) -> dict:
        header = make_header(self.access_token)
        url = self.stacks_url / stack_id
        request = url.get(headers=header, verify=False)
        lizzy_version = request.headers.get('X-Lizzy-Version')
        if lizzy_version and lizzy_version != TARGET_VERSION:
            warning("Version Mismatch (Client: {}, Server: {})".format(TARGET_VERSION, lizzy_version))
        request.raise_for_status()
        return request.json()

    def get_stacks(self) -> list:
        header = make_header(self.access_token)
        request = self.stacks_url.get(headers=header, verify=False)
        lizzy_version = request.headers.get('X-Lizzy-Version')
        if lizzy_version and lizzy_version != TARGET_VERSION:
            warning("Version Mismatch (Client: {}, Server: {})".format(TARGET_VERSION, lizzy_version))
        request.raise_for_status()
        return request.json()

    def new_stack(self, image_version: str, keep_stacks: str, new_traffic: int, senza_yaml_path: str,
                  application_version: Optional[str], parameters: List[str]) -> str:
        header = make_header(self.access_token)

        with open(senza_yaml_path) as senza_yaml_file:
            senza_yaml = senza_yaml_file.read()

        data = {'image_version': image_version,
                'keep_stacks': keep_stacks,
                'new_traffic': new_traffic,
                'parameters': parameters,
                'senza_yaml': senza_yaml}

        if application_version:
            data['application_version'] = application_version

        request = self.stacks_url.post(data=json.dumps(data), headers=header, verify=False)
        lizzy_version = request.headers.get('X-Lizzy-Version')
        if lizzy_version and lizzy_version != TARGET_VERSION:
            warning("Version Mismatch (Client: {}, Server: {})".format(TARGET_VERSION, lizzy_version))
        request.raise_for_status()
        stack_info = request.json()
        return stack_info['stack_id']

    def traffic(self, stack_id: str, percentage: int):
        url = self.stacks_url / stack_id
        data = {"new_traffic": percentage}

        header = make_header(self.access_token)
        request = url.patch(data=json.dumps(data), headers=header, verify=False)
        lizzy_version = request.headers.get('X-Lizzy-Version')
        if lizzy_version and lizzy_version != TARGET_VERSION:
            warning("Version Mismatch (Client: {}, Server: {})".format(TARGET_VERSION, lizzy_version))
        try:
            request.raise_for_status()
        except requests.RequestException:
            warning('Data Json:')
            print(json.dumps(data, indent=4))
            raise

    def wait_for_deployment(self, stack_id: str) -> [str]:
        retries = 3
        while retries:
            try:
                stack = self.get_stack(stack_id)
                status = stack["status"]
                retries = 3  # reset the number of retries
                yield status
                if status in FINAL_STATES:
                    return status
            except Exception as e:
                retries -= 1
                yield 'Failed to get stack ({retries} retries left): {exception}.'.format(retries=retries,
                                                                                exception=repr(e))

            time.sleep(10)
<|endoftext|>