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

from appscript import app, k, its, CommandError
from AppKit import NSApplication, NSApplicationDefined, NSBeep, NSSystemDefined, NSURL, NSWorkspace
from Foundation import NSDistributedNotificationCenter, NSSearchPathForDirectoriesInDomains, NSCachesDirectory, NSUserDomainMask
from PyObjCTools import AppHelper
from Carbon.CarbonEvt import RegisterEventHotKey, GetApplicationEventTarget
from Carbon.Events import cmdKey, shiftKey, controlKey
import httplib2
import os
import struct
import scrape
import HotKey

GROWL_APP_NAME = 'StreamVision'
NOTIFICATION_TRACK_INFO = 'iTunes Track Info'
NOTIFICATIONS_ALL = [NOTIFICATION_TRACK_INFO]

kEventHotKeyPressedSubtype = 6
kEventHotKeyReleasedSubtype = 9

kHIDUsage_Csmr_ScanNextTrack = 0xB5
kHIDUsage_Csmr_ScanPreviousTrack = 0xB6
kHIDUsage_Csmr_PlayOrPause = 0xCD

def growlRegister():
    global growl
    growl = app(id='com.Growl.GrowlHelperApp')

    growl.register(
        as_application=GROWL_APP_NAME,
        all_notifications=NOTIFICATIONS_ALL,
        default_notifications=NOTIFICATIONS_ALL,
        icon_of_application='iTunes.app')
        # if we leave off the .app, we can get Classic iTunes's icon

def growlNotify(title, description, **kw):
    try:
        growl.notify(
            with_name=NOTIFICATION_TRACK_INFO,
            title=title,
            description=description,
            application_name=GROWL_APP_NAME,
            **kw)
    except CommandError:
        growlRegister()
        growlNotify(title, description, **kw)

def radioParadiseURL():
    # XXX better to use http://www2.radioparadise.com/playlist.xml ?
    session = scrape.Session()
    session.go('http://www2.radioparadise.com/nowplay_b.php')
    return session.region.firsttag('a')['href']

def cleanStreamTitle(title):
    if title == k.missing_value:
        return ''
    title = title.split(' [')[0] # XXX move to description
    try: # incorrectly encoded?
        title = title.encode('iso-8859-1').decode('utf-8')
    except (UnicodeDecodeError, UnicodeEncodeError):
        pass
    title = title.replace('`', u'’')
    return title

def cleanStreamTrackName(name):
    name = name.split('. ')[0]
    name = name.split(': ')[0]
    name = name.split(' - ')
    if len(name) > 1:
        name = ' - '.join(name[:-1])
    else:
        name = name[0]
    return name

def iTunesApp(): return app(id='com.apple.iTunes')
def XTensionApp(): return app(creator='SHEx')
def AmuaApp(): return app('Amua.app')

HAVE_XTENSION = False
try:
    XTensionApp()
    HAVE_XTENSION = True
except:
    pass

HAVE_AMUA = False
try:
    AmuaApp()
    HAVE_AMUA = True
except:
    pass

needsStereoPowerOn = HAVE_XTENSION

def mayUseStereo():
    if not HAVE_XTENSION:
        return False
    systemEvents = app(id='com.apple.systemEvents')
    iTunesWindow = systemEvents.application_processes[u'iTunes'].windows[u'iTunes']
    try:
        remote_speakers = iTunesWindow.buttons[its.attributes['AXDescription'].value.endswith(u'AirPlay')].title()
    except CommandError:
        # with iTunes Store visible, the query fails with errAENoSuchObject
        for button in iTunesWindow.buttons():
            try:
                if button.attributes['AXDescription'].value().endswith('remote speakers'):
                    remote_speakers = [button.title()]
                    break
            except CommandError:
                pass
    return (remote_speakers and remote_speakers[0] != k.missing_value)

def turnStereoOn():
    global needsStereoPowerOn
    if not mayUseStereo():
        if HAVE_XTENSION and XTensionApp().status('Stereo'):
            XTensionApp().turnoff('Stereo')
        return
    if not XTensionApp().status('Stereo'):
        XTensionApp().turnon('Stereo')
    needsStereoPowerOn = False

def turnStereoOff():
    global needsStereoPowerOn
    if not mayUseStereo():
        return
    if not needsStereoPowerOn and XTensionApp().status('Stereo'):
        XTensionApp().turnoff('Stereo')
    needsStereoPowerOn = True

def amuaPlaying():
    if not HAVE_AMUA:
        return False
    return AmuaApp().is_playing()

class OneFileCache(object):
    __slots__ = ('key', 'cache')

    def __init__(self, cache):
        if not os.path.exists(cache):
            os.makedirs(cache)
        self.cache = os.path.join(cache, 'file')
        self.key = None

    def get(self, key):
        if key == self.key:
            return file(self.cache, 'r').read()

    def set(self, key, value):
        self.key = key
        file(self.cache, 'w').write(value)

    def delete(self, key):
        if key == self.key:
            self.key = None
            os.remove(cache)

class StreamVision(NSApplication):

    hotKeyActions = {}
    hotKeys = []

    def displayTrackInfo(self, playerInfo=None):
        iTunes = iTunesApp()

        try:
            trackClass = iTunes.current_track.class_()
        except CommandError:
            trackClass = k.property

        trackName = ''
        if trackClass != k.property:
            trackName = iTunes.current_track.name()

        if iTunes.player_state() != k.playing:
            growlNotify('iTunes is not playing.', trackName)
            turnStereoOff()
            return
        turnStereoOn()
        if trackClass == k.URL_track:
            if amuaPlaying():
                if playerInfo is None: # Amua displays it itself
                    AmuaApp().display_song_information()
                return
            url = iTunes.current_stream_URL()
            kw = {}
            if url != k.missing_value and url.endswith('.jpg'):
                response, content = self.http.request(url)
                if response['content-type'].startswith('image/'):
                    file(self.imagePath, 'w').write(content)
                    kw['image_from_location'] = self.imagePath
            growlNotify(cleanStreamTitle(iTunes.current_stream_title()),
                        cleanStreamTrackName(trackName), **kw)
            return
        if trackClass == k.property:
            growlNotify('iTunes is playing.', '')
            return
        kw = {}
        # XXX iTunes doesn't let you get artwork for shared tracks
        if trackClass != k.shared_track:
            artwork = iTunes.current_track.artworks()
            if artwork:
                try:
                    kw['pictImage'] = artwork[0].data_()
                except CommandError:
                    pass
        growlNotify(trackName + '  ' +
                    u'★' * (iTunes.current_track.rating() / 20),
                    iTunes.current_track.album() + '\n' +
                    iTunes.current_track.artist(),
                    **kw)

    def goToSite(self):
        iTunes = iTunesApp()
        if iTunes.player_state() == k.playing:
            if amuaPlaying():
                AmuaApp().display_album_details()
                return
            url = iTunes.current_stream_URL()
            if url != k.missing_value:
                if 'radioparadise.com' in url and 'review' not in url:
                    url = radioParadiseURL()
                NSWorkspace.sharedWorkspace().openURL_(NSURL.URLWithString_(url))
                return
        NSBeep()

    def registerHotKey(self, func, keyCode, mods=0):
        hotKeyRef = RegisterEventHotKey(keyCode, mods, (0, 0),
                                        GetApplicationEventTarget(), 0)
        self.hotKeys.append(hotKeyRef)
        self.hotKeyActions[HotKey.HotKeyAddress(hotKeyRef)] = func
        return hotKeyRef

    def unregisterHotKey(self, hotKeyRef):
        self.hotKeys.remove(hotKeyRef)
        del self.hotKeyActions[HotKey.HotKeyAddress(hotKeyRef)]
        hotKeyRef.UnregisterEventHotKey()

    def incrementRatingBy(self, increment):
        iTunes = iTunesApp()
        if amuaPlaying():
            if increment < 0:
                AmuaApp().ban_song()
                growlNotify('Banned song.', '', icon_of_application='Amua.app')
            else:
                AmuaApp().love_song()
                growlNotify('Loved song.', '', icon_of_application='Amua.app')
            return
        rating = iTunes.current_track.rating()
        rating += increment
        if rating < 0:
            rating = 0
            NSBeep()
        elif rating > 100:
            rating = 100
            NSBeep()
        iTunes.current_track.rating.set(rating)

    def playPause(self, useStereo=True):
        global needsStereoPowerOn

        iTunes = iTunesApp()
        was_playing = (iTunes.player_state() == k.playing)
        if not useStereo:
            needsStereoPowerOn = False
        if was_playing and amuaPlaying():
            AmuaApp().stop()
        else:
            iTunes.playpause()
        if not was_playing and iTunes.player_state() == k.stopped:
            # most likely, we're focused on the iPod, so playing does nothing
            iTunes.browser_windows[1].view.set(iTunes.user_playlists[its.name=='Stations'][1]())
            iTunes.play()
        if not useStereo:
            return
        if iTunes.player_state() == k.playing:
            turnStereoOn()
        else:
            turnStereoOff()

    def playPauseFront(self):
        systemEvents = app(id='com.apple.systemEvents')
        frontName = systemEvents.processes[its.frontmost == True][1].name()
	if frontName == 'RealPlayer':
	    realPlayer = app(id='com.RealNetworks.RealPlayer')
	    if len(realPlayer.players()) > 0:
		if realPlayer.players[1].state() == k.playing:
		    realPlayer.pause()
		else:
		    realPlayer.play()
		return
	elif frontName == 'VLC':
	    app(id='org.videolan.vlc').play() # equivalent to playpause
	else:
	    self.playPause(useStereo=False)

    def nextTrack(self):
        if amuaPlaying():
            AmuaApp().skip_song()
            return
        iTunesApp().next_track()

    def registerZoomWindowHotKey(self):
        self.zoomWindowHotKey = self.registerHotKey(self.zoomWindow, 42, cmdKey | controlKey) # cmd-ctrl-\

    def unregisterZoomWindowHotKey(self):
        self.unregisterHotKey(self.zoomWindowHotKey)
        self.zoomWindowHotKey = None

    def zoomWindow(self):
        # XXX detect if "enable access for assistive devices" needs to be enabled
        systemEvents = app(id='com.apple.systemEvents')
        frontName = systemEvents.processes[its.frontmost == True][1].name()
        if frontName == 'iTunes':
            systemEvents.processes['iTunes'].menu_bars[1]. \
                menu_bar_items['Window'].menus.menu_items['Zoom'].click()
            return
        elif frontName in ('X11', 'XQuartz', 'Emacs'): # preserve C-M-\
            self.unregisterZoomWindowHotKey()
            systemEvents.key_code(42, using=[k.command_down, k.control_down])
            self.registerZoomWindowHotKey()
            return
        frontPID = systemEvents.processes[its.frontmost == True][1].unix_id()
        try:
            zoomed = app(pid=frontPID).windows[1].zoomed
            zoomed.set(not zoomed())
        except (CommandError, RuntimeError):
            systemEvents.processes[frontName].windows \
                [its.subrole == 'AXStandardWindow'].windows[1]. \
                buttons[its.subrole == 'AXZoomButton'].buttons[1].click()

    def finishLaunching(self):
        super(StreamVision, self).finishLaunching()

        caches = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
                                                     NSUserDomainMask, True)[0]
        cache = os.path.join(caches, 'StreamVision')
        self.http = httplib2.Http(OneFileCache(cache), 5)
        self.imagePath = os.path.join(cache, 'image')

        self.registerHotKey(self.displayTrackInfo, 100) # F8
        self.registerHotKey(self.goToSite, 100, cmdKey) # cmd-F8
        self.registerHotKey(self.playPause, 101) # F9
        self.registerHotKey(lambda: iTunesApp().previous_track(), 109) # F10
        self.registerHotKey(self.nextTrack, 103) # F11
        self.registerHotKey(lambda: self.incrementRatingBy(-20), 109, shiftKey) # shift-F10
        self.registerHotKey(lambda: self.incrementRatingBy(20), 103, shiftKey) # shift-F11
        self.registerZoomWindowHotKey()
        NSDistributedNotificationCenter.defaultCenter().addObserver_selector_name_object_(self, self.displayTrackInfo, 'com.apple.iTunes.playerInfo', None)
        try:
            import HIDRemote
            HIDRemote.connect()
        except ImportError:
            print "failed to import HIDRemote (XXX fix - on Intel)"
        except OSError, e:
            print "failed to connect to remote: ", e

    def sendEvent_(self, theEvent):
        eventType = theEvent.type()
        if eventType == NSSystemDefined and \
               theEvent.subtype() == kEventHotKeyPressedSubtype:
            self.hotKeyActions[theEvent.data1()]()
        elif eventType == NSApplicationDefined:
            key = theEvent.data1()
            if key == kHIDUsage_Csmr_ScanNextTrack:
                self.nextTrack()
            elif key == kHIDUsage_Csmr_ScanPreviousTrack:
                iTunesApp().previous_track()
            elif key == kHIDUsage_Csmr_PlayOrPause:
                self.playPauseFront()
        super(StreamVision, self).sendEvent_(theEvent)

if __name__ == "__main__":
    growlRegister()
    AppHelper.runEventLoop()
    try:
        HIDRemote.disconnect()
    except:
        pass
<commit_msg>StreamVision.py: iTunes 10.1.2 AirPlay fix for iTunes Store layout too.<commit_after>#!/usr/bin/pythonw
# -*- coding: utf-8 -*-

from appscript import app, k, its, CommandError
from AppKit import NSApplication, NSApplicationDefined, NSBeep, NSSystemDefined, NSURL, NSWorkspace
from Foundation import NSDistributedNotificationCenter, NSSearchPathForDirectoriesInDomains, NSCachesDirectory, NSUserDomainMask
from PyObjCTools import AppHelper
from Carbon.CarbonEvt import RegisterEventHotKey, GetApplicationEventTarget
from Carbon.Events import cmdKey, shiftKey, controlKey
import httplib2
import os
import struct
import scrape
import HotKey

GROWL_APP_NAME = 'StreamVision'
NOTIFICATION_TRACK_INFO = 'iTunes Track Info'
NOTIFICATIONS_ALL = [NOTIFICATION_TRACK_INFO]

kEventHotKeyPressedSubtype = 6
kEventHotKeyReleasedSubtype = 9

kHIDUsage_Csmr_ScanNextTrack = 0xB5
kHIDUsage_Csmr_ScanPreviousTrack = 0xB6
kHIDUsage_Csmr_PlayOrPause = 0xCD

def growlRegister():
    global growl
    growl = app(id='com.Growl.GrowlHelperApp')

    growl.register(
        as_application=GROWL_APP_NAME,
        all_notifications=NOTIFICATIONS_ALL,
        default_notifications=NOTIFICATIONS_ALL,
        icon_of_application='iTunes.app')
        # if we leave off the .app, we can get Classic iTunes's icon

def growlNotify(title, description, **kw):
    try:
        growl.notify(
            with_name=NOTIFICATION_TRACK_INFO,
            title=title,
            description=description,
            application_name=GROWL_APP_NAME,
            **kw)
    except CommandError:
        growlRegister()
        growlNotify(title, description, **kw)

def radioParadiseURL():
    # XXX better to use http://www2.radioparadise.com/playlist.xml ?
    session = scrape.Session()
    session.go('http://www2.radioparadise.com/nowplay_b.php')
    return session.region.firsttag('a')['href']

def cleanStreamTitle(title):
    if title == k.missing_value:
        return ''
    title = title.split(' [')[0] # XXX move to description
    try: # incorrectly encoded?
        title = title.encode('iso-8859-1').decode('utf-8')
    except (UnicodeDecodeError, UnicodeEncodeError):
        pass
    title = title.replace('`', u'’')
    return title

def cleanStreamTrackName(name):
    name = name.split('. ')[0]
    name = name.split(': ')[0]
    name = name.split(' - ')
    if len(name) > 1:
        name = ' - '.join(name[:-1])
    else:
        name = name[0]
    return name

def iTunesApp(): return app(id='com.apple.iTunes')
def XTensionApp(): return app(creator='SHEx')
def AmuaApp(): return app('Amua.app')

HAVE_XTENSION = False
try:
    XTensionApp()
    HAVE_XTENSION = True
except:
    pass

HAVE_AMUA = False
try:
    AmuaApp()
    HAVE_AMUA = True
except:
    pass

needsStereoPowerOn = HAVE_XTENSION

def mayUseStereo():
    if not HAVE_XTENSION:
        return False
    systemEvents = app(id='com.apple.systemEvents')
    iTunesWindow = systemEvents.application_processes[u'iTunes'].windows[u'iTunes']
    try:
        remote_speakers = iTunesWindow.buttons[its.attributes['AXDescription'].value.endswith(u'AirPlay')].title()
    except CommandError:
        # with iTunes Store visible, the query fails with errAENoSuchObject
        for button in iTunesWindow.buttons():
            try:
                if button.attributes['AXDescription'].value().endswith('AirPlay'):
                    remote_speakers = [button.title()]
                    break
            except CommandError:
                pass
        else:
            return False # XXX shouldn't get here
    return remote_speakers and remote_speakers[0] not in (None, k.missing_value)

def turnStereoOn():
    global needsStereoPowerOn
    if not mayUseStereo():
        if HAVE_XTENSION and XTensionApp().status('Stereo'):
            XTensionApp().turnoff('Stereo')
        return
    if not XTensionApp().status('Stereo'):
        XTensionApp().turnon('Stereo')
    needsStereoPowerOn = False

def turnStereoOff():
    global needsStereoPowerOn
    if not mayUseStereo():
        return
    if not needsStereoPowerOn and XTensionApp().status('Stereo'):
        XTensionApp().turnoff('Stereo')
    needsStereoPowerOn = True

def amuaPlaying():
    if not HAVE_AMUA:
        return False
    return AmuaApp().is_playing()

class OneFileCache(object):
    __slots__ = ('key', 'cache')

    def __init__(self, cache):
        if not os.path.exists(cache):
            os.makedirs(cache)
        self.cache = os.path.join(cache, 'file')
        self.key = None

    def get(self, key):
        if key == self.key:
            return file(self.cache, 'r').read()

    def set(self, key, value):
        self.key = key
        file(self.cache, 'w').write(value)

    def delete(self, key):
        if key == self.key:
            self.key = None
            os.remove(cache)

class StreamVision(NSApplication):

    hotKeyActions = {}
    hotKeys = []

    def displayTrackInfo(self, playerInfo=None):
        iTunes = iTunesApp()

        try:
            trackClass = iTunes.current_track.class_()
        except CommandError:
            trackClass = k.property

        trackName = ''
        if trackClass != k.property:
            trackName = iTunes.current_track.name()

        if iTunes.player_state() != k.playing:
            growlNotify('iTunes is not playing.', trackName)
            turnStereoOff()
            return
        turnStereoOn()
        if trackClass == k.URL_track:
            if amuaPlaying():
                if playerInfo is None: # Amua displays it itself
                    AmuaApp().display_song_information()
                return
            url = iTunes.current_stream_URL()
            kw = {}
            if url != k.missing_value and url.endswith('.jpg'):
                response, content = self.http.request(url)
                if response['content-type'].startswith('image/'):
                    file(self.imagePath, 'w').write(content)
                    kw['image_from_location'] = self.imagePath
            growlNotify(cleanStreamTitle(iTunes.current_stream_title()),
                        cleanStreamTrackName(trackName), **kw)
            return
        if trackClass == k.property:
            growlNotify('iTunes is playing.', '')
            return
        kw = {}
        # XXX iTunes doesn't let you get artwork for shared tracks
        if trackClass != k.shared_track:
            artwork = iTunes.current_track.artworks()
            if artwork:
                try:
                    kw['pictImage'] = artwork[0].data_()
                except CommandError:
                    pass
        growlNotify(trackName + '  ' +
                    u'★' * (iTunes.current_track.rating() / 20),
                    iTunes.current_track.album() + '\n' +
                    iTunes.current_track.artist(),
                    **kw)

    def goToSite(self):
        iTunes = iTunesApp()
        if iTunes.player_state() == k.playing:
            if amuaPlaying():
                AmuaApp().display_album_details()
                return
            url = iTunes.current_stream_URL()
            if url != k.missing_value:
                if 'radioparadise.com' in url and 'review' not in url:
                    url = radioParadiseURL()
                NSWorkspace.sharedWorkspace().openURL_(NSURL.URLWithString_(url))
                return
        NSBeep()

    def registerHotKey(self, func, keyCode, mods=0):
        hotKeyRef = RegisterEventHotKey(keyCode, mods, (0, 0),
                                        GetApplicationEventTarget(), 0)
        self.hotKeys.append(hotKeyRef)
        self.hotKeyActions[HotKey.HotKeyAddress(hotKeyRef)] = func
        return hotKeyRef

    def unregisterHotKey(self, hotKeyRef):
        self.hotKeys.remove(hotKeyRef)
        del self.hotKeyActions[HotKey.HotKeyAddress(hotKeyRef)]
        hotKeyRef.UnregisterEventHotKey()

    def incrementRatingBy(self, increment):
        iTunes = iTunesApp()
        if amuaPlaying():
            if increment < 0:
                AmuaApp().ban_song()
                growlNotify('Banned song.', '', icon_of_application='Amua.app')
            else:
                AmuaApp().love_song()
                growlNotify('Loved song.', '', icon_of_application='Amua.app')
            return
        rating = iTunes.current_track.rating()
        rating += increment
        if rating < 0:
            rating = 0
            NSBeep()
        elif rating > 100:
            rating = 100
            NSBeep()
        iTunes.current_track.rating.set(rating)

    def playPause(self, useStereo=True):
        global needsStereoPowerOn

        iTunes = iTunesApp()
        was_playing = (iTunes.player_state() == k.playing)
        if not useStereo:
            needsStereoPowerOn = False
        if was_playing and amuaPlaying():
            AmuaApp().stop()
        else:
            iTunes.playpause()
        if not was_playing and iTunes.player_state() == k.stopped:
            # most likely, we're focused on the iPod, so playing does nothing
            iTunes.browser_windows[1].view.set(iTunes.user_playlists[its.name=='Stations'][1]())
            iTunes.play()
        if not useStereo:
            return
        if iTunes.player_state() == k.playing:
            turnStereoOn()
        else:
            turnStereoOff()

    def playPauseFront(self):
        systemEvents = app(id='com.apple.systemEvents')
        frontName = systemEvents.processes[its.frontmost == True][1].name()
	if frontName == 'RealPlayer':
	    realPlayer = app(id='com.RealNetworks.RealPlayer')
	    if len(realPlayer.players()) > 0:
		if realPlayer.players[1].state() == k.playing:
		    realPlayer.pause()
		else:
		    realPlayer.play()
		return
	elif frontName == 'VLC':
	    app(id='org.videolan.vlc').play() # equivalent to playpause
	else:
	    self.playPause(useStereo=False)

    def nextTrack(self):
        if amuaPlaying():
            AmuaApp().skip_song()
            return
        iTunesApp().next_track()

    def registerZoomWindowHotKey(self):
        self.zoomWindowHotKey = self.registerHotKey(self.zoomWindow, 42, cmdKey | controlKey) # cmd-ctrl-\

    def unregisterZoomWindowHotKey(self):
        self.unregisterHotKey(self.zoomWindowHotKey)
        self.zoomWindowHotKey = None

    def zoomWindow(self):
        # XXX detect if "enable access for assistive devices" needs to be enabled
        systemEvents = app(id='com.apple.systemEvents')
        frontName = systemEvents.processes[its.frontmost == True][1].name()
        if frontName == 'iTunes':
            systemEvents.processes['iTunes'].menu_bars[1]. \
                menu_bar_items['Window'].menus.menu_items['Zoom'].click()
            return
        elif frontName in ('X11', 'XQuartz', 'Emacs'): # preserve C-M-\
            self.unregisterZoomWindowHotKey()
            systemEvents.key_code(42, using=[k.command_down, k.control_down])
            self.registerZoomWindowHotKey()
            return
        frontPID = systemEvents.processes[its.frontmost == True][1].unix_id()
        try:
            zoomed = app(pid=frontPID).windows[1].zoomed
            zoomed.set(not zoomed())
        except (CommandError, RuntimeError):
            systemEvents.processes[frontName].windows \
                [its.subrole == 'AXStandardWindow'].windows[1]. \
                buttons[its.subrole == 'AXZoomButton'].buttons[1].click()

    def finishLaunching(self):
        super(StreamVision, self).finishLaunching()

        caches = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
                                                     NSUserDomainMask, True)[0]
        cache = os.path.join(caches, 'StreamVision')
        self.http = httplib2.Http(OneFileCache(cache), 5)
        self.imagePath = os.path.join(cache, 'image')

        self.registerHotKey(self.displayTrackInfo, 100) # F8
        self.registerHotKey(self.goToSite, 100, cmdKey) # cmd-F8
        self.registerHotKey(self.playPause, 101) # F9
        self.registerHotKey(lambda: iTunesApp().previous_track(), 109) # F10
        self.registerHotKey(self.nextTrack, 103) # F11
        self.registerHotKey(lambda: self.incrementRatingBy(-20), 109, shiftKey) # shift-F10
        self.registerHotKey(lambda: self.incrementRatingBy(20), 103, shiftKey) # shift-F11
        self.registerZoomWindowHotKey()
        NSDistributedNotificationCenter.defaultCenter().addObserver_selector_name_object_(self, self.displayTrackInfo, 'com.apple.iTunes.playerInfo', None)
        try:
            import HIDRemote
            HIDRemote.connect()
        except ImportError:
            print "failed to import HIDRemote (XXX fix - on Intel)"
        except OSError, e:
            print "failed to connect to remote: ", e

    def sendEvent_(self, theEvent):
        eventType = theEvent.type()
        if eventType == NSSystemDefined and \
               theEvent.subtype() == kEventHotKeyPressedSubtype:
            self.hotKeyActions[theEvent.data1()]()
        elif eventType == NSApplicationDefined:
            key = theEvent.data1()
            if key == kHIDUsage_Csmr_ScanNextTrack:
                self.nextTrack()
            elif key == kHIDUsage_Csmr_ScanPreviousTrack:
                iTunesApp().previous_track()
            elif key == kHIDUsage_Csmr_PlayOrPause:
                self.playPauseFront()
        super(StreamVision, self).sendEvent_(theEvent)

if __name__ == "__main__":
    growlRegister()
    AppHelper.runEventLoop()
    try:
        HIDRemote.disconnect()
    except:
        pass
<|endoftext|>


<commit_before>"""
Simulation of a variation of Buffon's Coin Experiment.

The program checks if the coin will balance in addition
to touching one of the lines of the grid.
"""

import random
import math

DEFAULT_TRIALS = 100000

def __convex__hull(points):
    """Computes the convex hull of a set of 2D points.

    Input: an iterable sequence of (x, y) pairs representing the points.
    Output: a list of vertices of the convex hull in counter-clockwise order,
      starting from the vertex with the lexicographically smallest coordinates.
    Implements Andrew's monotone chain algorithm. O(n log n) complexity.

    Taken from https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain
    """

    # Sort the points lexicographically (tuples are compared lexicographically).
    # Remove duplicates to detect the case we have just one unique point.
    points = sorted(set(points))

    # Boring case: no points or a single point, possibly repeated multiple times.
    if len(points) <= 1:
        return points

    # 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
    # Returns a positive value, if OAB makes a counter-clockwise turn,
    # negative for clockwise turn, and zero if the points are collinear.
    def cross(o, a, b):
        return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0])

    # Build lower hull
    lower = []
    for p in points:
        while len(lower) >= 2 and cross(lower[-2], lower[-1], p) <= 0:
            lower.pop()
        lower.append(p)

    # Build upper hull
    upper = []
    for p in reversed(points):
        while len(upper) >= 2 and cross(upper[-2], upper[-1], p) <= 0:
            upper.pop()
        upper.append(p)

    # Concatenation of the lower and upper hulls gives the convex hull.
    # Last point of each list is omitted because it is repeated at the beginning of the other list.
    return lower[:-1] + upper[:-1]

def __transform_center(gap_width, x, y):
    """
    Depending on the region which the coin lands,
    this function transforms the coin onto a
    Cartesian plane where the axes are the closest
    corner and returns the coordinates of the
    center of the circle.
    """

    split = gap_width/2

    if x > split:
        x = gap_width - x
    if y > split:
        y = gap_width - y

    return (x, y)

def __get_pivots(diameter, x, y):
    """
    Get the x-intercepts and y-intercepts of
    the circle and return a list of pivots which
    the coin lies on.
    """

    pivots = []
    radius = diameter / 2

    sqval = radius**2 - y**2
    if sqval > 0: # no imaginary numbers!
        sqrt = sqval**(0.5)
        pivots.append((x + sqrt, 0))
        pivots.append((x - sqrt, 0))
    elif sqval == 0: # tangent
        pivots.append((x, 0))

    sqval = radius**2 - x**2
    if sqval > 0:
        sqrt = sqval**(0.5)
        pivots.append((0, y + sqrt))
        pivots.append((0, y - sqrt))
    elif sqval == 0:
        pivots.append((0, y))

    return pivots

def run_trials(diameter=1.0, gap_width=1.0, trials=DEFAULT_TRIALS):
    """
    Run the simulation a specified number of times.
    """
    hits = 0
    for _ in xrange(trials):
        x = random.uniform(0.0, gap_width)
        y = random.uniform(0.0, gap_width)

        x, y = __transform_center(gap_width, x, y)

        # if the center of gravity actually lies on the edge
        # the coin will balance
        if x == 0 or y == 0:
            hits += 1
            continue

        pivots = __get_pivots(diameter, x, y)

        # if it is a tangent to either of the axes
        # it won't balance
        if len(pivots) < 4:
            continue

        # convex hull of pivots and center
        # check if the center of gravity is a point in the shape
        # if it is, the coin does not balance.
        # otherwise, the coin does.
        pivots.append((x, y))
        hull = __convex__hull(pivots)

        # if center is in the convex hull
        # whee we have a hit
        if not (x, y) in hull:
            hits += 1

    return hits

def predict_prob(diameter=1.0, gap_width=1.0):
    """
    For the variables passed into the simulation,
    predict the probability that the needle will hit
    at least one of the two parallel lines.

    diameter and gap_width can be scalars or arrays.
    """
    R = diameter / 2
    D = gap_width

    if D >= 2 * R:
        return (
            math.pi *
            (R / D) ** 2
        )
    elif D > R * math.sqrt(2):
        return (
            math.sqrt(
                4 *
                (R / D) ** 2
                - 1
            ) +
            (R / D) ** 2 *
            (math.pi - 4 * math.acos(D / (2*R)))
        )
    else:
        return 1
<commit_msg>Match code to diagram in report.<commit_after>"""
Simulation of a variation of Buffon's Coin Experiment.

The program checks if the coin will balance in addition
to touching one of the lines of the grid.
"""

import random
import math

DEFAULT_TRIALS = 100000

def __convex__hull(points):
    """Computes the convex hull of a set of 2D points.

    Input: an iterable sequence of (x, y) pairs representing the points.
    Output: a list of vertices of the convex hull in counter-clockwise order,
      starting from the vertex with the lexicographically smallest coordinates.
    Implements Andrew's monotone chain algorithm. O(n log n) complexity.

    Taken from https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain
    """

    # Sort the points lexicographically (tuples are compared lexicographically).
    # Remove duplicates to detect the case we have just one unique point.
    points = sorted(set(points))

    # Boring case: no points or a single point, possibly repeated multiple times.
    if len(points) <= 1:
        return points

    # 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
    # Returns a positive value, if OAB makes a counter-clockwise turn,
    # negative for clockwise turn, and zero if the points are collinear.
    def cross(o, a, b):
        return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0])

    # Build lower hull
    lower = []
    for p in points:
        while len(lower) >= 2 and cross(lower[-2], lower[-1], p) <= 0:
            lower.pop()
        lower.append(p)

    # Build upper hull
    upper = []
    for p in reversed(points):
        while len(upper) >= 2 and cross(upper[-2], upper[-1], p) <= 0:
            upper.pop()
        upper.append(p)

    # Concatenation of the lower and upper hulls gives the convex hull.
    # Last point of each list is omitted because it is repeated at the beginning of the other list.
    return lower[:-1] + upper[:-1]

def __transform_center(gap_width, x, y):
    """
    Depending on the region which the coin lands,
    this function transforms the coin onto a
    Cartesian plane where the axes are the closest
    corner and returns the coordinates of the
    center of the circle.
    """

    split = gap_width/2

    if x > split:
        x -= gap_width
    if y > split:
        y -= gap_width

    return (x, y)

def __get_pivots(diameter, x, y):
    """
    Get the x-intercepts and y-intercepts of
    the circle and return a list of pivots which
    the coin lies on.
    """

    pivots = []
    radius = diameter / 2

    sqval = radius**2 - y**2
    if sqval > 0: # no imaginary numbers!
        sqrt = sqval**(0.5)
        pivots.append((x + sqrt, 0))
        pivots.append((x - sqrt, 0))
    elif sqval == 0: # tangent
        pivots.append((x, 0))

    sqval = radius**2 - x**2
    if sqval > 0:
        sqrt = sqval**(0.5)
        pivots.append((0, y + sqrt))
        pivots.append((0, y - sqrt))
    elif sqval == 0:
        pivots.append((0, y))

    return pivots

def run_trials(diameter=1.0, gap_width=1.0, trials=DEFAULT_TRIALS):
    """
    Run the simulation a specified number of times.
    """
    hits = 0
    for _ in xrange(trials):
        x = random.uniform(0.0, gap_width)
        y = random.uniform(0.0, gap_width)

        x, y = __transform_center(gap_width, x, y)

        # if the center of gravity actually lies on the edge
        # the coin will balance
        if x == 0 or y == 0:
            hits += 1
            continue

        pivots = __get_pivots(diameter, x, y)

        # if it is a tangent to either of the axes
        # it won't balance
        if len(pivots) < 4:
            continue

        # convex hull of pivots and center
        # check if the center of gravity is a point in the shape
        # if it is, the coin does not balance.
        # otherwise, the coin does.
        pivots.append((x, y))
        hull = __convex__hull(pivots)

        # if center is in the convex hull
        # whee we have a hit
        if not (x, y) in hull:
            hits += 1

    return hits

def predict_prob(diameter=1.0, gap_width=1.0):
    """
    For the variables passed into the simulation,
    predict the probability that the needle will hit
    at least one of the two parallel lines.

    diameter and gap_width can be scalars or arrays.
    """
    R = diameter / 2
    D = gap_width

    if D >= 2 * R:
        return (
            math.pi *
            (R / D) ** 2
        )
    elif D > R * math.sqrt(2):
        return (
            math.sqrt(
                4 *
                (R / D) ** 2
                - 1
            ) +
            (R / D) ** 2 *
            (math.pi - 4 * math.acos(D / (2*R)))
        )
    else:
        return 1
<|endoftext|>


<commit_before>#!/usr/bin/env python
# encoding: utf-8

"""
@author: Jackling Gu
@file: img_process.py
@time: 2017-06-13 11:13
"""

from ..util import getcfg, data_load, get_abspath, get_y_labels
from sklearn.preprocessing import LabelEncoder
from keras.models import load_model
from keras.callbacks import CSVLogger
from keras.utils import to_categorical
from keras.applications import vgg16, vgg19, inception_v3
from scipy.misc import imread, imresize
import numpy as np
import os
from keras.preprocessing.image import ImageDataGenerator

def update_app_model(tmp_model, num_class):
    from keras.layers import Dense, Flatten, GlobalAveragePooling2D, Dropout
    # add a global spatial average pooling layer
    x = tmp_model.output
    try:
        x = Flatten()(x)  # vgg ?
    except:
        pass  # inception

    x = Dense(256, activation='relu', name='fc1')(x)
    x = Dropout(0.3)(x)

    if num_class == 2:
        # prediction layer
        x = Dense(1, activation='sigmoid', name='final_predictions')(x)
        my_model = Model(inputs=tmp_model.input, outputs=x)
        my_model.compile(loss='binary_crossentropy',
                         optimizer='rmsprop',
                         metrics=['accuracy'])
    else:
        # prediction layer
        x = Dense(num_class, activation='softmax', name='final_predictions')(x)
        my_model = Model(inputs=tmp_model.input, outputs=x)
        my_model.compile(loss='categorical_crossentropy',
                         optimizer='rmsprop',
                         metrics=['accuracy'])

    return my_model

class ImageClassification(object):
    def __init__(self):

        self.img_w = getcfg('IMG_WIDTH', 224)
        self.img_h = getcfg('IMG_HEIGHT', 224)
        self.epoch = getcfg('EPOCH', 10)
        self.default_shape = (3, self.img_h, self.img_w)  # channel first

        self.model_name = getcfg('MODEL_NAME', 'ALEXNET')
        self.data_path = getcfg('DATA_DIR', '../data/dog_vs_cat')
        self.model_save_path = get_abspath('../models/{}_{}_model.h5'.format(self.model_name, self.epoch))
        print('MODEL NAME', self.model_name, 'EPOCHS', self.epoch, 'DATA PATH', self.data_path)
        print('MODEL SAVE PATH', self.model_save_path)

        # get y information first
        self.encoder = LabelEncoder()
        self.encoder.fit(get_y_labels(self.data_path))
        self.num_class = len(self.encoder.classes_)

        if os.path.exists(self.model_save_path):
            # load model , do not have to load x data
            print('LOAD EXIST MODEL')
            self.model = load_model(self.model_save_path)
        else:
            # get data
            self.x, self.y = data_load(self.data_path, img_height=self.img_h, img_width=self.img_w)
            print('x shape', self.x.shape)

            self.label_y = self.encoder.transform(self.y)
            if self.num_class == 2:
                self.binary_y = self.label_y
            else:
                self.binary_y = to_categorical(self.label_y)
            print(self.num_class, self.y[:2], self.label_y[:2], self.binary_y[:2])

            # already shuffle ,split
            tmp_data_cnt = len(self.x)
            self.train_data_cnt = int(tmp_data_cnt * 0.7)
            self.x_train = self.x[:self.train_data_cnt]
            self.x_test = self.x[self.train_data_cnt:]
            self.y_train = self.binary_y[:self.train_data_cnt]
            self.y_test = self.binary_y[self.train_data_cnt:]

            self.model = None
            if self.model_name == 'ALEXNET':
                from .alexnet import AlexNet
                self.model = AlexNet(self.img_h, self.img_w, self.num_class).get_model()
            if self.model_name == 'SIMPLENET':
                from .simple_cnn import SimpleNet
                self.model = SimpleNet(self.img_h, self.img_w, self.num_class).get_model()
                # remove top fully connection layers and do not use imagenet weights ( hard to download )
            elif self.model_name == 'VGG16':
                tmp_model = vgg16.VGG16(input_shape=self.default_shape, include_top=True, weights='imagenet')
                self.model = update_app_model(tmp_model, self.num_class)
            elif self.model_name == 'VGG19':
                tmp_model = vgg19.VGG19(input_shape=self.default_shape, include_top=True, weights='imagenet')
                self.model = update_app_model(tmp_model, self.num_class)
            elif self.model_name == 'INCEPTIONV3':
                tmp_model = inception_v3.InceptionV3(input_shape=self.default_shape, include_top=True,
                                                     weights='imagenet')
                self.model = update_app_model(tmp_model, self.num_class)
            elif self.model_name == 'DENSENET':
                from .densenet import DenseNet
                tmp_model = DenseNet((3, self.img_h, self.img_w), depth=40, growth_rate=12, nb_filter=16)
                self.model = update_app_model(tmp_model, self.num_class)
            if self.model is not None:
                self.model.summary()
                self.train()

    def train(self):
        # use data augmentation
        datagen = ImageDataGenerator(
            rescale=1. / 255,
            shear_range=0.2,
            zoom_range=0.2,
            horizontal_flip=True)  # randomly flip images
        # self.model.fit(self.x, self.binary_y, epochs=self.epoch, validation_split=0.2)
        log_path = get_abspath('../models/{}_{}_training.log'.format(self.model_name, self.epoch))
        csv_logger = CSVLogger(log_path)
        self.model.fit_generator(datagen.flow(self.x_train, self.y_train, batch_size=50),
                                 steps_per_epoch=self.train_data_cnt,
                                 validation_data=(self.x_test, self.y_test),
                                 epochs=self.epoch, verbose=1,
                                 callbacks=[csv_logger])
        self.model.save(self.model_save_path)

    def run(self, img_file_path):
        img = imread(img_file_path)
        img = imresize(img, (self.img_h, self.img_w))
        img = np.transpose(img, (2, 1, 0))
        np_img = np.array([img])
        if self.num_class == 2:
            pred = self.model.predict(np_img)[0]
            class_type = int(pred)  # binary class 0 or 1
        else:
            pred = self.model.predict_proba(np_img)[0]
            class_type = np.argmax(pred)
        return_res = {'type': self.encoder.inverse_transform(class_type), 'prediction': str(pred)}
        return return_res
<commit_msg>fixed model import“<commit_after>#!/usr/bin/env python
# encoding: utf-8

"""
@author: Jackling Gu
@file: img_process.py
@time: 2017-06-13 11:13
"""

from ..util import getcfg, data_load, get_abspath, get_y_labels
from sklearn.preprocessing import LabelEncoder
from keras.models import load_model,Model
from keras.callbacks import CSVLogger
from keras.utils import to_categorical
from keras.applications import vgg16, vgg19, inception_v3
from scipy.misc import imread, imresize
import numpy as np
import os
from keras.preprocessing.image import ImageDataGenerator

def update_app_model(tmp_model, num_class):
    from keras.layers import Dense, Flatten, GlobalAveragePooling2D, Dropout
    # add a global spatial average pooling layer
    x = tmp_model.output
    try:
        x = Flatten()(x)  # vgg ?
    except:
        pass  # inception

    x = Dense(256, activation='relu', name='fc1')(x)
    x = Dropout(0.3)(x)

    if num_class == 2:
        # prediction layer
        x = Dense(1, activation='sigmoid', name='final_predictions')(x)
        my_model = Model(inputs=tmp_model.input, outputs=x)
        my_model.compile(loss='binary_crossentropy',
                         optimizer='rmsprop',
                         metrics=['accuracy'])
    else:
        # prediction layer
        x = Dense(num_class, activation='softmax', name='final_predictions')(x)
        my_model = Model(inputs=tmp_model.input, outputs=x)
        my_model.compile(loss='categorical_crossentropy',
                         optimizer='rmsprop',
                         metrics=['accuracy'])

    return my_model

class ImageClassification(object):
    def __init__(self):

        self.img_w = getcfg('IMG_WIDTH', 224)
        self.img_h = getcfg('IMG_HEIGHT', 224)
        self.epoch = getcfg('EPOCH', 10)
        self.default_shape = (3, self.img_h, self.img_w)  # channel first

        self.model_name = getcfg('MODEL_NAME', 'ALEXNET')
        self.data_path = getcfg('DATA_DIR', '../data/dog_vs_cat')
        self.model_save_path = get_abspath('../models/{}_{}_model.h5'.format(self.model_name, self.epoch))
        print('MODEL NAME', self.model_name, 'EPOCHS', self.epoch, 'DATA PATH', self.data_path)
        print('MODEL SAVE PATH', self.model_save_path)

        # get y information first
        self.encoder = LabelEncoder()
        self.encoder.fit(get_y_labels(self.data_path))
        self.num_class = len(self.encoder.classes_)

        if os.path.exists(self.model_save_path):
            # load model , do not have to load x data
            print('LOAD EXIST MODEL')
            self.model = load_model(self.model_save_path)
        else:
            # get data
            self.x, self.y = data_load(self.data_path, img_height=self.img_h, img_width=self.img_w)
            print('x shape', self.x.shape)

            self.label_y = self.encoder.transform(self.y)
            if self.num_class == 2:
                self.binary_y = self.label_y
            else:
                self.binary_y = to_categorical(self.label_y)
            print(self.num_class, self.y[:2], self.label_y[:2], self.binary_y[:2])

            # already shuffle ,split
            tmp_data_cnt = len(self.x)
            self.train_data_cnt = int(tmp_data_cnt * 0.7)
            self.x_train = self.x[:self.train_data_cnt]
            self.x_test = self.x[self.train_data_cnt:]
            self.y_train = self.binary_y[:self.train_data_cnt]
            self.y_test = self.binary_y[self.train_data_cnt:]

            self.model = None
            if self.model_name == 'ALEXNET':
                from .alexnet import AlexNet
                self.model = AlexNet(self.img_h, self.img_w, self.num_class).get_model()
            if self.model_name == 'SIMPLENET':
                from .simple_cnn import SimpleNet
                self.model = SimpleNet(self.img_h, self.img_w, self.num_class).get_model()
                # remove top fully connection layers and do not use imagenet weights ( hard to download )
            elif self.model_name == 'VGG16':
                tmp_model = vgg16.VGG16(input_shape=self.default_shape, include_top=True, weights='imagenet')
                self.model = update_app_model(tmp_model, self.num_class)
            elif self.model_name == 'VGG19':
                tmp_model = vgg19.VGG19(input_shape=self.default_shape, include_top=True, weights='imagenet')
                self.model = update_app_model(tmp_model, self.num_class)
            elif self.model_name == 'INCEPTIONV3':
                tmp_model = inception_v3.InceptionV3(input_shape=self.default_shape, include_top=True,
                                                     weights='imagenet')
                self.model = update_app_model(tmp_model, self.num_class)
            elif self.model_name == 'DENSENET':
                from .densenet import DenseNet
                tmp_model = DenseNet((3, self.img_h, self.img_w), depth=40, growth_rate=12, nb_filter=16)
                self.model = update_app_model(tmp_model, self.num_class)
            if self.model is not None:
                self.model.summary()
                self.train()

    def train(self):
        # use data augmentation
        datagen = ImageDataGenerator(
            rescale=1. / 255,
            shear_range=0.2,
            zoom_range=0.2,
            horizontal_flip=True)  # randomly flip images
        # self.model.fit(self.x, self.binary_y, epochs=self.epoch, validation_split=0.2)
        log_path = get_abspath('../models/{}_{}_training.log'.format(self.model_name, self.epoch))
        csv_logger = CSVLogger(log_path)
        self.model.fit_generator(datagen.flow(self.x_train, self.y_train, batch_size=50),
                                 steps_per_epoch=self.train_data_cnt,
                                 validation_data=(self.x_test, self.y_test),
                                 epochs=self.epoch, verbose=1,
                                 callbacks=[csv_logger])
        self.model.save(self.model_save_path)

    def run(self, img_file_path):
        img = imread(img_file_path)
        img = imresize(img, (self.img_h, self.img_w))
        img = np.transpose(img, (2, 1, 0))
        np_img = np.array([img])
        if self.num_class == 2:
            pred = self.model.predict(np_img)[0]
            class_type = int(pred)  # binary class 0 or 1
        else:
            pred = self.model.predict_proba(np_img)[0]
            class_type = np.argmax(pred)
        return_res = {'type': self.encoder.inverse_transform(class_type), 'prediction': str(pred)}
        return return_res
<|endoftext|>


<commit_before><commit_msg>use X-Forwarded-Host<commit_after><|endoftext|>


<commit_before>from django.db import models
from django.utils import timezone

class Currency(models.Model):
    cur_code = models.CharField(max_length=8, primary_key=True)
    shortcut = models.CharField(max_length=1)
    symbol = models.CharField(max_length=24)
    long_name = models.CharField(max_length=128)

    class Meta:
        unique_together = [['shortcut'], ['long_name']]

    def __str__(self):
        return self.cur_code

class Book(models.Model):
    book_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=64)
    created_at = models.DateTimeField()

    def set_created_at(self):
        "Instead of auto_now_add"
        if self.created_at is None:
            self.created_at = timezone.now()

    def save(self, *args, **kwargs):
        self.set_created_at()
        super(Book, self).save(*args, **kwargs)

    class Meta:
        ordering = ['created_at']
        unique_together = [['name']]

class AccountType(models.Model):
    account_type = models.CharField(max_length=128, primary_key=True)
    # (credits increase account balance) <=> (sign == True)
    sign = models.BooleanField(verbose_name="Credits increase balance", default=False)
    credit_term = models.CharField(max_length=32)
    debit_term = models.CharField(max_length=32)

    def __str__(self):
        return self.account_type
<commit_msg>Make flake8 happy<commit_after>from django.db import models
from django.utils import timezone

class Currency(models.Model):
    cur_code = models.CharField(max_length=8, primary_key=True)
    shortcut = models.CharField(max_length=1)
    symbol = models.CharField(max_length=24)
    long_name = models.CharField(max_length=128)

    class Meta:
        unique_together = [['shortcut'], ['long_name']]

    def __str__(self):
        return self.cur_code

class Book(models.Model):
    book_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=64)
    created_at = models.DateTimeField()

    def set_created_at(self):
        "Instead of auto_now_add"
        if self.created_at is None:
            self.created_at = timezone.now()

    def save(self, *args, **kwargs):
        self.set_created_at()
        super(Book, self).save(*args, **kwargs)

    class Meta:
        ordering = ['created_at']
        unique_together = [['name']]

class AccountType(models.Model):
    account_type = models.CharField(max_length=128, primary_key=True)
    # (credits increase account balance) <=> (sign == True)
    sign = models.BooleanField(verbose_name="Credits increase balance",
                               default=False)
    credit_term = models.CharField(max_length=32)
    debit_term = models.CharField(max_length=32)

    def __str__(self):
        return self.account_type
<|endoftext|>


<commit_before>import requests

from werkzeug.exceptions import ServiceUnavailable
from werkzeug.datastructures import MultiDict
from werkzeug.urls import url_parse

from flask import current_app, request, redirect

from .. import main

@main.route('/feedback', methods=["POST"])
def send_feedback():
    feedback_config = current_app.config['DM_FEEDBACK_FORM']
    form_data = MultiDict()
    for field, google_form_field in feedback_config['fields'].items():
        form_data.setlist(google_form_field, request.form.getlist(field))

    result = requests.post(feedback_config['uri'], list(form_data.iteritems(multi=True)))
    if result.status_code != 200:
        raise ServiceUnavailable('Google forms submission problem (status %d)'.format(result.status_code))
    came_from = url_parse(request.form['uri'])
    # strip netloc and scheme as we should ignore attempts to make us redirect elsewhere
    replaced = came_from._replace(scheme='', netloc='')

    return redirect(replaced, code=303)
<commit_msg>Add flash message on successful feedback submission.<commit_after>import requests

from werkzeug.exceptions import ServiceUnavailable
from werkzeug.datastructures import MultiDict
from werkzeug.urls import url_parse

from flask import current_app, request, redirect, flash, Markup

from .. import main

@main.route('/feedback', methods=["POST"])
def send_feedback():
    feedback_config = current_app.config['DM_FEEDBACK_FORM']
    form_data = MultiDict()
    for field, google_form_field in feedback_config['fields'].items():
        form_data.setlist(google_form_field, request.form.getlist(field))

    result = requests.post(feedback_config['uri'], list(form_data.iteritems(multi=True)))
    if result.status_code != 200:
        raise ServiceUnavailable('Google forms submission problem (status %d)'.format(result.status_code))
    came_from = url_parse(request.form['uri'])
    # strip netloc and scheme as we should ignore attempts to make us redirect elsewhere
    replaced = came_from._replace(scheme='', netloc='')

    flash(Markup(
        """Thank you for your message. If you have more extensive feedback, please
        email us or
        take part in our research.
        """))

    return redirect(replaced, code=303)
<|endoftext|>


<commit_before>import asyncio
import inspect
import logging
import logging.config
import os
import socket
import ssl
import sys
from typing import List, Tuple

import click

from uvicorn.importer import ImportFromStringError, import_from_string
from uvicorn.middleware.asgi2 import ASGI2Middleware
from uvicorn.middleware.debug import DebugMiddleware
from uvicorn.middleware.message_logger import MessageLoggerMiddleware
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
from uvicorn.middleware.wsgi import WSGIMiddleware

TRACE_LOG_LEVEL = 5

LOG_LEVELS = {
    "critical": logging.CRITICAL,
    "error": logging.ERROR,
    "warning": logging.WARNING,
    "info": logging.INFO,
    "debug": logging.DEBUG,
    "trace": TRACE_LOG_LEVEL,
}
HTTP_PROTOCOLS = {
    "auto": "uvicorn.protocols.http.auto:AutoHTTPProtocol",
    "h11": "uvicorn.protocols.http.h11_impl:H11Protocol",
    "httptools": "uvicorn.protocols.http.httptools_impl:HttpToolsProtocol",
}
WS_PROTOCOLS = {
    "auto": "uvicorn.protocols.websockets.auto:AutoWebSocketsProtocol",
    "none": None,
    "websockets": "uvicorn.protocols.websockets.websockets_impl:WebSocketProtocol",
    "wsproto": "uvicorn.protocols.websockets.wsproto_impl:WSProtocol",
}
LIFESPAN = {
    "auto": "uvicorn.lifespan.on:LifespanOn",
    "on": "uvicorn.lifespan.on:LifespanOn",
    "off": "uvicorn.lifespan.off:LifespanOff",
}
LOOP_SETUPS = {
    "none": None,
    "auto": "uvicorn.loops.auto:auto_loop_setup",
    "asyncio": "uvicorn.loops.asyncio:asyncio_setup",
    "uvloop": "uvicorn.loops.uvloop:uvloop_setup",
}
INTERFACES = ["auto", "asgi3", "asgi2", "wsgi"]

# Fallback to 'ssl.PROTOCOL_SSLv23' in order to support Python < 3.5.3.
SSL_PROTOCOL_VERSION = getattr(ssl, "PROTOCOL_TLS", ssl.PROTOCOL_SSLv23)

LOGGING_CONFIG = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "default": {
            "()": "uvicorn.logging.DefaultFormatter",
            "fmt": "%(levelprefix)s %(message)s",
            "use_colors": None,
        },
        "access": {
            "()": "uvicorn.logging.AccessFormatter",
            "fmt": '%(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s',  # noqa: E501
        },
    },
    "handlers": {
        "default": {
            "formatter": "default",
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stderr",
        },
        "access": {
            "formatter": "access",
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stdout",
        },
    },
    "loggers": {
        "uvicorn": {"handlers": ["default"], "level": "INFO"},
        "uvicorn.error": {"level": "INFO"},
        "uvicorn.access": {"handlers": ["access"], "level": "INFO", "propagate": False},
    },
}

logger = logging.getLogger("uvicorn.error")

def create_ssl_context(certfile, keyfile, ssl_version, cert_reqs, ca_certs, ciphers):
    ctx = ssl.SSLContext(ssl_version)
    ctx.load_cert_chain(certfile, keyfile)
    ctx.verify_mode = cert_reqs
    if ca_certs:
        ctx.load_verify_locations(ca_certs)
    if ciphers:
        ctx.set_ciphers(ciphers)
    return ctx

class Config:
    def __init__(
        self,
        app,
        host="127.0.0.1",
        port=8000,
        uds=None,
        fd=None,
        loop="auto",
        http="auto",
        ws="auto",
        lifespan="auto",
        env_file=None,
        log_config=LOGGING_CONFIG,
        log_level=None,
        access_log=True,
        use_colors=None,
        interface="auto",
        debug=False,
        reload=False,
        reload_dirs=None,
        workers=None,
        proxy_headers=True,
        forwarded_allow_ips=None,
        root_path="",
        limit_concurrency=None,
        limit_max_requests=None,
        backlog=2048,
        timeout_keep_alive=5,
        timeout_notify=30,
        callback_notify=None,
        ssl_keyfile=None,
        ssl_certfile=None,
        ssl_version=SSL_PROTOCOL_VERSION,
        ssl_cert_reqs=ssl.CERT_NONE,
        ssl_ca_certs=None,
        ssl_ciphers="TLSv1",
        headers=None,
    ):
        self.app = app
        self.host = host
        self.port = port
        self.uds = uds
        self.fd = fd
        self.loop = loop
        self.http = http
        self.ws = ws
        self.lifespan = lifespan
        self.log_config = log_config
        self.log_level = log_level
        self.access_log = access_log
        self.use_colors = use_colors
        self.interface = interface
        self.debug = debug
        self.reload = reload
        self.workers = workers or 1
        self.proxy_headers = proxy_headers
        self.root_path = root_path
        self.limit_concurrency = limit_concurrency
        self.limit_max_requests = limit_max_requests
        self.backlog = backlog
        self.timeout_keep_alive = timeout_keep_alive
        self.timeout_notify = timeout_notify
        self.callback_notify = callback_notify
        self.ssl_keyfile = ssl_keyfile
        self.ssl_certfile = ssl_certfile
        self.ssl_version = ssl_version
        self.ssl_cert_reqs = ssl_cert_reqs
        self.ssl_ca_certs = ssl_ca_certs
        self.ssl_ciphers = ssl_ciphers
        self.headers = headers if headers else []  # type: List[str]
        self.encoded_headers = None  # type: List[Tuple[bytes, bytes]]

        self.loaded = False
        self.configure_logging()

        if reload_dirs is None:
            self.reload_dirs = [os.getcwd()]
        else:
            self.reload_dirs = reload_dirs

        if env_file is not None:
            from dotenv import load_dotenv

            logger.info("Loading environment from '%s'", env_file)
            load_dotenv(dotenv_path=env_file)

        if workers is None and "WEB_CONCURRENCY" in os.environ:
            self.workers = int(os.environ["WEB_CONCURRENCY"])

        if forwarded_allow_ips is None:
            self.forwarded_allow_ips = os.environ.get(
                "FORWARDED_ALLOW_IPS", "127.0.0.1"
            )
        else:
            self.forwarded_allow_ips = forwarded_allow_ips

    @property
    def asgi_version(self) -> str:
        return {"asgi2": "2.0", "asgi3": "3.0", "wsgi": "3.0"}[self.interface]

    @property
    def is_ssl(self) -> bool:
        return bool(self.ssl_keyfile or self.ssl_certfile)

    def configure_logging(self):
        logging.addLevelName(TRACE_LOG_LEVEL, "TRACE")

        if self.log_config is not None:
            if isinstance(self.log_config, dict):
                if self.use_colors in (True, False):
                    self.log_config["formatters"]["default"][
                        "use_colors"
                    ] = self.use_colors
                    self.log_config["formatters"]["access"][
                        "use_colors"
                    ] = self.use_colors
                logging.config.dictConfig(self.log_config)
            else:
                logging.config.fileConfig(self.log_config)

        if self.log_level is not None:
            if isinstance(self.log_level, str):
                log_level = LOG_LEVELS[self.log_level]
            else:
                log_level = self.log_level
            logging.getLogger("").setLevel(log_level)
            logging.getLogger("uvicorn.error").setLevel(log_level)
            logging.getLogger("uvicorn.access").setLevel(log_level)
            logging.getLogger("uvicorn.asgi").setLevel(log_level)
        if self.access_log is False:
            logging.getLogger("uvicorn.access").handlers = []
            logging.getLogger("uvicorn.access").propagate = False

    def load(self):
        assert not self.loaded

        if self.is_ssl:
            self.ssl = create_ssl_context(
                keyfile=self.ssl_keyfile,
                certfile=self.ssl_certfile,
                ssl_version=self.ssl_version,
                cert_reqs=self.ssl_cert_reqs,
                ca_certs=self.ssl_ca_certs,
                ciphers=self.ssl_ciphers,
            )
        else:
            self.ssl = None

        encoded_headers = [
            (key.lower().encode("latin1"), value.encode("latin1"))
            for key, value in self.headers
        ]
        self.encoded_headers = (
            encoded_headers
            if b"server" in dict(encoded_headers)
            else [(b"server", b"uvicorn")] + encoded_headers
        )  # type: List[Tuple[bytes, bytes]]

        if isinstance(self.http, str):
            self.http_protocol_class = import_from_string(HTTP_PROTOCOLS[self.http])
        else:
            self.http_protocol_class = self.http

        if isinstance(self.ws, str):
            self.ws_protocol_class = import_from_string(WS_PROTOCOLS[self.ws])
        else:
            self.ws_protocol_class = self.ws

        self.lifespan_class = import_from_string(LIFESPAN[self.lifespan])

        try:
            self.loaded_app = import_from_string(self.app)
        except ImportFromStringError as exc:
            logger.error("Error loading ASGI app. %s" % exc)
            sys.exit(1)

        if self.interface == "auto":
            if inspect.isclass(self.loaded_app):
                use_asgi_3 = hasattr(self.loaded_app, "__await__")
            elif inspect.isfunction(self.loaded_app):
                use_asgi_3 = asyncio.iscoroutinefunction(self.loaded_app)
            else:
                call = getattr(self.loaded_app, "__call__", None)
                use_asgi_3 = asyncio.iscoroutinefunction(call)
            self.interface = "asgi3" if use_asgi_3 else "asgi2"

        if self.interface == "wsgi":
            self.loaded_app = WSGIMiddleware(self.loaded_app)
            self.ws_protocol_class = None
        elif self.interface == "asgi2":
            self.loaded_app = ASGI2Middleware(self.loaded_app)

        if self.debug:
            self.loaded_app = DebugMiddleware(self.loaded_app)
        if logger.level <= TRACE_LOG_LEVEL:
            self.loaded_app = MessageLoggerMiddleware(self.loaded_app)
        if self.proxy_headers:
            self.loaded_app = ProxyHeadersMiddleware(
                self.loaded_app, trusted_hosts=self.forwarded_allow_ips
            )

        self.loaded = True

    def setup_event_loop(self):
        loop_setup = import_from_string(LOOP_SETUPS[self.loop])
        if loop_setup is not None:
            loop_setup()

    def bind_socket(self):
        sock = socket.socket()
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        try:
            sock.bind((self.host, self.port))
        except OSError as exc:
            logger.error(exc)
            sys.exit(1)
        sock.set_inheritable(True)

        message = "Uvicorn running on %s://%s:%d (Press CTRL+C to quit)"
        color_message = (
            "Uvicorn running on "
            + click.style("%s://%s:%d", bold=True)
            + " (Press CTRL+C to quit)"
        )
        protocol_name = "https" if self.is_ssl else "http"
        logger.info(
            message,
            protocol_name,
            self.host,
            self.port,
            extra={"color_message": color_message},
        )
        return sock

    @property
    def should_reload(self):
        return isinstance(self.app, str) and (self.debug or self.reload)
<commit_msg>Fixes bug where --log-config disables uvicorn loggers (#512)<commit_after>import asyncio
import inspect
import logging
import logging.config
import os
import socket
import ssl
import sys
from typing import List, Tuple

import click

from uvicorn.importer import ImportFromStringError, import_from_string
from uvicorn.middleware.asgi2 import ASGI2Middleware
from uvicorn.middleware.debug import DebugMiddleware
from uvicorn.middleware.message_logger import MessageLoggerMiddleware
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
from uvicorn.middleware.wsgi import WSGIMiddleware

TRACE_LOG_LEVEL = 5

LOG_LEVELS = {
    "critical": logging.CRITICAL,
    "error": logging.ERROR,
    "warning": logging.WARNING,
    "info": logging.INFO,
    "debug": logging.DEBUG,
    "trace": TRACE_LOG_LEVEL,
}
HTTP_PROTOCOLS = {
    "auto": "uvicorn.protocols.http.auto:AutoHTTPProtocol",
    "h11": "uvicorn.protocols.http.h11_impl:H11Protocol",
    "httptools": "uvicorn.protocols.http.httptools_impl:HttpToolsProtocol",
}
WS_PROTOCOLS = {
    "auto": "uvicorn.protocols.websockets.auto:AutoWebSocketsProtocol",
    "none": None,
    "websockets": "uvicorn.protocols.websockets.websockets_impl:WebSocketProtocol",
    "wsproto": "uvicorn.protocols.websockets.wsproto_impl:WSProtocol",
}
LIFESPAN = {
    "auto": "uvicorn.lifespan.on:LifespanOn",
    "on": "uvicorn.lifespan.on:LifespanOn",
    "off": "uvicorn.lifespan.off:LifespanOff",
}
LOOP_SETUPS = {
    "none": None,
    "auto": "uvicorn.loops.auto:auto_loop_setup",
    "asyncio": "uvicorn.loops.asyncio:asyncio_setup",
    "uvloop": "uvicorn.loops.uvloop:uvloop_setup",
}
INTERFACES = ["auto", "asgi3", "asgi2", "wsgi"]

# Fallback to 'ssl.PROTOCOL_SSLv23' in order to support Python < 3.5.3.
SSL_PROTOCOL_VERSION = getattr(ssl, "PROTOCOL_TLS", ssl.PROTOCOL_SSLv23)

LOGGING_CONFIG = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "default": {
            "()": "uvicorn.logging.DefaultFormatter",
            "fmt": "%(levelprefix)s %(message)s",
            "use_colors": None,
        },
        "access": {
            "()": "uvicorn.logging.AccessFormatter",
            "fmt": '%(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s',  # noqa: E501
        },
    },
    "handlers": {
        "default": {
            "formatter": "default",
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stderr",
        },
        "access": {
            "formatter": "access",
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stdout",
        },
    },
    "loggers": {
        "uvicorn": {"handlers": ["default"], "level": "INFO"},
        "uvicorn.error": {"level": "INFO"},
        "uvicorn.access": {"handlers": ["access"], "level": "INFO", "propagate": False},
    },
}

logger = logging.getLogger("uvicorn.error")

def create_ssl_context(certfile, keyfile, ssl_version, cert_reqs, ca_certs, ciphers):
    ctx = ssl.SSLContext(ssl_version)
    ctx.load_cert_chain(certfile, keyfile)
    ctx.verify_mode = cert_reqs
    if ca_certs:
        ctx.load_verify_locations(ca_certs)
    if ciphers:
        ctx.set_ciphers(ciphers)
    return ctx

class Config:
    def __init__(
        self,
        app,
        host="127.0.0.1",
        port=8000,
        uds=None,
        fd=None,
        loop="auto",
        http="auto",
        ws="auto",
        lifespan="auto",
        env_file=None,
        log_config=LOGGING_CONFIG,
        log_level=None,
        access_log=True,
        use_colors=None,
        interface="auto",
        debug=False,
        reload=False,
        reload_dirs=None,
        workers=None,
        proxy_headers=True,
        forwarded_allow_ips=None,
        root_path="",
        limit_concurrency=None,
        limit_max_requests=None,
        backlog=2048,
        timeout_keep_alive=5,
        timeout_notify=30,
        callback_notify=None,
        ssl_keyfile=None,
        ssl_certfile=None,
        ssl_version=SSL_PROTOCOL_VERSION,
        ssl_cert_reqs=ssl.CERT_NONE,
        ssl_ca_certs=None,
        ssl_ciphers="TLSv1",
        headers=None,
    ):
        self.app = app
        self.host = host
        self.port = port
        self.uds = uds
        self.fd = fd
        self.loop = loop
        self.http = http
        self.ws = ws
        self.lifespan = lifespan
        self.log_config = log_config
        self.log_level = log_level
        self.access_log = access_log
        self.use_colors = use_colors
        self.interface = interface
        self.debug = debug
        self.reload = reload
        self.workers = workers or 1
        self.proxy_headers = proxy_headers
        self.root_path = root_path
        self.limit_concurrency = limit_concurrency
        self.limit_max_requests = limit_max_requests
        self.backlog = backlog
        self.timeout_keep_alive = timeout_keep_alive
        self.timeout_notify = timeout_notify
        self.callback_notify = callback_notify
        self.ssl_keyfile = ssl_keyfile
        self.ssl_certfile = ssl_certfile
        self.ssl_version = ssl_version
        self.ssl_cert_reqs = ssl_cert_reqs
        self.ssl_ca_certs = ssl_ca_certs
        self.ssl_ciphers = ssl_ciphers
        self.headers = headers if headers else []  # type: List[str]
        self.encoded_headers = None  # type: List[Tuple[bytes, bytes]]

        self.loaded = False
        self.configure_logging()

        if reload_dirs is None:
            self.reload_dirs = [os.getcwd()]
        else:
            self.reload_dirs = reload_dirs

        if env_file is not None:
            from dotenv import load_dotenv

            logger.info("Loading environment from '%s'", env_file)
            load_dotenv(dotenv_path=env_file)

        if workers is None and "WEB_CONCURRENCY" in os.environ:
            self.workers = int(os.environ["WEB_CONCURRENCY"])

        if forwarded_allow_ips is None:
            self.forwarded_allow_ips = os.environ.get(
                "FORWARDED_ALLOW_IPS", "127.0.0.1"
            )
        else:
            self.forwarded_allow_ips = forwarded_allow_ips

    @property
    def asgi_version(self) -> str:
        return {"asgi2": "2.0", "asgi3": "3.0", "wsgi": "3.0"}[self.interface]

    @property
    def is_ssl(self) -> bool:
        return bool(self.ssl_keyfile or self.ssl_certfile)

    def configure_logging(self):
        logging.addLevelName(TRACE_LOG_LEVEL, "TRACE")

        if self.log_config is not None:
            if isinstance(self.log_config, dict):
                if self.use_colors in (True, False):
                    self.log_config["formatters"]["default"][
                        "use_colors"
                    ] = self.use_colors
                    self.log_config["formatters"]["access"][
                        "use_colors"
                    ] = self.use_colors
                logging.config.dictConfig(self.log_config)
            else:
                logging.config.fileConfig(
                    self.log_config, disable_existing_loggers=False
                )

        if self.log_level is not None:
            if isinstance(self.log_level, str):
                log_level = LOG_LEVELS[self.log_level]
            else:
                log_level = self.log_level
            logging.getLogger("").setLevel(log_level)
            logging.getLogger("uvicorn.error").setLevel(log_level)
            logging.getLogger("uvicorn.access").setLevel(log_level)
            logging.getLogger("uvicorn.asgi").setLevel(log_level)
        if self.access_log is False:
            logging.getLogger("uvicorn.access").handlers = []
            logging.getLogger("uvicorn.access").propagate = False

    def load(self):
        assert not self.loaded

        if self.is_ssl:
            self.ssl = create_ssl_context(
                keyfile=self.ssl_keyfile,
                certfile=self.ssl_certfile,
                ssl_version=self.ssl_version,
                cert_reqs=self.ssl_cert_reqs,
                ca_certs=self.ssl_ca_certs,
                ciphers=self.ssl_ciphers,
            )
        else:
            self.ssl = None

        encoded_headers = [
            (key.lower().encode("latin1"), value.encode("latin1"))
            for key, value in self.headers
        ]
        self.encoded_headers = (
            encoded_headers
            if b"server" in dict(encoded_headers)
            else [(b"server", b"uvicorn")] + encoded_headers
        )  # type: List[Tuple[bytes, bytes]]

        if isinstance(self.http, str):
            self.http_protocol_class = import_from_string(HTTP_PROTOCOLS[self.http])
        else:
            self.http_protocol_class = self.http

        if isinstance(self.ws, str):
            self.ws_protocol_class = import_from_string(WS_PROTOCOLS[self.ws])
        else:
            self.ws_protocol_class = self.ws

        self.lifespan_class = import_from_string(LIFESPAN[self.lifespan])

        try:
            self.loaded_app = import_from_string(self.app)
        except ImportFromStringError as exc:
            logger.error("Error loading ASGI app. %s" % exc)
            sys.exit(1)

        if self.interface == "auto":
            if inspect.isclass(self.loaded_app):
                use_asgi_3 = hasattr(self.loaded_app, "__await__")
            elif inspect.isfunction(self.loaded_app):
                use_asgi_3 = asyncio.iscoroutinefunction(self.loaded_app)
            else:
                call = getattr(self.loaded_app, "__call__", None)
                use_asgi_3 = asyncio.iscoroutinefunction(call)
            self.interface = "asgi3" if use_asgi_3 else "asgi2"

        if self.interface == "wsgi":
            self.loaded_app = WSGIMiddleware(self.loaded_app)
            self.ws_protocol_class = None
        elif self.interface == "asgi2":
            self.loaded_app = ASGI2Middleware(self.loaded_app)

        if self.debug:
            self.loaded_app = DebugMiddleware(self.loaded_app)
        if logger.level <= TRACE_LOG_LEVEL:
            self.loaded_app = MessageLoggerMiddleware(self.loaded_app)
        if self.proxy_headers:
            self.loaded_app = ProxyHeadersMiddleware(
                self.loaded_app, trusted_hosts=self.forwarded_allow_ips
            )

        self.loaded = True

    def setup_event_loop(self):
        loop_setup = import_from_string(LOOP_SETUPS[self.loop])
        if loop_setup is not None:
            loop_setup()

    def bind_socket(self):
        sock = socket.socket()
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        try:
            sock.bind((self.host, self.port))
        except OSError as exc:
            logger.error(exc)
            sys.exit(1)
        sock.set_inheritable(True)

        message = "Uvicorn running on %s://%s:%d (Press CTRL+C to quit)"
        color_message = (
            "Uvicorn running on "
            + click.style("%s://%s:%d", bold=True)
            + " (Press CTRL+C to quit)"
        )
        protocol_name = "https" if self.is_ssl else "http"
        logger.info(
            message,
            protocol_name,
            self.host,
            self.port,
            extra={"color_message": color_message},
        )
        return sock

    @property
    def should_reload(self):
        return isinstance(self.app, str) and (self.debug or self.reload)
<|endoftext|>


<commit_before>"""Key class and associated stuff.

TODO: docstrings, style
"""

import base64
import os

from google.appengine.datastore import entity_pb

class Key(object):
  """An immutable datastore key.

  Constructor forms:
    Key(pairs=[(kind, idorname), (kind, idorname), ...])
    Key(flat=[kind, idorname, kind, idorname, ...])
    Key(reference=<reference>)
    Key(serialized=<serialized reference>)
    Key(urlsafe=<urlsafe base64 encoded serialized reference>)

  TODO: namespace, appid, parent
  """

  __slots__ = ['__reference']

  def __new__(cls, _kwargs=None, **kwargs):
    assert cls is Key
    if _kwargs:  # For pickling only
      assert isinstance(_kwargs, dict)
      assert not kwargs
      kwargs = _kwargs
    pairs = kwargs.pop('pairs', None)
    flat = kwargs.pop('flat', None)
    reference = kwargs.pop('reference', None)
    serialized = kwargs.pop('serialized', None)
    urlsafe = kwargs.pop('urlsafe', None)
    assert not kwargs
    howmany = (bool(pairs) + bool(flat) +
               bool(reference) + bool(serialized) + bool(urlsafe))
    assert howmany == 1
    if flat or pairs:
      if flat:
        assert len(flat) % 2 == 0
        pairs = [(flat[i], flat[i+1]) for i in xrange(0, len(flat), 2)]
      assert pairs
      reference = _ReferenceFromPairs(pairs)
    else:
      if urlsafe:
        serialized = _DecodeUrlSafe(urlsafe)
      if serialized:
        reference = _ReferenceFromSerialized(serialized)
      assert reference.path().element_size()
      # TODO: assert that each element has a type and either an id or a name
      if not serialized:
        reference = _ReferenceFromReference(reference)
    if not reference.app():
      reference.set_app(os.getenv('APPLICATION_ID', '_'))
    self = super(Key, cls).__new__(cls)
    self.__reference = reference
    return self

  def __repr__(self):
    pairs = []
    for kind, idorname in self.pairs():
      if isinstance(kind, unicode):
        kind = kind.encoded('utf8')
      if isinstance(idorname, unicode):
        idorname = idorname.encode('utf8')
      if isinstance(idorname, basestring):
        idorname = repr(idorname)
      pairs.append("(%r, %s)" % (kind, idorname))
    return 'Key(pairs=[%s])' % (", ".join(pairs))

  __str__ = __repr__

  def __hash__(self):
    return hash(tuple(self.pairs()))

  def __eq__(self, other):
    if not isinstance(other, Key):
      return NotImplemented
    # TODO: app, namespace
    return tuple(self.pairs()) == tuple(other.pairs())

  def __ne__(self, other):
    if not isinstance(other, Key):
      return NotImplemented
    return not self.__eq__(other)

  def __getstate__(self):
    return ({'pairs': tuple(self.pairs())},)

  def __setstate__(self, state):
    dummy = Key(*state)
    self.__reference = dummy.__reference

  def __getnewargs__(self):
    # TODO: app, namespace
    return ({'pairs': tuple(self.pairs())},)

  def pairs(self):
    for elem in self.__reference.path().element_list():
      kind = elem.type()
      if elem.has_id():
        idorname = elem.id()
      else:
        idorname = elem.name()
      yield (kind, idorname)

  def flat(self):
    for kind, idorname in self.pairs():
      yield kind
      yield idorname

  def reference(self):
    # TODO: In order to guarantee immutability, this must make a copy.
    # But most uses are from internal code which won't touch the
    # result and prefers to skip the copy.  What to do about this
    # moral dilemma?  Currently everybody uses k._Key__reference,
    # which seems the worst possible outcome.
    return _ReferenceFromReference(self.__reference)

  def serialized(self):
    return self.__reference.Encode()

  def urlsafe(self):
    urlsafe = base64.b64encode(self.__reference.Encode())
    return urlsafe.rstrip('=').replace('+', '-').replace('/', '_')

def _ReferenceFromPairs(pairs):
  reference = entity_pb.Reference()
  path = reference.mutable_path()
  last = False
  for kind, idorname in pairs:
    assert not last, 'incomplete entry must be last'
    assert isinstance(kind, basestring)
    if isinstance(kind, unicode):
      kind = kind.encode('utf8')
    assert 1 <= len(kind) <= 500
    elem = path.add_element()
    elem.set_type(kind)
    if isinstance(idorname, (int, long)):
      assert 1 <= idorname < 2**63
      elem.set_id(idorname)
    elif isinstance(idorname, basestring):
      if isinstance(idorname, unicode):
        idorname = idorname.encode('utf8')
      assert 1 <= len(idorname) <= 500
      elem.set_name(idorname)
    elif idorname is None:
      elem.set_id(0)
      last = True
    else:
      assert False, 'bad idorname (%r)' % (idorname,)
  return reference

def _ReferenceFromReference(reference):
  new_reference = entity_pb.Reference()
  new_reference.CopyFrom(reference)
  return new_reference

def _ReferenceFromSerialized(serialized):
  assert isinstance(serialized, basestring)
  if isinstance(serialized, unicode):
    serialized = serialized.encode('utf8')
  return entity_pb.Reference(serialized)

def _DecodeUrlSafe(urlsafe):
  assert isinstance(urlsafe, basestring)
  if isinstance(urlsafe, unicode):
    urlsafe = urlsafe.encode('utf8')
  mod = len(urlsafe) % 4
  if mod:
    urlsafe += '=' * (4 - mod)
  # This is 3-4x faster than urlsafe_b64decode()
  return base64.b64decode(urlsafe.replace('-', '+').replace('_', '/'))
<commit_msg>Improve __new__ signature.<commit_after>"""Key class and associated stuff.

TODO: docstrings, style
"""

import base64
import os

from google.appengine.datastore import entity_pb

from core.datastore_rpc import _positional as positional

class Key(object):
  """An immutable datastore key.

  Constructor forms:
    Key(pairs=[(kind, idorname), (kind, idorname), ...])
    Key(flat=[kind, idorname, kind, idorname, ...])
    Key(reference=<reference>)
    Key(serialized=<serialized reference>)
    Key(urlsafe=<urlsafe base64 encoded serialized reference>)

  TODO: namespace, appid, parent
  """

  __slots__ = ['__reference']

  def __new__(cls, *args, **kwargs):
    if args:
      # For pickling only: one positional argument is allowed,
      # giving a dict specifying the keyword arguments.
      assert not kwargs
      assert len(args) == 1
      kwargs = args[0]
      assert isinstance(kwargs, dict)
    return cls.construct(**kwargs)

  @classmethod
  @positional(1)
  def construct(cls, pairs=None, flat=None,
                reference=None, serialized=None, urlsafe=None):
    assert cls is Key
    howmany = (bool(pairs) + bool(flat) +
               bool(reference) + bool(serialized) + bool(urlsafe))
    assert howmany == 1
    if flat or pairs:
      if flat:
        assert len(flat) % 2 == 0
        pairs = [(flat[i], flat[i+1]) for i in xrange(0, len(flat), 2)]
      assert pairs
      reference = _ReferenceFromPairs(pairs)
    else:
      if urlsafe:
        serialized = _DecodeUrlSafe(urlsafe)
      if serialized:
        reference = _ReferenceFromSerialized(serialized)
      assert reference.path().element_size()
      # TODO: assert that each element has a type and either an id or a name
      if not serialized:
        reference = _ReferenceFromReference(reference)
    if not reference.app():
      reference.set_app(os.getenv('APPLICATION_ID', '_'))
    self = super(Key, cls).__new__(cls)
    self.__reference = reference
    return self

  def __repr__(self):
    pairs = []
    for kind, idorname in self.pairs():
      if isinstance(kind, unicode):
        kind = kind.encoded('utf8')
      if isinstance(idorname, unicode):
        idorname = idorname.encode('utf8')
      if isinstance(idorname, basestring):
        idorname = repr(idorname)
      pairs.append("(%r, %s)" % (kind, idorname))
    return 'Key(pairs=[%s])' % (", ".join(pairs))

  __str__ = __repr__

  def __hash__(self):
    return hash(tuple(self.pairs()))

  def __eq__(self, other):
    if not isinstance(other, Key):
      return NotImplemented
    # TODO: app, namespace
    return tuple(self.pairs()) == tuple(other.pairs())

  def __ne__(self, other):
    if not isinstance(other, Key):
      return NotImplemented
    return not self.__eq__(other)

  def __getstate__(self):
    return ({'pairs': tuple(self.pairs())},)

  def __setstate__(self, state):
    dummy = Key(*state)
    self.__reference = dummy.__reference

  def __getnewargs__(self):
    # TODO: app, namespace
    return ({'pairs': tuple(self.pairs())},)

  def pairs(self):
    for elem in self.__reference.path().element_list():
      kind = elem.type()
      if elem.has_id():
        idorname = elem.id()
      else:
        idorname = elem.name()
      yield (kind, idorname)

  def flat(self):
    for kind, idorname in self.pairs():
      yield kind
      yield idorname

  def reference(self):
    # TODO: In order to guarantee immutability, this must make a copy.
    # But most uses are from internal code which won't touch the
    # result and prefers to skip the copy.  What to do about this
    # moral dilemma?  Currently everybody uses k._Key__reference,
    # which seems the worst possible outcome.
    return _ReferenceFromReference(self.__reference)

  def serialized(self):
    return self.__reference.Encode()

  def urlsafe(self):
    urlsafe = base64.b64encode(self.__reference.Encode())
    return urlsafe.rstrip('=').replace('+', '-').replace('/', '_')

def _ReferenceFromPairs(pairs):
  reference = entity_pb.Reference()
  path = reference.mutable_path()
  last = False
  for kind, idorname in pairs:
    assert not last, 'incomplete entry must be last'
    assert isinstance(kind, basestring)
    if isinstance(kind, unicode):
      kind = kind.encode('utf8')
    assert 1 <= len(kind) <= 500
    elem = path.add_element()
    elem.set_type(kind)
    if isinstance(idorname, (int, long)):
      assert 1 <= idorname < 2**63
      elem.set_id(idorname)
    elif isinstance(idorname, basestring):
      if isinstance(idorname, unicode):
        idorname = idorname.encode('utf8')
      assert 1 <= len(idorname) <= 500
      elem.set_name(idorname)
    elif idorname is None:
      elem.set_id(0)
      last = True
    else:
      assert False, 'bad idorname (%r)' % (idorname,)
  return reference

def _ReferenceFromReference(reference):
  new_reference = entity_pb.Reference()
  new_reference.CopyFrom(reference)
  return new_reference

def _ReferenceFromSerialized(serialized):
  assert isinstance(serialized, basestring)
  if isinstance(serialized, unicode):
    serialized = serialized.encode('utf8')
  return entity_pb.Reference(serialized)

def _DecodeUrlSafe(urlsafe):
  assert isinstance(urlsafe, basestring)
  if isinstance(urlsafe, unicode):
    urlsafe = urlsafe.encode('utf8')
  mod = len(urlsafe) % 4
  if mod:
    urlsafe += '=' * (4 - mod)
  # This is 3-4x faster than urlsafe_b64decode()
  return base64.b64decode(urlsafe.replace('-', '+').replace('_', '/'))
<|endoftext|>


<commit_before>from collections import namedtuple

class InvalidArrowException(Exception):
    pass

def run_workflow(func, args, state, error_step=None):
    ARROWS = namedtuple('ARROWS', 'continues aborts')("_continues_",
                                                      "_aborts_")
    for step in func(args):
        try:
            state, arrow = step(state, ARROWS)
            if isinstance(arrow, Exception):
                setattr(arrow, 'state', state)
                raise arrow
        except Exception as exception:
            if error_step is None:
                raise
            else:
                state, arrow = error_step(exception, state, ARROWS)

        if arrow == ARROWS.continues:
            continue
        elif arrow == ARROWS.aborts:
            return state
        else:
            raise InvalidArrowException()

    return state

def reduces(reducer):
    return lambda state, arrows: (reducer(state), arrows.continues)

def aborts():
    return lambda state, arrows: (state, arrows.aborts)

def sums(xs):
    for x in xs:
        if x > 12:
            yield aborts()
        yield reduces(lambda state: state + x)

print run_workflow(sums, range(20), 0)
<commit_msg>workflow decorator.<commit_after>from collections import namedtuple
from functools import wraps

class InvalidArrowException(Exception):
    pass

def run_workflow(func, args, kwargs, state, error_step=None):
    ARROWS = namedtuple('ARROWS', 'continues aborts')("_continues_",
                                                      "_aborts_")
    for step in func(*args, **kwargs):
        try:
            state, arrow = step(state, ARROWS)
            if isinstance(arrow, Exception):
                setattr(arrow, 'state', state)
                raise arrow
        except Exception as exception:
            if error_step is None:
                raise
            else:
                state, arrow = error_step(exception, state, ARROWS)

        if arrow == ARROWS.continues:
            continue
        elif arrow == ARROWS.aborts:
            return state
        else:
            raise InvalidArrowException()

    return state

def workflow(state, error_step):
    def _(func):
        @wraps(func)
        def __(*args, **kwargs):
            return run_workflow(func, args, kwargs, state, error_step)

        return __

    return _

def reduces(reducer):
    return lambda state, arrows: (reducer(state), arrows.continues)

def aborts():
    return lambda state, arrows: (state, arrows.aborts)

def raises(exception):
    return lambda state, arrows: (state, exception)

def twelve_sucks(state, arrows):
    return state + 1213, arrows.continues

def sums_error(exception, state, arrows):
    return state + 10**6, arrows.continues

@workflow(state=0, error_step=sums_error)
def sums(xs):
    for x in xs:
        if x == 12:
            yield twelve_sucks
            continue
        if x > 16:
            yield raises(Exception("Noooo"))
            yield aborts()
        yield reduces(lambda state: state + x)

print sums(range(30))
<|endoftext|>