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

import os
import tempfile
import shutil
from functools import partial
from types import ModuleType
from typing import Optional, Union, Callable
import weakref

from wdom.options import config
from wdom.interface import Event
from wdom.node import Node, DocumentType, Text, RawHtml, Comment
from wdom.node import DocumentFragment
from wdom.element import Element, Attr, _create_element
from wdom.web_node import WebElement
from wdom.tag import HTMLElement
from wdom.tag import Html, Head, Body, Meta, Link, Title, Script
from wdom.window import Window

def getElementById(id: Union[str, int]) -> Optional[Node]:
    elm = Element._elements_with_id.get(str(id))
    if elm and elm.ownerDocument:
        return elm
    else:
        return None

def getElementByRimoId(id: Union[str, int]) -> Optional[WebElement]:
    elm = WebElement._elements_with_rimo_id.get(str(id))
    if elm and elm.ownerDocument:
        return elm
    else:
        return None

def _cleanup(path):
    if os.path.isdir(path):
        shutil.rmtree(path)

class Document(Node):
    nodeType = Node.DOCUMENT_NODE
    nodeName = '#document'

    @property
    def defaultView(self) -> Window:
        return self._window

    @property
    def tempdir(self) -> str:
        return self._tempdir

    def __init__(self, doctype='html', title='W-DOM', charset='utf-8',
                 default_class=HTMLElement, autoreload=None, reload_wait=None):
        self._tempdir = _tempdir = tempfile.mkdtemp()
        self._finalizer = weakref.finalize(self, partial(_cleanup, _tempdir))
        super().__init__()
        self._window = Window(self)
        self._default_class = default_class
        self._autoreload = autoreload
        self._reload_wait = reload_wait

        self.doctype = DocumentType(doctype, parent=self)
        self.html = Html(parent=self)
        self.head = Head(parent=self.html)
        self.charset_element = Meta(parent=self.head)
        self.characterSet = charset
        self.title_element = Title(parent=self.head)
        self.title = title

        self.body = Body(parent=self.html)
        self.script = Script(parent=self.body)
        self._autoreload_script = Script(parent=self.head)

    def _set_autoreload(self):
        self._autoreload_script.textContent = ''
        if self._autoreload is None:
            autoreload = (config.autoreload or config.debug)
        else:
            autoreload = self._autoreload

        if autoreload:
            ar_script = []
            ar_script.append('var RIMO_AUTORELOAD = true')
            if self._reload_wait is not None:
                ar_script.append('var RIMO_RELOAD_WAIT = {}'.format(
                    self._reload_wait))
            self._autoreload_script.textContent = '\n{}\n'.format(
                '\n'.join(ar_script))

    def getElementById(self, id: Union[str, int]) -> Optional[Node]:
        elm = getElementById(id)
        if elm and elm.ownerDocument is self:
            return elm

    def getElementByRimoId(self, id: Union[str, int]) -> Optional[WebElement]:
        elm = getElementByRimoId(id)
        if elm and elm.ownerDocument is self:
            return elm

    def createElement(self, tag: str):
        return _create_element(tag, base=self._default_class)

    def createDocumentFragment(self):
        return DocumentFragment()

    def createTextNode(self, text: str):
        return Text(text)

    def createComment(self, text: str):
        return Comment(text)

    def createEvent(self, event: str):
        return Event(event)

    def createAttribute(self, name: str):
        return Attr(name)

    @property
    def title(self) -> str:
        return self.title_element.textContent

    @title.setter
    def title(self, value: str):
        self.title_element.textContent = value

    @property
    def characterSet(self) -> str:
        return self.charset_element.getAttribute('charset')

    @characterSet.setter
    def characterSet(self, value: str):
        self.charset_element.setAttribute('charset', value)

    @property
    def charset(self) -> str:
        return self.characterSet

    @charset.setter
    def charset(self, value: str):
        self.characterSet = value

    def add_jsfile(self, src: str):
        self.body.appendChild(Script(src=src))

    def add_jsfile_head(self, src: str):
        self.head.appendChild(Script(src=src))

    def add_cssfile(self, src: str):
        self.head.appendChild(Link(rel='stylesheet', href=src))

    def add_header(self, header: str):
        self.head.appendChild(RawHtml(header))

    def register_theme(self, theme: ModuleType) -> None:
        if not hasattr(theme, 'css_files'):
            raise ValueError('theme module must include `css_files`.')
        for css in getattr(theme, 'css_files', []):
            self.add_cssfile(css)
        for js in getattr(theme, 'js_files', []):
            self.add_jsfile(js)
        for header in getattr(theme, 'headers', []):
            self.add_header(header)
        for cls in getattr(theme, 'extended_classes', []):
            self.defaultView.customElements.define(cls)

    def build(self) -> str:
        self._set_autoreload()
        return ''.join(child.html for child in self.childNodes)

def get_new_document(include_rimo: bool = True,
                     include_skeleton: bool = False,
                     include_normalizecss: bool = False,
                     autoreload: Optional[bool] = None,
                     reload_wait: int = None,
                     log_level: int = None,
                     log_prefix: str = None,
                     log_console: bool = False,
                     ws_url: str = None,
                     document_factory: Callable[..., Document] = Document,
                     **kwargs) -> Document:
    document = document_factory(
        autoreload=autoreload,
        reload_wait=reload_wait,
        **kwargs)
    if log_level is None:
        log_level = config.logging

    log_script = []
    if log_level is not None:
        if isinstance(log_level, str):
            log_script.append('var RIMO_LOG_LEVEL = \'{}\''.format(log_level))
        elif isinstance(log_level, int):
            log_script.append('var RIMO_LOG_LEVEL = {}'.format(log_level))
    if log_prefix is not None:
        log_script.append('var RIMO_LOG_PREFIX = \'{}\''.format(log_prefix))
    if log_console:
        log_script.append('var RIMO_LOG_CONSOLE = true')
    if log_script:
        _s = Script(parent=document.head)
        _s.textContent = '\n{}\n'.format('\n'.join(log_script))

    if ws_url is not None:
        _s = Script(parent=document.head)
        _s.textContent = '\nvar RIMO_WS_URL = \'{}\'\n'.format(ws_url)

    if include_rimo:
        document.add_jsfile_head('_static/js/rimo/rimo.js')

    return document

# get_document = get_new_document
def get_document(*args, **kwargs):
    return rootDocument

def set_document(new_document: Document, *args, **kwargs):
    global rootDocument
    rootDocument = new_document

rootDocument = get_new_document()
<commit_msg>Cleanup code<commit_after>#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import tempfile
import shutil
from functools import partial
from types import ModuleType
from typing import Optional, Union, Callable
import weakref

from wdom.options import config
from wdom.interface import Event
from wdom.node import Node, DocumentType, Text, RawHtml, Comment
from wdom.node import DocumentFragment
from wdom.element import Element, Attr, _create_element
from wdom.web_node import WebElement
from wdom.tag import HTMLElement
from wdom.tag import Html, Head, Body, Meta, Link, Title, Script
from wdom.window import Window

def getElementById(id: Union[str, int]) -> Optional[Node]:
    elm = Element._elements_with_id.get(str(id))
    if elm and elm.ownerDocument:
        return elm
    else:
        return None

def getElementByRimoId(id: Union[str, int]) -> Optional[WebElement]:
    elm = WebElement._elements_with_rimo_id.get(str(id))
    if elm and elm.ownerDocument:
        return elm
    else:
        return None

def _cleanup(path):
    if os.path.isdir(path):
        shutil.rmtree(path)

class Document(Node):
    nodeType = Node.DOCUMENT_NODE
    nodeName = '#document'

    @property
    def defaultView(self) -> Window:
        return self._window

    @property
    def tempdir(self) -> str:
        return self._tempdir

    def __init__(self, doctype='html', title='W-DOM', charset='utf-8',
                 default_class=HTMLElement, autoreload=None, reload_wait=None):
        self._tempdir = _tempdir = tempfile.mkdtemp()
        self._finalizer = weakref.finalize(self, partial(_cleanup, _tempdir))
        super().__init__()
        self._window = Window(self)
        self._default_class = default_class
        self._autoreload = autoreload
        self._reload_wait = reload_wait

        self.doctype = DocumentType(doctype, parent=self)
        self.html = Html(parent=self)
        self.head = Head(parent=self.html)
        self.charset_element = Meta(parent=self.head)
        self.characterSet = charset
        self.title_element = Title(parent=self.head)
        self.title = title

        self.body = Body(parent=self.html)
        self.script = Script(parent=self.body)
        self._autoreload_script = Script(parent=self.head)

    def _set_autoreload(self):
        self._autoreload_script.textContent = ''
        if self._autoreload is None:
            autoreload = (config.autoreload or config.debug)
        else:
            autoreload = self._autoreload

        if autoreload:
            ar_script = []
            ar_script.append('var RIMO_AUTORELOAD = true')
            if self._reload_wait is not None:
                ar_script.append('var RIMO_RELOAD_WAIT = {}'.format(
                    self._reload_wait))
            self._autoreload_script.textContent = '\n{}\n'.format(
                '\n'.join(ar_script))

    def getElementById(self, id: Union[str, int]) -> Optional[Node]:
        elm = getElementById(id)
        if elm and elm.ownerDocument is self:
            return elm

    def getElementByRimoId(self, id: Union[str, int]) -> Optional[WebElement]:
        elm = getElementByRimoId(id)
        if elm and elm.ownerDocument is self:
            return elm

    def createElement(self, tag: str):
        return _create_element(tag, base=self._default_class)

    def createDocumentFragment(self):
        return DocumentFragment()

    def createTextNode(self, text: str):
        return Text(text)

    def createComment(self, text: str):
        return Comment(text)

    def createEvent(self, event: str):
        return Event(event)

    def createAttribute(self, name: str):
        return Attr(name)

    @property
    def title(self) -> str:
        return self.title_element.textContent

    @title.setter
    def title(self, value: str):
        self.title_element.textContent = value

    @property
    def characterSet(self) -> str:
        return self.charset_element.getAttribute('charset')

    @characterSet.setter
    def characterSet(self, value: str):
        self.charset_element.setAttribute('charset', value)

    @property
    def charset(self) -> str:
        return self.characterSet

    @charset.setter
    def charset(self, value: str):
        self.characterSet = value

    def add_jsfile(self, src: str):
        self.body.appendChild(Script(src=src))

    def add_jsfile_head(self, src: str):
        self.head.appendChild(Script(src=src))

    def add_cssfile(self, src: str):
        self.head.appendChild(Link(rel='stylesheet', href=src))

    def add_header(self, header: str):
        self.head.appendChild(RawHtml(header))

    def register_theme(self, theme: ModuleType) -> None:
        if not hasattr(theme, 'css_files'):
            raise ValueError('theme module must include `css_files`.')
        for css in getattr(theme, 'css_files', []):
            self.add_cssfile(css)
        for js in getattr(theme, 'js_files', []):
            self.add_jsfile(js)
        for header in getattr(theme, 'headers', []):
            self.add_header(header)
        for cls in getattr(theme, 'extended_classes', []):
            self.defaultView.customElements.define(cls)

    def build(self) -> str:
        self._set_autoreload()
        return ''.join(child.html for child in self.childNodes)

def get_new_document(include_rimo: bool = True,
                     include_skeleton: bool = False,
                     include_normalizecss: bool = False,
                     autoreload: Optional[bool] = None,
                     reload_wait: int = None,
                     log_level: int = None,
                     log_prefix: str = None,
                     log_console: bool = False,
                     ws_url: str = None,
                     document_factory: Callable[..., Document] = Document,
                     **kwargs) -> Document:
    """Make and return new `document` object."""
    document = document_factory(
        autoreload=autoreload,
        reload_wait=reload_wait,
        **kwargs)

    if log_level is None:
        log_level = config.logging

    log_script = []
    if isinstance(log_level, str):
        log_script.append('var RIMO_LOG_LEVEL = \'{}\''.format(log_level))
    elif isinstance(log_level, int):
        log_script.append('var RIMO_LOG_LEVEL = {}'.format(log_level))
    if log_prefix:
        log_script.append('var RIMO_LOG_PREFIX = \'{}\''.format(log_prefix))
    if log_console:
        log_script.append('var RIMO_LOG_CONSOLE = true')
    if log_script:
        _s = Script(parent=document.head)
        _s.textContent = '\n{}\n'.format('\n'.join(log_script))

    if ws_url:
        _s = Script(parent=document.head)
        _s.textContent = '\nvar RIMO_WS_URL = \'{}\'\n'.format(ws_url)

    if include_rimo:
        document.add_jsfile_head('_static/js/rimo/rimo.js')

    return document

# get_document = get_new_document
def get_document(*args, **kwargs):
    return rootDocument

def set_document(new_document: Document, *args, **kwargs):
    global rootDocument
    rootDocument = new_document

rootDocument = get_new_document()
<|endoftext|>


<commit_before># !/usr/bin/env python3
# -*- coding: utf-8 -*-
# -----------------------------
# Author:  Bruce Zhang
# Email:   zy183525594@163.com
# Version: 0.1
# -----------------------------

import irc.bot
import irc.client
import irc.buffer
import os
import json
import logging
from termcolor import colored
import re
import sys
import signal

PREFIX = '>>'
PLUGINDIR = './plugins/'

sys.path.append(PLUGINDIR)

from echo import echo
from linkhandler import linkhandler
pluginlist = ["echo"]
handlerlist = ["linkhandler"]
funclist = [echo]
handlerfuncs = [linkhandler]

class MyBot(irc.bot.SingleServerIRCBot):

    version = "201605-dev"

    def __init__(self, channels, nickname, server, port, realname):
        irc.bot.SingleServerIRCBot.__init__(self, [(server, port)],
                                            nickname, realname)
        self.chs = channels
        logger.info("Bot started successfully.")
        signal.signal(signal.SIGINT, self._quit)

    def _quit(self, arg1, arg2):
        logger.info("Bot interuptted from console.")
        msg = input("The reason for stopping bot:")
        self.die(msg or "")

    def on_nicknameinuse(self, c, e):
        c.nick(c.get_nickname() + "_")

    def on_welcome(self, c, e):
        for channel in self.chs:
            c.join(channel)

    def on_kick(self, c, e):
        channel = e.target
        c.join(channel)

    def exec_command(self, commandline):
        cmdargs = commandline.split(' ', 1)
        if cmdargs[0] in pluginlist:
            index = pluginlist.index(cmdargs[0])
            msg = funclist[index](cmdargs[1])
            return msg
        return False

    def passive_exec(self, line, nick='', channel=''):
        if line.strip().endswith(" #"):
            return False
        for handler in handlerlist:
            index = handlerlist.index(handler)
            resmsg = handlerfuncs[index](line, nick, channel)
            return resmsg

    def on_privmsg(self, c, e):
        nm = e.source
        line = e.arguments[0]
        try:
            if line.startswith(PREFIX):
                commandline = line.strip(PREFIX).strip()
                msg = self.exec_command(commandline)
                if msg:
                    c.privmsg(nm.nick, msg)
            else:
                msgs = self.passive_exec(line, nm.nick)
                for msg in msgs:
                    if msg:
                        c.privmsg(nm.nick, msg)
        except irc.client.InvalidCharacters:
            logger.warning("Invalid characters sent.")
            _do_nothing()

    def on_pubmsg(self, c, e):
        nick = e.source.nick
        channel = e.target
        line = e.arguments[0]
        try:
            if line.startswith(PREFIX):
                commandline = line.strip(PREFIX).strip()
                msg = self.exec_command(commandline)
                if msg:
                    c.privmsg(channel, "%s: %s" % (nick, msg))
            else:
                msgs = self.passive_exec(line, nick, channel)
                for msg in msgs:
                    if msg:
                        c.privmsg(channel, "%s" % msg)
        except irc.client.InvalidCharacters:
            logger.warning("Invalid characters sent.")
            _do_nothing()

    def on_dccmsg(self, c, e):
        # non-chat DCC messages are raw bytes; decode as text
        pass

    def on_dccchat(self, c, e):
        pass

    def get_version(self):
        return "PyIrcBot | https://github.com/BruceZhang1993/PyIrcBot | Version: %s" % self.version

def _do_nothing():
    pass

class IgnoreErrorsBuffer(irc.buffer.DecodingLineBuffer):
    def handle_exception(self):
        pass

def main():
    # DONE:10 Try using config file
    confdir = os.environ['HOME'] + "/.pyircbot/"
    conffile = confdir + "config.json"
    logfile = confdir + "bot.log"

    try:
        os.mkdir(confdir)
    except FileExistsError:
        _do_nothing()

    # Logging
    global logger
    logger = logging.getLogger("ircbot")
    logger.setLevel(logging.DEBUG)
    logfilehandler = logging.FileHandler(logfile)
    logfilehandler.setLevel(logging.NOTSET)
    consolehandler = logging.StreamHandler()
    consolehandler.setLevel(logging.NOTSET)
    formatter = logging.Formatter("[%(levelname)s] %(msg)s (%(name)s)")
    consolehandler.setFormatter(formatter)
    logfilehandler.setFormatter(formatter)
    logger.addHandler(consolehandler)
    logger.addHandler(logfilehandler)

    if os.path.exists(conffile):
        logger.debug("Configure file found. Using now...")
        fp = None
        try:
            fp = open(conffile, "r")
            config = json.load(fp)
            channels = config["channels"]
            nickname = config["nick"]
            server = config["network"]
            port = config["port"]
            realname = config["realname"]
        except IOError:
            logger.error("I/O Error. Check filesystem permissions.")
            import sys
            sys.exit(1)
        finally:
            if fp:
                fp.close()
        logger.debug("Configure file loaded. Starting bot...")
    else:
        logger.info("Configure file not found. Creating now...")
        print(colored("-- PyIrcBot 配置向导 --", "yellow"))
        config = dict()
        config['nick'] = input(colored("Nickname: ", "green")).strip()
        config["realname"] = input(colored("Real Name: ", "green")).strip()
        print(colored("-- 配置 IRC 服务器 --", "blue"))
        config['network'] = input(colored("Server: ", "green")).strip()
        config['port'] = int(input(colored("Port: ", "green")).strip())
        config['channels'] = re.split(r'\s+', input(colored("Channels (Split with space): ", "green")))
        fp = None
        try:
            fp = open(conffile, "w")
            json.dump(config, fp)
        except IOError:
            logger.error("I/O Error. Check filesystem permissions.")
            import sys
            sys.exit(1)
        finally:
            if fp:
                fp.close()
        logger.debug("Configure file created. Starting bot...")
        print(colored("配置文件创建成功，启动 PyIrcBot...", "yellow"))
        channels = config["channels"]
        nickname = config["nick"]
        server = config["network"]
        port = config["port"]
        realname = config["realname"]
    logger.info("Loading plugins...")
    bot = MyBot(channels, nickname, server, port, realname)
    irc.client.ServerConnection.buffer_class = IgnoreErrorsBuffer
    bot.start()

if __name__ == "__main__":
    main()
<commit_msg>fix bug<commit_after># !/usr/bin/env python3
# -*- coding: utf-8 -*-
# -----------------------------
# Author:  Bruce Zhang
# Email:   zy183525594@163.com
# Version: 0.1
# -----------------------------

import irc.bot
import irc.client
import irc.buffer
import os
import json
import logging
from termcolor import colored
import re
import sys
import signal

PREFIX = '>>'
PLUGINDIR = './plugins/'

sys.path.append(PLUGINDIR)

from echo import echo
from linkhandler import linkhandler
pluginlist = ["echo"]
handlerlist = ["linkhandler"]
funclist = [echo]
handlerfuncs = [linkhandler]

class MyBot(irc.bot.SingleServerIRCBot):

    version = "201605-dev"

    def __init__(self, channels, nickname, server, port, realname):
        irc.bot.SingleServerIRCBot.__init__(self, [(server, port)],
                                            nickname, realname)
        self.chs = channels
        logger.info("Bot started successfully.")
        signal.signal(signal.SIGINT, self._quit)

    def _quit(self, arg1, arg2):
        logger.info("Bot interuptted from console.")
        msg = input("The reason for stopping bot:")
        self.die(msg or "")

    def on_nicknameinuse(self, c, e):
        c.nick(c.get_nickname() + "_")

    def on_welcome(self, c, e):
        for channel in self.chs:
            c.join(channel)

    def on_kick(self, c, e):
        channel = e.target
        c.join(channel)

    def exec_command(self, commandline):
        cmdargs = commandline.split(' ', 1)
        if cmdargs[0] in pluginlist:
            index = pluginlist.index(cmdargs[0])
            msg = funclist[index](cmdargs[1])
            return msg
        return False

    def passive_exec(self, line, nick='', channel=''):
        if line.strip().endswith(" #"):
            return []
        for handler in handlerlist:
            index = handlerlist.index(handler)
            resmsg = handlerfuncs[index](line, nick, channel)
            return resmsg

    def on_privmsg(self, c, e):
        nm = e.source
        line = e.arguments[0]
        try:
            if line.startswith(PREFIX):
                commandline = line.strip(PREFIX).strip()
                msg = self.exec_command(commandline)
                if msg:
                    c.privmsg(nm.nick, msg)
            else:
                msgs = self.passive_exec(line, nm.nick)
                for msg in msgs:
                    if msg:
                        c.privmsg(nm.nick, msg)
        except irc.client.InvalidCharacters:
            logger.warning("Invalid characters sent.")
            _do_nothing()

    def on_pubmsg(self, c, e):
        nick = e.source.nick
        channel = e.target
        line = e.arguments[0]
        try:
            if line.startswith(PREFIX):
                commandline = line.strip(PREFIX).strip()
                msg = self.exec_command(commandline)
                if msg:
                    c.privmsg(channel, "%s: %s" % (nick, msg))
            else:
                msgs = self.passive_exec(line, nick, channel)
                for msg in msgs:
                    if msg:
                        c.privmsg(channel, "%s" % msg)
        except irc.client.InvalidCharacters:
            logger.warning("Invalid characters sent.")
            _do_nothing()

    def on_dccmsg(self, c, e):
        # non-chat DCC messages are raw bytes; decode as text
        pass

    def on_dccchat(self, c, e):
        pass

    def get_version(self):
        return "PyIrcBot | https://github.com/BruceZhang1993/PyIrcBot | Version: %s" % self.version

def _do_nothing():
    pass

class IgnoreErrorsBuffer(irc.buffer.DecodingLineBuffer):
    def handle_exception(self):
        pass

def main():
    # DONE:10 Try using config file
    confdir = os.environ['HOME'] + "/.pyircbot/"
    conffile = confdir + "config.json"
    logfile = confdir + "bot.log"

    try:
        os.mkdir(confdir)
    except FileExistsError:
        _do_nothing()

    # Logging
    global logger
    logger = logging.getLogger("ircbot")
    logger.setLevel(logging.DEBUG)
    logfilehandler = logging.FileHandler(logfile)
    logfilehandler.setLevel(logging.NOTSET)
    consolehandler = logging.StreamHandler()
    consolehandler.setLevel(logging.NOTSET)
    formatter = logging.Formatter("[%(levelname)s] %(msg)s (%(name)s)")
    consolehandler.setFormatter(formatter)
    logfilehandler.setFormatter(formatter)
    logger.addHandler(consolehandler)
    logger.addHandler(logfilehandler)

    if os.path.exists(conffile):
        logger.debug("Configure file found. Using now...")
        fp = None
        try:
            fp = open(conffile, "r")
            config = json.load(fp)
            channels = config["channels"]
            nickname = config["nick"]
            server = config["network"]
            port = config["port"]
            realname = config["realname"]
        except IOError:
            logger.error("I/O Error. Check filesystem permissions.")
            import sys
            sys.exit(1)
        finally:
            if fp:
                fp.close()
        logger.debug("Configure file loaded. Starting bot...")
    else:
        logger.info("Configure file not found. Creating now...")
        print(colored("-- PyIrcBot 配置向导 --", "yellow"))
        config = dict()
        config['nick'] = input(colored("Nickname: ", "green")).strip()
        config["realname"] = input(colored("Real Name: ", "green")).strip()
        print(colored("-- 配置 IRC 服务器 --", "blue"))
        config['network'] = input(colored("Server: ", "green")).strip()
        config['port'] = int(input(colored("Port: ", "green")).strip())
        config['channels'] = re.split(r'\s+', input(colored("Channels (Split with space): ", "green")))
        fp = None
        try:
            fp = open(conffile, "w")
            json.dump(config, fp)
        except IOError:
            logger.error("I/O Error. Check filesystem permissions.")
            import sys
            sys.exit(1)
        finally:
            if fp:
                fp.close()
        logger.debug("Configure file created. Starting bot...")
        print(colored("配置文件创建成功，启动 PyIrcBot...", "yellow"))
        channels = config["channels"]
        nickname = config["nick"]
        server = config["network"]
        port = config["port"]
        realname = config["realname"]
    logger.info("Loading plugins...")
    bot = MyBot(channels, nickname, server, port, realname)
    irc.client.ServerConnection.buffer_class = IgnoreErrorsBuffer
    bot.start()

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


<commit_before>from django.conf import settings
from django.contrib import messages
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy

from corehq.util.es.elasticsearch import TransportError
from memoized import memoized

from corehq.apps.es import cases as case_es
from corehq.apps.es.utils import track_es_report_load
from corehq.apps.locations.permissions import location_safe
from corehq.apps.reports.api import ReportDataSource
from corehq.apps.reports.datatables import DataTablesColumn, DataTablesHeader
from corehq.apps.reports.exceptions import BadRequestError
from corehq.apps.reports.filters.case_list import CaseListFilter as EMWF
from corehq.apps.reports.filters.select import SelectOpenCloseFilter
from corehq.apps.reports.generic import ElasticProjectInspectionReport
from corehq.apps.reports.standard import ProjectReportParametersMixin
from corehq.apps.reports.standard.cases.filters import CaseSearchFilter
from corehq.apps.reports.standard.cases.utils import (
    all_project_data_filter,
    deactivated_case_owners,
    get_case_owners,
    query_location_restricted_cases,
)
from corehq.apps.reports.standard.inspect import ProjectInspectionReport
from corehq.const import SERVER_DATETIME_FORMAT
from corehq.elastic import ESError
from corehq.toggles import CASE_LIST_EXPLORER
from corehq.util.timezones.conversions import PhoneTime

from .data_sources import CaseDisplay, CaseInfo

class CaseListMixin(ElasticProjectInspectionReport, ProjectReportParametersMixin):
    fields = [
        'corehq.apps.reports.filters.case_list.CaseListFilter',
        'corehq.apps.reports.filters.select.CaseTypeFilter',
        'corehq.apps.reports.filters.select.SelectOpenCloseFilter',
        'corehq.apps.reports.standard.cases.filters.CaseSearchFilter',
    ]

    case_filter = {}
    ajax_pagination = True
    asynchronous = True
    search_class = case_es.CaseES

    def _build_query(self):
        query = (self.search_class()
                 .domain(self.domain)
                 .size(self.pagination.count)
                 .start(self.pagination.start))
        query.es_query['sort'] = self.get_sorting_block()
        mobile_user_and_group_slugs = self.request.GET.getlist(EMWF.slug)

        if self.case_filter:
            query = query.filter(self.case_filter)

        query = query.NOT(case_es.case_type("user-owner-mapping-case"))

        if self.case_type:
            query = query.case_type(self.case_type)

        if self.case_status:
            query = query.is_closed(self.case_status == 'closed')

        case_owner_filters = []

        if (
            self.request.can_access_all_locations
            and EMWF.show_project_data(mobile_user_and_group_slugs)
        ):
            case_owner_filters.append(all_project_data_filter(self.domain, mobile_user_and_group_slugs))

        if (
            self.request.can_access_all_locations
            and EMWF.show_deactivated_data(mobile_user_and_group_slugs)
        ):
            case_owner_filters.append(deactivated_case_owners(self.domain))

        # Only show explicit matches
        if (
            EMWF.selected_user_ids(mobile_user_and_group_slugs)
            or EMWF.selected_user_types(mobile_user_and_group_slugs)
            or EMWF.selected_group_ids(mobile_user_and_group_slugs)
            or EMWF.selected_location_ids(mobile_user_and_group_slugs)
        ):
            track_es_report_load(self.domain, self.slug, len(self.case_owners))
            case_owner_filters.append(case_es.owner(self.case_owners))

        query = query.OR(*case_owner_filters)

        if not self.request.can_access_all_locations:
            query = query_location_restricted_cases(query, self.request)

        search_string = CaseSearchFilter.get_value(self.request, self.domain)
        if search_string:
            query = query.set_query({"query_string": {"query": search_string}})

        return query

    @property
    @memoized
    def es_results(self):
        try:
            return self._build_query().run().raw
        except ESError as e:
            original_exception = e.args[0]
            if isinstance(original_exception, TransportError):
                if hasattr(original_exception.info, "get"):
                    if original_exception.info.get('status') == 400:
                        raise BadRequestError()
            raise e

    @property
    @memoized
    def case_owners(self):
        mobile_user_and_group_slugs = self.request.GET.getlist(EMWF.slug)
        return get_case_owners(self.request, self.domain, mobile_user_and_group_slugs)

    def get_case(self, row):
        if '_source' in row:
            case_dict = row['_source']
        else:
            raise ValueError("Case object is not in search result %s" % row)

        if case_dict['domain'] != self.domain:
            raise Exception("case.domain != self.domain; %r and %r, respectively" % (case_dict['domain'], self.domain))

        return case_dict

    @property
    def shared_pagination_GET_params(self):
        shared_params = super(CaseListMixin, self).shared_pagination_GET_params
        shared_params.append(dict(
            name=SelectOpenCloseFilter.slug,
            value=self.request.GET.get(SelectOpenCloseFilter.slug, '')
        ))
        return shared_params

@location_safe
class CaseListReport(CaseListMixin, ProjectInspectionReport, ReportDataSource):

    # note that this class is not true to the spirit of ReportDataSource; the whole
    # point is the decouple generating the raw report data from the report view/django
    # request. but currently these are too tightly bound to decouple

    name = ugettext_lazy('Case List')
    slug = 'case_list'

    @classmethod
    def get_subpages(cls):
        def _get_case_name(request=None, **context):
            if 'case' in context and context['case'].name:
                return mark_safe(context['case'].name)
            else:
                return _('View Case')

        from corehq.apps.reports.views import CaseDataView
        return [
            {
                'title': _get_case_name,
                'urlname': CaseDataView.urlname,
            },
        ]

    @property
    def can_upgrade_to_case_list_explorer(self):
        if settings.ENTERPRISE_MODE:
            return False

        if self.request.couch_user.is_dimagi and not CASE_LIST_EXPLORER.enabled(self.domain):
            return True

        return False

    @property
    def view_response(self):
        if self.can_upgrade_to_case_list_explorer:
            messages.warning(
                self.request,
                'Hey Dimagi User! Have you tried out the Case List Explorer yet? It might be just what you are looking for!',
                extra_tags='html',
            )
        return super(CaseListReport, self).view_response

    @classmethod
    def display_in_dropdown(cls, domain=None, project=None, user=None):
        if project and project.commtrack_enabled:
            return False
        else:
            return True

    def slugs(self):
        return [
            '_case',
            'case_id',
            'case_name',
            'case_type',
            'detail_url',
            'is_open',
            'opened_on',
            'modified_on',
            'closed_on',
            'creator_id',
            'creator_name',
            'owner_type',
            'owner_id',
            'owner_name',
            'external_id',
        ]

    def get_data(self):
        for row in self.es_results['hits'].get('hits', []):
            case = self.get_case(row)
            ci = CaseInfo(self, case)
            data = {
                '_case': case,
                'detail_url': ci.case_detail_url,
            }
            data.update((prop, getattr(ci, prop)) for prop in (
                    'case_type', 'case_name', 'case_id', 'external_id',
                    'is_closed', 'opened_on', 'modified_on', 'closed_on',
                ))

            creator = ci.creating_user or {}
            data.update({
                'creator_id': creator.get('id'),
                'creator_name': creator.get('name'),
            })
            owner = ci.owner
            data.update({
                'owner_type': owner[0],
                'owner_id': owner[1]['id'],
                'owner_name': owner[1]['name'],
            })

            yield data

    @property
    def headers(self):
        headers = DataTablesHeader(
            DataTablesColumn(_("Case Type"), prop_name="type.exact"),
            DataTablesColumn(_("Name"), prop_name="name.exact", css_class="case-name-link"),
            DataTablesColumn(_("Owner"), prop_name="owner_display", sortable=False),
            DataTablesColumn(_("Created Date"), prop_name="opened_on"),
            DataTablesColumn(_("Created By"), prop_name="opened_by_display", sortable=False),
            DataTablesColumn(_("Modified Date"), prop_name="modified_on"),
            DataTablesColumn(_("Status"), prop_name="get_status_display", sortable=False)
        )
        headers.custom_sort = [[5, 'desc']]
        return headers

    @property
    def rows(self):
        for data in self.get_data():
            display = CaseDisplay(self, data['_case'])

            yield [
                display.case_type,
                display.case_link,
                display.owner_display,
                display.opened_on,
                display.creating_user,
                display.modified_on,
                display.closed_display
            ]

    def date_to_json(self, date):
        if date:
            return (PhoneTime(date, self.timezone).user_time(self.timezone)
                    .ui_string(SERVER_DATETIME_FORMAT))
        else:
            return ''
<commit_msg>format case lists dates in user format<commit_after>from django.conf import settings
from django.contrib import messages
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy

from corehq.util.es.elasticsearch import TransportError
from memoized import memoized

from corehq.apps.es import cases as case_es
from corehq.apps.es.utils import track_es_report_load
from corehq.apps.locations.permissions import location_safe
from corehq.apps.reports.api import ReportDataSource
from corehq.apps.reports.datatables import DataTablesColumn, DataTablesHeader
from corehq.apps.reports.exceptions import BadRequestError
from corehq.apps.reports.filters.case_list import CaseListFilter as EMWF
from corehq.apps.reports.filters.select import SelectOpenCloseFilter
from corehq.apps.reports.generic import ElasticProjectInspectionReport
from corehq.apps.reports.standard import ProjectReportParametersMixin
from corehq.apps.reports.standard.cases.filters import CaseSearchFilter
from corehq.apps.reports.standard.cases.utils import (
    all_project_data_filter,
    deactivated_case_owners,
    get_case_owners,
    query_location_restricted_cases,
)
from corehq.apps.reports.standard.inspect import ProjectInspectionReport
from corehq.const import USER_DATETIME_FORMAT_WITH_SEC
from corehq.elastic import ESError
from corehq.toggles import CASE_LIST_EXPLORER
from corehq.util.timezones.conversions import PhoneTime

from .data_sources import CaseDisplay

class CaseListMixin(ElasticProjectInspectionReport, ProjectReportParametersMixin):
    fields = [
        'corehq.apps.reports.filters.case_list.CaseListFilter',
        'corehq.apps.reports.filters.select.CaseTypeFilter',
        'corehq.apps.reports.filters.select.SelectOpenCloseFilter',
        'corehq.apps.reports.standard.cases.filters.CaseSearchFilter',
    ]

    case_filter = {}
    ajax_pagination = True
    asynchronous = True
    search_class = case_es.CaseES

    def _build_query(self):
        query = (self.search_class()
                 .domain(self.domain)
                 .size(self.pagination.count)
                 .start(self.pagination.start))
        query.es_query['sort'] = self.get_sorting_block()
        mobile_user_and_group_slugs = self.request.GET.getlist(EMWF.slug)

        if self.case_filter:
            query = query.filter(self.case_filter)

        query = query.NOT(case_es.case_type("user-owner-mapping-case"))

        if self.case_type:
            query = query.case_type(self.case_type)

        if self.case_status:
            query = query.is_closed(self.case_status == 'closed')

        case_owner_filters = []

        if (
            self.request.can_access_all_locations
            and EMWF.show_project_data(mobile_user_and_group_slugs)
        ):
            case_owner_filters.append(all_project_data_filter(self.domain, mobile_user_and_group_slugs))

        if (
            self.request.can_access_all_locations
            and EMWF.show_deactivated_data(mobile_user_and_group_slugs)
        ):
            case_owner_filters.append(deactivated_case_owners(self.domain))

        # Only show explicit matches
        if (
            EMWF.selected_user_ids(mobile_user_and_group_slugs)
            or EMWF.selected_user_types(mobile_user_and_group_slugs)
            or EMWF.selected_group_ids(mobile_user_and_group_slugs)
            or EMWF.selected_location_ids(mobile_user_and_group_slugs)
        ):
            track_es_report_load(self.domain, self.slug, len(self.case_owners))
            case_owner_filters.append(case_es.owner(self.case_owners))

        query = query.OR(*case_owner_filters)

        if not self.request.can_access_all_locations:
            query = query_location_restricted_cases(query, self.request)

        search_string = CaseSearchFilter.get_value(self.request, self.domain)
        if search_string:
            query = query.set_query({"query_string": {"query": search_string}})

        return query

    @property
    @memoized
    def es_results(self):
        try:
            return self._build_query().run().raw
        except ESError as e:
            original_exception = e.args[0]
            if isinstance(original_exception, TransportError):
                if hasattr(original_exception.info, "get"):
                    if original_exception.info.get('status') == 400:
                        raise BadRequestError()
            raise e

    @property
    @memoized
    def case_owners(self):
        mobile_user_and_group_slugs = self.request.GET.getlist(EMWF.slug)
        return get_case_owners(self.request, self.domain, mobile_user_and_group_slugs)

    def get_case(self, row):
        if '_source' in row:
            case_dict = row['_source']
        else:
            raise ValueError("Case object is not in search result %s" % row)

        if case_dict['domain'] != self.domain:
            raise Exception("case.domain != self.domain; %r and %r, respectively" % (case_dict['domain'], self.domain))

        return case_dict

    @property
    def shared_pagination_GET_params(self):
        shared_params = super(CaseListMixin, self).shared_pagination_GET_params
        shared_params.append(dict(
            name=SelectOpenCloseFilter.slug,
            value=self.request.GET.get(SelectOpenCloseFilter.slug, '')
        ))
        return shared_params

@location_safe
class CaseListReport(CaseListMixin, ProjectInspectionReport, ReportDataSource):

    # note that this class is not true to the spirit of ReportDataSource; the whole
    # point is the decouple generating the raw report data from the report view/django
    # request. but currently these are too tightly bound to decouple

    name = ugettext_lazy('Case List')
    slug = 'case_list'

    @classmethod
    def get_subpages(cls):
        def _get_case_name(request=None, **context):
            if 'case' in context and context['case'].name:
                return mark_safe(context['case'].name)
            else:
                return _('View Case')

        from corehq.apps.reports.views import CaseDataView
        return [
            {
                'title': _get_case_name,
                'urlname': CaseDataView.urlname,
            },
        ]

    @property
    def can_upgrade_to_case_list_explorer(self):
        if settings.ENTERPRISE_MODE:
            return False

        if self.request.couch_user.is_dimagi and not CASE_LIST_EXPLORER.enabled(self.domain):
            return True

        return False

    @property
    def view_response(self):
        if self.can_upgrade_to_case_list_explorer:
            messages.warning(
                self.request,
                'Hey Dimagi User! Have you tried out the Case List Explorer yet? It might be just what you are looking for!',
                extra_tags='html',
            )
        return super(CaseListReport, self).view_response

    @classmethod
    def display_in_dropdown(cls, domain=None, project=None, user=None):
        if project and project.commtrack_enabled:
            return False
        else:
            return True

    def slugs(self):
        return [
            '_case',
            'case_id',
            'case_name',
            'case_type',
            'detail_url',
            'is_open',
            'opened_on',
            'modified_on',
            'closed_on',
            'creator_id',
            'creator_name',
            'owner_type',
            'owner_id',
            'owner_name',
            'external_id',
        ]

    def get_data(self):
        for row in self.es_results['hits'].get('hits', []):
            case = self.get_case(row)
            ci = CaseInfo(self, case)
            data = {
                '_case': case,
                'detail_url': ci.case_detail_url,
            }
            data.update((prop, getattr(ci, prop)) for prop in (
                    'case_type', 'case_name', 'case_id', 'external_id',
                    'is_closed', 'opened_on', 'modified_on', 'closed_on',
                ))

            creator = ci.creating_user or {}
            data.update({
                'creator_id': creator.get('id'),
                'creator_name': creator.get('name'),
            })
            owner = ci.owner
            data.update({
                'owner_type': owner[0],
                'owner_id': owner[1]['id'],
                'owner_name': owner[1]['name'],
            })

            yield data

    @property
    def headers(self):
        headers = DataTablesHeader(
            DataTablesColumn(_("Case Type"), prop_name="type.exact"),
            DataTablesColumn(_("Name"), prop_name="name.exact", css_class="case-name-link"),
            DataTablesColumn(_("Owner"), prop_name="owner_display", sortable=False),
            DataTablesColumn(_("Created Date"), prop_name="opened_on"),
            DataTablesColumn(_("Created By"), prop_name="opened_by_display", sortable=False),
            DataTablesColumn(_("Modified Date"), prop_name="modified_on"),
            DataTablesColumn(_("Status"), prop_name="get_status_display", sortable=False)
        )
        headers.custom_sort = [[5, 'desc']]
        return headers

    @property
    def rows(self):
        for data in self.get_data():
            display = CaseDisplay(self, data['_case'])

            yield [
                display.case_type,
                display.case_link,
                display.owner_display,
                display.opened_on,
                display.creating_user,
                display.modified_on,
                display.closed_display
            ]

    def date_to_json(self, date):
        if date:
            return (PhoneTime(date, self.timezone).user_time(self.timezone)
                    .ui_string(USER_DATETIME_FORMAT_WITH_SEC))
        else:
            return ''
<|endoftext|>


<commit_before><commit_msg>feat(table): make default cache capacity configurable<commit_after><|endoftext|>


<commit_before>from subprocess import Popen, PIPE
from pytest import fixture
from proclib.streaming import StreamProcess, \
        StreamResponse, StreamPipe

@fixture
def response(request):
    p = Popen(['echo', 'm'], stdout=PIPE, stdin=PIPE, stderr=PIPE)
    res = StreamResponse(['echo', 'm'], p, p.stdout, p.stderr)
    request.addfinalizer(res.terminate)
    return res

def test_response_returncode(response):
    response.wait()
    assert response.ok

def test_response_contextmanager(response):
    with response:
        assert response.stdout.read() == b'm\n'
        assert not response.stderr.read()
    assert response.stdout.closed
    assert response.stderr.closed

@fixture
def process(request):
    return StreamProcess(['echo', 'm'])

def test_process_run(process):
    res = process.run()
    with res:
        assert res.stdout.read() == 'm\n'
    assert res.ok

@fixture
def pipe(request):
    return StreamPipe([['yes'], ['cat'], ['head', '-n', '5']])

def test_pipe_run(pipe):
    r = pipe.run()
    with r:
        assert r.command[0] == 'head'
        assert r.stdout.read() == 'y\ny\ny\ny\ny\n'

    [p.terminate() for p in r.history]
    assert r.returncode == 0
<commit_msg>more succint tests<commit_after>from pytest import fixture
from proclib.streaming import StreamProcess, StreamPipe

@fixture
def response(request):
    return StreamProcess(['echo', 'm']).run()

def test_response(response):
    with response:
        assert response.stdout.read() == 'm\n'
        assert not response.stderr.read()
    assert response.stdout.closed
    assert response.stderr.closed
    assert response.ok

@fixture
def pipe(request):
    return StreamPipe([['yes'], ['cat'], ['head', '-n', '5']])

def test_pipe_run(pipe):
    r = pipe.run()
    with r:
        assert r.command[0] == 'head'
        assert r.stdout.read() == 'y\ny\ny\ny\ny\n'

    [p.terminate() for p in r.history]
    assert r.returncode == 0
<|endoftext|>


<commit_before># Licensed under a 3-clause BSD style license - see LICENSE.rst

"""
A set of standard astronomical equivalencies.
"""

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

from ..constants import si as _si
from . import si
from . import cgs
from . import astrophys

__all__ = ['parallax', 'spectral', 'spectral_density', 'doppler_radio',
           'doppler_optical', 'doppler_relativistic']

def parallax():
    """
    Returns a list of equivalence pairs that handle the conversion
    between parallax angle and distance.
    """

    return [
        (si.arcsecond, astrophys.parsec, lambda x: 1. / x)
    ]

def spectral():
    """
    Returns a list of equivalence pairs that handle spectral
    wavelength, frequency, and energy equivalences.

    Allows conversions between wavelength units, frequency units and
    energy units as they relate to light.
    """

    return [
        (si.m, si.Hz, lambda x: _si.c.value / x),
        (si.m, si.J, lambda x: (_si.c.value * _si.h.value) / x),
        (si.Hz, si.J, lambda x: _si.h.value * x)
    ]

def spectral_density(sunit, sfactor):
    """
    Returns a list of equivalence pairs that handle spectral density
    with regard to wavelength and frequency.
    """
    c_Aps = _si.c.value * 10 ** 10

    fla = cgs.erg / si.angstrom / si.cm ** 2 / si.s
    fnu = cgs.erg / si.Hz / si.cm ** 2 / si.s
    nufnu = cgs.erg / si.cm ** 2 / si.s
    lafla = nufnu

    def converter(x):
        return x * (sunit.to(si.AA, sfactor, spectral()) ** 2 / c_Aps)

    def iconverter(x):
        return x / (sunit.to(si.AA, sfactor, spectral()) ** 2 / c_Aps)

    def converter_fnu_nufnu(x):
        return x * sunit.to(si.Hz, sfactor, spectral())

    def iconverter_fnu_nufnu(x):
        return x / sunit.to(si.Hz, sfactor, spectral())

    def converter_fla_lafla(x):
        return x * sunit.to(si.AA, sfactor, spectral())

    def iconverter_fla_lafla(x):
        return x / sunit.to(si.AA, sfactor, spectral())

    return [
        (si.AA, fnu, converter, iconverter),
        (fla, fnu, converter, iconverter),
        (si.AA, si.Hz, converter, iconverter),
        (fla, si.Hz, converter, iconverter),
        (fnu, nufnu, converter_fnu_nufnu, iconverter_fnu_nufnu),
        (fla, lafla, converter_fla_lafla, iconverter_fla_lafla),
    ]

def doppler_radio(rest):
    """
    Return the equivalency pairs for the radio convention for velocity:

    http://www.gb.nrao.edu/~fghigo/gbtdoc/doppler.html
    Radio   :math:`V = c \frac{f_0 - f}{f_0}  ;  f(V) = f_0 ( 1 - V/c )`

    Parameters
    ----------
    rest : Quantity
        Any quantity supported by the standard spectral equivalencies
        (wavelength, energy, frequency)

    Example
    -------
    >>> CO_restfreq = 115.27120*u.GHz  # rest frequency of 12 CO 1-0 in GHz
    >>> radio_CO_equiv = doppler_radio(CO_restfreq)
    >>> measured_freq = 115.2832*u.GHz
    >>> doppler_radio = measured_freq.to(u.km/u.s, equivalencies=radio_CO_equiv)
    >>> print doppler_radio
    -31.2090920889 km / s
    """
    restfreq = rest.to(si.Hz, spectral())

    def to_vel(x):
        x = x.to(si.Hz, equivalencies=spectral())
        return (restfreq.value-x) / restfreq.value * _si.c.to('km/s').value

    def from_vel(x):
        return (1-x/_si.c.to('km/s').value) * restfreq

    return [(si.Hz, si.km/si.s, to_vel, from_vel),
            (si.m, si.km/si.s, to_vel, from_vel),
            (si.eV, si.km/si.s, to_vel, from_vel),
            ]

def doppler_optical(rest):
    """
    Return the equivalency pairs for the optical convention for velocity:

    http://www.gb.nrao.edu/~fghigo/gbtdoc/doppler.html
    Optical       :math:`V = c \frac{f_0 - f}{f  }  ;  f(V) = f_0 ( 1 + V/c )^{-1}`

    Parameters
    ----------
    rest : Quantity
        Any quantity supported by the standard spectral equivalencies
        (wavelength, energy, frequency)

    Example
    -------
    >>> CO_restfreq = 115.27120*u.GHz  # rest frequency of 12 CO 1-0 in GHz
    >>> optical_CO_equiv = doppler_optical(CO_restfreq)
    >>> measured_freq = 115.2832*u.GHz
    >>> doppler_optical = measured_freq.to(u.km/u.s, equivalencies=optical_CO_equiv)
    >>> print doppler_optical
    -31.205843488 km / s
    """
    restfreq = rest.to(si.Hz, spectral())

    def to_vel(x):
        x = x.to(si.Hz, equivalencies=spectral())
        return (restfreq.value-x) / x * _si.c.to('km/s').value

    def from_vel(x):
        return (1+x/_si.c.to('km/s').value)**(-1) * restfreq

    return [(si.Hz, si.km/si.s, to_vel, from_vel),
            (si.m, si.km/si.s, to_vel, from_vel),
            (si.eV, si.km/si.s, to_vel, from_vel),
            ]

def doppler_relativistic(rest):
    r"""
    Return the equivalency pairs for the relativistic convention for velocity:

    http://www.gb.nrao.edu/~fghigo/gbtdoc/doppler.html
    Relativistic  :math:`V = c \frac{f_0^2 - f^2}{f_0^2 + f^2} ;  f(V) = f_0 \frac{\left(1 - (V/c)^2\right)^{1/2}}{(1+V/c)}`

    Parameters
    ----------
    rest : Quantity
        Any quantity supported by the standard spectral equivalencies
        (wavelength, energy, frequency)

    Example
    -------
    >>> CO_restfreq = 115.27120*u.GHz  # rest frequency of 12 CO 1-0 in GHz
    >>> relativistic_CO_equiv = doppler_relativistic(CO_restfreq)
    >>> measured_freq = 115.2832*u.GHz
    >>> doppler_relativistic = measured_freq.to(u.km/u.s, equivalencies=relativistic_CO_equiv)
    >>> print doppler_relativistic
    -31.2074676194 km / s
    >>> measured_velocity = 1250 * u.km/u.s
    >>> relativistic_frequency = measured_freq.to(u.GHz, equivalencies=relativistic_CO_equiv)
    >>> print relativistic_frequency
    115.2832 GHz
    """
    restfreq = rest.to(si.Hz, equivalencies=spectral())

    def to_vel(x):
        x = x.to(si.Hz, equivalencies=spectral())
        return (restfreq.value**2-x**2) / (restfreq.value**2+x**2) * _si.c.to('km/s').value

    def from_vel(x):
        return (1-(x/_si.c.to('km/s').value)**2)**0.5 / (1+(x/_si.c.to('km/s').value))

    return [(si.Hz, si.km/si.s, to_vel, from_vel),
            (si.m, si.km/si.s, to_vel, from_vel),
            (si.eV, si.km/si.s, to_vel, from_vel),
            ]
<commit_msg>fixed equivalencies issues, but tests won't run<commit_after># Licensed under a 3-clause BSD style license - see LICENSE.rst

"""
A set of standard astronomical equivalencies.
"""

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

from ..constants import si as _si
from . import si
from . import cgs
from . import astrophys

__all__ = ['parallax', 'spectral', 'spectral_density', 'doppler_radio',
           'doppler_optical', 'doppler_relativistic']

def parallax():
    """
    Returns a list of equivalence pairs that handle the conversion
    between parallax angle and distance.
    """

    return [
        (si.arcsecond, astrophys.parsec, lambda x: 1. / x)
    ]

def spectral():
    """
    Returns a list of equivalence pairs that handle spectral
    wavelength, frequency, and energy equivalences.

    Allows conversions between wavelength units, frequency units and
    energy units as they relate to light.
    """

    return [
        (si.m, si.Hz, lambda x: _si.c.value / x),
        (si.m, si.J, lambda x: (_si.c.value * _si.h.value) / x),
        (si.Hz, si.J, lambda x: _si.h.value * x)
    ]

def spectral_density(sunit, sfactor):
    """
    Returns a list of equivalence pairs that handle spectral density
    with regard to wavelength and frequency.
    """
    c_Aps = _si.c.value * 10 ** 10

    fla = cgs.erg / si.angstrom / si.cm ** 2 / si.s
    fnu = cgs.erg / si.Hz / si.cm ** 2 / si.s
    nufnu = cgs.erg / si.cm ** 2 / si.s
    lafla = nufnu

    def converter(x):
        return x * (sunit.to(si.AA, sfactor, spectral()) ** 2 / c_Aps)

    def iconverter(x):
        return x / (sunit.to(si.AA, sfactor, spectral()) ** 2 / c_Aps)

    def converter_fnu_nufnu(x):
        return x * sunit.to(si.Hz, sfactor, spectral())

    def iconverter_fnu_nufnu(x):
        return x / sunit.to(si.Hz, sfactor, spectral())

    def converter_fla_lafla(x):
        return x * sunit.to(si.AA, sfactor, spectral())

    def iconverter_fla_lafla(x):
        return x / sunit.to(si.AA, sfactor, spectral())

    return [
        (si.AA, fnu, converter, iconverter),
        (fla, fnu, converter, iconverter),
        (si.AA, si.Hz, converter, iconverter),
        (fla, si.Hz, converter, iconverter),
        (fnu, nufnu, converter_fnu_nufnu, iconverter_fnu_nufnu),
        (fla, lafla, converter_fla_lafla, iconverter_fla_lafla),
    ]

def doppler_radio(rest):
    r"""
    Return the equivalency pairs for the radio convention for velocity:

    http://www.gb.nrao.edu/~fghigo/gbtdoc/doppler.html
    Radio   :math:`V = c \frac{f_0 - f}{f_0}  ;  f(V) = f_0 ( 1 - V/c )`

    Parameters
    ----------
    rest : Quantity
        Any quantity supported by the standard spectral equivalencies
        (wavelength, energy, frequency)

    Example
    -------
    >>> CO_restfreq = 115.27120*u.GHz  # rest frequency of 12 CO 1-0 in GHz
    >>> radio_CO_equiv = doppler_radio(CO_restfreq)
    >>> measured_freq = 115.2832*u.GHz
    >>> doppler_radio = measured_freq.to(u.km/u.s, equivalencies=radio_CO_equiv)
    >>> print doppler_radio
    -31.2090920889 km / s
    """
    ckms = _si.c.to('km/s').value

    def to_vel_freq(x):
        restfreq = rest.to(si.Hz, equivalencies=spectral()).value
        return (restfreq-x) / (restfreq) * ckms
    def from_vel_freq(x):
        restfreq = rest.to(si.Hz, equivalencies=spectral()).value
        voverc = x/ckms
        return restfreq * (1-voverc)

    def to_vel_wav(x):
        restwav = rest.to(si.AA, spectral()).value
        return (x-restwav) / (x) * ckms
    def from_vel_wav(x):
        restwav = rest.to(si.AA, spectral()).value
        return restwav * ckms / (ckms-x)

    def to_vel_en(x):
        resten = rest.to(si.eV, equivalencies=spectral()).value
        return (resten-x) / (resten) * ckms
    def from_vel_freq(x):
        resten = rest.to(si.eV, equivalencies=spectral()).value
        voverc = x/ckms
        return resten * (1-voverc)

    return [(si.Hz, si.km/si.s, to_vel_freq, from_vel_freq),
            (si.AA, si.km/si.s, to_vel_wav, from_vel_wav),
            (si.eV, si.km/si.s, to_vel_en, from_vel_en),
            ]

def doppler_optical(rest):
    r"""
    Return the equivalency pairs for the optical convention for velocity:

    http://www.gb.nrao.edu/~fghigo/gbtdoc/doppler.html
    Optical       :math:`V = c \frac{f_0 - f}{f  }  ;  f(V) = f_0 ( 1 + V/c )^{-1}`

    Parameters
    ----------
    rest : Quantity
        Any quantity supported by the standard spectral equivalencies
        (wavelength, energy, frequency)

    Example
    -------
    >>> CO_restfreq = 115.27120*u.GHz  # rest frequency of 12 CO 1-0 in GHz
    >>> optical_CO_equiv = doppler_optical(CO_restfreq)
    >>> measured_freq = 115.2832*u.GHz
    >>> doppler_optical = measured_freq.to(u.km/u.s, equivalencies=optical_CO_equiv)
    >>> print doppler_optical
    -31.205843488 km / s
    """
    ckms = _si.c.to('km/s').value

    def to_vel_freq(x):
        restfreq = rest.to(si.Hz, equivalencies=spectral()).value
        return ckms * (restfreq-x) / x
    def from_vel_freq(x):
        restfreq = rest.to(si.Hz, equivalencies=spectral()).value
        voverc = x/ckms
        return restfreq / (1+voverc)

    def to_vel_wav(x):
        restwav = rest.to(si.AA, spectral()).value
        return ckms * (x/restwav-1)
    def from_vel_wav(x):
        restwav = rest.to(si.AA, spectral()).value
        voverc = x/ckms
        return restwav * (1+voverc)

    def to_vel_en(x):
        resten = rest.to(si.eV, equivalencies=spectral()).value
        return ckms * (resten-x) / x
    def from_vel_en(x):
        resten = rest.to(si.eV, equivalencies=spectral()).value
        voverc = x/ckms
        return resten / (1+voverc)

    return [(si.Hz, si.km/si.s, to_vel_freq, from_vel_freq),
            (si.AA, si.km/si.s, to_vel_wav, from_vel_wav),
            (si.eV, si.km/si.s, to_vel_en, from_vel_en),
            ]

def doppler_relativistic(rest):
    r"""
    Return the equivalency pairs for the relativistic convention for velocity:

    http://www.gb.nrao.edu/~fghigo/gbtdoc/doppler.html
    Relativistic  :math:`V = c \frac{f_0^2 - f^2}{f_0^2 + f^2} ;  f(V) = f_0 \frac{\left(1 - (V/c)^2\right)^{1/2}}{(1+V/c)}`

    Parameters
    ----------
    rest : Quantity
        Any quantity supported by the standard spectral equivalencies
        (wavelength, energy, frequency)

    Example
    -------
    >>> CO_restfreq = 115.27120*u.GHz  # rest frequency of 12 CO 1-0 in GHz
    >>> relativistic_CO_equiv = doppler_relativistic(CO_restfreq)
    >>> measured_freq = 115.2832*u.GHz
    >>> doppler_relativistic = measured_freq.to(u.km/u.s, equivalencies=relativistic_CO_equiv)
    >>> print doppler_relativistic
    -31.2074676194 km / s
    >>> measured_velocity = 1250 * u.km/u.s
    >>> relativistic_frequency = measured_velocity.to(u.GHz, equivalencies=relativistic_CO_equiv)
    >>> print relativistic_frequency
    114.79156866993587 GHz
    >>> relativistic_wavelength = measured_velocity.to(u.mm, equivalencies=relativistic_CO_equiv)
    >>> print relativistic_wavelength
    2.61162436818 mm
    """

    ckms = _si.c.to('km/s').value

    def to_vel_freq(x):
        restfreq = rest.to(si.Hz, equivalencies=spectral()).value
        return (restfreq**2-x**2) / (restfreq**2+x**2) * ckms
    def from_vel_freq(x):
        restfreq = rest.to(si.Hz, equivalencies=spectral()).value
        voverc = x/ckms
        return restfreq * ((1-voverc) / (1+(voverc)))**0.5

    def to_vel_wav(x):
        restwav = rest.to(si.AA, spectral()).value
        return (x**2-restwav**2) / (restwav**2+x**2) * ckms
    def from_vel_wav(x):
        restwav = rest.to(si.AA, spectral()).value
        voverc = x/ckms
        return restwav * ((1+voverc) / (1-voverc))**0.5

    def to_vel_en(x):
        resten = rest.to(si.eV, spectral()).value
        return (resten**2-x**2) / (resten**2+x**2) * ckms
    def from_vel_en(x):
        resten = rest.to(si.eV, spectral()).value
        voverc = x/ckms
        return resten * ((1-voverc) / (1+(voverc)))**0.5

    return [(si.Hz, si.km/si.s, to_vel_freq, from_vel_freq),
            (si.AA, si.km/si.s, to_vel_wav, from_vel_wav),
            (si.eV, si.km/si.s, to_vel_en, from_vel_en),
            ]
<|endoftext|>


<commit_before>import glob
import os

paths = ['src/*.cpp', 'src/kademlia/*.cpp', 'include/libtorrent/*.hpp', 'include/libtorrent/kademlia/*.hpp', 'include/libtorrent/aux_/*.hpp', 'include/libtorrent/extensions/*.hpp']

os.system('ctags %s' % ' '.join(paths))

files = []

for p in paths:
	files.extend(glob.glob(p))

output = open('todo.rst', 'w+')

for f in files:
	h = open(f)

	state = ''
	line_no = 0

	for line in h:
		line_no += 1
		line = line.strip()
		if 'TODO:' in line and line.startswith('//'):
			line = line.split('TODO:')[1]
			state = 'todo'
			headline = '%s:%d' % (f.replace('_', '\\_'), line_no)
			print >>output, '\n' + headline
			print >>output, ('-' * len(headline)) + '\n'
			print >>output, line.strip()
			continue

		if state == '': continue

		if state == 'todo':
			if line.strip().startswith('//'):
				print >>output, line[2:].strip()
			else:
				state = 'context'
				print >>output, '\n::\n'
				print >>output, '\t%s' % line
			continue

		if state == 'context':
			print >>output, '\t%s' % line
			state = ''

	h.close()

output.close()

<commit_msg>genrate html in gather_todo.py<commit_after>import glob
import os

paths = ['src/*.cpp', 'src/kademlia/*.cpp', 'include/libtorrent/*.hpp', 'include/libtorrent/kademlia/*.hpp', 'include/libtorrent/aux_/*.hpp', 'include/libtorrent/extensions/*.hpp']

os.system('ctags %s' % ' '.join(paths))

files = []

for p in paths:
	files.extend(glob.glob(p))

output = open('todo.rst', 'w+')

for f in files:
	h = open(f)

	state = ''
	line_no = 0

	for line in h:
		line_no += 1
		line = line.strip()
		if 'TODO:' in line and line.startswith('//'):
			line = line.split('TODO:')[1]
			state = 'todo'
			headline = '%s:%d' % (f.replace('_', '\\_'), line_no)
			print >>output, '\n' + headline
			print >>output, ('-' * len(headline)) + '\n'
			print >>output, line.strip()
			continue

		if state == '': continue

		if state == 'todo':
			if line.strip().startswith('//'):
				print >>output, line[2:].strip()
			else:
				state = 'context'
				print >>output, '\n::\n'
				print >>output, '\t%s' % line
			continue

		if state == 'context':
			print >>output, '\t%s' % line
			state = ''

	h.close()

output.close()

os.system('rst2html.py todo.rst >todo.html')

<|endoftext|>


<commit_before>from django.http import HttpResponseNotAllowed, HttpResponseForbidden, HttpResponse, HttpResponseBadRequest
from django.core.urlresolvers import reverse
from django.core.cache import cache
from django import get_version as django_version
from django.core.mail import send_mail, mail_admins
from django.conf import settings
from django.utils.translation import ugettext as _
from django.template import loader
from django.contrib.sites.models import Site
from decorator import decorator

from datetime import datetime, timedelta

__version__ = '0.2.2'

def get_version():
    return __version__

def format_error(error):
    return u"Piston/%s (Django %s) crash report:\n\n%s" % \
        (get_version(), django_version(), error)

class rc_factory(object):
    """
    Status codes.
    """
    CODES = dict(ALL_OK = ('OK', 200),
                 CREATED = ('Created', 201),
                 DELETED = ('', 204), # 204 says "Don't send a body!"
                 BAD_REQUEST = ('Bad Request', 400),
                 FORBIDDEN = ('Forbidden', 401),
                 NOT_FOUND = ('Not Found', 404),
                 DUPLICATE_ENTRY = ('Conflict/Duplicate', 409),
                 NOT_HERE = ('Gone', 410),
                 NOT_IMPLEMENTED = ('Not Implemented', 501),
                 THROTTLED = ('Throttled', 503))

    def __getattr__(self, attr):
        """
        Returns a fresh `HttpResponse` when getting
        an "attribute". This is backwards compatible
        with 0.2, which is important.
        """
        try:
            (r, c) = self.CODES.get(attr)
        except TypeError:
            raise AttributeError(attr)

        return HttpResponse(r, content_type='text/plain', status=c)

rc = rc_factory()

class FormValidationError(Exception):
    def __init__(self, form):
        self.form = form

class HttpStatusCode(Exception):
    def __init__(self, response):
        self.response = response

def validate(v_form, operation='POST'):
    @decorator
    def wrap(f, self, request, *a, **kwa):
        form = v_form(getattr(request, operation))

        if form.is_valid():
            return f(self, request, *a, **kwa)
        else:
            raise FormValidationError(form)
    return wrap

def throttle(max_requests, timeout=60*60, extra=''):
    """
    Simple throttling decorator, caches
    the amount of requests made in cache.

    If used on a view where users are required to
    log in, the username is used, otherwise the
    IP address of the originating request is used.

    Parameters::
     - `max_requests`: The maximum number of requests
     - `timeout`: The timeout for the cache entry (default: 1 hour)
    """
    @decorator
    def wrap(f, self, request, *args, **kwargs):
        if request.user.is_authenticated():
            ident = request.user.username
        else:
            ident = request.META.get('REMOTE_ADDR', None)

        if hasattr(request, 'throttle_extra'):
            """
            Since we want to be able to throttle on a per-
            application basis, it's important that we realize
            that `throttle_extra` might be set on the request
            object. If so, append the identifier name with it.
            """
            ident += ':%s' % str(request.throttle_extra)

        if ident:
            """
            Preferrably we'd use incr/decr here, since they're
            atomic in memcached, but it's in django-trunk so we
            can't use it yet. If someone sees this after it's in
            stable, you can change it here.
            """
            ident += ':%s' % extra

            now = datetime.now()
            ts_key = 'throttle:ts:%s' % ident
            timestamp = cache.get(ts_key)
            offset = now + timedelta(seconds=timeout)

            if timestamp and timestamp < offset:
                t = rc.THROTTLED
                wait = timeout - (offset-timestamp).seconds
                t.content = 'Throttled, wait %d seconds.' % wait

                return t

            count = cache.get(ident, 1)
            cache.set(ident, count+1)

            if count >= max_requests:
                cache.set(ts_key, offset, timeout)
                cache.set(ident, 1)

        return f(self, request, *args, **kwargs)
    return wrap

def coerce_put_post(request):
    """
    Django doesn't particularly understand REST.
    In case we send data over PUT, Django won't
    actually look at the data and load it. We need
    to twist its arm here.

    The try/except abominiation here is due to a bug
    in mod_python. This should fix it.
    """
    if request.method == "PUT":
        try:
            request.method = "POST"
            request._load_post_and_files()
            request.method = "PUT"
        except AttributeError:
            request.META['REQUEST_METHOD'] = 'POST'
            request._load_post_and_files()
            request.META['REQUEST_METHOD'] = 'PUT'

        request.PUT = request.POST

class MimerDataException(Exception):
    """
    Raised if the content_type and data don't match
    """
    pass

class Mimer(object):
    TYPES = dict()

    def __init__(self, request):
        self.request = request

    def is_multipart(self):
        content_type = self.content_type()

        if content_type is not None:
            return content_type.lstrip().startswith('multipart')

        return False

    def loader_for_type(self, ctype):
        """
        Gets a function ref to deserialize content
        for a certain mimetype.
        """
        for loadee, mimes in Mimer.TYPES.iteritems():
            for mime in mimes:
                if ctype.startswith(mime):
                    return loadee

    def content_type(self):
        """
        Returns the content type of the request in all cases where it is
        different than a submitted form - application/x-www-form-urlencoded
        """
        type_formencoded = "application/x-www-form-urlencoded"

        ctype = self.request.META.get('CONTENT_TYPE', type_formencoded)

        if ctype.startswith(type_formencoded):
            return None

        return ctype

    def translate(self):
        """
        Will look at the `Content-type` sent by the client, and maybe
        deserialize the contents into the format they sent. This will
        work for JSON, YAML, XML and Pickle. Since the data is not just
        key-value (and maybe just a list), the data will be placed on
        `request.data` instead, and the handler will have to read from
        there.

        It will also set `request.content_type` so the handler has an easy
        way to tell what's going on. `request.content_type` will always be
        None for form-encoded and/or multipart form data (what your browser sends.)
        """
        ctype = self.content_type()
        self.request.content_type = ctype

        if not self.is_multipart() and ctype:
            loadee = self.loader_for_type(ctype)

            try:
                self.request.data = loadee(self.request.raw_post_data)

                # Reset both POST and PUT from request, as its
                # misleading having their presence around.
                self.request.POST = self.request.PUT = dict()
            except (TypeError, ValueError):
                raise MimerDataException

        return self.request

    @classmethod
    def register(cls, loadee, types):
        cls.TYPES[loadee] = types

    @classmethod
    def unregister(cls, loadee):
        return cls.TYPES.pop(loadee)

def translate_mime(request):
    request = Mimer(request).translate()

def require_mime(*mimes):
    """
    Decorator requiring a certain mimetype. There's a nifty
    helper called `require_extended` below which requires everything
    we support except for post-data via form.
    """
    @decorator
    def wrap(f, self, request, *args, **kwargs):
        m = Mimer(request)
        realmimes = set()

        rewrite = { 'json':   'application/json',
                    'yaml':   'application/x-yaml',
                    'xml':    'text/xml',
                    'pickle': 'application/python-pickle' }

        for idx, mime in enumerate(mimes):
            realmimes.add(rewrite.get(mime, mime))

        if not m.content_type() in realmimes:
            return rc.BAD_REQUEST

        return f(self, request, *args, **kwargs)
    return wrap

require_extended = require_mime('json', 'yaml', 'xml', 'pickle')

def send_consumer_mail(consumer):
    """
    Send a consumer an email depending on what their status is.
    """
    try:
        subject = settings.PISTON_OAUTH_EMAIL_SUBJECTS[consumer.status]
    except AttributeError:
        subject = "Your API Consumer for %s " % Site.objects.get_current().name
        if consumer.status == "accepted":
            subject += "was accepted!"
        elif consumer.status == "canceled":
            subject += "has been canceled."
        elif consumer.status == "rejected":
            subject += "has been rejected."
        else:
            subject += "is awaiting approval."

    template = "piston/mails/consumer_%s.txt" % consumer.status

    body = loader.render_to_string(template,
        { 'consumer' : consumer, 'user' : consumer.user })

    try:
        sender = settings.PISTON_FROM_EMAIL
    except AttributeError:
        sender = settings.DEFAULT_FROM_EMAIL

    send_mail(_(subject), body, sender, [consumer.user.email], fail_silently=True)

    if consumer.status == 'pending':
        mail_admins(_(subject), body, fail_silently=True)

    if settings.DEBUG:
        print "Mail being sent, to=%s" % consumer.user.email
        print "Subject: %s" % _(subject)
        print body

<commit_msg>- Fail silently if email templates are not present. - Don't send email to admins if there are no settings.ADMINS.<commit_after>from django.http import HttpResponseNotAllowed, HttpResponseForbidden, HttpResponse, HttpResponseBadRequest
from django.core.urlresolvers import reverse
from django.core.cache import cache
from django import get_version as django_version
from django.core.mail import send_mail, mail_admins
from django.conf import settings
from django.utils.translation import ugettext as _
from django.template import loader, TemplateDoesNotExist
from django.contrib.sites.models import Site
from decorator import decorator

from datetime import datetime, timedelta

__version__ = '0.2.2'

def get_version():
    return __version__

def format_error(error):
    return u"Piston/%s (Django %s) crash report:\n\n%s" % \
        (get_version(), django_version(), error)

class rc_factory(object):
    """
    Status codes.
    """
    CODES = dict(ALL_OK = ('OK', 200),
                 CREATED = ('Created', 201),
                 DELETED = ('', 204), # 204 says "Don't send a body!"
                 BAD_REQUEST = ('Bad Request', 400),
                 FORBIDDEN = ('Forbidden', 401),
                 NOT_FOUND = ('Not Found', 404),
                 DUPLICATE_ENTRY = ('Conflict/Duplicate', 409),
                 NOT_HERE = ('Gone', 410),
                 NOT_IMPLEMENTED = ('Not Implemented', 501),
                 THROTTLED = ('Throttled', 503))

    def __getattr__(self, attr):
        """
        Returns a fresh `HttpResponse` when getting
        an "attribute". This is backwards compatible
        with 0.2, which is important.
        """
        try:
            (r, c) = self.CODES.get(attr)
        except TypeError:
            raise AttributeError(attr)

        return HttpResponse(r, content_type='text/plain', status=c)

rc = rc_factory()

class FormValidationError(Exception):
    def __init__(self, form):
        self.form = form

class HttpStatusCode(Exception):
    def __init__(self, response):
        self.response = response

def validate(v_form, operation='POST'):
    @decorator
    def wrap(f, self, request, *a, **kwa):
        form = v_form(getattr(request, operation))

        if form.is_valid():
            return f(self, request, *a, **kwa)
        else:
            raise FormValidationError(form)
    return wrap

def throttle(max_requests, timeout=60*60, extra=''):
    """
    Simple throttling decorator, caches
    the amount of requests made in cache.

    If used on a view where users are required to
    log in, the username is used, otherwise the
    IP address of the originating request is used.

    Parameters::
     - `max_requests`: The maximum number of requests
     - `timeout`: The timeout for the cache entry (default: 1 hour)
    """
    @decorator
    def wrap(f, self, request, *args, **kwargs):
        if request.user.is_authenticated():
            ident = request.user.username
        else:
            ident = request.META.get('REMOTE_ADDR', None)

        if hasattr(request, 'throttle_extra'):
            """
            Since we want to be able to throttle on a per-
            application basis, it's important that we realize
            that `throttle_extra` might be set on the request
            object. If so, append the identifier name with it.
            """
            ident += ':%s' % str(request.throttle_extra)

        if ident:
            """
            Preferrably we'd use incr/decr here, since they're
            atomic in memcached, but it's in django-trunk so we
            can't use it yet. If someone sees this after it's in
            stable, you can change it here.
            """
            ident += ':%s' % extra

            now = datetime.now()
            ts_key = 'throttle:ts:%s' % ident
            timestamp = cache.get(ts_key)
            offset = now + timedelta(seconds=timeout)

            if timestamp and timestamp < offset:
                t = rc.THROTTLED
                wait = timeout - (offset-timestamp).seconds
                t.content = 'Throttled, wait %d seconds.' % wait

                return t

            count = cache.get(ident, 1)
            cache.set(ident, count+1)

            if count >= max_requests:
                cache.set(ts_key, offset, timeout)
                cache.set(ident, 1)

        return f(self, request, *args, **kwargs)
    return wrap

def coerce_put_post(request):
    """
    Django doesn't particularly understand REST.
    In case we send data over PUT, Django won't
    actually look at the data and load it. We need
    to twist its arm here.

    The try/except abominiation here is due to a bug
    in mod_python. This should fix it.
    """
    if request.method == "PUT":
        try:
            request.method = "POST"
            request._load_post_and_files()
            request.method = "PUT"
        except AttributeError:
            request.META['REQUEST_METHOD'] = 'POST'
            request._load_post_and_files()
            request.META['REQUEST_METHOD'] = 'PUT'

        request.PUT = request.POST

class MimerDataException(Exception):
    """
    Raised if the content_type and data don't match
    """
    pass

class Mimer(object):
    TYPES = dict()

    def __init__(self, request):
        self.request = request

    def is_multipart(self):
        content_type = self.content_type()

        if content_type is not None:
            return content_type.lstrip().startswith('multipart')

        return False

    def loader_for_type(self, ctype):
        """
        Gets a function ref to deserialize content
        for a certain mimetype.
        """
        for loadee, mimes in Mimer.TYPES.iteritems():
            for mime in mimes:
                if ctype.startswith(mime):
                    return loadee

    def content_type(self):
        """
        Returns the content type of the request in all cases where it is
        different than a submitted form - application/x-www-form-urlencoded
        """
        type_formencoded = "application/x-www-form-urlencoded"

        ctype = self.request.META.get('CONTENT_TYPE', type_formencoded)

        if ctype.startswith(type_formencoded):
            return None

        return ctype

    def translate(self):
        """
        Will look at the `Content-type` sent by the client, and maybe
        deserialize the contents into the format they sent. This will
        work for JSON, YAML, XML and Pickle. Since the data is not just
        key-value (and maybe just a list), the data will be placed on
        `request.data` instead, and the handler will have to read from
        there.

        It will also set `request.content_type` so the handler has an easy
        way to tell what's going on. `request.content_type` will always be
        None for form-encoded and/or multipart form data (what your browser sends.)
        """
        ctype = self.content_type()
        self.request.content_type = ctype

        if not self.is_multipart() and ctype:
            loadee = self.loader_for_type(ctype)

            try:
                self.request.data = loadee(self.request.raw_post_data)

                # Reset both POST and PUT from request, as its
                # misleading having their presence around.
                self.request.POST = self.request.PUT = dict()
            except (TypeError, ValueError):
                raise MimerDataException

        return self.request

    @classmethod
    def register(cls, loadee, types):
        cls.TYPES[loadee] = types

    @classmethod
    def unregister(cls, loadee):
        return cls.TYPES.pop(loadee)

def translate_mime(request):
    request = Mimer(request).translate()

def require_mime(*mimes):
    """
    Decorator requiring a certain mimetype. There's a nifty
    helper called `require_extended` below which requires everything
    we support except for post-data via form.
    """
    @decorator
    def wrap(f, self, request, *args, **kwargs):
        m = Mimer(request)
        realmimes = set()

        rewrite = { 'json':   'application/json',
                    'yaml':   'application/x-yaml',
                    'xml':    'text/xml',
                    'pickle': 'application/python-pickle' }

        for idx, mime in enumerate(mimes):
            realmimes.add(rewrite.get(mime, mime))

        if not m.content_type() in realmimes:
            return rc.BAD_REQUEST

        return f(self, request, *args, **kwargs)
    return wrap

require_extended = require_mime('json', 'yaml', 'xml', 'pickle')

def send_consumer_mail(consumer):
    """
    Send a consumer an email depending on what their status is.
    """
    try:
        subject = settings.PISTON_OAUTH_EMAIL_SUBJECTS[consumer.status]
    except AttributeError:
        subject = "Your API Consumer for %s " % Site.objects.get_current().name
        if consumer.status == "accepted":
            subject += "was accepted!"
        elif consumer.status == "canceled":
            subject += "has been canceled."
        elif consumer.status == "rejected":
            subject += "has been rejected."
        else:
            subject += "is awaiting approval."

    template = "piston/mails/consumer_%s.txt" % consumer.status

    try:
        body = loader.render_to_string(template,
            { 'consumer' : consumer, 'user' : consumer.user })
    except TemplateDoesNotExist:
        """
        They haven't set up the templates, which means they might not want
        these emails sent.
        """
        return

    try:
        sender = settings.PISTON_FROM_EMAIL
    except AttributeError:
        sender = settings.DEFAULT_FROM_EMAIL

    send_mail(_(subject), body, sender, [consumer.user.email], fail_silently=True)

    if consumer.status == 'pending' and len(settings.ADMINS):
        mail_admins(_(subject), body, fail_silently=True)

    if settings.DEBUG:
        print "Mail being sent, to=%s" % consumer.user.email
        print "Subject: %s" % _(subject)
        print body

<|endoftext|>