<commit_before>from __future__ import print_function
from logger import Logger

import json
import os
import re
import requests

try:
    from urllib.parse import urlencode
except ImportError as e:
    from urllib import urlencode

class SpeechRecognitionError(Exception):
    pass

class SpeechRecognition():
    """
    @author: Fabio "BlackLight" Manganiello <blacklight86@gmail.com>
    """

    def __init__(self, api_key=None, languages=['en-us']):
        if not api_key:
            raise Exception('No Google speech recognition API key found in your configuration or GOOGLE_SPEECH_API_KEY environment variable')

        self.api_key = api_key
        self.languages = languages

        Logger.get_logger().info({
            'msg_type': 'Initializing speech recognition backend',
            'module': self.__class__.__name__,
            'api_key': '******',
            'languages': languages,
        })

    def recognize_speech_from_file(self, filename):
        Logger.get_logger().info({
            'msg_type': 'Google Speech Recognition API request',
            'module': self.__class__.__name__,
            'api_key': '******',
            'language': self.languages[0],
        })

        r = requests.post( \
            'http://www.google.com/speech-api/v2/recognize?' + urlencode({
                'lang': self.languages[0],
                'key': self.api_key,
                'output': 'json',
            }),

            data = open(filename, 'rb').read(),
            headers = {
                'Content-type': 'audio/x-flac; rate=44100',
            },
        )

        if not r.ok:
            raise Exception('Got an unexpected HTTP response %d from the server' % r.status_code)

        Logger.get_logger().info({
            'msg_type': 'Google Speech Recognition API response',
            'module': self.__class__.__name__,
            'response': r.text,
        })

        response = []
        for line in re.split('\r?\n', r.text):
            if re.match('^\s*$', line):
                continue
            response.append(json.loads(line))

        for item in response:
            if 'result' in item and len(item['result']):
                for _ in item['result']:
                    if 'final' in _:
                        if 'alternative' in _ and len(_['alternative']):
                            return _['alternative'][0]['transcript'], \
                                _['alternative'][0]['confidence'] if 'confidence' in _['alternative'][0] else 1

        raise SpeechRecognitionError('Speech not recognized')

# vim:sw=4:ts=4:et:

<commit_msg>Documented speechrecognition module<commit_after>from __future__ import print_function
from logger import Logger

import json
import os
import re
import requests

try:
    from urllib.parse import urlencode
except ImportError as e:
    from urllib import urlencode

class SpeechRecognitionError(Exception):
    pass

class SpeechRecognition():
    """
    Plugin to interact with speech recognition by using Google Speech Recognition API
    @depend: requests [pip install requests]
    @author: Fabio "BlackLight" Manganiello <blacklight86@gmail.com>
    """

    def __init__(self, api_key=None, languages=['en-us']):
        """
        api_key -- Google Speech Recognition API key - instructions on how to get one: http://www.chromium.org/developers/how-tos/api-keys
        languages -- Array of languages to use for speech detection. So far only the first language is supported, but TODO use of
            secondary language(s) in case the confidence score reported by the API is below a certain threshold
        """

        if not api_key:
            raise Exception('No Google speech recognition API key found in your configuration or GOOGLE_SPEECH_API_KEY environment variable')

        self.api_key = api_key
        self.languages = languages

        Logger.get_logger().info({
            'msg_type': 'Initializing speech recognition backend',
            'module': self.__class__.__name__,
            'api_key': '******',
            'languages': languages,
        })

    def recognize_speech_from_file(self, filename):
        """
        Recognizes the speech contained in a FLAC audio file
        filename -- Path to the FLAC file containing any speech
        """

        Logger.get_logger().info({
            'msg_type': 'Google Speech Recognition API request',
            'module': self.__class__.__name__,
            'api_key': '******',
            'language': self.languages[0],
        })

        r = requests.post( \
            'http://www.google.com/speech-api/v2/recognize?' + urlencode({
                'lang': self.languages[0],
                'key': self.api_key,
                'output': 'json',
            }),

            data = open(filename, 'rb').read(),
            headers = {
                'Content-type': 'audio/x-flac; rate=44100',
            },
        )

        if not r.ok:
            raise Exception('Got an unexpected HTTP response %d from the server' % r.status_code)

        Logger.get_logger().info({
            'msg_type': 'Google Speech Recognition API response',
            'module': self.__class__.__name__,
            'response': r.text,
        })

        response = []
        for line in re.split('\r?\n', r.text):
            if re.match('^\s*$', line):
                continue
            response.append(json.loads(line))

        for item in response:
            if 'result' in item and len(item['result']):
                for _ in item['result']:
                    if 'final' in _:
                        if 'alternative' in _ and len(_['alternative']):
                            return _['alternative'][0]['transcript'], \
                                _['alternative'][0]['confidence'] if 'confidence' in _['alternative'][0] else 1

        raise SpeechRecognitionError('Speech not recognized')

# vim:sw=4:ts=4:et:

<|endoftext|>


<commit_before>#!/usr/bin/env python3

from proxy import proxy
from select import select
import importlib
import json
import os
import pprint
import re
import sys
import telnetlib
import threading
import traceback
telnetlib.GMCP = b'\xc9'

class Session(object):
    def __init__(self, world_module, port, arg):
        self.mud_encoding = 'iso-8859-1'
        self.client_encoding = 'utf-8'
        self.gmcp = {}
        self.world_module = world_module
        self.arg = arg
        self.world = world_module.getClass()(self, self.arg)
        try:
            self.socketToPipeR, self.pipeToSocketW, self.stopFlag, runProxy = proxy('::1', port)
            self.pipeToSocketW = os.fdopen(self.pipeToSocketW, 'wb')
            self.proxyThread = threading.Thread(target=runProxy)
            self.proxyThread.start()
            host_port = self.world.getHostPort()
            self.log("Connecting")
            self.telnet = self.connect(*host_port)
            self.log("Connected")
        except:
            self.log("Shutting down")
            self.stopFlag.set()
            self.world.quit()
            raise

    def join(self):
        self.thr.join()

    def log(self, *args, **kwargs):
        if len(args) == 1 and type(args[0]) == str:
            line = args[0]
        else:
            line = pprint.pformat(args)
        self.pipeToSocketW.write("---------\n".encode(self.client_encoding))
        self.pipeToSocketW.write(line.encode(self.client_encoding))
        self.pipeToSocketW.write(b"\n")
        self.pipeToSocketW.flush()

    def strip_ansi(self, line):
        return re.sub(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]', '', line)

    def gmcpOut(self, msg):
        self.telnet.sock.sendall(telnetlib.IAC + telnetlib.SB + telnetlib.GMCP + msg.encode(self.mud_encoding) + telnetlib.IAC + telnetlib.SE)

    def iac(self, sock, cmd, option):
        if cmd == telnetlib.WILL:
            if option == telnetlib.GMCP:
                self.log("Enabling GMCP")
                sock.sendall(telnetlib.IAC + telnetlib.DO + option)
                self.gmcpOut('Core.Hello { "client": "Cizra", "version": "1" }')
                supportables = ['char 1', 'char.base 1', 'char.maxstats 1', 'char.status 1', 'char.statusvars 1', 'char.vitals 1', 'char.worth 1', 'comm 1', 'comm.tick 1', 'group 1', 'room 1', 'room.info 1']
                self.gmcpOut('Core.Supports.Set ' + str(supportables).replace("'", '"'))
                self.gmcpOut('request room')
                self.gmcpOut('request char')
            elif option == telnetlib.TTYPE:
                self.log("Sending terminal type 'Cizra'")
                sock.sendall(telnetlib.IAC + telnetlib.DO + option +
                        telnetlib.IAC + telnetlib.SB + telnetlib.TTYPE + telnetlib.BINARY + b'Cizra' + telnetlib.IAC + telnetlib.SE)

            else:
                sock.sendall(telnetlib.IAC + telnetlib.DONT + option)
        elif cmd == telnetlib.SE:
            data = self.telnet.read_sb_data()
            if data and data[0] == ord(telnetlib.GMCP):
                try:
                    self.handleGmcp(data[1:].decode(self.mud_encoding))
                except Exception as e:
                    traceback.print_exc()

    def handleGmcp(self, data):
        # this.that {JSON blob}
        # TODO: move into clients
        space_idx = data.find(' ')
        whole_key = data[:space_idx]
        value_json = data[space_idx + 1:]
        nesting = whole_key.split('.')
        current = self.world.gmcp
        for nest in nesting[:-1]:
            if nest not in current:
                current[nest] = {}
            current = current[nest]
        lastkey = nesting[-1]
        try:
            val = json.loads(value_json)
        except json.decoder.JSONDecodeError:
            val = {"string": value_json}
        if lastkey not in current:
            current[lastkey] = {}
        current[lastkey] = val
        self.world.handleGmcp(whole_key, val)

    def connect(self, host, port):
        t = telnetlib.Telnet()
        t.set_option_negotiation_callback(self.iac)
        # t.set_debuglevel(1)
        t.open(host, int(port))
        return t

    def send(self, line):
        print("> ", line)
        self.telnet.write((line + '\n').encode(self.mud_encoding))

    def handle_from_telnet(self):
        try:
            data = self.telnet.read_very_eager()
        except:
            self.log("EOF on telnet")
            self.stopFlag.set()
            self.world.quit()
            raise
        try:
            data = data.decode(self.mud_encoding)
        except UnicodeError as e:
            print("Unicode error:", e)
            print("Data was:", data)
            data = ''

        if not data:
            _ = self.telnet.read_sb_data()
        prn = []
        for line in data.split('\n'):
            if line:
                replacement = None
                try:
                    replacement = self.world.trigger(line.strip())
                except Exception as e:
                    traceback.print_exc()
                if replacement is not None:
                    line = replacement
            prn.append(line)
        self.pipeToSocketW.write('\n'.join(prn).encode(self.mud_encoding))
        self.pipeToSocketW.flush()

    def show(self, line):
        self.pipeToSocketW.write(line.encode(self.client_encoding))
        self.pipeToSocketW.flush()

    def handle_from_pipe(self):
        data = b''  # to handle partial lines
        try:
            data += os.read(self.socketToPipeR, 4096)
            lines = data.split(b'\n')
            if lines[-1] != '':  # received partial line, don't process
                data = lines[-1]
            else:
                data = b''
            lines = lines[:-1]  # chop off either the last empty line, or the partial line

            for line in lines:
                line = line.decode(self.client_encoding)
                if line[-1] == '\r':
                    line = line[:-1]
                self.handle_output_line(line)
        except EOFError:
            self.log("EOF in pipe")
            self.stopFlag.set()
            self.world.quit()
            raise

    def handle_output_line(self, data):
        pprint.pprint(data)
        if data == '#reload' and self.world:
            self.log('Reloading world')
            try:
                state = self.world.state
                gmcp = self.world.gmcp
                self.world.quit()
                self.world_module = importlib.reload(self.world_module)
                self.world = self.world_module.getClass()(self, self.arg)
                self.world.state = state
                self.world.gmcp = gmcp
            except Exception:
                traceback.print_exc()
            return
        else:
            handled = False
            try:
                handled = self.world.alias(data)
            except Exception as e:
                traceback.print_exc()
            else:
                if not handled:
                    self.send(data)

    def run(self):
        try:
            while True:
                fds, _, _ = select([self.telnet.get_socket(), self.socketToPipeR], [], [])
                for fd in fds:
                    if fd == self.telnet.get_socket():
                        self.handle_from_telnet()
                    elif fd == self.socketToPipeR:
                        self.handle_from_pipe()
        except Exception as e:
            self.log("Exception in run():", e)
        finally:
            self.log("Closing")
            self.telnet.close()

def main():
    if len(sys.argv) < 3 or len(sys.argv) > 4:
        print("Usage: {} worldmodule (without .py) port [arg]".format(sys.argv[0]))
        exit(1)

    world_module = importlib.import_module(sys.argv[1])
    port = int(sys.argv[2])
    arg = sys.argv[3] if len(sys.argv) == 4 else None
    ses = Session(world_module, port, arg)
    ses.run()

assert(__name__ == '__main__')
main()
<commit_msg>remove unused var<commit_after>#!/usr/bin/env python3

from proxy import proxy
from select import select
import importlib
import json
import os
import pprint
import re
import sys
import telnetlib
import threading
import traceback
telnetlib.GMCP = b'\xc9'

class Session(object):
    def __init__(self, world_module, port, arg):
        self.mud_encoding = 'iso-8859-1'
        self.client_encoding = 'utf-8'
        self.world_module = world_module
        self.arg = arg
        self.world = world_module.getClass()(self, self.arg)
        try:
            self.socketToPipeR, self.pipeToSocketW, self.stopFlag, runProxy = proxy('::1', port)
            self.pipeToSocketW = os.fdopen(self.pipeToSocketW, 'wb')
            self.proxyThread = threading.Thread(target=runProxy)
            self.proxyThread.start()
            host_port = self.world.getHostPort()
            self.log("Connecting")
            self.telnet = self.connect(*host_port)
            self.log("Connected")
        except:
            self.log("Shutting down")
            self.stopFlag.set()
            self.world.quit()
            raise

    def join(self):
        self.thr.join()

    def log(self, *args, **kwargs):
        if len(args) == 1 and type(args[0]) == str:
            line = args[0]
        else:
            line = pprint.pformat(args)
        self.pipeToSocketW.write("---------\n".encode(self.client_encoding))
        self.pipeToSocketW.write(line.encode(self.client_encoding))
        self.pipeToSocketW.write(b"\n")
        self.pipeToSocketW.flush()

    def strip_ansi(self, line):
        return re.sub(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]', '', line)

    def gmcpOut(self, msg):
        self.telnet.sock.sendall(telnetlib.IAC + telnetlib.SB + telnetlib.GMCP + msg.encode(self.mud_encoding) + telnetlib.IAC + telnetlib.SE)

    def iac(self, sock, cmd, option):
        if cmd == telnetlib.WILL:
            if option == telnetlib.GMCP:
                self.log("Enabling GMCP")
                sock.sendall(telnetlib.IAC + telnetlib.DO + option)
                self.gmcpOut('Core.Hello { "client": "Cizra", "version": "1" }')
                supportables = ['char 1', 'char.base 1', 'char.maxstats 1', 'char.status 1', 'char.statusvars 1', 'char.vitals 1', 'char.worth 1', 'comm 1', 'comm.tick 1', 'group 1', 'room 1', 'room.info 1']
                self.gmcpOut('Core.Supports.Set ' + str(supportables).replace("'", '"'))
                self.gmcpOut('request room')
                self.gmcpOut('request char')
            elif option == telnetlib.TTYPE:
                self.log("Sending terminal type 'Cizra'")
                sock.sendall(telnetlib.IAC + telnetlib.DO + option +
                        telnetlib.IAC + telnetlib.SB + telnetlib.TTYPE + telnetlib.BINARY + b'Cizra' + telnetlib.IAC + telnetlib.SE)

            else:
                sock.sendall(telnetlib.IAC + telnetlib.DONT + option)
        elif cmd == telnetlib.SE:
            data = self.telnet.read_sb_data()
            if data and data[0] == ord(telnetlib.GMCP):
                try:
                    self.handleGmcp(data[1:].decode(self.mud_encoding))
                except Exception as e:
                    traceback.print_exc()

    def handleGmcp(self, data):
        # this.that {JSON blob}
        # TODO: move into clients
        space_idx = data.find(' ')
        whole_key = data[:space_idx]
        value_json = data[space_idx + 1:]
        nesting = whole_key.split('.')
        current = self.world.gmcp
        for nest in nesting[:-1]:
            if nest not in current:
                current[nest] = {}
            current = current[nest]
        lastkey = nesting[-1]
        try:
            val = json.loads(value_json)
        except json.decoder.JSONDecodeError:
            val = {"string": value_json}
        if lastkey not in current:
            current[lastkey] = {}
        current[lastkey] = val
        self.world.handleGmcp(whole_key, val)

    def connect(self, host, port):
        t = telnetlib.Telnet()
        t.set_option_negotiation_callback(self.iac)
        # t.set_debuglevel(1)
        t.open(host, int(port))
        return t

    def send(self, line):
        print("> ", line)
        self.telnet.write((line + '\n').encode(self.mud_encoding))

    def handle_from_telnet(self):
        try:
            data = self.telnet.read_very_eager()
        except:
            self.log("EOF on telnet")
            self.stopFlag.set()
            self.world.quit()
            raise
        try:
            data = data.decode(self.mud_encoding)
        except UnicodeError as e:
            print("Unicode error:", e)
            print("Data was:", data)
            data = ''

        if not data:
            _ = self.telnet.read_sb_data()
        prn = []
        for line in data.split('\n'):
            if line:
                replacement = None
                try:
                    replacement = self.world.trigger(line.strip())
                except Exception as e:
                    traceback.print_exc()
                if replacement is not None:
                    line = replacement
            prn.append(line)
        self.pipeToSocketW.write('\n'.join(prn).encode(self.mud_encoding))
        self.pipeToSocketW.flush()

    def show(self, line):
        self.pipeToSocketW.write(line.encode(self.client_encoding))
        self.pipeToSocketW.flush()

    def handle_from_pipe(self):
        data = b''  # to handle partial lines
        try:
            data += os.read(self.socketToPipeR, 4096)
            lines = data.split(b'\n')
            if lines[-1] != '':  # received partial line, don't process
                data = lines[-1]
            else:
                data = b''
            lines = lines[:-1]  # chop off either the last empty line, or the partial line

            for line in lines:
                line = line.decode(self.client_encoding)
                if line[-1] == '\r':
                    line = line[:-1]
                self.handle_output_line(line)
        except EOFError:
            self.log("EOF in pipe")
            self.stopFlag.set()
            self.world.quit()
            raise

    def handle_output_line(self, data):
        pprint.pprint(data)
        if data == '#reload' and self.world:
            self.log('Reloading world')
            try:
                state = self.world.state
                gmcp = self.world.gmcp
                self.world.quit()
                self.world_module = importlib.reload(self.world_module)
                self.world = self.world_module.getClass()(self, self.arg)
                self.world.state = state
                self.world.gmcp = gmcp
            except Exception:
                traceback.print_exc()
            return
        else:
            handled = False
            try:
                handled = self.world.alias(data)
            except Exception as e:
                traceback.print_exc()
            else:
                if not handled:
                    self.send(data)

    def run(self):
        try:
            while True:
                fds, _, _ = select([self.telnet.get_socket(), self.socketToPipeR], [], [])
                for fd in fds:
                    if fd == self.telnet.get_socket():
                        self.handle_from_telnet()
                    elif fd == self.socketToPipeR:
                        self.handle_from_pipe()
        except Exception as e:
            self.log("Exception in run():", e)
        finally:
            self.log("Closing")
            self.telnet.close()

def main():
    if len(sys.argv) < 3 or len(sys.argv) > 4:
        print("Usage: {} worldmodule (without .py) port [arg]".format(sys.argv[0]))
        exit(1)

    world_module = importlib.import_module(sys.argv[1])
    port = int(sys.argv[2])
    arg = sys.argv[3] if len(sys.argv) == 4 else None
    ses = Session(world_module, port, arg)
    ses.run()

assert(__name__ == '__main__')
main()
<|endoftext|>


<commit_before>"""
Python wrapper around the Core Audio Windows API.
"""
import comtypes
from enum import Enum
from ctypes import HRESULT, POINTER, c_float, c_void_p
from ctypes.wintypes import BOOL, DWORD, UINT, INT, LPWSTR
from comtypes import GUID, COMMETHOD

IID_IAudioEndpointVolume = GUID(
    '{5CDF2C82-841E-4546-9722-0CF74078229A}')
IID_IMMDevice = GUID(
    '{D666063F-1587-4E43-81F1-B948E807363F}')
IID_IMMDeviceCollection = GUID(
    '{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}')
IID_IMMDeviceEnumerator = GUID(
    '{A95664D2-9614-4F35-A746-DE8DB63617E6}')
IID_IAudioSessionEnumerator = GUID(
    '{E2F5BB11-0570-40CA-ACDD-3AA01277DEE8}')
IID_IAudioSessionManager2 = GUID(
    '{77aa99a0-1bd6-484f-8bc7-2c654c9a9b6f}')
IID_IAudioSessionControl = GUID(
    '{F4B1A599-7266-4319-A8CA-E70ACB11E8CD}')
IID_IAudioSessionControl2 = GUID(
    '{BFB7FF88-7239-4FC9-8FA2-07C950BE9C6D}')

CLSID_MMDeviceEnumerator = GUID(
    '{BCDE0395-E52F-467C-8E3D-C4579291692E}')

class ERole(Enum):
    eConsole = 0
    eMultimedia = 1
    eCommunications = 2
    ERole_enum_count = 3

class EDataFlow(Enum):
    eRender = 0
    eCapture = 1
    eAll = 2
    EDataFlow_enum_count = 3

class IAudioEndpointVolume(comtypes.IUnknown):
    _iid_ = IID_IAudioEndpointVolume
    _methods_ = (
        # HRESULT RegisterControlChangeNotify(
        # [in] IAudioEndpointVolumeCallback *pNotify);
        COMMETHOD([], HRESULT, 'NotImpl1'),
        # HRESULT UnregisterControlChangeNotify(
        # [in] IAudioEndpointVolumeCallback *pNotify);
        COMMETHOD([], HRESULT, 'NotImpl2'),
        # HRESULT GetChannelCount([out] UINT *pnChannelCount);
        COMMETHOD([], HRESULT, 'GetChannelCount',
                  (['out'], POINTER(UINT), 'pnChannelCount')),
        # HRESULT SetMasterVolumeLevel(
        # [in] float fLevelDB, [in] LPCGUID pguidEventContext);
        COMMETHOD([], HRESULT, 'SetMasterVolumeLevel',
                  (['in'], c_float, 'fLevelDB'),
                  (['in'], POINTER(GUID), 'pguidEventContext')),
        # HRESULT SetMasterVolumeLevelScalar(
        # [in] float fLevel, [in] LPCGUID pguidEventContext);
        COMMETHOD([], HRESULT, 'SetMasterVolumeLevelScalar',
                  (['in'], c_float, 'fLevelDB'),
                  (['in'], POINTER(GUID), 'pguidEventContext')),
        # HRESULT GetMasterVolumeLevel([out] float *pfLevelDB);
        COMMETHOD([], HRESULT, 'GetMasterVolumeLevel',
                  (['out'], POINTER(c_float), 'pfLevelDB')),
        # HRESULT GetMasterVolumeLevelScalar([out] float *pfLevel);
        COMMETHOD([], HRESULT, 'GetMasterVolumeLevelScalar',
                  (['out'], POINTER(c_float), 'pfLevelDB')),
        # HRESULT SetChannelVolumeLevel(
        # [in] UINT nChannel,
        # [in] float fLevelDB,
        # [in] LPCGUID pguidEventContext);
        COMMETHOD([], HRESULT, 'SetChannelVolumeLevel',
                  (['in'], UINT, 'nChannel'),
                  (['in'], c_float, 'fLevelDB'),
                  (['in'], POINTER(GUID), 'pguidEventContext')),
        # HRESULT SetChannelVolumeLevelScalar(
        # [in] UINT nChannel,
        # [in] float fLevel,
        # [in] LPCGUID pguidEventContext);
        COMMETHOD([], HRESULT, 'SetChannelVolumeLevelScalar',
                  (['in'], DWORD, 'nChannel'),
                  (['in'], c_float, 'fLevelDB'),
                  (['in'], POINTER(GUID), 'pguidEventContext')),
        # HRESULT GetChannelVolumeLevel(
        # [in]  UINT nChannel,
        # [out] float *pfLevelDB);
        COMMETHOD([], HRESULT, 'GetChannelVolumeLevel',
                  (['in'], UINT, 'nChannel'),
                  (['out'], POINTER(c_float), 'pfLevelDB')),
        # HRESULT GetChannelVolumeLevelScalar(
        # [in]  UINT nChannel,
        # [out] float *pfLevel);
        COMMETHOD([], HRESULT, 'GetChannelVolumeLevelScalar',
                  (['in'], DWORD, 'nChannel'),
                  (['out'], POINTER(c_float), 'pfLevelDB')),
        # HRESULT SetMute([in] BOOL bMute, [in] LPCGUID pguidEventContext);
        COMMETHOD([], HRESULT, 'SetMute',
                  (['in'], BOOL, 'bMute'),
                  (['in'], POINTER(GUID), 'pguidEventContext')),
        # HRESULT GetMute([out] BOOL *pbMute);
        COMMETHOD([], HRESULT, 'GetMute',
                  (['out'], POINTER(BOOL), 'pbMute')),
        # HRESULT GetVolumeStepInfo(
        # [out] UINT *pnStep,
        # [out] UINT *pnStepCount);
        COMMETHOD([], HRESULT, 'GetVolumeStepInfo',
                  (['out'], POINTER(c_float), 'pnStep'),
                  (['out'], POINTER(c_float), 'pnStepCount')),
        # HRESULT VolumeStepUp([in] LPCGUID pguidEventContext);
        COMMETHOD([], HRESULT, 'VolumeStepUp',
                  (['in'], POINTER(GUID), 'pguidEventContext')),
        # HRESULT VolumeStepDown([in] LPCGUID pguidEventContext);
        COMMETHOD([], HRESULT, 'VolumeStepDown',
                  (['in'], POINTER(GUID), 'pguidEventContext')),
        # HRESULT QueryHardwareSupport([out] DWORD *pdwHardwareSupportMask);
        COMMETHOD([], HRESULT, 'QueryHardwareSupport',
                  (['out'], POINTER(DWORD), 'pdwHardwareSupportMask')),
        # HRESULT GetVolumeRange(
        # [out] float *pfLevelMinDB,
        # [out] float *pfLevelMaxDB,
        # [out] float *pfVolumeIncrementDB);
        COMMETHOD([], HRESULT, 'GetVolumeRange',
                  (['out'], POINTER(c_float), 'pfMin'),
                  (['out'], POINTER(c_float), 'pfMax'),
                  (['out'], POINTER(c_float), 'pfIncr')))

class IMMDeviceCollection(comtypes.IUnknown):
    _iid_ = IID_IMMDeviceCollection
    _methods_ = (
        # HRESULT GetCount([out] UINT *pcDevices);
        COMMETHOD([], HRESULT, 'NotImpl1'),
        # HRESULT Item([in] UINT nDevice, [out] IMMDevice **ppDevice);
        COMMETHOD([], HRESULT, 'NotImpl2'))

class IAudioSessionControl(comtypes.IUnknown):
    _iid_ = IID_IAudioSessionControl
    _methods_ = (
        # HRESULT GetState ([out] AudioSessionState *pRetVal);
        COMMETHOD([], HRESULT, 'NotImpl1'),
        # HRESULT GetDisplayName([out] LPWSTR *pRetVal);
        COMMETHOD([], HRESULT, 'GetDisplayName',
                  (['out'], POINTER(LPWSTR), 'pRetVal')),
        # HRESULT SetDisplayName(
        # [in] LPCWSTR Value,
        # [in] LPCGUID EventContext);
        COMMETHOD([], HRESULT, 'NotImpl2'),
        # HRESULT GetIconPath([out] LPWSTR *pRetVal);
        COMMETHOD([], HRESULT, 'NotImpl3'),
        # HRESULT SetIconPath(
        # [in] LPCWSTR Value,
        # [in] LPCGUID EventContext);
        COMMETHOD([], HRESULT, 'NotImpl4'),
        # HRESULT GetGroupingParam([out] GUID *pRetVal);
        COMMETHOD([], HRESULT, 'NotImpl5'),
        # HRESULT SetGroupingParam(
        # [in] LPCGUID Grouping,
        # [in] LPCGUID EventContext);
        COMMETHOD([], HRESULT, 'NotImpl6'),
        # HRESULT RegisterAudioSessionNotification(
        # [in] IAudioSessionEvents *NewNotifications);
        COMMETHOD([], HRESULT, 'NotImpl7'),
        # HRESULT UnregisterAudioSessionNotification(
        # [in] IAudioSessionEvents *NewNotifications);
        COMMETHOD([], HRESULT, 'NotImpl8'))

class IAudioSessionControl2(IAudioSessionControl):
    _iid_ = IID_IAudioSessionControl2
    _methods_ = (
        # HRESULT GetSessionIdentifier([out] LPWSTR *pRetVal);
        COMMETHOD([], HRESULT, 'NotImpl1'),
        # HRESULT GetSessionInstanceIdentifier([out] LPWSTR *pRetVal);
        COMMETHOD([], HRESULT, 'NotImpl2'),
        # HRESULT GetProcessId([out] DWORD *pRetVal);
        COMMETHOD([], HRESULT, 'GetProcessId',
                  (['out'], POINTER((DWORD)), 'pRetVal')),
        # HRESULT IsSystemSoundsSession();
        COMMETHOD([], HRESULT, 'IsSystemSoundsSession'))

class IAudioSessionEnumerator(comtypes.IUnknown):
    _iid_ = IID_IAudioSessionEnumerator
    _methods_ = (
        # HRESULT GetCount([out] int *SessionCount);
        COMMETHOD([], HRESULT, 'GetCount',
                  (['out'], POINTER(INT), 'SessionCount')),
        # HRESULT GetSession(
        # [in] int SessionCount,
        # [out] IAudioSessionControl **Session);
        COMMETHOD([], HRESULT, 'GetSession',
                  (['in'], INT, 'SessionCount'),
                  (['out'],
                   POINTER(POINTER(IAudioSessionControl)), 'Session')))
<commit_msg>Added IAudioSessionManager class<commit_after>"""
Python wrapper around the Core Audio Windows API.
"""
import comtypes
from enum import Enum
from ctypes import HRESULT, POINTER, c_float, c_void_p
from ctypes.wintypes import BOOL, DWORD, UINT, INT, LPWSTR
from comtypes import GUID, COMMETHOD

IID_IAudioEndpointVolume = GUID(
    '{5CDF2C82-841E-4546-9722-0CF74078229A}')
IID_IMMDevice = GUID(
    '{D666063F-1587-4E43-81F1-B948E807363F}')
IID_IMMDeviceCollection = GUID(
    '{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}')
IID_IMMDeviceEnumerator = GUID(
    '{A95664D2-9614-4F35-A746-DE8DB63617E6}')
IID_IAudioSessionEnumerator = GUID(
    '{E2F5BB11-0570-40CA-ACDD-3AA01277DEE8}')
IID_IAudioSessionManager = GUID(
    '{BFA971F1-4d5e-40bb-935e-967039bfbee4}')
IID_IAudioSessionManager2 = GUID(
    '{77aa99a0-1bd6-484f-8bc7-2c654c9a9b6f}')
IID_IAudioSessionControl = GUID(
    '{F4B1A599-7266-4319-A8CA-E70ACB11E8CD}')
IID_IAudioSessionControl2 = GUID(
    '{BFB7FF88-7239-4FC9-8FA2-07C950BE9C6D}')

CLSID_MMDeviceEnumerator = GUID(
    '{BCDE0395-E52F-467C-8E3D-C4579291692E}')

class ERole(Enum):
    eConsole = 0
    eMultimedia = 1
    eCommunications = 2
    ERole_enum_count = 3

class EDataFlow(Enum):
    eRender = 0
    eCapture = 1
    eAll = 2
    EDataFlow_enum_count = 3

class IAudioEndpointVolume(comtypes.IUnknown):
    _iid_ = IID_IAudioEndpointVolume
    _methods_ = (
        # HRESULT RegisterControlChangeNotify(
        # [in] IAudioEndpointVolumeCallback *pNotify);
        COMMETHOD([], HRESULT, 'NotImpl1'),
        # HRESULT UnregisterControlChangeNotify(
        # [in] IAudioEndpointVolumeCallback *pNotify);
        COMMETHOD([], HRESULT, 'NotImpl2'),
        # HRESULT GetChannelCount([out] UINT *pnChannelCount);
        COMMETHOD([], HRESULT, 'GetChannelCount',
                  (['out'], POINTER(UINT), 'pnChannelCount')),
        # HRESULT SetMasterVolumeLevel(
        # [in] float fLevelDB, [in] LPCGUID pguidEventContext);
        COMMETHOD([], HRESULT, 'SetMasterVolumeLevel',
                  (['in'], c_float, 'fLevelDB'),
                  (['in'], POINTER(GUID), 'pguidEventContext')),
        # HRESULT SetMasterVolumeLevelScalar(
        # [in] float fLevel, [in] LPCGUID pguidEventContext);
        COMMETHOD([], HRESULT, 'SetMasterVolumeLevelScalar',
                  (['in'], c_float, 'fLevelDB'),
                  (['in'], POINTER(GUID), 'pguidEventContext')),
        # HRESULT GetMasterVolumeLevel([out] float *pfLevelDB);
        COMMETHOD([], HRESULT, 'GetMasterVolumeLevel',
                  (['out'], POINTER(c_float), 'pfLevelDB')),
        # HRESULT GetMasterVolumeLevelScalar([out] float *pfLevel);
        COMMETHOD([], HRESULT, 'GetMasterVolumeLevelScalar',
                  (['out'], POINTER(c_float), 'pfLevelDB')),
        # HRESULT SetChannelVolumeLevel(
        # [in] UINT nChannel,
        # [in] float fLevelDB,
        # [in] LPCGUID pguidEventContext);
        COMMETHOD([], HRESULT, 'SetChannelVolumeLevel',
                  (['in'], UINT, 'nChannel'),
                  (['in'], c_float, 'fLevelDB'),
                  (['in'], POINTER(GUID), 'pguidEventContext')),
        # HRESULT SetChannelVolumeLevelScalar(
        # [in] UINT nChannel,
        # [in] float fLevel,
        # [in] LPCGUID pguidEventContext);
        COMMETHOD([], HRESULT, 'SetChannelVolumeLevelScalar',
                  (['in'], DWORD, 'nChannel'),
                  (['in'], c_float, 'fLevelDB'),
                  (['in'], POINTER(GUID), 'pguidEventContext')),
        # HRESULT GetChannelVolumeLevel(
        # [in]  UINT nChannel,
        # [out] float *pfLevelDB);
        COMMETHOD([], HRESULT, 'GetChannelVolumeLevel',
                  (['in'], UINT, 'nChannel'),
                  (['out'], POINTER(c_float), 'pfLevelDB')),
        # HRESULT GetChannelVolumeLevelScalar(
        # [in]  UINT nChannel,
        # [out] float *pfLevel);
        COMMETHOD([], HRESULT, 'GetChannelVolumeLevelScalar',
                  (['in'], DWORD, 'nChannel'),
                  (['out'], POINTER(c_float), 'pfLevelDB')),
        # HRESULT SetMute([in] BOOL bMute, [in] LPCGUID pguidEventContext);
        COMMETHOD([], HRESULT, 'SetMute',
                  (['in'], BOOL, 'bMute'),
                  (['in'], POINTER(GUID), 'pguidEventContext')),
        # HRESULT GetMute([out] BOOL *pbMute);
        COMMETHOD([], HRESULT, 'GetMute',
                  (['out'], POINTER(BOOL), 'pbMute')),
        # HRESULT GetVolumeStepInfo(
        # [out] UINT *pnStep,
        # [out] UINT *pnStepCount);
        COMMETHOD([], HRESULT, 'GetVolumeStepInfo',
                  (['out'], POINTER(c_float), 'pnStep'),
                  (['out'], POINTER(c_float), 'pnStepCount')),
        # HRESULT VolumeStepUp([in] LPCGUID pguidEventContext);
        COMMETHOD([], HRESULT, 'VolumeStepUp',
                  (['in'], POINTER(GUID), 'pguidEventContext')),
        # HRESULT VolumeStepDown([in] LPCGUID pguidEventContext);
        COMMETHOD([], HRESULT, 'VolumeStepDown',
                  (['in'], POINTER(GUID), 'pguidEventContext')),
        # HRESULT QueryHardwareSupport([out] DWORD *pdwHardwareSupportMask);
        COMMETHOD([], HRESULT, 'QueryHardwareSupport',
                  (['out'], POINTER(DWORD), 'pdwHardwareSupportMask')),
        # HRESULT GetVolumeRange(
        # [out] float *pfLevelMinDB,
        # [out] float *pfLevelMaxDB,
        # [out] float *pfVolumeIncrementDB);
        COMMETHOD([], HRESULT, 'GetVolumeRange',
                  (['out'], POINTER(c_float), 'pfMin'),
                  (['out'], POINTER(c_float), 'pfMax'),
                  (['out'], POINTER(c_float), 'pfIncr')))

class IMMDeviceCollection(comtypes.IUnknown):
    _iid_ = IID_IMMDeviceCollection
    _methods_ = (
        # HRESULT GetCount([out] UINT *pcDevices);
        COMMETHOD([], HRESULT, 'NotImpl1'),
        # HRESULT Item([in] UINT nDevice, [out] IMMDevice **ppDevice);
        COMMETHOD([], HRESULT, 'NotImpl2'))

class IAudioSessionControl(comtypes.IUnknown):
    _iid_ = IID_IAudioSessionControl
    _methods_ = (
        # HRESULT GetState ([out] AudioSessionState *pRetVal);
        COMMETHOD([], HRESULT, 'NotImpl1'),
        # HRESULT GetDisplayName([out] LPWSTR *pRetVal);
        COMMETHOD([], HRESULT, 'GetDisplayName',
                  (['out'], POINTER(LPWSTR), 'pRetVal')),
        # HRESULT SetDisplayName(
        # [in] LPCWSTR Value,
        # [in] LPCGUID EventContext);
        COMMETHOD([], HRESULT, 'NotImpl2'),
        # HRESULT GetIconPath([out] LPWSTR *pRetVal);
        COMMETHOD([], HRESULT, 'NotImpl3'),
        # HRESULT SetIconPath(
        # [in] LPCWSTR Value,
        # [in] LPCGUID EventContext);
        COMMETHOD([], HRESULT, 'NotImpl4'),
        # HRESULT GetGroupingParam([out] GUID *pRetVal);
        COMMETHOD([], HRESULT, 'NotImpl5'),
        # HRESULT SetGroupingParam(
        # [in] LPCGUID Grouping,
        # [in] LPCGUID EventContext);
        COMMETHOD([], HRESULT, 'NotImpl6'),
        # HRESULT RegisterAudioSessionNotification(
        # [in] IAudioSessionEvents *NewNotifications);
        COMMETHOD([], HRESULT, 'NotImpl7'),
        # HRESULT UnregisterAudioSessionNotification(
        # [in] IAudioSessionEvents *NewNotifications);
        COMMETHOD([], HRESULT, 'NotImpl8'))

class IAudioSessionControl2(IAudioSessionControl):
    _iid_ = IID_IAudioSessionControl2
    _methods_ = (
        # HRESULT GetSessionIdentifier([out] LPWSTR *pRetVal);
        COMMETHOD([], HRESULT, 'NotImpl1'),
        # HRESULT GetSessionInstanceIdentifier([out] LPWSTR *pRetVal);
        COMMETHOD([], HRESULT, 'NotImpl2'),
        # HRESULT GetProcessId([out] DWORD *pRetVal);
        COMMETHOD([], HRESULT, 'GetProcessId',
                  (['out'], POINTER((DWORD)), 'pRetVal')),
        # HRESULT IsSystemSoundsSession();
        COMMETHOD([], HRESULT, 'IsSystemSoundsSession'))

class IAudioSessionEnumerator(comtypes.IUnknown):
    _iid_ = IID_IAudioSessionEnumerator
    _methods_ = (
        # HRESULT GetCount([out] int *SessionCount);
        COMMETHOD([], HRESULT, 'GetCount',
                  (['out'], POINTER(INT), 'SessionCount')),
        # HRESULT GetSession(
        # [in] int SessionCount,
        # [out] IAudioSessionControl **Session);
        COMMETHOD([], HRESULT, 'GetSession',
                  (['in'], INT, 'SessionCount'),
                  (['out'],
                   POINTER(POINTER(IAudioSessionControl)), 'Session')))

class IAudioSessionManager(comtypes.IUnknown):
    _iid_ = IID_IAudioSessionManager
    _methods_ = (
        # HRESULT GetAudioSessionControl(
        # [in] LPCGUID AudioSessionGuid,
        # [in] DWORD StreamFlags,
        # [out] IAudioSessionControl **SessionControl);
        COMMETHOD([], HRESULT, 'NotImpl1'),
        # HRESULT GetSimpleAudioVolume(
        # [in] LPCGUID AudioSessionGuid,
        # [in] DWORD CrossProcessSession,
        # [out] ISimpleAudioVolume **AudioVolume);
        COMMETHOD([], HRESULT, 'NotImpl2'))
<|endoftext|>


<commit_before>import copy

class Proxy(object):
    """
    The proxy is a transparent wrapper that intercepts all access to the
    underlying object. When first created, is keeps creates a shallow copy
    of the underlying object and behaves like a shadow reference. When
    any attribute of the underlying object is modified, the Proxy either
    creates a complete deep copy (it deep copies the entire object it was
    tracking) or creates a partial deep copy (it deep copies only the
    attribute that was touched). This behavior is triggered by an appropriate
    flag.

    Example:
    >>> #some examples here
    """
    __slots__ = ["_obj", "__weakref__", "__slots__", "_is_copied", "_enable_partial_copy"]

    _is_copied = False

    def __init__(self, obj, _partial_copy=False):
        object.__setattr__(self, "_obj", obj)
        object.__setattr__(self, "_enable_partial_copy", _partial_copy)

    def __getattribute__(self, name):
        """
        In order to fetch the attribute of the underlying object,
        the proxy redirects it the call to the reference of the
        underlying object, _obj.
        """
        slots = object.__getattribute__(self, "__slots__")
        if name not in slots:
            return getattr(object.__getattribute__(self, "_obj"), name)
        else:
            return object.__getattribute__(self, name)

    def __delattr__(self, name):
        slots = object.__getattribute__(self, "__slots__")
        if name not in slots:
            delattr(object.__getattribute__(self, "_obj"), name)
        else:
            raise Exception("Modification of proxy objects can lead to unexpected behavior")

    def __setattr__(self, name, value):
        slots = object.__getattribute__(self, "__slots__")
        if name not in slots:
            if not self._is_copied and not self._enable_partial_copy:
                self._obj = copy.deepcopy(self._obj)
                self._is_copied = True
            setattr(object.__getattribute__(self, "_obj"), name, value)
        else:
            object.__setattr__(self, name, value)

    _special_names = [
        '__abs__', '__add__', '__and__', '__call__', '__cmp__', '__coerce__',
        '__contains__', '__delitem__', '__delslice__', '__div__', '__divmod__',
        '__eq__', '__float__', '__floordiv__', '__ge__', '__getitem__',
        '__getslice__', '__gt__', '__hash__', '__hex__', '__iadd__', '__iand__',
        '__idiv__', '__idivmod__', '__ifloordiv__', '__ilshift__', '__imod__',
        '__imul__', '__int__', '__invert__', '__ior__', '__ipow__', '__irshift__',
        '__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__', '__len__',
        '__long__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__',
        '__neg__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__',
        '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__',
        '__repr__', '__reversed__', '__rfloorfiv__', '__rlshift__', '__rmod__',
        '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__',
        '__rtruediv__', '__rxor__', '__setitem__', '__setslice__', '__str__',
        '__sub__', '__truediv__', '__xor__', 'next',
    ]

    @classmethod
    def _create_class_proxy(cls, theclass):
        """creates a proxy for the given class"""

        def make_method(name):
            def method(self, *args, **kw):
                if name in cls._special_names and args is not ():
                    args = map(lambda x: x._obj if isinstance(x, Proxy) else x, args)
                return getattr(object.__getattribute__(self, "_obj"), name)(*args, **kw)
            return method

        namespace = {}
        for name in cls._special_names:
            if hasattr(theclass, name):
                namespace[name] = make_method(name)
        return type("%s(%s)" % (cls.__name__, theclass.__name__), (cls,), namespace)

    def __new__(cls, obj, *args, **kwargs):
        """
        creates an proxy instance referencing `obj`. (obj, *args, **kwargs) are
        passed to this class' __init__, so deriving classes can define an
        __init__ method of their own.
        note: _class_proxy_cache is unique per deriving class (each deriving
        class must hold its own cache)
        """
        try:
            cache = cls.__dict__["_class_proxy_cache"]
        except KeyError:
            cls._class_proxy_cache = cache = {}
        try:
            theclass = cache[obj.__class__]
        except KeyError:
            cache[obj.__class__] = theclass = cls._create_class_proxy(obj.__class__)
        ins = object.__new__(theclass)
        theclass.__init__(ins, obj, *args, **kwargs)
        return ins
<commit_msg>Buggy but working partial copy-on-write<commit_after>import copy

class Proxy(object):
    """
    The proxy is a transparent wrapper that intercepts all access to the
    underlying object. When first created, is keeps creates a shallow copy
    of the underlying object and behaves like a shadow reference. When
    any attribute of the underlying object is modified, the Proxy either
    creates a complete deep copy (it deep copies the entire object it was
    tracking) or creates a partial deep copy (it deep copies only the
    attribute that was touched). This behavior is triggered by an appropriate
    flag.

    Example:
    >>> #some examples here
    """
    __slots__ = ["_obj", "__weakref__", "__slots__", "_is_copied",
                 "_enable_partial_copy", "_attr_map"]

    _is_copied = False
    _attr_map = {}

    def __init__(self, obj, _partial_copy=False):
        object.__setattr__(self, "_obj", obj)
        object.__setattr__(self, "_enable_partial_copy", _partial_copy)

    def __getattribute__(self, name):
        """
        In order to fetch the attribute of the underlying object,
        the proxy redirects it the call to the reference of the
        underlying object, _obj.
        """
        slots = object.__getattribute__(self, "__slots__")
        attr_map = object.__getattribute__(self, "_attr_map")
        if name not in slots:
            print "Getting attribute: " + name
            if name in attr_map:
                print "Returning value in attr map"
                return attr_map[name]
            attr = getattr(object.__getattribute__(self, "_obj"), name)
            if isinstance(attr, int):
                return attr
            proxy_attr = Proxy(attr)
            attr_map[name] = proxy_attr
            object.__setattr__(self, "_attr_map", attr_map)
            return attr
            #return getattr(object.__getattribute__(self, "_obj"), name)
        else:
            return object.__getattribute__(self, name)

    def __delattr__(self, name):
        slots = object.__getattribute__(self, "__slots__")
        if name not in slots:
            delattr(object.__getattribute__(self, "_obj"), name)
        else:
            raise Exception("Modification of proxy objects can lead to unexpected behavior")

    def __setattr__(self, name, value):
        print "Setting attribute: " + name + " " + str(value)
        slots = object.__getattribute__(self, "__slots__")
        attr_map = object.__getattribute__(self, "_attr_map")
        if name not in slots:
            # If we are not partially copying, copy everything
            if not self._is_copied and not self._enable_partial_copy:
                print "Deep copy"
                self._obj = copy.deepcopy(self._obj)
                self._is_copied = True

            # If partial copying is enabled, store the new value in the attribute map
            if self._enable_partial_copy:
                self._attr_map[name] = value
                return

            setattr(object.__getattribute__(self, "_obj"), name, value)
            if name in attr_map:
                attr_map[name] = value
            object.__setattr__(self, "_attr_map", attr_map)
            print "Set attribute " + name + " " + str(value)
        else:
            object.__setattr__(self, name, value)

    _special_names = [
        '__abs__', '__add__', '__and__', '__call__', '__cmp__', '__coerce__',
        '__contains__', '__delitem__', '__delslice__', '__div__', '__divmod__',
        '__eq__', '__float__', '__floordiv__', '__ge__', '__getitem__',
        '__getslice__', '__gt__', '__hash__', '__hex__', '__iadd__', '__iand__',
        '__idiv__', '__idivmod__', '__ifloordiv__', '__ilshift__', '__imod__',
        '__imul__', '__int__', '__invert__', '__ior__', '__ipow__', '__irshift__',
        '__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__', '__len__',
        '__long__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__',
        '__neg__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__',
        '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__',
        '__repr__', '__reversed__', '__rfloorfiv__', '__rlshift__', '__rmod__',
        '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__',
        '__rtruediv__', '__rxor__', '__setitem__', '__setslice__', '__str__',
        '__sub__', '__truediv__', '__xor__', 'next',
    ]

    @classmethod
    def _create_class_proxy(cls, theclass):
        """creates a proxy for the given class"""

        def make_method(name):
            def method(self, *args, **kw):
                if name in cls._special_names and args is not ():
                    args = map(lambda x: x._obj if isinstance(x, Proxy) else x, args)
                return getattr(object.__getattribute__(self, "_obj"), name)(*args, **kw)
            return method

        namespace = {}
        for name in cls._special_names:
            if hasattr(theclass, name):
                namespace[name] = make_method(name)
        return type("%s(%s)" % (cls.__name__, theclass.__name__), (cls,), namespace)

    def __new__(cls, obj, *args, **kwargs):
        """
        creates an proxy instance referencing `obj`. (obj, *args, **kwargs) are
        passed to this class' __init__, so deriving classes can define an
        __init__ method of their own.
        note: _class_proxy_cache is unique per deriving class (each deriving
        class must hold its own cache)
        """
        try:
            cache = cls.__dict__["_class_proxy_cache"]
        except KeyError:
            cls._class_proxy_cache = cache = {}
        try:
            theclass = cache[obj.__class__]
        except KeyError:
            cache[obj.__class__] = theclass = cls._create_class_proxy(obj.__class__)
        ins = object.__new__(theclass)
        theclass.__init__(ins, obj, *args, **kwargs)
        return ins
<|endoftext|>


<commit_before>import simulator

"""
    назначение: функция определения множителя к параметру
    входные параметры:
        param        -- параметр студента
    выходные параметры:
        множитель
    значение границы, множителя: [-100, 10], [100, 0.1]
"""
def multiplier(param):
    return -4.95 * param + 5.5

class Quest:
    """
        Каждое задание имеет два возможных варианта исхода,
        которые по разному изменяют параметры студента.
        Автоматически будет выбираться тот вариант,
        который "подвинет" студента ближе к нормальному состоянию,
        т.е. минимизируется модуль суммы векторов задания и студента.
    """
    # название задания
    name = 'demo-quest'
    # первый вариант выполнения задания
    #   влияние задания на студента
    impact_one = {
        'mood':     0,
        'progress': 0,
        'satiety':  0,
        'finances': 0
    }
    #   название решения
    one_name = 'first'
    # первый вариант выполнения задания
    #   влияние задания на студента
    impact_two = {
        'mood':     0,
        'progress': 0,
        'satiety':  0,
        'finances': 0
    }
    #   название решения
    two_name = 'second'
    # получаемый опыт
    xp = 0
    # продолжительность (в шагах)
    duration = 1
    # текст выводимый при получении задания
    info = ''

    """
        назначение: инициализация класса
        входные параметры:
            name        -- название задания
            one         -- словарь влияния первого варианта решения на студента
            one_name    -- название первого варианта решения
            two         -- словарь влияния второго варианта решения на студента
            two_name    -- название второго варианта решения
            xp          -- количество получаемого опыта
            name        -- название задания
            duration    -- продолжительность задания
            info        -- текст выводимый при получении задания
        выходные параметры:
            None
    """
    def __init__(self, name='кнопку "Старт" для начала симуляции',
                       one_name='Нажмите',
                       one={'mood':0,'progress':0,'satiety':0,'finances':0},
                       two_name='Жмякни',
                       two={'mood':0,'progress':0,'satiety':0,'finances':0},
                       xp=0, duration=1, info=''):
        self.name       = name
        self.one_name   = one_name
        self.one_impact = one
        self.two_name   = two_name
        self.two_impact = two
        self.xp         = xp
        self.duration   = duration
        self.info       = info

    """
        назначение: функция переопределения значений квеста в соответствии с параметрами студента
        входные параметры:
            quest        -- выбранный квест
            student      -- параметры студента
        выходные параметры:
            None
    """
    def multParam(self, student):
        mood, progress, satiety, finances = student
        self.impact_one['mood'] *= multiplier(mood)
        self.impact_one['progress'] *= multiplier(progress)
        self.impact_one['satiety'] *= multiplier(satiety)
        self.impact_one['finances'] *= multiplier(finances)
        self.impact_two['mood'] *= multiplier(mood)
        self.impact_two['progress'] *= multiplier(progress)
        self.impact_two['satiety'] *= multiplier(satiety)
        self.impact_two['finances'] *= multiplier(finances)

    def __str__(self):
        return '{}, {}, {}; {}: {}, {}: {}'.format(self.name, self.xp, self.duration,
            self.one_name, self.one_impact, self.two_name, self.two_impact)

def auto_choice(student, quest):
    one = [
        quest.one_impact['mood'],
        quest.one_impact['progress'],
        quest.one_impact['satiety'],
        quest.one_impact['finances']
    ]
    two = [
        quest.two_impact['mood'],
        quest.two_impact['progress'],
        quest.two_impact['satiety'],
        quest.two_impact['finances']
    ]
    st_one = abs(sum(list(map(lambda i, j: (i + j) ** 2, student, one))))
    st_two = abs(sum(list(map(lambda i, j: (i + j) ** 2, student, two))))
    if st_one > st_two:
        # student choses second type
        return 0
    else:
        # student choses first type
        return 1

job_list = [
    # шаблон задания:
    # Quest(name,
    #       one_name, {'mood': mood1, 'progress': progress1, 'satiety': satiety1, 'finances': finances1},
    #       two_name, {'mood': mood2, 'progress': progress2, 'satiety': satiety2, 'finances': finances2},
    #       xp, duration)
    # Значения mood1,2, progress1,2 и др. являются коэффициентами (!),
    # реальное значение изменений зависит от текущего состояния студента
    Quest('пары',
          'Посетить',      {'mood':  0, 'progress':  1, 'satiety':  0, 'finances':  0},
          'Пропустить',    {'mood':  1, 'progress': -1, 'satiety':  0, 'finances':  0},
           30, 3, 'Пора и поучиться'),
    Quest('курсовую',
          'Сделать',       {'mood': -1, 'progress':  3, 'satiety': -1, 'finances':  0},
          'Купить',        {'mood':  1, 'progress':  3, 'satiety':  0, 'finances': -2},
           50, 5, 'Hate this'),
    Quest('',
          'Играться',      {'mood':  2, 'progress':  0, 'satiety': -1, 'finances':  0},
          'Прогуляться',   {'mood':  3, 'progress':  0, 'satiety': -1, 'finances': -1},
           30, 3, 'I love it!'),
    Quest('еду',
          'Приготовить',   {'mood':  1, 'progress':  0, 'satiety':  2, 'finances':  0},
          'Заказать',      {'mood':  3, 'progress':  0, 'satiety':  2, 'finances': -1},
           10, 1, 'omnomnom'),
    Quest('денег',
          'Работать ради', {'mood':  1, 'progress': -1, 'satiety': -1, 'finances':  3},
          'Одолжить',      {'mood': -1, 'progress':  0, 'satiety':  0, 'finances':  3},
           50, 5, 'no money - no honey')
]

def generate(student):
    from random import choice
    from copy import deepcopy
    mood, progress, satiety, finances = student
    # принудительный выбор заданий при достижении границ
    if satiety < -80:
        quest = deepcopy(job_list[3])
    elif mood < -80:
        quest = deepcopy(job_list[2])
    elif progress < -80:
        quest = deepcopy(job_list[1])
    elif finances < -80:
        quest = deepcopy(job_list[4])
    else:
        quest = deepcopy(choice(job_list))
    quest.multParam(student)
    return quest
<commit_msg>[fix] impact_{1,2} -> {1,2}_impact, mult functions & etc<commit_after>import simulator

"""
    назначение: функция определения множителя к параметру
    входные параметры:
        param        -- параметр студента
    выходные параметры:
        множитель
    значение границы, множителя: [-100, 10], [100, 0.1]
"""
def multiplier(param):
    return -0.0495 * param + 5.5

class Quest:
    """
        Каждое задание имеет два возможных варианта исхода,
        которые по разному изменяют параметры студента.
        Автоматически будет выбираться тот вариант,
        который "подвинет" студента ближе к нормальному состоянию,
        т.е. минимизируется модуль суммы векторов задания и студента.
    """
    # название задания
    name = 'demo-quest'
    # первый вариант выполнения задания
    #   влияние задания на студента
    one_impact = {
        'mood':     0,
        'progress': 0,
        'satiety':  0,
        'finances': 0
    }
    #   название решения
    one_name = 'first'
    # первый вариант выполнения задания
    #   влияние задания на студента
    two_impact = {
        'mood':     0,
        'progress': 0,
        'satiety':  0,
        'finances': 0
    }
    #   название решения
    two_name = 'second'
    # получаемый опыт
    xp = 0
    # продолжительность (в шагах)
    duration = 1
    # текст выводимый при получении задания
    info = ''

    """
        назначение: инициализация класса
        входные параметры:
            name        -- название задания
            one         -- словарь влияния первого варианта решения на студента
            one_name    -- название первого варианта решения
            two         -- словарь влияния второго варианта решения на студента
            two_name    -- название второго варианта решения
            xp          -- количество получаемого опыта
            name        -- название задания
            duration    -- продолжительность задания
            info        -- текст выводимый при получении задания
        выходные параметры:
            None
    """
    def __init__(self, name='кнопку "Старт" для начала симуляции',
                       one_name='Нажмите',
                       one={'mood':0,'progress':0,'satiety':0,'finances':0},
                       two_name='Жмякни',
                       two={'mood':0,'progress':0,'satiety':0,'finances':0},
                       xp=0, duration=1, info=''):
        self.name       = name
        self.one_name   = one_name
        self.one_impact = one
        self.two_name   = two_name
        self.two_impact = two
        self.xp         = xp
        self.duration   = duration
        self.info       = info

    """
        назначение: функция переопределения значений квеста в соответствии с параметрами студента
        входные параметры:
            quest        -- выбранный квест
            student      -- параметры студента
        выходные параметры:
            None
    """
    def multParam(self, student):
        mood, progress, satiety, finances = student
        self.one_impact['mood'] *= multiplier(mood)
        self.one_impact['progress'] *= multiplier(progress)
        self.one_impact['satiety'] *= multiplier(satiety)
        self.one_impact['finances'] *= multiplier(finances)
        self.two_impact['mood'] *= multiplier(mood)
        self.two_impact['progress'] *= multiplier(progress)
        self.two_impact['satiety'] *= multiplier(satiety)
        self.two_impact['finances'] *= multiplier(finances)

    def __str__(self):
        return '{}, {}, {}; {}: {}, {}: {}'.format(self.name, self.xp, self.duration,
            self.one_name, self.one_impact, self.two_name, self.two_impact)

def auto_choice(student, quest):
    one = [
        quest.one_impact['mood'],
        quest.one_impact['progress'],
        quest.one_impact['satiety'],
        quest.one_impact['finances']
    ]
    two = [
        quest.two_impact['mood'],
        quest.two_impact['progress'],
        quest.two_impact['satiety'],
        quest.two_impact['finances']
    ]
    st_one = abs(sum(list(map(lambda i, j: (i + j) ** 2, student, one))))
    st_two = abs(sum(list(map(lambda i, j: (i + j) ** 2, student, two))))
    if st_one > st_two:
        # student choses second type
        return 0
    else:
        # student choses first type
        return 1

job_list = [
    # шаблон задания:
    # Quest(name,
    #       one_name, {'mood': mood1, 'progress': progress1, 'satiety': satiety1, 'finances': finances1},
    #       two_name, {'mood': mood2, 'progress': progress2, 'satiety': satiety2, 'finances': finances2},
    #       xp, duration)
    # Значения mood1,2, progress1,2 и др. являются коэффициентами (!),
    # реальное значение изменений зависит от текущего состояния студента
    Quest('пары',
          'Посетить',      {'mood':  0, 'progress':  1, 'satiety':  0, 'finances':  0},
          'Пропустить',    {'mood':  1, 'progress': -1, 'satiety':  0, 'finances':  0},
           30, 3, 'Пора и поучиться'),
    Quest('курсовую',
          'Сделать',       {'mood': -1, 'progress':  3, 'satiety': -1, 'finances':  0},
          'Купить',        {'mood':  1, 'progress':  3, 'satiety':  0, 'finances': -2},
           50, 5, 'Hate this'),
    Quest('',
          'Играться',      {'mood':  2, 'progress':  0, 'satiety': -1, 'finances':  0},
          'Прогуляться',   {'mood':  3, 'progress':  0, 'satiety': -1, 'finances': -1},
           30, 3, 'I love it!'),
    Quest('еду',
          'Приготовить',   {'mood':  1, 'progress':  0, 'satiety':  2, 'finances':  0},
          'Заказать',      {'mood':  3, 'progress':  0, 'satiety':  2, 'finances': -1},
           10, 1, 'omnomnom'),
    Quest('денег',
          'Работать ради', {'mood':  1, 'progress': -1, 'satiety': -1, 'finances':  3},
          'Одолжить',      {'mood': -1, 'progress':  0, 'satiety':  0, 'finances':  3},
           50, 5, 'no money - no honey')
]

def generate(student):
    from random import choice
    from copy import deepcopy
    mood, progress, satiety, finances = student
    # принудительный выбор заданий при достижении границ
    if satiety < -80:
        quest = deepcopy(job_list[3])
    elif mood < -80:
        quest = deepcopy(job_list[2])
    elif progress < -80:
        quest = deepcopy(job_list[1])
    elif finances < -80:
        quest = deepcopy(job_list[4])
    else:
        quest = deepcopy(choice(job_list))
    quest.multParam(student)
    return quest
<|endoftext|>


<commit_before>__author__ = 'Valeria'

symbol = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

def to_base_10(number, base):
    error = False
    result = 0
    figures = []
    number = str(number)
    for k in range(len(number)):
        i = symbol.index(number[k])
        if i > 32:
            i -= 26
        if i > base:
            error = True
        figures.append(i)
    for k in range(len(figures)):
        result += (figures[k]) * base**(len(figures)-k-1)
    if error:
        return 'ERROR: Not valid number'
    else:
        return result

def from_base_10(number, base):
    values = []
    while number > 0:
        remainder = number % base
        values.append(remainder)
        number = number/base
    result = ''
    for i in range(len(values)):
        result += symbol[values[len(values)-1-i]]
    return result

def new_radix(number, old_base = 10 , new_base = 10):
    if old_base != 10:
        number = to_base_10(number, old_base)
    if new_base != 10:
        number = from_base_10(number, new_base)
    return number

def new_radix(number, old_base = 10 , new_base = 10):
    if old_base != 10:
        number = to_base_10(number, old_base)
    if new_base != 10:
        number = from_base_10(number, new_base)
    return number<commit_msg>Data types have beed corrected<commit_after>__author__ = 'Valeria'

symbol = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

def to_base_10(number, base):
    error = False
    result = 0
    figures = []
    number = str(number)
    for k in range(len(number)):
        i = symbol.index(number[k])
        if i > 32:
            i -= 26
        if i > base:
            error = True
        figures.append(i)
    for k in range(len(figures)):
        result += (figures[k]) * base**(len(figures)-k-1)
    result = str(result)
    if error:
        return 'ERROR: Not valid number'
    else:
        return result

def from_base_10(number, base):
    values = []
    try:
        number = int(number)
    except:
        return 'ERROR: Not valid number'
    while number > 0:
        remainder = number % base
        values.append(remainder)
        number = number/base
    result = ''
    for i in range(len(values)):
        result += symbol[values[len(values)-1-i]]
    return result

def new_radix(number, old_base = 10 , new_base = 10):
    if old_base != 10:
        number = to_base_10(number, old_base)
    if new_base != 10:
        number = from_base_10(number, new_base)
    return number

print new_radix(10, 8, 8)<|endoftext|>


<commit_before>"""
The :mod:`tslearn.preprocessing` module gathers time series scalers.
"""

import numpy
from sklearn.base import TransformerMixin
from scipy.interpolate import interp1d
import warnings

from tslearn.utils import to_time_series_dataset, check_equal_size, ts_size

__author__ = 'Romain Tavenard romain.tavenard[at]univ-rennes2.fr'

class TimeSeriesResampler(TransformerMixin):
    """Resampler for time series. Resample time series so that they reach the
    target size.

    Parameters
    ----------
    sz : int
        Size of the output time series.

    Examples
    --------
    >>> TimeSeriesResampler(sz=5).fit_transform([[0, 3, 6]])
    array([[[0. ],
            [1.5],
            [3. ],
            [4.5],
            [6. ]]])
    """
    def __init__(self, sz):
        self.sz_ = sz

    def fit(self, X, y=None, **kwargs):
        """A dummy method such that it complies to the sklearn requirements.
        Since this method is completely stateless, it just returns itself.

        Parameters
        ----------
        X
            Ignored

        Returns
        -------
        self
        """
        return self

    def transform(self, X, **kwargs):
        """Fit to data, then transform it.

        Parameters
        ----------
        X : array-like
            Time series dataset to be resampled.

        Returns
        -------
        numpy.ndarray
            Resampled time series dataset.
        """
        X_ = to_time_series_dataset(X)
        n_ts, sz, d = X_.shape
        equal_size = check_equal_size(X_)
        X_out = numpy.empty((n_ts, self.sz_, d))
        for i in range(X_.shape[0]):
            xnew = numpy.linspace(0, 1, self.sz_)
            if not equal_size:
                sz = ts_size(X_[i])
            for di in range(d):
                f = interp1d(numpy.linspace(0, 1, sz), X_[i, :sz, di],
                             kind="slinear")
                X_out[i, :, di] = f(xnew)
        return X_out

class TimeSeriesScalerMinMax(TransformerMixin):
    """Scaler for time series. Scales time series so that their span in each
    dimension is between ``min`` and ``max``.

    Parameters
    ----------
    value_range : tuple (default: (0., 1.))
        The minimum and maximum value for the output time series.

    min : float (default: 0.)
        Minimum value for output time series.

        .. deprecated:: 0.2
            min is deprecated in version 0.2 and will be
            removed in 0.4. Use value_range instead.

    max : float (default: 1.)
        Maximum value for output time series.

        .. deprecated:: 0.2
            min is deprecated in version 0.2 and will be
            removed in 0.4. Use value_range instead.

    Notes
    -----
        This method requires a dataset of equal-sized time series.

        NaNs within a time series are ignored when calculating min and max.

    Examples
    --------
    >>> TimeSeriesScalerMinMax(value_range=(1., 2.)).fit_transform([[0, 3, 6]])
    array([[[1. ],
            [1.5],
            [2. ]]])
    >>> TimeSeriesScalerMinMax(value_range=(1., 2.)).fit_transform([[numpy.nan, 3, 6]])
    array([[[nan],
            [1. ],
            [2. ]]])
    """
    def __init__(self, value_range=(0., 1.), min=None, max=None):
        self.value_range = value_range
        self.min_ = min
        self.max_ = max

    def fit(self, X, y=None, **kwargs):
        """A dummy method such that it complies to the sklearn requirements.
        Since this method is completely stateless, it just returns itself.

        Parameters
        ----------
        X
            Ignored

        Returns
        -------
        self
        """
        return self

    def transform(self, X, y=None, **kwargs):
        """Will normalize (min-max) each of the timeseries. IMPORTANT: this
        transformation is completely stateless, and is applied to each of
        the timeseries individually.

        Parameters
        ----------
        X : array-like
            Time series dataset to be rescaled.

        Returns
        -------
        numpy.ndarray
            Rescaled time series dataset.
        """
        if self.min_ is not None:
            warnings.warn(
                "'min' is deprecated in version 0.2 and will be "
                "removed in 0.4. Use value_range instead.",
                DeprecationWarning, stacklevel=2)
            self.value_range = (self.min_, self.value_range[1])

        if self.max_ is not None:
            warnings.warn(
                "'max' is deprecated in version 0.2 and will be "
                "removed in 0.4. Use value_range instead.",
                DeprecationWarning, stacklevel=2)
            self.value_range = (self.value_range[0], self.max_)

        if self.value_range[0] >= self.value_range[1]:
            raise ValueError("Minimum of desired range must be smaller"
                             " than maximum. Got %s." % str(self.value_range))

        X_ = to_time_series_dataset(X)
        min_t = numpy.nanmin(X_, axis=1)[:, numpy.newaxis, :]
        max_t = numpy.nanmax(X_, axis=1)[:, numpy.newaxis, :]
        range_t = max_t - min_t
        nomin = (X_ - min_t) * (self.value_range[1] - self.value_range[0])
        X_ = nomin / range_t + self.value_range[0]
        return X_

class TimeSeriesScalerMeanVariance(TransformerMixin):
    """Scaler for time series. Scales time series so that their mean (resp.
    standard deviation) in each dimension is
    mu (resp. std).

    Parameters
    ----------
    mu : float (default: 0.)
        Mean of the output time series.
    std : float (default: 1.)
        Standard deviation of the output time series.

    Notes
    -----
        This method requires a dataset of equal-sized time series.

        NaNs within a time series are ignored when calculating mu and std.

    Examples
    --------
    >>> TimeSeriesScalerMeanVariance(mu=0.,
    ...                              std=1.).fit_transform([[0, 3, 6]])
    array([[[-1.22474487],
            [ 0.        ],
            [ 1.22474487]]])
    >>> TimeSeriesScalerMeanVariance(mu=0.,
    ...                              std=1.).fit_transform([[numpy.nan, 3, 6]])
    array([[[nan],
            [-1.],
            [ 1.]]])
    """
    def __init__(self, mu=0., std=1.):
        self.mu_ = mu
        self.std_ = std
        self.global_mean = None
        self.global_std = None

    def fit(self, X, y=None, **kwargs):
        """A dummy method such that it complies to the sklearn requirements.
        Since this method is completely stateless, it just returns itself.

        Parameters
        ----------
        X
            Ignored

        Returns
        -------
        self
        """
        return self

    def transform(self, X, **kwargs):
        """Fit to data, then transform it.

        Parameters
        ----------
        X
            Time series dataset to be rescaled

        Returns
        -------
        numpy.ndarray
            Rescaled time series dataset
        """
        X_ = to_time_series_dataset(X)
        mean_t = numpy.nanmean(X_, axis=1)[:, numpy.newaxis, :]
        std_t = numpy.nanstd(X_, axis=1)[:, numpy.newaxis, :]
        std_t[std_t == 0.] = 1.

        X_ = (X_ - mean_t) * self.std_ / std_t + self.mu_

        return X_
<commit_msg>linter fix<commit_after>"""
The :mod:`tslearn.preprocessing` module gathers time series scalers.
"""

import numpy
from sklearn.base import TransformerMixin
from scipy.interpolate import interp1d
import warnings

from tslearn.utils import to_time_series_dataset, check_equal_size, ts_size

__author__ = 'Romain Tavenard romain.tavenard[at]univ-rennes2.fr'

class TimeSeriesResampler(TransformerMixin):
    """Resampler for time series. Resample time series so that they reach the
    target size.

    Parameters
    ----------
    sz : int
        Size of the output time series.

    Examples
    --------
    >>> TimeSeriesResampler(sz=5).fit_transform([[0, 3, 6]])
    array([[[0. ],
            [1.5],
            [3. ],
            [4.5],
            [6. ]]])
    """
    def __init__(self, sz):
        self.sz_ = sz

    def fit(self, X, y=None, **kwargs):
        """A dummy method such that it complies to the sklearn requirements.
        Since this method is completely stateless, it just returns itself.

        Parameters
        ----------
        X
            Ignored

        Returns
        -------
        self
        """
        return self

    def transform(self, X, **kwargs):
        """Fit to data, then transform it.

        Parameters
        ----------
        X : array-like
            Time series dataset to be resampled.

        Returns
        -------
        numpy.ndarray
            Resampled time series dataset.
        """
        X_ = to_time_series_dataset(X)
        n_ts, sz, d = X_.shape
        equal_size = check_equal_size(X_)
        X_out = numpy.empty((n_ts, self.sz_, d))
        for i in range(X_.shape[0]):
            xnew = numpy.linspace(0, 1, self.sz_)
            if not equal_size:
                sz = ts_size(X_[i])
            for di in range(d):
                f = interp1d(numpy.linspace(0, 1, sz), X_[i, :sz, di],
                             kind="slinear")
                X_out[i, :, di] = f(xnew)
        return X_out

class TimeSeriesScalerMinMax(TransformerMixin):
    """Scaler for time series. Scales time series so that their span in each
    dimension is between ``min`` and ``max``.

    Parameters
    ----------
    value_range : tuple (default: (0., 1.))
        The minimum and maximum value for the output time series.

    min : float (default: 0.)
        Minimum value for output time series.

        .. deprecated:: 0.2
            min is deprecated in version 0.2 and will be
            removed in 0.4. Use value_range instead.

    max : float (default: 1.)
        Maximum value for output time series.

        .. deprecated:: 0.2
            min is deprecated in version 0.2 and will be
            removed in 0.4. Use value_range instead.

    Notes
    -----
        This method requires a dataset of equal-sized time series.

        NaNs within a time series are ignored when calculating min and max.

    Examples
    --------
    >>> TimeSeriesScalerMinMax(value_range=(1., 2.)).fit_transform([[0, 3, 6]])
    array([[[1. ],
            [1.5],
            [2. ]]])
    >>> TimeSeriesScalerMinMax(value_range=(1., 2.)).fit_transform(
    ...     [[numpy.nan, 3, 6]]
    ... )
    array([[[nan],
            [1. ],
            [2. ]]])
    """
    def __init__(self, value_range=(0., 1.), min=None, max=None):
        self.value_range = value_range
        self.min_ = min
        self.max_ = max

    def fit(self, X, y=None, **kwargs):
        """A dummy method such that it complies to the sklearn requirements.
        Since this method is completely stateless, it just returns itself.

        Parameters
        ----------
        X
            Ignored

        Returns
        -------
        self
        """
        return self

    def transform(self, X, y=None, **kwargs):
        """Will normalize (min-max) each of the timeseries. IMPORTANT: this
        transformation is completely stateless, and is applied to each of
        the timeseries individually.

        Parameters
        ----------
        X : array-like
            Time series dataset to be rescaled.

        Returns
        -------
        numpy.ndarray
            Rescaled time series dataset.
        """
        if self.min_ is not None:
            warnings.warn(
                "'min' is deprecated in version 0.2 and will be "
                "removed in 0.4. Use value_range instead.",
                DeprecationWarning, stacklevel=2)
            self.value_range = (self.min_, self.value_range[1])

        if self.max_ is not None:
            warnings.warn(
                "'max' is deprecated in version 0.2 and will be "
                "removed in 0.4. Use value_range instead.",
                DeprecationWarning, stacklevel=2)
            self.value_range = (self.value_range[0], self.max_)

        if self.value_range[0] >= self.value_range[1]:
            raise ValueError("Minimum of desired range must be smaller"
                             " than maximum. Got %s." % str(self.value_range))

        X_ = to_time_series_dataset(X)
        min_t = numpy.nanmin(X_, axis=1)[:, numpy.newaxis, :]
        max_t = numpy.nanmax(X_, axis=1)[:, numpy.newaxis, :]
        range_t = max_t - min_t
        nomin = (X_ - min_t) * (self.value_range[1] - self.value_range[0])
        X_ = nomin / range_t + self.value_range[0]
        return X_

class TimeSeriesScalerMeanVariance(TransformerMixin):
    """Scaler for time series. Scales time series so that their mean (resp.
    standard deviation) in each dimension is
    mu (resp. std).

    Parameters
    ----------
    mu : float (default: 0.)
        Mean of the output time series.
    std : float (default: 1.)
        Standard deviation of the output time series.

    Notes
    -----
        This method requires a dataset of equal-sized time series.

        NaNs within a time series are ignored when calculating mu and std.

    Examples
    --------
    >>> TimeSeriesScalerMeanVariance(mu=0.,
    ...                              std=1.).fit_transform([[0, 3, 6]])
    array([[[-1.22474487],
            [ 0.        ],
            [ 1.22474487]]])
    >>> TimeSeriesScalerMeanVariance(mu=0.,
    ...                              std=1.).fit_transform([[numpy.nan, 3, 6]])
    array([[[nan],
            [-1.],
            [ 1.]]])
    """
    def __init__(self, mu=0., std=1.):
        self.mu_ = mu
        self.std_ = std
        self.global_mean = None
        self.global_std = None

    def fit(self, X, y=None, **kwargs):
        """A dummy method such that it complies to the sklearn requirements.
        Since this method is completely stateless, it just returns itself.

        Parameters
        ----------
        X
            Ignored

        Returns
        -------
        self
        """
        return self

    def transform(self, X, **kwargs):
        """Fit to data, then transform it.

        Parameters
        ----------
        X
            Time series dataset to be rescaled

        Returns
        -------
        numpy.ndarray
            Rescaled time series dataset
        """
        X_ = to_time_series_dataset(X)
        mean_t = numpy.nanmean(X_, axis=1)[:, numpy.newaxis, :]
        std_t = numpy.nanstd(X_, axis=1)[:, numpy.newaxis, :]
        std_t[std_t == 0.] = 1.

        X_ = (X_ - mean_t) * self.std_ / std_t + self.mu_

        return X_
<|endoftext|>


<commit_before>"""Generic manager for all indexable content and common queries."""
from django.conf import settings
from django.utils import timezone

from djes.models import IndexableManager
from elasticsearch_dsl import filter as es_filter
from polymorphic import PolymorphicManager

from .filters import (
    Authors, Evergreen, FeatureTypes, InstantArticle, Published, Status, Tags,
    VideohubChannel, VideohubVideo,
)

class ContentManager(PolymorphicManager, IndexableManager):
    """a specialized version of `djes.models.SearchManager` for `bulbs.content.Content`."""

    def evergreen(self, included_channel_ids=None, excluded_channel_ids=None, **kwargs):
        """
        Search containing any evergreen piece of Content.

        :included_channel_ids list: Contains ids for channel ids relevant to the query.
        :excluded_channel_ids list: Contains ids for channel ids excluded from the query.
        """
        eqs = self.search(**kwargs)
        eqs = eqs.filter(Evergreen())
        if included_channel_ids:
            eqs = eqs.filter(VideohubChannel(included_ids=included_channel_ids))
        if excluded_channel_ids:
            eqs = eqs.filter(VideohubChannel(excluded_ids=excluded_channel_ids))
        return eqs

    def evergreen_video(self, **kwargs):
        """Filter evergreen content to exclusively video content."""
        eqs = self.evergreen(**kwargs)
        eqs = eqs.filter(VideohubVideo())
        return eqs

    def recent_videos(self, **kw):
        return self.search(**kw).filter(
            Published()  # TODO: Or leverage .search()
        ).filter(
            VideohubVideo(),
        ).sort(
            '-published', '-last_modified',  # TODO: Or leverage .search()?
        )

    def instant_articles(self, **kwargs):
        """
        QuerySet including all published content approved for instant articles.

        Instant articles are configured via FeatureType. FeatureType.instant_article = True.
        """
        eqs = self.search(**kwargs).sort('-last_modified', '-published')
        return eqs.filter(InstantArticle())

    def sponsored(self, **kwargs):
        """Search containing any sponsored pieces of Content."""
        eqs = self.search(**kwargs)
        eqs = eqs.filter(es_filter.Exists(field="tunic_campaign_id"))
        published_offset = getattr(settings, "RECENT_SPONSORED_OFFSET_HOURS", None)
        if published_offset:
            now = timezone.now()
            eqs = eqs.filter(
                Published(
                    after=now - timezone.timedelta(hours=published_offset),
                    before=now
                )
            )
        return eqs

    def search(self, **kwargs):
        """
        Query using ElasticSearch, returning an elasticsearch queryset.

        :param kwargs: keyword arguments (optional)
         * query : ES Query spec
         * tags : content tags
         * types : content types
         * feature_types : featured types
         * published : date range
        """
        search_query = super(ContentManager, self).search()

        if "query" in kwargs:
            search_query = search_query.query("match", _all=kwargs.get("query"))
        else:
            search_query = search_query.sort('-published', '-last_modified')

        # Right now we have "Before", "After" (datetimes),
        # and "published" (a boolean). Should simplify this in the future.
        if "before" in kwargs or "after" in kwargs:
            published_filter = Published(before=kwargs.get("before"), after=kwargs.get("after"))
            search_query = search_query.filter(published_filter)
        else:
            # TODO: kill this "published" param. it sucks
            if kwargs.get("published", True) and "status" not in kwargs:
                published_filter = Published()
                search_query = search_query.filter(published_filter)

        if "status" in kwargs:
            search_query = search_query.filter(Status(kwargs["status"]))

        if "excluded_ids" in kwargs:
            exclusion_filter = ~es_filter.Ids(values=kwargs.get("excluded_ids", []))
            search_query = search_query.filter(exclusion_filter)

        tag_filter = Tags(kwargs.get("tags", []))
        search_query = search_query.filter(tag_filter)

        author_filter = Authors(kwargs.get("authors", []))
        search_query = search_query.filter(author_filter)

        feature_type_filter = FeatureTypes(kwargs.get("feature_types", []))
        search_query = search_query.filter(feature_type_filter)

        # Is this good enough? Are we even using this feature at all?
        types = kwargs.pop("types", [])
        if types:
            search_query._doc_type = types
        return search_query
<commit_msg>Cleanup recent_videos() TODOs<commit_after>"""Generic manager for all indexable content and common queries."""
from django.conf import settings
from django.utils import timezone

from djes.models import IndexableManager
from elasticsearch_dsl import filter as es_filter
from polymorphic import PolymorphicManager

from .filters import (
    Authors, Evergreen, FeatureTypes, InstantArticle, Published, Status, Tags,
    VideohubChannel, VideohubVideo,
)

class ContentManager(PolymorphicManager, IndexableManager):
    """a specialized version of `djes.models.SearchManager` for `bulbs.content.Content`."""

    def evergreen(self, included_channel_ids=None, excluded_channel_ids=None, **kwargs):
        """
        Search containing any evergreen piece of Content.

        :included_channel_ids list: Contains ids for channel ids relevant to the query.
        :excluded_channel_ids list: Contains ids for channel ids excluded from the query.
        """
        eqs = self.search(**kwargs)
        eqs = eqs.filter(Evergreen())
        if included_channel_ids:
            eqs = eqs.filter(VideohubChannel(included_ids=included_channel_ids))
        if excluded_channel_ids:
            eqs = eqs.filter(VideohubChannel(excluded_ids=excluded_channel_ids))
        return eqs

    def evergreen_video(self, **kwargs):
        """Filter evergreen content to exclusively video content."""
        eqs = self.evergreen(**kwargs)
        eqs = eqs.filter(VideohubVideo())
        return eqs

    def recent_videos(self, **kwargs):
        return self.search(**kwargs).filter(
            VideohubVideo()
        )

    def instant_articles(self, **kwargs):
        """
        QuerySet including all published content approved for instant articles.

        Instant articles are configured via FeatureType. FeatureType.instant_article = True.
        """
        eqs = self.search(**kwargs).sort('-last_modified', '-published')
        return eqs.filter(InstantArticle())

    def sponsored(self, **kwargs):
        """Search containing any sponsored pieces of Content."""
        eqs = self.search(**kwargs)
        eqs = eqs.filter(es_filter.Exists(field="tunic_campaign_id"))
        published_offset = getattr(settings, "RECENT_SPONSORED_OFFSET_HOURS", None)
        if published_offset:
            now = timezone.now()
            eqs = eqs.filter(
                Published(
                    after=now - timezone.timedelta(hours=published_offset),
                    before=now
                )
            )
        return eqs

    def search(self, **kwargs):
        """
        Query using ElasticSearch, returning an elasticsearch queryset.

        :param kwargs: keyword arguments (optional)
         * query : ES Query spec
         * tags : content tags
         * types : content types
         * feature_types : featured types
         * published : date range
        """
        search_query = super(ContentManager, self).search()

        if "query" in kwargs:
            search_query = search_query.query("match", _all=kwargs.get("query"))
        else:
            search_query = search_query.sort('-published', '-last_modified')

        # Right now we have "Before", "After" (datetimes),
        # and "published" (a boolean). Should simplify this in the future.
        if "before" in kwargs or "after" in kwargs:
            published_filter = Published(before=kwargs.get("before"), after=kwargs.get("after"))
            search_query = search_query.filter(published_filter)
        else:
            # TODO: kill this "published" param. it sucks
            if kwargs.get("published", True) and "status" not in kwargs:
                published_filter = Published()
                search_query = search_query.filter(published_filter)

        if "status" in kwargs:
            search_query = search_query.filter(Status(kwargs["status"]))

        if "excluded_ids" in kwargs:
            exclusion_filter = ~es_filter.Ids(values=kwargs.get("excluded_ids", []))
            search_query = search_query.filter(exclusion_filter)

        tag_filter = Tags(kwargs.get("tags", []))
        search_query = search_query.filter(tag_filter)

        author_filter = Authors(kwargs.get("authors", []))
        search_query = search_query.filter(author_filter)

        feature_type_filter = FeatureTypes(kwargs.get("feature_types", []))
        search_query = search_query.filter(feature_type_filter)

        # Is this good enough? Are we even using this feature at all?
        types = kwargs.pop("types", [])
        if types:
            search_query._doc_type = types
        return search_query
<|endoftext|>